Bug Summary

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