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