Bug Summary

File:tools/lldb/tools/driver/Driver.cpp
Warning:line 777, column 41
Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

Press '?' to see keyboard shortcuts

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 LLDB_USE_BUILTIN_DEMANGLER -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn337490/build-llvm/tools/lldb/tools/driver -I /build/llvm-toolchain-snapshot-7~svn337490/tools/lldb/tools/driver -I /build/llvm-toolchain-snapshot-7~svn337490/build-llvm/tools/lldb/include -I /build/llvm-toolchain-snapshot-7~svn337490/tools/lldb/include -I /build/llvm-toolchain-snapshot-7~svn337490/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn337490/include -I /usr/include/python2.7 -I /build/llvm-toolchain-snapshot-7~svn337490/tools/clang/include -I /build/llvm-toolchain-snapshot-7~svn337490/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-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~svn337490/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-20-043646-20380-1 -x c++ /build/llvm-toolchain-snapshot-7~svn337490/tools/lldb/tools/driver/Driver.cpp -faddrsig
1//===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
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// Includes for pipe()
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
54using namespace lldb;
55
56static void reset_stdin_termios();
57static bool g_old_stdin_termios_is_valid = false;
58static struct termios g_old_stdin_termios;
59
60static Driver *g_driver = NULL__null;
61
62// In the Driver::MainLoop, we change the terminal settings. This function is
63// added as an atexit handler to make sure we clean them up.
64static 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
71typedef struct {
72 uint32_t usage_mask; // Used to mark options that can be used together. If (1
73 // << n & usage_mask) != 0
74 // then this option belongs to option set n.
75 bool required; // This option is required (in the current usage level)
76 const char *long_option; // Full name for this option.
77 int short_option; // Single character for this option.
78 int option_has_arg; // no_argument, required_argument or optional_argument
79 uint32_t completion_type; // Cookie the option class can use to do define the
80 // argument completion.
81 lldb::CommandArgumentType argument_type; // Type of argument this option takes
82 const char *usage_text; // Full text explaining what this options does and
83 // what (if any) argument to
84 // pass it.
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
90static 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
165static const uint32_t last_option_set_with_args = 2;
166
167Driver::Driver()
168 : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)),
169 m_option_data() {
170 // We want to be able to handle CTRL+D in the terminal to have it terminate
171 // certain input
172 m_debugger.SetCloseInputOnEOF(false);
173 g_driver = this;
174}
175
176Driver::~Driver() { g_driver = NULL__null; }
177
178// This function takes INDENT, which tells how many spaces to output at the
179// front
180// of each line; TEXT, which is the text that is to be output. It outputs the
181// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
182// front of each line. It breaks lines on spaces, tabs or newlines, shortening
183// the line if necessary to not break in the middle of a word. It assumes that
184// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
185
186void 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 // Force indentation to be reasonable.
192 if (indent >= output_max_columns)
193 indent = 0;
194
195 // Will it all fit on one line?
196
197 if (len + indent < output_max_columns)
198 // Output as a single line
199 fprintf(out, "%*s%s\n", indent, "", text);
200 else {
201 // We need to break it up into multiple lines.
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 // Dont start the 'text' on a space, since we're already outputting the
210 // indentation.
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 // If we're not at the end of the text, make sure we break the line on
219 // white space.
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
232void 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 // First, show each usage level set of options, e.g. <cmd>
243 // [options-for-level-0]
244 // <cmd>
245 // [options-for-level-1]
246 // etc.
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 // This is a bit of a hack, but there's no way to say certain options
283 // don't have arguments yet...
284 // so we do it by hand here.
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 // Now print out all the detailed information about the various options: long
313 // form, short form and help text:
314 // -- long_name <argument>
315 // - short <argument>
316 // help text
317
318 // This variable is used to keep track of which options' info we've printed
319 // out, because some options can be in
320 // more than one usage level, but we only want to print the long form of its
321 // information once.
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 // Only print this option if we haven't already seen it.
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
383void 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
414Driver::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
424Driver::OptionData::~OptionData() {}
425
426void 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 // If there is a local .lldbinit, add that to the
433 // list of things to be sourced, if the settings
434 // permit it.
435 SBFileSpec local_lldbinit(".lldbinit", true);
436
437 SBFileSpec homedir_dot_lldb = SBHostOS::GetUserHomeDirectory();
438 homedir_dot_lldb.AppendPathComponent(".lldbinit");
439
440 // Only read .lldbinit in the current working directory
441 // if it's not the same as the .lldbinit in the home
442 // directory (which is already being read in).
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
466void 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
497void Driver::ResetOptionValues() { m_option_data.Clear(); }
498
499const 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
505const 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
511lldb::ScriptLanguage Driver::GetScriptLanguage() const {
512 return m_option_data.m_script_lang;
513}
514
515void 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 // If this command_entry is a file to be sourced, and it's the ./.lldbinit
534 // file (the .lldbinit
535 // file in the current working directory), only read it if
536 // target.load-cwd-lldbinit is 'true'.
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
571bool Driver::GetDebugMode() const { return m_option_data.m_debug_mode; }
572
573// Check the arguments that were passed to this program to make sure they are
574// valid and to get their
575// argument values (if any). Return a boolean value indicating whether or not
576// to start up the full
577// debugger (i.e. the Command Interpreter) or not. Return FALSE if the
578// arguments were invalid OR
579// if the user only wanted help or version information.
580
581SBError 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 /* Do Nothing. */;
596
597 if (num_options == 0) {
5
Taking false branch
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
7
Taking false branch
606 long_options = NULL__null;
607 else
608 long_options = &long_options_vector.front();
609
610 if (long_options == NULL__null) {
8
Taking false branch
611 error.SetErrorStringWithFormat("invalid long options");
612 return error;
613 }
614
615 // Build the option_string argument for call to getopt_long_only.
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 // This is kind of a pain, but since we make the debugger in the Driver's
635 // constructor, we can't
636 // know at that point whether we should read in init files yet. So we don't
637 // read them in in the
638 // Driver constructor, then set the flags back to "read them in" here, and
639 // then if we see the
640 // "-n" flag, we'll turn it off again. Finally we have to read them in by
641 // hand later in the
642 // main loop.
643
644 m_debugger.SkipLLDBInitFiles(false);
645 m_debugger.SkipAppInitFiles(false);
646
647// Prepare for & make calls to getopt_long_only.
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
13
Taking false branch
28
Assuming the condition is false
29
Taking false branch
662 break;
663 else if (val == '?') {
14
Assuming the condition is false
15
Taking false branch
30
Assuming the condition is false
31
Taking false branch
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
17
Taking false branch
32
Assuming 'val' is not equal to 0
33
Taking false branch
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
19
Taking false branch
34
Assuming the condition is false
35
Taking false branch
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
21
Taking true branch
36
Assuming 'long_options_index' is >= 0
37
Taking true branch
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
26
Taking false branch
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 // Any arguments that are left over after option parsing are for
852 // the program. If a file was specified with -f then the filename
853 // is already in the m_option_data.m_args array, and any remaining args
854 // are arguments for the inferior program. If no file was specified with
855 // -f, then what is left is the program name followed by any arguments.
856
857 // Skip any options we consumed with getopt_long_only
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 // Skip any options we consumed with getopt_long_only
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
881static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
882 size_t commands_size, int fds[2]) {
883 enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and 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// Close the write end of the pipe so when we give the read end to
903// the debugger/command interpreter it will exit when it consumes all
904// of the data
905#ifdef _WIN32
906 _close(fds[WRITE]);
907 fds[WRITE] = -1;
908#else
909 close(fds[WRITE]);
910 fds[WRITE] = -1;
911#endif
912 // Now open the read file descriptor in a FILE * that we can give to
913 // the debugger as an input handle
914 commands_file = fdopen(fds[READ], "r");
915 if (commands_file) {
916 fds[READ] =
917 -1; // The FILE * 'commands_file' now owns the read descriptor
918 // Hand ownership if the FILE * over to the debugger for
919 // "commands_file".
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
934void CleanupAfterCommandSourcing(int fds[2]) {
935 enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
936
937 // Close any pipes that we still have ownership of
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
959std::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
968int 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 // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
976 // which causes it to miss newlines depending on whether there have been an
977 // odd or even number of characters. Bug has been reported to MS via Connect.
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); // Don't take ownership of STDIN yet...
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 // Before we handle any options from the command line, we parse the
999 // .lldbinit file in the user's home directory.
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 // We allow the user to specify an exit code when calling quit which we will
1008 // return when exiting.
1009 m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
1010
1011 // Now we handle options we got from the command line
1012 SBStream commands_stream;
1013
1014 // First source in the commands specified to be run before the file arguments
1015 // are processed.
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 // Check if we have any data in the commands stream, and if so, save it to a
1082 // temp file
1083 // so we can then run the command interpreter using the file contents.
1084 const char *commands_data = commands_stream.GetData();
1085 const size_t commands_size = commands_stream.GetSize();
1086
1087 // The command file might have requested that we quit, this variable will
1088 // track that.
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 // Set the debugger into Sync mode when running the command file.
1100 // Otherwise command files
1101 // that run the target won't run in a sensible way.
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 // Close any pipes that we still have ownership of
1142 CleanupAfterCommandSourcing(initial_commands_fds);
1143
1144 // Something went wrong with command pipe
1145 if (!success) {
1146 exit(1);
1147 }
1148 }
1149
1150 // Now set the input file handle to STDIN and run the command
1151 // interpreter again in interactive mode and let the debugger
1152 // take ownership of stdin
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
1174void Driver::ResizeWindow(unsigned short col) {
1175 GetDebugger().SetTerminalWidth(col);
1176}
1177
1178void 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
1188void 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
1201void 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
1210void 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
1219int
1220#ifdef _MSC_VER
1221wmain(int argc, wchar_t const *wargv[])
1222#else
1223main(int argc, char const *argv[])
1224#endif
1225{
1226#ifdef _MSC_VER
1227 // Convert wide arguments to UTF-8
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 // Create a scope for driver so that the driver object will destroy itself
1255 // before SBDebugger::Terminate() is called.
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}