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