clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name Driver.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-8/lib/clang/8.0.0 -D HAVE_ROUND -D LLDB_CONFIGURATION_RELEASE -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lldb/tools/driver -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/tools/driver -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lldb/include -I /build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/include -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/include -I /build/llvm-toolchain-snapshot-8~svn345461/include -I /usr/include/python2.7 -I /build/llvm-toolchain-snapshot-8~svn345461/tools/clang/include -I /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lldb/../clang/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/include/clang/8.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-8/lib/clang/8.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-deprecated-register -Wno-vla-extension -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-8~svn345461/build-llvm/tools/lldb/tools/driver -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-10-27-211344-32123-1 -x c++ /build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/tools/driver/Driver.cpp -faddrsig
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #include "Driver.h" |
11 | |
12 | #include <algorithm> |
13 | #include <atomic> |
14 | #include <bitset> |
15 | #include <csignal> |
16 | #include <fcntl.h> |
17 | #include <limits.h> |
18 | #include <stdio.h> |
19 | #include <stdlib.h> |
20 | #include <string.h> |
21 | |
22 | |
23 | #if defined(_WIN32) |
24 | #include <fcntl.h> |
25 | #include <io.h> |
26 | #else |
27 | #include <unistd.h> |
28 | #endif |
29 | |
30 | #include <string> |
31 | |
32 | #include "lldb/API/SBBreakpoint.h" |
33 | #include "lldb/API/SBCommandInterpreter.h" |
34 | #include "lldb/API/SBCommandReturnObject.h" |
35 | #include "lldb/API/SBCommunication.h" |
36 | #include "lldb/API/SBDebugger.h" |
37 | #include "lldb/API/SBEvent.h" |
38 | #include "lldb/API/SBHostOS.h" |
39 | #include "lldb/API/SBLanguageRuntime.h" |
40 | #include "lldb/API/SBListener.h" |
41 | #include "lldb/API/SBProcess.h" |
42 | #include "lldb/API/SBStream.h" |
43 | #include "lldb/API/SBStringList.h" |
44 | #include "lldb/API/SBTarget.h" |
45 | #include "lldb/API/SBThread.h" |
46 | #include "llvm/ADT/StringRef.h" |
47 | #include "llvm/Support/ConvertUTF.h" |
48 | #include "llvm/Support/PrettyStackTrace.h" |
49 | #include "llvm/Support/Signals.h" |
50 | #include <thread> |
51 | #include <utility> |
52 | |
53 | #if !defined(__APPLE__) |
54 | #include "llvm/Support/DataTypes.h" |
55 | #endif |
56 | |
57 | using namespace lldb; |
58 | |
59 | static void reset_stdin_termios(); |
60 | static bool g_old_stdin_termios_is_valid = false; |
61 | static struct termios g_old_stdin_termios; |
62 | |
63 | static Driver *g_driver = NULL__null; |
64 | |
65 | |
66 | |
67 | static void reset_stdin_termios() { |
68 | if (g_old_stdin_termios_is_valid) { |
69 | g_old_stdin_termios_is_valid = false; |
70 | ::tcsetattr(STDIN_FILENO0, TCSANOW0, &g_old_stdin_termios); |
71 | } |
72 | } |
73 | |
74 | typedef struct { |
75 | uint32_t usage_mask; |
76 | |
77 | |
78 | bool required; |
79 | const char *long_option; |
80 | int short_option; |
81 | int option_has_arg; |
82 | uint32_t completion_type; |
83 | |
84 | lldb::CommandArgumentType argument_type; |
85 | const char *usage_text; |
86 | |
87 | |
88 | } OptionDefinition; |
89 | |
90 | #define LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4) LLDB_OPT_SET_3(1U << 2) | LLDB_OPT_SET_4(1U << 3) | LLDB_OPT_SET_5(1U << 4) |
91 | #define LLDB_4_TO_5(1U << 3) | (1U << 4) LLDB_OPT_SET_4(1U << 3) | LLDB_OPT_SET_5(1U << 4) |
92 | |
93 | static constexpr OptionDefinition g_options[] = { |
94 | {LLDB_OPT_SET_1(1U << 0), true, "help", 'h', no_argument0, 0, eArgTypeNone, |
95 | "Prints out the usage information for the LLDB debugger."}, |
96 | {LLDB_OPT_SET_2(1U << 1), true, "version", 'v', no_argument0, 0, eArgTypeNone, |
97 | "Prints out the current version number of the LLDB debugger."}, |
98 | {LLDB_OPT_SET_3(1U << 2), true, "arch", 'a', required_argument1, 0, |
99 | eArgTypeArchitecture, |
100 | "Tells the debugger to use the specified architecture when starting and " |
101 | "running the program. <architecture> must " |
102 | "be one of the architectures for which the program was compiled."}, |
103 | {LLDB_OPT_SET_3(1U << 2), true, "file", 'f', required_argument1, 0, eArgTypeFilename, |
104 | "Tells the debugger to use the file <filename> as the program to be " |
105 | "debugged."}, |
106 | {LLDB_OPT_SET_3(1U << 2), false, "core", 'c', required_argument1, 0, eArgTypeFilename, |
107 | "Tells the debugger to use the fullpath to <path> as the core file."}, |
108 | {LLDB_OPT_SET_5(1U << 4), true, "attach-pid", 'p', required_argument1, 0, eArgTypePid, |
109 | "Tells the debugger to attach to a process with the given pid."}, |
110 | {LLDB_OPT_SET_4(1U << 3), true, "attach-name", 'n', required_argument1, 0, |
111 | eArgTypeProcessName, |
112 | "Tells the debugger to attach to a process with the given name."}, |
113 | {LLDB_OPT_SET_4(1U << 3), true, "wait-for", 'w', no_argument0, 0, eArgTypeNone, |
114 | "Tells the debugger to wait for a process with the given pid or name to " |
115 | "launch before attaching."}, |
116 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "source", 's', required_argument1, 0, eArgTypeFilename, |
117 | "Tells the debugger to read in and execute the lldb commands in the given " |
118 | "file, after any file provided on the command line has been loaded."}, |
119 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "one-line", 'o', required_argument1, 0, eArgTypeNone, |
120 | "Tells the debugger to execute this one-line lldb command after any file " |
121 | "provided on the command line has been loaded."}, |
122 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "source-before-file", 'S', required_argument1, 0, |
123 | eArgTypeFilename, "Tells the debugger to read in and execute the lldb " |
124 | "commands in the given file, before any file provided " |
125 | "on the command line has been loaded."}, |
126 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "one-line-before-file", 'O', required_argument1, 0, |
127 | eArgTypeNone, "Tells the debugger to execute this one-line lldb command " |
128 | "before any file provided on the command line has been " |
129 | "loaded."}, |
130 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "one-line-on-crash", 'k', required_argument1, 0, |
131 | eArgTypeNone, "When in batch mode, tells the debugger to execute this " |
132 | "one-line lldb command if the target crashes."}, |
133 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "source-on-crash", 'K', required_argument1, 0, |
134 | eArgTypeFilename, "When in batch mode, tells the debugger to source this " |
135 | "file of lldb commands if the target crashes."}, |
136 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "source-quietly", 'Q', no_argument0, 0, eArgTypeNone, |
137 | "Tells the debugger to execute this one-line lldb command before any file " |
138 | "provided on the command line has been loaded."}, |
139 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "batch", 'b', no_argument0, 0, eArgTypeNone, |
140 | "Tells the debugger to run the commands from -s, -S, -o & -O, and " |
141 | "then quit. However if any run command stopped due to a signal or crash, " |
142 | "the debugger will return to the interactive prompt at the place of the " |
143 | "crash."}, |
144 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "editor", 'e', no_argument0, 0, eArgTypeNone, |
145 | "Tells the debugger to open source files using the host's \"external " |
146 | "editor\" mechanism."}, |
147 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "no-lldbinit", 'x', no_argument0, 0, eArgTypeNone, |
148 | "Do not automatically parse any '.lldbinit' files."}, |
149 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "no-use-colors", 'X', no_argument0, 0, eArgTypeNone, |
150 | "Do not use colors."}, |
151 | {LLDB_OPT_SET_6(1U << 5), true, "python-path", 'P', no_argument0, 0, eArgTypeNone, |
152 | "Prints out the path to the lldb.py file for this version of lldb."}, |
153 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "script-language", 'l', required_argument1, 0, |
154 | eArgTypeScriptLang, |
155 | "Tells the debugger to use the specified scripting language for " |
156 | "user-defined scripts, rather than the default. " |
157 | "Valid scripting languages that can be specified include Python, Perl, " |
158 | "Ruby and Tcl. Currently only the Python " |
159 | "extensions have been implemented."}, |
160 | {LLDB_3_TO_5(1U << 2) | (1U << 3) | (1U << 4), false, "debug", 'd', no_argument0, 0, eArgTypeNone, |
161 | "Tells the debugger to print out extra information for debugging itself."}, |
162 | {LLDB_OPT_SET_7(1U << 6), true, "repl", 'r', optional_argument2, 0, eArgTypeNone, |
163 | "Runs lldb in REPL mode with a stub process."}, |
164 | {LLDB_OPT_SET_7(1U << 6), true, "repl-language", 'R', required_argument1, 0, |
165 | eArgTypeNone, "Chooses the language for the REPL."}}; |
166 | |
167 | static constexpr auto g_num_options = sizeof(g_options)/sizeof(OptionDefinition); |
168 | |
169 | static const uint32_t last_option_set_with_args = 2; |
170 | |
171 | Driver::Driver() |
172 | : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)), |
173 | m_option_data() { |
174 | |
175 | |
176 | m_debugger.SetCloseInputOnEOF(false); |
177 | g_driver = this; |
178 | } |
179 | |
180 | Driver::~Driver() { g_driver = NULL__null; } |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | |
189 | |
190 | void OutputFormattedUsageText(FILE *out, int indent, const char *text, |
191 | int output_max_columns) { |
192 | int len = strlen(text); |
193 | std::string text_string(text); |
194 | |
195 | |
196 | if (indent >= output_max_columns) |
197 | indent = 0; |
198 | |
199 | |
200 | |
201 | if (len + indent < output_max_columns) |
202 | |
203 | fprintf(out, "%*s%s\n", indent, "", text); |
204 | else { |
205 | |
206 | int text_width = output_max_columns - indent - 1; |
207 | int start = 0; |
208 | int end = start; |
209 | int final_end = len; |
210 | int sub_len; |
211 | |
212 | while (end < final_end) { |
213 | |
214 | |
215 | while ((start < final_end) && (text[start] == ' ')) |
216 | start++; |
217 | |
218 | end = start + text_width; |
219 | if (end > final_end) |
220 | end = final_end; |
221 | else { |
222 | |
223 | |
224 | while (end > start && text[end] != ' ' && text[end] != '\t' && |
225 | text[end] != '\n') |
226 | end--; |
227 | } |
228 | sub_len = end - start; |
229 | std::string substring = text_string.substr(start, sub_len); |
230 | fprintf(out, "%*s%s\n", indent, "", substring.c_str()); |
231 | start = end + 1; |
232 | } |
233 | } |
234 | } |
235 | |
236 | static void ShowUsage(FILE *out, Driver::OptionData data) { |
237 | uint32_t screen_width = 80; |
238 | uint32_t indent_level = 0; |
239 | const char *name = "lldb"; |
240 | |
241 | fprintf(out, "\nUsage:\n\n"); |
242 | |
243 | indent_level += 2; |
244 | |
245 | |
246 | |
247 | |
248 | |
249 | |
250 | |
251 | uint32_t num_option_sets = 0; |
252 | |
253 | for (const auto &opt : g_options) { |
254 | uint32_t this_usage_mask = opt.usage_mask; |
255 | if (this_usage_mask == LLDB_OPT_SET_ALL0xFFFFFFFFU) { |
256 | if (num_option_sets == 0) |
257 | num_option_sets = 1; |
258 | } else { |
259 | for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS32; j++) { |
260 | if (this_usage_mask & 1 << j) { |
261 | if (num_option_sets <= j) |
262 | num_option_sets = j + 1; |
263 | } |
264 | } |
265 | } |
266 | } |
267 | |
268 | for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++) { |
269 | uint32_t opt_set_mask; |
270 | |
271 | opt_set_mask = 1 << opt_set; |
272 | |
273 | if (opt_set > 0) |
274 | fprintf(out, "\n"); |
275 | fprintf(out, "%*s%s", indent_level, "", name); |
276 | bool is_help_line = false; |
277 | |
278 | for (const auto &opt : g_options) { |
279 | if (opt.usage_mask & opt_set_mask) { |
280 | CommandArgumentType arg_type = opt.argument_type; |
281 | const char *arg_name = |
282 | SBCommandInterpreter::GetArgumentTypeAsCString(arg_type); |
283 | |
284 | |
285 | |
286 | if (opt.short_option == 'h') |
287 | is_help_line = true; |
288 | |
289 | if (opt.required) { |
290 | if (opt.option_has_arg == required_argument1) |
291 | fprintf(out, " -%c <%s>", opt.short_option, arg_name); |
292 | else if (opt.option_has_arg == optional_argument2) |
293 | fprintf(out, " -%c [<%s>]", opt.short_option, arg_name); |
294 | else |
295 | fprintf(out, " -%c", opt.short_option); |
296 | } else { |
297 | if (opt.option_has_arg == required_argument1) |
298 | fprintf(out, " [-%c <%s>]", opt.short_option, arg_name); |
299 | else if (opt.option_has_arg == optional_argument2) |
300 | fprintf(out, " [-%c [<%s>]]", opt.short_option, |
301 | arg_name); |
302 | else |
303 | fprintf(out, " [-%c]", opt.short_option); |
304 | } |
305 | } |
306 | } |
307 | if (!is_help_line && (opt_set <= last_option_set_with_args)) |
308 | fprintf(out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]"); |
309 | } |
310 | |
311 | fprintf(out, "\n\n"); |
312 | |
313 | |
314 | |
315 | |
316 | |
317 | |
318 | |
319 | |
320 | |
321 | |
322 | |
323 | |
324 | Driver::OptionData::OptionSet options_seen; |
325 | Driver::OptionData::OptionSet::iterator pos; |
326 | |
327 | indent_level += 5; |
328 | |
329 | for (const auto &opt : g_options) { |
330 | |
331 | pos = options_seen.find(opt.short_option); |
332 | if (pos == options_seen.end()) { |
333 | CommandArgumentType arg_type = opt.argument_type; |
334 | const char *arg_name = |
335 | SBCommandInterpreter::GetArgumentTypeAsCString(arg_type); |
336 | |
337 | options_seen.insert(opt.short_option); |
338 | fprintf(out, "%*s-%c ", indent_level, "", opt.short_option); |
339 | if (arg_type != eArgTypeNone) |
340 | fprintf(out, "<%s>", arg_name); |
341 | fprintf(out, "\n"); |
342 | fprintf(out, "%*s--%s ", indent_level, "", opt.long_option); |
343 | if (arg_type != eArgTypeNone) |
344 | fprintf(out, "<%s>", arg_name); |
345 | fprintf(out, "\n"); |
346 | indent_level += 5; |
347 | OutputFormattedUsageText(out, indent_level, opt.usage_text, |
348 | screen_width); |
349 | indent_level -= 5; |
350 | fprintf(out, "\n"); |
351 | } |
352 | } |
353 | |
354 | indent_level -= 5; |
355 | |
356 | fprintf(out, "\n%*sNotes:\n", indent_level, ""); |
357 | indent_level += 5; |
358 | |
359 | fprintf(out, |
360 | "\n%*sMultiple \"-s\" and \"-o\" options can be provided. They will " |
361 | "be processed" |
362 | "\n%*sfrom left to right in order, with the source files and commands" |
363 | "\n%*sinterleaved. The same is true of the \"-S\" and \"-O\" " |
364 | "options. The before" |
365 | "\n%*sfile and after file sets can intermixed freely, the command " |
366 | "parser will" |
367 | "\n%*ssort them out. The order of the file specifiers (\"-c\", " |
368 | "\"-f\", etc.) is" |
369 | "\n%*snot significant in this regard.\n\n", |
370 | indent_level, "", indent_level, "", indent_level, "", indent_level, |
371 | "", indent_level, "", indent_level, ""); |
372 | |
373 | fprintf( |
374 | out, |
375 | "\n%*sIf you don't provide -f then the first argument will be the file " |
376 | "to be" |
377 | "\n%*sdebugged which means that '%s -- <filename> [<ARG1> [<ARG2>]]' also" |
378 | "\n%*sworks. But remember to end the options with \"--\" if any of your" |
379 | "\n%*sarguments have a \"-\" in them.\n\n", |
380 | indent_level, "", indent_level, "", name, indent_level, "", indent_level, |
381 | ""); |
382 | } |
383 | |
384 | static void BuildGetOptTable(std::vector<option> &getopt_table) { |
385 | getopt_table.resize(g_num_options + 1); |
386 | |
387 | std::bitset<256> option_seen; |
388 | uint32_t j = 0; |
389 | for (const auto &opt : g_options) { |
390 | char short_opt = opt.short_option; |
391 | |
392 | if (option_seen.test(short_opt) == false) { |
393 | getopt_table[j].name = opt.long_option; |
394 | getopt_table[j].has_arg = opt.option_has_arg; |
395 | getopt_table[j].flag = NULL__null; |
396 | getopt_table[j].val = opt.short_option; |
397 | option_seen.set(short_opt); |
398 | ++j; |
399 | } |
400 | } |
401 | |
402 | getopt_table[j].name = NULL__null; |
403 | getopt_table[j].has_arg = 0; |
404 | getopt_table[j].flag = NULL__null; |
405 | getopt_table[j].val = 0; |
406 | } |
407 | |
408 | Driver::OptionData::OptionData() |
409 | : m_args(), m_script_lang(lldb::eScriptLanguageDefault), m_core_file(), |
410 | m_crash_log(), m_initial_commands(), m_after_file_commands(), |
411 | m_after_crash_commands(), m_debug_mode(false), m_source_quietly(false), |
412 | m_print_version(false), m_print_python_path(false), m_print_help(false), |
413 | m_wait_for(false), m_repl(false), m_repl_lang(eLanguageTypeUnknown), |
414 | m_repl_options(), m_process_name(), |
415 | m_process_pid(LLDB_INVALID_PROCESS_ID0), m_use_external_editor(false), |
416 | m_batch(false), m_seen_options() {} |
417 | |
418 | Driver::OptionData::~OptionData() {} |
419 | |
420 | void Driver::OptionData::Clear() { |
421 | m_args.clear(); |
422 | m_script_lang = lldb::eScriptLanguageDefault; |
423 | m_initial_commands.clear(); |
424 | m_after_file_commands.clear(); |
425 | |
426 | |
427 | |
428 | |
429 | SBFileSpec local_lldbinit(".lldbinit", true); |
430 | |
431 | SBFileSpec homedir_dot_lldb = SBHostOS::GetUserHomeDirectory(); |
432 | homedir_dot_lldb.AppendPathComponent(".lldbinit"); |
433 | |
434 | |
435 | |
436 | |
437 | if (local_lldbinit.Exists() && |
438 | strcmp(local_lldbinit.GetDirectory(), homedir_dot_lldb.GetDirectory()) != |
439 | 0) { |
440 | char path[2048]; |
441 | local_lldbinit.GetPath(path, 2047); |
442 | InitialCmdEntry entry(path, true, true, true); |
443 | m_after_file_commands.push_back(entry); |
444 | } |
445 | |
446 | m_debug_mode = false; |
447 | m_source_quietly = false; |
448 | m_print_help = false; |
449 | m_print_version = false; |
450 | m_print_python_path = false; |
451 | m_use_external_editor = false; |
452 | m_wait_for = false; |
453 | m_process_name.erase(); |
454 | m_batch = false; |
455 | m_after_crash_commands.clear(); |
456 | |
457 | m_process_pid = LLDB_INVALID_PROCESS_ID0; |
458 | } |
459 | |
460 | void Driver::OptionData::AddInitialCommand(const char *command, |
461 | CommandPlacement placement, |
462 | bool is_file, SBError &error) { |
463 | std::vector<InitialCmdEntry> *command_set; |
464 | switch (placement) { |
465 | case eCommandPlacementBeforeFile: |
466 | command_set = &(m_initial_commands); |
467 | break; |
468 | case eCommandPlacementAfterFile: |
469 | command_set = &(m_after_file_commands); |
470 | break; |
471 | case eCommandPlacementAfterCrash: |
472 | command_set = &(m_after_crash_commands); |
473 | break; |
474 | } |
475 | |
476 | if (is_file) { |
477 | SBFileSpec file(command); |
478 | if (file.Exists()) |
479 | command_set->push_back(InitialCmdEntry(command, is_file, false)); |
480 | else if (file.ResolveExecutableLocation()) { |
481 | char final_path[PATH_MAX4096]; |
482 | file.GetPath(final_path, sizeof(final_path)); |
483 | command_set->push_back(InitialCmdEntry(final_path, is_file, false)); |
484 | } else |
485 | error.SetErrorStringWithFormat( |
486 | "file specified in --source (-s) option doesn't exist: '%s'", optarg); |
487 | } else |
488 | command_set->push_back(InitialCmdEntry(command, is_file, false)); |
489 | } |
490 | |
491 | void Driver::ResetOptionValues() { m_option_data.Clear(); } |
492 | |
493 | const char *Driver::GetFilename() const { |
494 | if (m_option_data.m_args.empty()) |
495 | return NULL__null; |
496 | return m_option_data.m_args.front().c_str(); |
497 | } |
498 | |
499 | const char *Driver::GetCrashLogFilename() const { |
500 | if (m_option_data.m_crash_log.empty()) |
501 | return NULL__null; |
502 | return m_option_data.m_crash_log.c_str(); |
503 | } |
504 | |
505 | lldb::ScriptLanguage Driver::GetScriptLanguage() const { |
506 | return m_option_data.m_script_lang; |
507 | } |
508 | |
509 | void Driver::WriteCommandsForSourcing(CommandPlacement placement, |
510 | SBStream &strm) { |
511 | std::vector<OptionData::InitialCmdEntry> *command_set; |
512 | switch (placement) { |
513 | case eCommandPlacementBeforeFile: |
514 | command_set = &m_option_data.m_initial_commands; |
515 | break; |
516 | case eCommandPlacementAfterFile: |
517 | command_set = &m_option_data.m_after_file_commands; |
518 | break; |
519 | case eCommandPlacementAfterCrash: |
520 | command_set = &m_option_data.m_after_crash_commands; |
521 | break; |
522 | } |
523 | |
524 | for (const auto &command_entry : *command_set) { |
525 | const char *command = command_entry.contents.c_str(); |
526 | if (command_entry.is_file) { |
527 | |
528 | |
529 | |
530 | |
531 | if (command_entry.is_cwd_lldbinit_file_read) { |
532 | SBStringList strlist = m_debugger.GetInternalVariableValue( |
533 | "target.load-cwd-lldbinit", m_debugger.GetInstanceName()); |
534 | if (strlist.GetSize() == 1 && |
535 | strcmp(strlist.GetStringAtIndex(0), "warn") == 0) { |
536 | FILE *output = m_debugger.GetOutputFileHandle(); |
537 | ::fprintf( |
538 | output, |
539 | "There is a .lldbinit file in the current directory which is not " |
540 | "being read.\n" |
541 | "To silence this warning without sourcing in the local " |
542 | ".lldbinit,\n" |
543 | "add the following to the lldbinit file in your home directory:\n" |
544 | " settings set target.load-cwd-lldbinit false\n" |
545 | "To allow lldb to source .lldbinit files in the current working " |
546 | "directory,\n" |
547 | "set the value of this variable to true. Only do so if you " |
548 | "understand and\n" |
549 | "accept the security risk.\n"); |
550 | return; |
551 | } |
552 | if (strlist.GetSize() == 1 && |
553 | strcmp(strlist.GetStringAtIndex(0), "false") == 0) { |
554 | return; |
555 | } |
556 | } |
557 | bool source_quietly = |
558 | m_option_data.m_source_quietly || command_entry.source_quietly; |
559 | strm.Printf("command source -s %i '%s'\n", source_quietly, command); |
560 | } else |
561 | strm.Printf("%s\n", command); |
562 | } |
563 | } |
564 | |
565 | bool Driver::GetDebugMode() const { return m_option_data.m_debug_mode; } |
566 | |
567 | |
568 | |
569 | |
570 | |
571 | |
572 | |
573 | |
574 | |
575 | SBError Driver::ParseArgs(int argc, const char *argv[], FILE *out_fh, |
576 | bool &exiting) { |
577 | static_assert(g_num_options > 0, "cannot handle arguments"); |
578 | |
579 | ResetOptionValues(); |
580 | |
581 | SBError error; |
582 | std::vector<option> long_options_vector; |
583 | BuildGetOptTable(long_options_vector); |
584 | if (long_options_vector.empty()) { |
| 2 | | Assuming the condition is false | |
|
| |
585 | error.SetErrorStringWithFormat("invalid long options"); |
586 | return error; |
587 | } |
588 | |
589 | |
590 | std::string option_string; |
591 | auto sentinel_it = std::prev(std::end(long_options_vector)); |
592 | for (auto long_opt_it = std::begin(long_options_vector); |
| 4 | | Loop condition is false. Execution continues on line 620 | |
|
593 | long_opt_it != sentinel_it; ++long_opt_it) { |
594 | if (long_opt_it->flag == nullptr) { |
595 | option_string.push_back(static_cast<char>(long_opt_it->val)); |
596 | switch (long_opt_it->has_arg) { |
597 | default: |
598 | case no_argument0: |
599 | break; |
600 | case required_argument1: |
601 | option_string.push_back(':'); |
602 | break; |
603 | case optional_argument2: |
604 | option_string.append("::"); |
605 | break; |
606 | } |
607 | } |
608 | } |
609 | |
610 | |
611 | |
612 | |
613 | |
614 | |
615 | |
616 | |
617 | |
618 | |
619 | |
620 | m_debugger.SkipLLDBInitFiles(false); |
621 | m_debugger.SkipAppInitFiles(false); |
622 | |
623 | |
624 | #if __GLIBC__2 |
625 | optind = 0; |
626 | #else |
627 | optreset = 1; |
628 | optind = 1; |
629 | #endif |
630 | int val; |
631 | while (1) { |
| 5 | | Loop condition is true. Entering loop body | |
|
| 22 | | Loop condition is true. Entering loop body | |
|
632 | int long_options_index = -1; |
633 | val = ::getopt_long_only(argc, const_cast<char **>(argv), |
634 | option_string.c_str(), long_options_vector.data(), |
635 | &long_options_index); |
636 | |
637 | if (val == -1) |
| 6 | | Assuming the condition is false | |
|
| |
| 23 | | Assuming the condition is false | |
|
| |
638 | break; |
639 | else if (val == '?') { |
| 8 | | Assuming the condition is false | |
|
| |
| 25 | | Assuming the condition is false | |
|
| |
640 | m_option_data.m_print_help = true; |
641 | error.SetErrorStringWithFormat("unknown or ambiguous option"); |
642 | break; |
643 | } else if (val == 0) |
| 10 | | Assuming 'val' is not equal to 0 | |
|
| |
| 27 | | Assuming 'val' is not equal to 0 | |
|
| |
644 | continue; |
645 | else { |
646 | m_option_data.m_seen_options.insert((char)val); |
647 | if (long_options_index == -1) { |
| 12 | | Assuming the condition is false | |
|
| |
| 29 | | Assuming the condition is false | |
|
| |
648 | auto long_opt_it = std::find_if(std::begin(long_options_vector), sentinel_it, |
649 | [val](const option &long_option) { return long_option.val == val; }); |
650 | if (std::end(long_options_vector) != long_opt_it) |
651 | long_options_index = |
652 | std::distance(std::begin(long_options_vector), long_opt_it); |
653 | } |
654 | |
655 | if (long_options_index >= 0) { |
| 14 | | Assuming 'long_options_index' is >= 0 | |
|
| |
| 31 | | Assuming 'long_options_index' is >= 0 | |
|
| |
656 | const int short_option = g_options[long_options_index].short_option; |
657 | |
658 | switch (short_option) { |
| 16 | | Control jumps to 'case 114:' at line 756 | |
|
| 33 | | Control jumps to 'case 112:' at line 748 | |
|
659 | case 'h': |
660 | m_option_data.m_print_help = true; |
661 | break; |
662 | |
663 | case 'v': |
664 | m_option_data.m_print_version = true; |
665 | break; |
666 | |
667 | case 'P': |
668 | m_option_data.m_print_python_path = true; |
669 | break; |
670 | |
671 | case 'b': |
672 | m_option_data.m_batch = true; |
673 | break; |
674 | |
675 | case 'c': { |
676 | SBFileSpec file(optarg); |
677 | if (file.Exists()) { |
678 | m_option_data.m_core_file = optarg; |
679 | } else |
680 | error.SetErrorStringWithFormat( |
681 | "file specified in --core (-c) option doesn't exist: '%s'", |
682 | optarg); |
683 | } break; |
684 | |
685 | case 'e': |
686 | m_option_data.m_use_external_editor = true; |
687 | break; |
688 | |
689 | case 'x': |
690 | m_debugger.SkipLLDBInitFiles(true); |
691 | m_debugger.SkipAppInitFiles(true); |
692 | break; |
693 | |
694 | case 'X': |
695 | m_debugger.SetUseColor(false); |
696 | break; |
697 | |
698 | case 'f': { |
699 | SBFileSpec file(optarg); |
700 | if (file.Exists()) { |
701 | m_option_data.m_args.push_back(optarg); |
702 | } else if (file.ResolveExecutableLocation()) { |
703 | char path[PATH_MAX4096]; |
704 | file.GetPath(path, sizeof(path)); |
705 | m_option_data.m_args.push_back(path); |
706 | } else |
707 | error.SetErrorStringWithFormat( |
708 | "file specified in --file (-f) option doesn't exist: '%s'", |
709 | optarg); |
710 | } break; |
711 | |
712 | case 'a': |
713 | if (!m_debugger.SetDefaultArchitecture(optarg)) |
714 | error.SetErrorStringWithFormat( |
715 | "invalid architecture in the -a or --arch option: '%s'", |
716 | optarg); |
717 | break; |
718 | |
719 | case 'l': |
720 | m_option_data.m_script_lang = m_debugger.GetScriptingLanguage(optarg); |
721 | break; |
722 | |
723 | case 'd': |
724 | m_option_data.m_debug_mode = true; |
725 | break; |
726 | |
727 | case 'Q': |
728 | m_option_data.m_source_quietly = true; |
729 | break; |
730 | |
731 | case 'K': |
732 | m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, |
733 | true, error); |
734 | break; |
735 | case 'k': |
736 | m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, |
737 | false, error); |
738 | break; |
739 | |
740 | case 'n': |
741 | m_option_data.m_process_name = optarg; |
742 | break; |
743 | |
744 | case 'w': |
745 | m_option_data.m_wait_for = true; |
746 | break; |
747 | |
748 | case 'p': { |
749 | char *remainder; |
750 | m_option_data.m_process_pid = strtol(optarg, &remainder, 0); |
| 34 | | Null pointer passed as an argument to a 'nonnull' parameter |
|
751 | if (remainder == optarg || *remainder != '\0') |
752 | error.SetErrorStringWithFormat( |
753 | "Could not convert process PID: \"%s\" into a pid.", optarg); |
754 | } break; |
755 | |
756 | case 'r': |
757 | m_option_data.m_repl = true; |
758 | if (optarg && optarg[0]) |
| 17 | | Assuming 'optarg' is null | |
|
| 18 | | Assuming pointer value is null | |
|
759 | m_option_data.m_repl_options = optarg; |
760 | else |
761 | m_option_data.m_repl_options.clear(); |
762 | break; |
| 19 | | Execution continues on line 798 | |
|
763 | |
764 | case 'R': |
765 | m_option_data.m_repl_lang = |
766 | SBLanguageRuntime::GetLanguageTypeFromString(optarg); |
767 | if (m_option_data.m_repl_lang == eLanguageTypeUnknown) { |
768 | error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"", |
769 | optarg); |
770 | } |
771 | break; |
772 | |
773 | case 's': |
774 | m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, |
775 | true, error); |
776 | break; |
777 | case 'o': |
778 | m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, |
779 | false, error); |
780 | break; |
781 | case 'S': |
782 | m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, |
783 | true, error); |
784 | break; |
785 | case 'O': |
786 | m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, |
787 | false, error); |
788 | break; |
789 | default: |
790 | m_option_data.m_print_help = true; |
791 | error.SetErrorStringWithFormat("unrecognized option %c", |
792 | short_option); |
793 | break; |
794 | } |
795 | } else { |
796 | error.SetErrorStringWithFormat("invalid option with value %i", val); |
797 | } |
798 | if (error.Fail()) { |
| 20 | | Assuming the condition is false | |
|
| |
799 | return error; |
800 | } |
801 | } |
802 | } |
803 | |
804 | if (error.Fail() || m_option_data.m_print_help) { |
805 | ShowUsage(out_fh, m_option_data); |
806 | exiting = true; |
807 | } else if (m_option_data.m_print_version) { |
808 | ::fprintf(out_fh, "%s\n", m_debugger.GetVersionString()); |
809 | exiting = true; |
810 | } else if (m_option_data.m_print_python_path) { |
811 | SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath(); |
812 | if (python_file_spec.IsValid()) { |
813 | char python_path[PATH_MAX4096]; |
814 | size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX4096); |
815 | if (num_chars < PATH_MAX4096) { |
816 | ::fprintf(out_fh, "%s\n", python_path); |
817 | } else |
818 | ::fprintf(out_fh, "<PATH TOO LONG>\n"); |
819 | } else |
820 | ::fprintf(out_fh, "<COULD NOT FIND PATH>\n"); |
821 | exiting = true; |
822 | } else if (m_option_data.m_process_name.empty() && |
823 | m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID0) { |
824 | |
825 | |
826 | |
827 | |
828 | |
829 | |
830 | |
831 | argc -= optind; |
832 | argv += optind; |
833 | |
834 | if (argc > 0) { |
835 | for (int arg_idx = 0; arg_idx < argc; ++arg_idx) { |
836 | const char *arg = argv[arg_idx]; |
837 | if (arg) |
838 | m_option_data.m_args.push_back(arg); |
839 | } |
840 | } |
841 | |
842 | } else { |
843 | |
844 | argc -= optind; |
845 | |
846 | if (argc > 0) |
847 | ::fprintf(out_fh, |
848 | "Warning: program arguments are ignored when attaching.\n"); |
849 | } |
850 | |
851 | return error; |
852 | } |
853 | |
854 | static ::FILE *PrepareCommandsForSourcing(const char *commands_data, |
855 | size_t commands_size, int fds[2]) { |
856 | enum PIPES { READ, WRITE }; |
857 | |
858 | ::FILE *commands_file = NULL__null; |
859 | fds[0] = -1; |
860 | fds[1] = -1; |
861 | int err = 0; |
862 | #ifdef _WIN32 |
863 | err = _pipe(fds, commands_size, O_BINARY); |
864 | #else |
865 | err = pipe(fds); |
866 | #endif |
867 | if (err == 0) { |
868 | ssize_t nrwr = write(fds[WRITE], commands_data, commands_size); |
869 | if (nrwr < 0) { |
870 | fprintf(stderrstderr, "error: write(%i, %p, %" PRIu64"l" "u" ") failed (errno = %i) " |
871 | "when trying to open LLDB commands pipe\n", |
872 | fds[WRITE], static_cast<const void *>(commands_data), |
873 | static_cast<uint64_t>(commands_size), errno(*__errno_location ())); |
874 | } else if (static_cast<size_t>(nrwr) == commands_size) { |
875 | |
876 | |
877 | |
878 | #ifdef _WIN32 |
879 | _close(fds[WRITE]); |
880 | fds[WRITE] = -1; |
881 | #else |
882 | close(fds[WRITE]); |
883 | fds[WRITE] = -1; |
884 | #endif |
885 | |
886 | |
887 | commands_file = fdopen(fds[READ], "r"); |
888 | if (commands_file) { |
889 | fds[READ] = |
890 | -1; |
891 | |
892 | |
893 | } else { |
894 | fprintf(stderrstderr, "error: fdopen(%i, \"r\") failed (errno = %i) when " |
895 | "trying to open LLDB commands pipe\n", |
896 | fds[READ], errno(*__errno_location ())); |
897 | } |
898 | } |
899 | } else { |
900 | fprintf(stderrstderr, |
901 | "error: can't create pipe file descriptors for LLDB commands\n"); |
902 | } |
903 | |
904 | return commands_file; |
905 | } |
906 | |
907 | void CleanupAfterCommandSourcing(int fds[2]) { |
908 | enum PIPES { READ, WRITE }; |
909 | |
910 | |
911 | if (fds[WRITE] != -1) { |
912 | #ifdef _WIN32 |
913 | _close(fds[WRITE]); |
914 | fds[WRITE] = -1; |
915 | #else |
916 | close(fds[WRITE]); |
917 | fds[WRITE] = -1; |
918 | #endif |
919 | } |
920 | |
921 | if (fds[READ] != -1) { |
922 | #ifdef _WIN32 |
923 | _close(fds[READ]); |
924 | fds[READ] = -1; |
925 | #else |
926 | close(fds[READ]); |
927 | fds[READ] = -1; |
928 | #endif |
929 | } |
930 | } |
931 | |
932 | std::string EscapeString(std::string arg) { |
933 | std::string::size_type pos = 0; |
934 | while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) { |
935 | arg.insert(pos, 1, '\\'); |
936 | pos += 2; |
937 | } |
938 | return '"' + arg + '"'; |
939 | } |
940 | |
941 | int Driver::MainLoop() { |
942 | if (::tcgetattr(STDIN_FILENO0, &g_old_stdin_termios) == 0) { |
943 | g_old_stdin_termios_is_valid = true; |
944 | atexit(reset_stdin_termios); |
945 | } |
946 | |
947 | #ifndef _MSC_VER |
948 | |
949 | |
950 | |
951 | ::setbuf(stdinstdin, NULL__null); |
952 | #endif |
953 | ::setbuf(stdoutstdout, NULL__null); |
954 | |
955 | m_debugger.SetErrorFileHandle(stderrstderr, false); |
956 | m_debugger.SetOutputFileHandle(stdoutstdout, false); |
957 | m_debugger.SetInputFileHandle(stdinstdin, |
958 | false); |
959 | |
960 | m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); |
961 | |
962 | struct winsize window_size; |
963 | if (isatty(STDIN_FILENO0) && |
964 | ::ioctl(STDIN_FILENO0, TIOCGWINSZ0x5413, &window_size) == 0) { |
965 | if (window_size.ws_col > 0) |
966 | m_debugger.SetTerminalWidth(window_size.ws_col); |
967 | } |
968 | |
969 | SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); |
970 | |
971 | |
972 | |
973 | SBCommandReturnObject result; |
974 | sb_interpreter.SourceInitFileInHomeDirectory(result); |
975 | if (GetDebugMode()) { |
976 | result.PutError(m_debugger.GetErrorFileHandle()); |
977 | result.PutOutput(m_debugger.GetOutputFileHandle()); |
978 | } |
979 | |
980 | |
981 | |
982 | m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true); |
983 | |
984 | |
985 | SBStream commands_stream; |
986 | |
987 | |
988 | |
989 | WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream); |
990 | |
991 | const size_t num_args = m_option_data.m_args.size(); |
992 | if (num_args > 0) { |
993 | char arch_name[64]; |
994 | if (m_debugger.GetDefaultArchitecture(arch_name, sizeof(arch_name))) |
995 | commands_stream.Printf("target create --arch=%s %s", arch_name, |
996 | EscapeString(m_option_data.m_args[0]).c_str()); |
997 | else |
998 | commands_stream.Printf("target create %s", |
999 | EscapeString(m_option_data.m_args[0]).c_str()); |
1000 | |
1001 | if (!m_option_data.m_core_file.empty()) { |
1002 | commands_stream.Printf(" --core %s", |
1003 | EscapeString(m_option_data.m_core_file).c_str()); |
1004 | } |
1005 | commands_stream.Printf("\n"); |
1006 | |
1007 | if (num_args > 1) { |
1008 | commands_stream.Printf("settings set -- target.run-args "); |
1009 | for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) |
1010 | commands_stream.Printf( |
1011 | " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str()); |
1012 | commands_stream.Printf("\n"); |
1013 | } |
1014 | } else if (!m_option_data.m_core_file.empty()) { |
1015 | commands_stream.Printf("target create --core %s\n", |
1016 | EscapeString(m_option_data.m_core_file).c_str()); |
1017 | } else if (!m_option_data.m_process_name.empty()) { |
1018 | commands_stream.Printf("process attach --name %s", |
1019 | EscapeString(m_option_data.m_process_name).c_str()); |
1020 | |
1021 | if (m_option_data.m_wait_for) |
1022 | commands_stream.Printf(" --waitfor"); |
1023 | |
1024 | commands_stream.Printf("\n"); |
1025 | |
1026 | } else if (LLDB_INVALID_PROCESS_ID0 != m_option_data.m_process_pid) { |
1027 | commands_stream.Printf("process attach --pid %" PRIu64"l" "u" "\n", |
1028 | m_option_data.m_process_pid); |
1029 | } |
1030 | |
1031 | WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream); |
1032 | |
1033 | if (GetDebugMode()) { |
1034 | result.PutError(m_debugger.GetErrorFileHandle()); |
1035 | result.PutOutput(m_debugger.GetOutputFileHandle()); |
1036 | } |
1037 | |
1038 | bool handle_events = true; |
1039 | bool spawn_thread = false; |
1040 | |
1041 | if (m_option_data.m_repl) { |
1042 | const char *repl_options = NULL__null; |
1043 | if (!m_option_data.m_repl_options.empty()) |
1044 | repl_options = m_option_data.m_repl_options.c_str(); |
1045 | SBError error(m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options)); |
1046 | if (error.Fail()) { |
1047 | const char *error_cstr = error.GetCString(); |
1048 | if (error_cstr && error_cstr[0]) |
1049 | fprintf(stderrstderr, "error: %s\n", error_cstr); |
1050 | else |
1051 | fprintf(stderrstderr, "error: %u\n", error.GetError()); |
1052 | } |
1053 | } else { |
1054 | |
1055 | |
1056 | |
1057 | const char *commands_data = commands_stream.GetData(); |
1058 | const size_t commands_size = commands_stream.GetSize(); |
1059 | |
1060 | |
1061 | |
1062 | bool quit_requested = false; |
1063 | bool stopped_for_crash = false; |
1064 | if (commands_data && commands_size) { |
1065 | int initial_commands_fds[2]; |
1066 | bool success = true; |
1067 | FILE *commands_file = PrepareCommandsForSourcing( |
1068 | commands_data, commands_size, initial_commands_fds); |
1069 | if (commands_file) { |
1070 | m_debugger.SetInputFileHandle(commands_file, true); |
1071 | |
1072 | |
1073 | |
1074 | |
1075 | bool old_async = m_debugger.GetAsync(); |
1076 | m_debugger.SetAsync(false); |
1077 | int num_errors; |
1078 | |
1079 | SBCommandInterpreterRunOptions options; |
1080 | options.SetStopOnError(true); |
1081 | if (m_option_data.m_batch) |
1082 | options.SetStopOnCrash(true); |
1083 | |
1084 | m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, |
1085 | num_errors, quit_requested, |
1086 | stopped_for_crash); |
1087 | |
1088 | if (m_option_data.m_batch && stopped_for_crash && |
1089 | !m_option_data.m_after_crash_commands.empty()) { |
1090 | int crash_command_fds[2]; |
1091 | SBStream crash_commands_stream; |
1092 | WriteCommandsForSourcing(eCommandPlacementAfterCrash, |
1093 | crash_commands_stream); |
1094 | const char *crash_commands_data = crash_commands_stream.GetData(); |
1095 | const size_t crash_commands_size = crash_commands_stream.GetSize(); |
1096 | commands_file = PrepareCommandsForSourcing( |
1097 | crash_commands_data, crash_commands_size, crash_command_fds); |
1098 | if (commands_file) { |
1099 | bool local_quit_requested; |
1100 | bool local_stopped_for_crash; |
1101 | m_debugger.SetInputFileHandle(commands_file, true); |
1102 | |
1103 | m_debugger.RunCommandInterpreter( |
1104 | handle_events, spawn_thread, options, num_errors, |
1105 | local_quit_requested, local_stopped_for_crash); |
1106 | if (local_quit_requested) |
1107 | quit_requested = true; |
1108 | } |
1109 | } |
1110 | m_debugger.SetAsync(old_async); |
1111 | } else |
1112 | success = false; |
1113 | |
1114 | |
1115 | CleanupAfterCommandSourcing(initial_commands_fds); |
1116 | |
1117 | |
1118 | if (!success) { |
1119 | exit(1); |
1120 | } |
1121 | } |
1122 | |
1123 | |
1124 | |
1125 | |
1126 | |
1127 | bool go_interactive = true; |
1128 | if (quit_requested) |
1129 | go_interactive = false; |
1130 | else if (m_option_data.m_batch && !stopped_for_crash) |
1131 | go_interactive = false; |
1132 | |
1133 | if (go_interactive) { |
1134 | m_debugger.SetInputFileHandle(stdinstdin, true); |
1135 | m_debugger.RunCommandInterpreter(handle_events, spawn_thread); |
1136 | } |
1137 | } |
1138 | |
1139 | reset_stdin_termios(); |
1140 | fclose(stdinstdin); |
1141 | |
1142 | int exit_code = sb_interpreter.GetQuitStatus(); |
1143 | SBDebugger::Destroy(m_debugger); |
1144 | return exit_code; |
1145 | } |
1146 | |
1147 | void Driver::ResizeWindow(unsigned short col) { |
1148 | GetDebugger().SetTerminalWidth(col); |
1149 | } |
1150 | |
1151 | void sigwinch_handler(int signo) { |
1152 | struct winsize window_size; |
1153 | if (isatty(STDIN_FILENO0) && |
1154 | ::ioctl(STDIN_FILENO0, TIOCGWINSZ0x5413, &window_size) == 0) { |
1155 | if ((window_size.ws_col > 0) && g_driver != NULL__null) { |
1156 | g_driver->ResizeWindow(window_size.ws_col); |
1157 | } |
1158 | } |
1159 | } |
1160 | |
1161 | void sigint_handler(int signo) { |
1162 | static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT{ 0 }; |
1163 | if (g_driver) { |
1164 | if (!g_interrupt_sent.test_and_set()) { |
1165 | g_driver->GetDebugger().DispatchInputInterrupt(); |
1166 | g_interrupt_sent.clear(); |
1167 | return; |
1168 | } |
1169 | } |
1170 | |
1171 | _exit(signo); |
1172 | } |
1173 | |
1174 | void sigtstp_handler(int signo) { |
1175 | if (g_driver) |
1176 | g_driver->GetDebugger().SaveInputTerminalState(); |
1177 | |
1178 | signal(signo, SIG_DFL((__sighandler_t) 0)); |
1179 | kill(getpid(), signo); |
1180 | signal(signo, sigtstp_handler); |
1181 | } |
1182 | |
1183 | void sigcont_handler(int signo) { |
1184 | if (g_driver) |
1185 | g_driver->GetDebugger().RestoreInputTerminalState(); |
1186 | |
1187 | signal(signo, SIG_DFL((__sighandler_t) 0)); |
1188 | kill(getpid(), signo); |
1189 | signal(signo, sigcont_handler); |
1190 | } |
1191 | |
1192 | int |
1193 | #ifdef _MSC_VER |
1194 | wmain(int argc, wchar_t const *wargv[]) |
1195 | #else |
1196 | main(int argc, char const *argv[]) |
1197 | #endif |
1198 | { |
1199 | #ifdef _MSC_VER |
1200 | |
1201 | std::vector<std::string> argvStrings(argc); |
1202 | std::vector<const char *> argvPointers(argc); |
1203 | for (int i = 0; i != argc; ++i) { |
1204 | llvm::convertWideToUTF8(wargv[i], argvStrings[i]); |
1205 | argvPointers[i] = argvStrings[i].c_str(); |
1206 | } |
1207 | const char **argv = argvPointers.data(); |
1208 | #endif |
1209 | |
1210 | llvm::StringRef ToolName = argv[0]; |
1211 | llvm::sys::PrintStackTraceOnErrorSignal(ToolName); |
1212 | llvm::PrettyStackTraceProgram X(argc, argv); |
1213 | |
1214 | SBDebugger::Initialize(); |
1215 | |
1216 | SBHostOS::ThreadCreated("<lldb.driver.main-thread>"); |
1217 | |
1218 | signal(SIGINT2, sigint_handler); |
1219 | #if !defined(_MSC_VER) |
1220 | signal(SIGPIPE13, SIG_IGN((__sighandler_t) 1)); |
1221 | signal(SIGWINCH28, sigwinch_handler); |
1222 | signal(SIGTSTP20, sigtstp_handler); |
1223 | signal(SIGCONT18, sigcont_handler); |
1224 | #endif |
1225 | |
1226 | int exit_code = 0; |
1227 | |
1228 | |
1229 | { |
1230 | Driver driver; |
1231 | |
1232 | bool exiting = false; |
1233 | SBError error(driver.ParseArgs(argc, argv, stdoutstdout, exiting)); |
| 1 | Calling 'Driver::ParseArgs' | |
|
1234 | if (error.Fail()) { |
1235 | exit_code = 1; |
1236 | const char *error_cstr = error.GetCString(); |
1237 | if (error_cstr) |
1238 | ::fprintf(stderrstderr, "error: %s\n", error_cstr); |
1239 | } else if (!exiting) { |
1240 | exit_code = driver.MainLoop(); |
1241 | } |
1242 | } |
1243 | |
1244 | SBDebugger::Terminate(); |
1245 | return exit_code; |
1246 | } |