xref: /freebsd/contrib/llvm-project/lldb/tools/driver/Driver.cpp (revision 963f5dc7a30624e95d72fb7f87b8892651164e46)
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:
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.
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 
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 
116 Driver::~Driver() {
117   SBDebugger::Destroy(m_debugger);
118   g_driver = nullptr;
119 }
120 
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 
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.
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 
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 
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 
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 
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 
686 void Driver::ResizeWindow(unsigned short col) {
687   GetDebugger().SetTerminalWidth(col);
688 }
689 
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 
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 
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 
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 
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 
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 
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 
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