1 //===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "Driver.h"
10
11 #include "lldb/API/SBCommandInterpreter.h"
12 #include "lldb/API/SBCommandInterpreterRunOptions.h"
13 #include "lldb/API/SBCommandReturnObject.h"
14 #include "lldb/API/SBDebugger.h"
15 #include "lldb/API/SBFile.h"
16 #include "lldb/API/SBHostOS.h"
17 #include "lldb/API/SBLanguageRuntime.h"
18 #include "lldb/API/SBReproducer.h"
19 #include "lldb/API/SBStream.h"
20 #include "lldb/API/SBStringList.h"
21
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/Support/Format.h"
24 #include "llvm/Support/InitLLVM.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/Process.h"
27 #include "llvm/Support/Signals.h"
28 #include "llvm/Support/WithColor.h"
29 #include "llvm/Support/raw_ostream.h"
30
31 #include <algorithm>
32 #include <atomic>
33 #include <bitset>
34 #include <clocale>
35 #include <csignal>
36 #include <string>
37 #include <thread>
38 #include <utility>
39
40 #include <climits>
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
44 #include <fcntl.h>
45
46 // Includes for pipe()
47 #if defined(_WIN32)
48 #include <fcntl.h>
49 #include <io.h>
50 #else
51 #include <unistd.h>
52 #endif
53
54 #if !defined(__APPLE__)
55 #include "llvm/Support/DataTypes.h"
56 #endif
57
58 using namespace lldb;
59 using namespace llvm;
60
61 namespace {
62 enum ID {
63 OPT_INVALID = 0, // This is not an option ID.
64 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
65 HELPTEXT, METAVAR, VALUES) \
66 OPT_##ID,
67 #include "Options.inc"
68 #undef OPTION
69 };
70
71 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
72 #include "Options.inc"
73 #undef PREFIX
74
75 const opt::OptTable::Info InfoTable[] = {
76 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
77 HELPTEXT, METAVAR, VALUES) \
78 { \
79 PREFIX, NAME, HELPTEXT, \
80 METAVAR, OPT_##ID, opt::Option::KIND##Class, \
81 PARAM, FLAGS, OPT_##GROUP, \
82 OPT_##ALIAS, ALIASARGS, VALUES},
83 #include "Options.inc"
84 #undef OPTION
85 };
86
87 class LLDBOptTable : public opt::OptTable {
88 public:
LLDBOptTable()89 LLDBOptTable() : OptTable(InfoTable) {}
90 };
91 } // namespace
92
93 static void reset_stdin_termios();
94 static bool g_old_stdin_termios_is_valid = false;
95 static struct termios g_old_stdin_termios;
96
97 static Driver *g_driver = nullptr;
98
99 // In the Driver::MainLoop, we change the terminal settings. This function is
100 // added as an atexit handler to make sure we clean them up.
reset_stdin_termios()101 static void reset_stdin_termios() {
102 if (g_old_stdin_termios_is_valid) {
103 g_old_stdin_termios_is_valid = false;
104 ::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
105 }
106 }
107
Driver()108 Driver::Driver()
109 : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {
110 // We want to be able to handle CTRL+D in the terminal to have it terminate
111 // certain input
112 m_debugger.SetCloseInputOnEOF(false);
113 g_driver = this;
114 }
115
~Driver()116 Driver::~Driver() {
117 SBDebugger::Destroy(m_debugger);
118 g_driver = nullptr;
119 }
120
AddInitialCommand(std::string command,CommandPlacement placement,bool is_file,SBError & error)121 void Driver::OptionData::AddInitialCommand(std::string command,
122 CommandPlacement placement,
123 bool is_file, SBError &error) {
124 std::vector<InitialCmdEntry> *command_set;
125 switch (placement) {
126 case eCommandPlacementBeforeFile:
127 command_set = &(m_initial_commands);
128 break;
129 case eCommandPlacementAfterFile:
130 command_set = &(m_after_file_commands);
131 break;
132 case eCommandPlacementAfterCrash:
133 command_set = &(m_after_crash_commands);
134 break;
135 }
136
137 if (is_file) {
138 SBFileSpec file(command.c_str());
139 if (file.Exists())
140 command_set->push_back(InitialCmdEntry(command, is_file));
141 else if (file.ResolveExecutableLocation()) {
142 char final_path[PATH_MAX];
143 file.GetPath(final_path, sizeof(final_path));
144 command_set->push_back(InitialCmdEntry(final_path, is_file));
145 } else
146 error.SetErrorStringWithFormat(
147 "file specified in --source (-s) option doesn't exist: '%s'",
148 command.c_str());
149 } else
150 command_set->push_back(InitialCmdEntry(command, is_file));
151 }
152
WriteCommandsForSourcing(CommandPlacement placement,SBStream & strm)153 void Driver::WriteCommandsForSourcing(CommandPlacement placement,
154 SBStream &strm) {
155 std::vector<OptionData::InitialCmdEntry> *command_set;
156 switch (placement) {
157 case eCommandPlacementBeforeFile:
158 command_set = &m_option_data.m_initial_commands;
159 break;
160 case eCommandPlacementAfterFile:
161 command_set = &m_option_data.m_after_file_commands;
162 break;
163 case eCommandPlacementAfterCrash:
164 command_set = &m_option_data.m_after_crash_commands;
165 break;
166 }
167
168 for (const auto &command_entry : *command_set) {
169 const char *command = command_entry.contents.c_str();
170 if (command_entry.is_file) {
171 bool source_quietly =
172 m_option_data.m_source_quietly || command_entry.source_quietly;
173 strm.Printf("command source -s %i '%s'\n",
174 static_cast<int>(source_quietly), command);
175 } else
176 strm.Printf("%s\n", command);
177 }
178 }
179
180 // Check the arguments that were passed to this program to make sure they are
181 // valid and to get their argument values (if any). Return a boolean value
182 // indicating whether or not to start up the full debugger (i.e. the Command
183 // Interpreter) or not. Return FALSE if the arguments were invalid OR if the
184 // user only wanted help or version information.
ProcessArgs(const opt::InputArgList & args,bool & exiting)185 SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
186 SBError error;
187
188 // This is kind of a pain, but since we make the debugger in the Driver's
189 // constructor, we can't know at that point whether we should read in init
190 // files yet. So we don't read them in in the Driver constructor, then set
191 // the flags back to "read them in" here, and then if we see the "-n" flag,
192 // we'll turn it off again. Finally we have to read them in by hand later in
193 // the main loop.
194 m_debugger.SkipLLDBInitFiles(false);
195 m_debugger.SkipAppInitFiles(false);
196
197 if (args.hasArg(OPT_version)) {
198 m_option_data.m_print_version = true;
199 }
200
201 if (args.hasArg(OPT_python_path)) {
202 m_option_data.m_print_python_path = true;
203 }
204
205 if (args.hasArg(OPT_batch)) {
206 m_option_data.m_batch = true;
207 }
208
209 if (auto *arg = args.getLastArg(OPT_core)) {
210 auto arg_value = arg->getValue();
211 SBFileSpec file(arg_value);
212 if (!file.Exists()) {
213 error.SetErrorStringWithFormat(
214 "file specified in --core (-c) option doesn't exist: '%s'",
215 arg_value);
216 return error;
217 }
218 m_option_data.m_core_file = arg_value;
219 }
220
221 if (args.hasArg(OPT_editor)) {
222 m_option_data.m_use_external_editor = true;
223 }
224
225 if (args.hasArg(OPT_no_lldbinit)) {
226 m_debugger.SkipLLDBInitFiles(true);
227 m_debugger.SkipAppInitFiles(true);
228 }
229
230 if (args.hasArg(OPT_local_lldbinit)) {
231 lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
232 m_debugger.GetInstanceName());
233 }
234
235 if (args.hasArg(OPT_no_use_colors)) {
236 m_debugger.SetUseColor(false);
237 m_option_data.m_debug_mode = true;
238 }
239
240 if (auto *arg = args.getLastArg(OPT_file)) {
241 auto arg_value = arg->getValue();
242 SBFileSpec file(arg_value);
243 if (file.Exists()) {
244 m_option_data.m_args.emplace_back(arg_value);
245 } else if (file.ResolveExecutableLocation()) {
246 char path[PATH_MAX];
247 file.GetPath(path, sizeof(path));
248 m_option_data.m_args.emplace_back(path);
249 } else {
250 error.SetErrorStringWithFormat(
251 "file specified in --file (-f) option doesn't exist: '%s'",
252 arg_value);
253 return error;
254 }
255 }
256
257 if (auto *arg = args.getLastArg(OPT_arch)) {
258 auto arg_value = arg->getValue();
259 if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
260 error.SetErrorStringWithFormat(
261 "invalid architecture in the -a or --arch option: '%s'", arg_value);
262 return error;
263 }
264 }
265
266 if (auto *arg = args.getLastArg(OPT_script_language)) {
267 auto arg_value = arg->getValue();
268 m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
269 }
270
271 if (args.hasArg(OPT_source_quietly)) {
272 m_option_data.m_source_quietly = true;
273 }
274
275 if (auto *arg = args.getLastArg(OPT_attach_name)) {
276 auto arg_value = arg->getValue();
277 m_option_data.m_process_name = arg_value;
278 }
279
280 if (args.hasArg(OPT_wait_for)) {
281 m_option_data.m_wait_for = true;
282 }
283
284 if (auto *arg = args.getLastArg(OPT_attach_pid)) {
285 auto arg_value = arg->getValue();
286 char *remainder;
287 m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
288 if (remainder == arg_value || *remainder != '\0') {
289 error.SetErrorStringWithFormat(
290 "Could not convert process PID: \"%s\" into a pid.", arg_value);
291 return error;
292 }
293 }
294
295 if (auto *arg = args.getLastArg(OPT_repl_language)) {
296 auto arg_value = arg->getValue();
297 m_option_data.m_repl_lang =
298 SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
299 if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
300 error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
301 arg_value);
302 return error;
303 }
304 }
305
306 if (args.hasArg(OPT_repl)) {
307 m_option_data.m_repl = true;
308 }
309
310 if (auto *arg = args.getLastArg(OPT_repl_)) {
311 m_option_data.m_repl = true;
312 if (auto arg_value = arg->getValue())
313 m_option_data.m_repl_options = arg_value;
314 }
315
316 // We need to process the options below together as their relative order
317 // matters.
318 for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
319 OPT_source, OPT_source_before_file,
320 OPT_one_line, OPT_one_line_before_file)) {
321 auto arg_value = arg->getValue();
322 if (arg->getOption().matches(OPT_source_on_crash)) {
323 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
324 true, error);
325 if (error.Fail())
326 return error;
327 }
328
329 if (arg->getOption().matches(OPT_one_line_on_crash)) {
330 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
331 false, error);
332 if (error.Fail())
333 return error;
334 }
335
336 if (arg->getOption().matches(OPT_source)) {
337 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
338 true, error);
339 if (error.Fail())
340 return error;
341 }
342
343 if (arg->getOption().matches(OPT_source_before_file)) {
344 m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
345 true, error);
346 if (error.Fail())
347 return error;
348 }
349
350 if (arg->getOption().matches(OPT_one_line)) {
351 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
352 false, error);
353 if (error.Fail())
354 return error;
355 }
356
357 if (arg->getOption().matches(OPT_one_line_before_file)) {
358 m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
359 false, error);
360 if (error.Fail())
361 return error;
362 }
363 }
364
365 if (m_option_data.m_process_name.empty() &&
366 m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
367
368 for (auto *arg : args.filtered(OPT_INPUT))
369 m_option_data.m_args.push_back(arg->getAsString((args)));
370
371 // Any argument following -- is an argument for the inferior.
372 if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
373 for (auto value : arg->getValues())
374 m_option_data.m_args.emplace_back(value);
375 }
376 } else if (args.getLastArgNoClaim() != nullptr) {
377 WithColor::warning() << "program arguments are ignored when attaching.\n";
378 }
379
380 if (m_option_data.m_print_version) {
381 llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
382 exiting = true;
383 return error;
384 }
385
386 if (m_option_data.m_print_python_path) {
387 SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
388 if (python_file_spec.IsValid()) {
389 char python_path[PATH_MAX];
390 size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
391 if (num_chars < PATH_MAX) {
392 llvm::outs() << python_path << '\n';
393 } else
394 llvm::outs() << "<PATH TOO LONG>\n";
395 } else
396 llvm::outs() << "<COULD NOT FIND PATH>\n";
397 exiting = true;
398 return error;
399 }
400
401 return error;
402 }
403
OpenPipe(int fds[2],std::size_t size)404 static inline int OpenPipe(int fds[2], std::size_t size) {
405 #ifdef _WIN32
406 return _pipe(fds, size, O_BINARY);
407 #else
408 (void)size;
409 return pipe(fds);
410 #endif
411 }
412
PrepareCommandsForSourcing(const char * commands_data,size_t commands_size)413 static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
414 size_t commands_size) {
415 enum PIPES { READ, WRITE }; // Indexes for the read and write fds
416 int fds[2] = {-1, -1};
417
418 if (OpenPipe(fds, commands_size) != 0) {
419 WithColor::error()
420 << "can't create pipe file descriptors for LLDB commands\n";
421 return nullptr;
422 }
423
424 ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
425 if (size_t(nrwr) != commands_size) {
426 WithColor::error()
427 << format(
428 "write(%i, %p, %" PRIu64
429 ") failed (errno = %i) when trying to open LLDB commands pipe",
430 fds[WRITE], static_cast<const void *>(commands_data),
431 static_cast<uint64_t>(commands_size), errno)
432 << '\n';
433 llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
434 llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
435 return nullptr;
436 }
437
438 // Close the write end of the pipe, so that the command interpreter will exit
439 // when it consumes all the data.
440 llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
441
442 // Open the read file descriptor as a FILE * that we can return as an input
443 // handle.
444 ::FILE *commands_file = fdopen(fds[READ], "rb");
445 if (commands_file == nullptr) {
446 WithColor::error() << format("fdopen(%i, \"rb\") failed (errno = %i) "
447 "when trying to open LLDB commands pipe",
448 fds[READ], errno)
449 << '\n';
450 llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
451 return nullptr;
452 }
453
454 // 'commands_file' now owns the read descriptor.
455 return commands_file;
456 }
457
EscapeString(std::string arg)458 std::string EscapeString(std::string arg) {
459 std::string::size_type pos = 0;
460 while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
461 arg.insert(pos, 1, '\\');
462 pos += 2;
463 }
464 return '"' + arg + '"';
465 }
466
MainLoop()467 int Driver::MainLoop() {
468 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
469 g_old_stdin_termios_is_valid = true;
470 atexit(reset_stdin_termios);
471 }
472
473 #ifndef _MSC_VER
474 // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
475 // which causes it to miss newlines depending on whether there have been an
476 // odd or even number of characters. Bug has been reported to MS via Connect.
477 ::setbuf(stdin, nullptr);
478 #endif
479 ::setbuf(stdout, nullptr);
480
481 m_debugger.SetErrorFileHandle(stderr, false);
482 m_debugger.SetOutputFileHandle(stdout, false);
483 // Don't take ownership of STDIN yet...
484 m_debugger.SetInputFileHandle(stdin, false);
485
486 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
487
488 struct winsize window_size;
489 if ((isatty(STDIN_FILENO) != 0) &&
490 ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
491 if (window_size.ws_col > 0)
492 m_debugger.SetTerminalWidth(window_size.ws_col);
493 }
494
495 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
496
497 // Before we handle any options from the command line, we parse the
498 // REPL init file or the default file in the user's home directory.
499 SBCommandReturnObject result;
500 sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
501 if (m_option_data.m_debug_mode) {
502 result.PutError(m_debugger.GetErrorFile());
503 result.PutOutput(m_debugger.GetOutputFile());
504 }
505
506 // Source the local .lldbinit file if it exists and we're allowed to source.
507 // Here we want to always print the return object because it contains the
508 // warning and instructions to load local lldbinit files.
509 sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
510 result.PutError(m_debugger.GetErrorFile());
511 result.PutOutput(m_debugger.GetOutputFile());
512
513 // We allow the user to specify an exit code when calling quit which we will
514 // return when exiting.
515 m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
516
517 // Now we handle options we got from the command line
518 SBStream commands_stream;
519
520 // First source in the commands specified to be run before the file arguments
521 // are processed.
522 WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
523
524 // If we're not in --repl mode, add the commands to process the file
525 // arguments, and the commands specified to run afterwards.
526 if (!m_option_data.m_repl) {
527 const size_t num_args = m_option_data.m_args.size();
528 if (num_args > 0) {
529 char arch_name[64];
530 if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
531 sizeof(arch_name)))
532 commands_stream.Printf("target create --arch=%s %s", arch_name,
533 EscapeString(m_option_data.m_args[0]).c_str());
534 else
535 commands_stream.Printf("target create %s",
536 EscapeString(m_option_data.m_args[0]).c_str());
537
538 if (!m_option_data.m_core_file.empty()) {
539 commands_stream.Printf(" --core %s",
540 EscapeString(m_option_data.m_core_file).c_str());
541 }
542 commands_stream.Printf("\n");
543
544 if (num_args > 1) {
545 commands_stream.Printf("settings set -- target.run-args ");
546 for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
547 commands_stream.Printf(
548 " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
549 commands_stream.Printf("\n");
550 }
551 } else if (!m_option_data.m_core_file.empty()) {
552 commands_stream.Printf("target create --core %s\n",
553 EscapeString(m_option_data.m_core_file).c_str());
554 } else if (!m_option_data.m_process_name.empty()) {
555 commands_stream.Printf(
556 "process attach --name %s",
557 EscapeString(m_option_data.m_process_name).c_str());
558
559 if (m_option_data.m_wait_for)
560 commands_stream.Printf(" --waitfor");
561
562 commands_stream.Printf("\n");
563
564 } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
565 commands_stream.Printf("process attach --pid %" PRIu64 "\n",
566 m_option_data.m_process_pid);
567 }
568
569 WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
570 } else if (!m_option_data.m_after_file_commands.empty()) {
571 // We're in repl mode and after-file-load commands were specified.
572 WithColor::warning() << "commands specified to run after file load (via -o "
573 "or -s) are ignored in REPL mode.\n";
574 }
575
576 if (m_option_data.m_debug_mode) {
577 result.PutError(m_debugger.GetErrorFile());
578 result.PutOutput(m_debugger.GetOutputFile());
579 }
580
581 const bool handle_events = true;
582 const bool spawn_thread = false;
583
584 // Check if we have any data in the commands stream, and if so, save it to a
585 // temp file
586 // so we can then run the command interpreter using the file contents.
587 const char *commands_data = commands_stream.GetData();
588 const size_t commands_size = commands_stream.GetSize();
589
590 bool go_interactive = true;
591 if ((commands_data != nullptr) && (commands_size != 0u)) {
592 FILE *commands_file =
593 PrepareCommandsForSourcing(commands_data, commands_size);
594
595 if (commands_file == nullptr) {
596 // We should have already printed an error in PrepareCommandsForSourcing.
597 return 1;
598 }
599
600 m_debugger.SetInputFileHandle(commands_file, true);
601
602 // Set the debugger into Sync mode when running the command file. Otherwise
603 // command files that run the target won't run in a sensible way.
604 bool old_async = m_debugger.GetAsync();
605 m_debugger.SetAsync(false);
606
607 SBCommandInterpreterRunOptions options;
608 options.SetAutoHandleEvents(true);
609 options.SetSpawnThread(false);
610 options.SetStopOnError(true);
611 options.SetStopOnCrash(m_option_data.m_batch);
612
613 SBCommandInterpreterRunResult results =
614 m_debugger.RunCommandInterpreter(options);
615 if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
616 go_interactive = false;
617 if (m_option_data.m_batch &&
618 results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
619 go_interactive = false;
620
621 // When running in batch mode and stopped because of an error, exit with a
622 // non-zero exit status.
623 if (m_option_data.m_batch &&
624 results.GetResult() == lldb::eCommandInterpreterResultCommandError)
625 return 1;
626
627 if (m_option_data.m_batch &&
628 results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
629 !m_option_data.m_after_crash_commands.empty()) {
630 SBStream crash_commands_stream;
631 WriteCommandsForSourcing(eCommandPlacementAfterCrash,
632 crash_commands_stream);
633 const char *crash_commands_data = crash_commands_stream.GetData();
634 const size_t crash_commands_size = crash_commands_stream.GetSize();
635 commands_file =
636 PrepareCommandsForSourcing(crash_commands_data, crash_commands_size);
637 if (commands_file != nullptr) {
638 m_debugger.SetInputFileHandle(commands_file, true);
639 SBCommandInterpreterRunResult local_results =
640 m_debugger.RunCommandInterpreter(options);
641 if (local_results.GetResult() ==
642 lldb::eCommandInterpreterResultQuitRequested)
643 go_interactive = false;
644
645 // When running in batch mode and an error occurred while sourcing
646 // the crash commands, exit with a non-zero exit status.
647 if (m_option_data.m_batch &&
648 local_results.GetResult() ==
649 lldb::eCommandInterpreterResultCommandError)
650 return 1;
651 }
652 }
653 m_debugger.SetAsync(old_async);
654 }
655
656 // Now set the input file handle to STDIN and run the command interpreter
657 // again in interactive mode or repl mode and let the debugger take ownership
658 // of stdin.
659 if (go_interactive) {
660 m_debugger.SetInputFileHandle(stdin, true);
661
662 if (m_option_data.m_repl) {
663 const char *repl_options = nullptr;
664 if (!m_option_data.m_repl_options.empty())
665 repl_options = m_option_data.m_repl_options.c_str();
666 SBError error(
667 m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
668 if (error.Fail()) {
669 const char *error_cstr = error.GetCString();
670 if ((error_cstr != nullptr) && (error_cstr[0] != 0))
671 WithColor::error() << error_cstr << '\n';
672 else
673 WithColor::error() << error.GetError() << '\n';
674 }
675 } else {
676 m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
677 }
678 }
679
680 reset_stdin_termios();
681 fclose(stdin);
682
683 return sb_interpreter.GetQuitStatus();
684 }
685
ResizeWindow(unsigned short col)686 void Driver::ResizeWindow(unsigned short col) {
687 GetDebugger().SetTerminalWidth(col);
688 }
689
sigwinch_handler(int signo)690 void sigwinch_handler(int signo) {
691 struct winsize window_size;
692 if ((isatty(STDIN_FILENO) != 0) &&
693 ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
694 if ((window_size.ws_col > 0) && g_driver != nullptr) {
695 g_driver->ResizeWindow(window_size.ws_col);
696 }
697 }
698 }
699
sigint_handler(int signo)700 void sigint_handler(int signo) {
701 #ifdef _WIN32 // Restore handler as it is not persistent on Windows
702 signal(SIGINT, sigint_handler);
703 #endif
704 static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
705 if (g_driver != nullptr) {
706 if (!g_interrupt_sent.test_and_set()) {
707 g_driver->GetDebugger().DispatchInputInterrupt();
708 g_interrupt_sent.clear();
709 return;
710 }
711 }
712
713 _exit(signo);
714 }
715
sigtstp_handler(int signo)716 void sigtstp_handler(int signo) {
717 if (g_driver != nullptr)
718 g_driver->GetDebugger().SaveInputTerminalState();
719
720 signal(signo, SIG_DFL);
721 kill(getpid(), signo);
722 signal(signo, sigtstp_handler);
723 }
724
sigcont_handler(int signo)725 void sigcont_handler(int signo) {
726 if (g_driver != nullptr)
727 g_driver->GetDebugger().RestoreInputTerminalState();
728
729 signal(signo, SIG_DFL);
730 kill(getpid(), signo);
731 signal(signo, sigcont_handler);
732 }
733
reproducer_handler(void * finalize_cmd)734 void reproducer_handler(void *finalize_cmd) {
735 if (SBReproducer::Generate()) {
736 int result = std::system(static_cast<const char *>(finalize_cmd));
737 (void)result;
738 fflush(stdout);
739 }
740 }
741
printHelp(LLDBOptTable & table,llvm::StringRef tool_name)742 static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
743 std::string usage_str = tool_name.str() + " [options]";
744 table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
745
746 std::string examples = R"___(
747 EXAMPLES:
748 The debugger can be started in several modes.
749
750 Passing an executable as a positional argument prepares lldb to debug the
751 given executable. To disambiguate between arguments passed to lldb and
752 arguments passed to the debugged executable, arguments starting with a - must
753 be passed after --.
754
755 lldb --arch x86_64 /path/to/program program argument -- --arch armv7
756
757 For convenience, passing the executable after -- is also supported.
758
759 lldb --arch x86_64 -- /path/to/program program argument --arch armv7
760
761 Passing one of the attach options causes lldb to immediately attach to the
762 given process.
763
764 lldb -p <pid>
765 lldb -n <process-name>
766
767 Passing --repl starts lldb in REPL mode.
768
769 lldb -r
770
771 Passing --core causes lldb to debug the core file.
772
773 lldb -c /path/to/core
774
775 Command options can be combined with these modes and cause lldb to run the
776 specified commands before or after events, like loading the file or crashing,
777 in the order provided on the command line.
778
779 lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
780 lldb -S /source/before/file -s /source/after/file
781 lldb -K /source/before/crash -k /source/after/crash
782
783 Note: In REPL mode no file is loaded, so commands specified to run after
784 loading the file (via -o or -s) will be ignored.)___";
785 llvm::outs() << examples << '\n';
786 }
787
InitializeReproducer(llvm::StringRef argv0,opt::InputArgList & input_args)788 static llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0,
789 opt::InputArgList &input_args) {
790 if (auto *finalize_path = input_args.getLastArg(OPT_reproducer_finalize)) {
791 if (const char *error = SBReproducer::Finalize(finalize_path->getValue())) {
792 WithColor::error() << "reproducer finalization failed: " << error << '\n';
793 return 1;
794 }
795
796 llvm::outs() << "********************\n";
797 llvm::outs() << "Crash reproducer for ";
798 llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
799 llvm::outs() << '\n';
800 llvm::outs() << "Reproducer written to '" << SBReproducer::GetPath()
801 << "'\n";
802 llvm::outs() << '\n';
803 llvm::outs() << "Before attaching the reproducer to a bug report:\n";
804 llvm::outs() << " - Look at the directory to ensure you're willing to "
805 "share its content.\n";
806 llvm::outs()
807 << " - Make sure the reproducer works by replaying the reproducer.\n";
808 llvm::outs() << '\n';
809 llvm::outs() << "Replay the reproducer with the following command:\n";
810 llvm::outs() << argv0 << " -replay " << finalize_path->getValue() << "\n";
811 llvm::outs() << "********************\n";
812 return 0;
813 }
814
815 if (auto *replay_path = input_args.getLastArg(OPT_replay)) {
816 SBReplayOptions replay_options;
817 replay_options.SetCheckVersion(!input_args.hasArg(OPT_no_version_check));
818 replay_options.SetVerify(!input_args.hasArg(OPT_no_verification));
819 if (const char *error =
820 SBReproducer::Replay(replay_path->getValue(), replay_options)) {
821 WithColor::error() << "reproducer replay failed: " << error << '\n';
822 return 1;
823 }
824 return 0;
825 }
826
827 bool capture = input_args.hasArg(OPT_capture);
828 bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit);
829 auto *capture_path = input_args.getLastArg(OPT_capture_path);
830
831 if (generate_on_exit && !capture) {
832 WithColor::warning()
833 << "-reproducer-generate-on-exit specified without -capture\n";
834 }
835
836 if (capture || capture_path) {
837 if (capture_path) {
838 if (!capture)
839 WithColor::warning() << "-capture-path specified without -capture\n";
840 if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
841 WithColor::error() << "reproducer capture failed: " << error << '\n';
842 return 1;
843 }
844 } else {
845 const char *error = SBReproducer::Capture();
846 if (error) {
847 WithColor::error() << "reproducer capture failed: " << error << '\n';
848 return 1;
849 }
850 }
851 if (generate_on_exit)
852 SBReproducer::SetAutoGenerate(true);
853
854 // Register the reproducer signal handler.
855 if (!input_args.hasArg(OPT_no_generate_on_signal)) {
856 if (const char *reproducer_path = SBReproducer::GetPath()) {
857 static std::string *finalize_cmd = new std::string(argv0);
858 finalize_cmd->append(" --reproducer-finalize '");
859 finalize_cmd->append(reproducer_path);
860 finalize_cmd->append("'");
861 llvm::sys::AddSignalHandler(reproducer_handler,
862 const_cast<char *>(finalize_cmd->c_str()));
863 }
864 }
865 }
866
867 return llvm::None;
868 }
869
main(int argc,char const * argv[])870 int main(int argc, char const *argv[]) {
871 // Editline uses for example iswprint which is dependent on LC_CTYPE.
872 std::setlocale(LC_ALL, "");
873 std::setlocale(LC_CTYPE, "");
874
875 // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
876 // destruction.
877 llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
878
879 // Parse arguments.
880 LLDBOptTable T;
881 unsigned MissingArgIndex;
882 unsigned MissingArgCount;
883 ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
884 opt::InputArgList input_args =
885 T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
886 llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
887
888 if (input_args.hasArg(OPT_help)) {
889 printHelp(T, argv0);
890 return 0;
891 }
892
893 // Check for missing argument error.
894 if (MissingArgCount) {
895 WithColor::error() << "argument to '"
896 << input_args.getArgString(MissingArgIndex)
897 << "' is missing\n";
898 }
899 // Error out on unknown options.
900 if (input_args.hasArg(OPT_UNKNOWN)) {
901 for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
902 WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
903 }
904 }
905 if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {
906 llvm::errs() << "Use '" << argv0
907 << " --help' for a complete list of options.\n";
908 return 1;
909 }
910
911 if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
912 return *exit_code;
913 }
914
915 SBError error = SBDebugger::InitializeWithErrorHandling();
916 if (error.Fail()) {
917 WithColor::error() << "initialization failed: " << error.GetCString()
918 << '\n';
919 return 1;
920 }
921 SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
922
923 signal(SIGINT, sigint_handler);
924 #if !defined(_MSC_VER)
925 signal(SIGPIPE, SIG_IGN);
926 signal(SIGWINCH, sigwinch_handler);
927 signal(SIGTSTP, sigtstp_handler);
928 signal(SIGCONT, sigcont_handler);
929 #endif
930
931 int exit_code = 0;
932 // Create a scope for driver so that the driver object will destroy itself
933 // before SBDebugger::Terminate() is called.
934 {
935 Driver driver;
936
937 bool exiting = false;
938 SBError error(driver.ProcessArgs(input_args, exiting));
939 if (error.Fail()) {
940 exit_code = 1;
941 if (const char *error_cstr = error.GetCString())
942 WithColor::error() << error_cstr << '\n';
943 } else if (!exiting) {
944 exit_code = driver.MainLoop();
945 }
946 }
947
948 SBDebugger::Terminate();
949 return exit_code;
950 }
951