xref: /freebsd/contrib/llvm-project/lldb/tools/driver/Driver.cpp (revision dd41de95a84d979615a2ef11df6850622bf6184e)
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     for (auto *arg : args.filtered(OPT_INPUT))
365       m_option_data.m_args.push_back(arg->getAsString((args)));
366 
367     // Any argument following -- is an argument for the inferior.
368     if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
369       for (auto value : arg->getValues())
370         m_option_data.m_args.emplace_back(value);
371     }
372   } else if (args.getLastArgNoClaim() != nullptr) {
373     WithColor::warning() << "program arguments are ignored when attaching.\n";
374   }
375 
376   if (m_option_data.m_print_version) {
377     llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
378     exiting = true;
379     return error;
380   }
381 
382   if (m_option_data.m_print_python_path) {
383     SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
384     if (python_file_spec.IsValid()) {
385       char python_path[PATH_MAX];
386       size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
387       if (num_chars < PATH_MAX) {
388         llvm::outs() << python_path << '\n';
389       } else
390         llvm::outs() << "<PATH TOO LONG>\n";
391     } else
392       llvm::outs() << "<COULD NOT FIND PATH>\n";
393     exiting = true;
394     return error;
395   }
396 
397   return error;
398 }
399 
400 static inline int OpenPipe(int fds[2], std::size_t size) {
401 #ifdef _WIN32
402   return _pipe(fds, size, O_BINARY);
403 #else
404   (void)size;
405   return pipe(fds);
406 #endif
407 }
408 
409 static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
410                                           size_t commands_size) {
411   enum PIPES { READ, WRITE }; // Indexes for the read and write fds
412   int fds[2] = {-1, -1};
413 
414   if (OpenPipe(fds, commands_size) != 0) {
415     WithColor::error()
416         << "can't create pipe file descriptors for LLDB commands\n";
417     return nullptr;
418   }
419 
420   ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
421   if (size_t(nrwr) != commands_size) {
422     WithColor::error()
423         << format(
424                "write(%i, %p, %" PRIu64
425                ") failed (errno = %i) when trying to open LLDB commands pipe",
426                fds[WRITE], static_cast<const void *>(commands_data),
427                static_cast<uint64_t>(commands_size), errno)
428         << '\n';
429     llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
430     llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
431     return nullptr;
432   }
433 
434   // Close the write end of the pipe, so that the command interpreter will exit
435   // when it consumes all the data.
436   llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
437 
438   // Open the read file descriptor as a FILE * that we can return as an input
439   // handle.
440   ::FILE *commands_file = fdopen(fds[READ], "rb");
441   if (commands_file == nullptr) {
442     WithColor::error() << format("fdopen(%i, \"rb\") failed (errno = %i) "
443                                  "when trying to open LLDB commands pipe",
444                                  fds[READ], errno)
445                        << '\n';
446     llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
447     return nullptr;
448   }
449 
450   // 'commands_file' now owns the read descriptor.
451   return commands_file;
452 }
453 
454 std::string EscapeString(std::string arg) {
455   std::string::size_type pos = 0;
456   while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
457     arg.insert(pos, 1, '\\');
458     pos += 2;
459   }
460   return '"' + arg + '"';
461 }
462 
463 int Driver::MainLoop() {
464   if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
465     g_old_stdin_termios_is_valid = true;
466     atexit(reset_stdin_termios);
467   }
468 
469 #ifndef _MSC_VER
470   // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
471   // which causes it to miss newlines depending on whether there have been an
472   // odd or even number of characters.  Bug has been reported to MS via Connect.
473   ::setbuf(stdin, nullptr);
474 #endif
475   ::setbuf(stdout, nullptr);
476 
477   m_debugger.SetErrorFileHandle(stderr, false);
478   m_debugger.SetOutputFileHandle(stdout, false);
479   // Don't take ownership of STDIN yet...
480   m_debugger.SetInputFileHandle(stdin, false);
481 
482   m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
483 
484   struct winsize window_size;
485   if ((isatty(STDIN_FILENO) != 0) &&
486       ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
487     if (window_size.ws_col > 0)
488       m_debugger.SetTerminalWidth(window_size.ws_col);
489   }
490 
491   SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
492 
493   // Before we handle any options from the command line, we parse the
494   // .lldbinit file in the user's home directory.
495   SBCommandReturnObject result;
496   sb_interpreter.SourceInitFileInHomeDirectory(result);
497   if (m_option_data.m_debug_mode) {
498     result.PutError(m_debugger.GetErrorFile());
499     result.PutOutput(m_debugger.GetOutputFile());
500   }
501 
502   // Source the local .lldbinit file if it exists and we're allowed to source.
503   // Here we want to always print the return object because it contains the
504   // warning and instructions to load local lldbinit files.
505   sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
506   result.PutError(m_debugger.GetErrorFile());
507   result.PutOutput(m_debugger.GetOutputFile());
508 
509   // We allow the user to specify an exit code when calling quit which we will
510   // return when exiting.
511   m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
512 
513   // Now we handle options we got from the command line
514   SBStream commands_stream;
515 
516   // First source in the commands specified to be run before the file arguments
517   // are processed.
518   WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
519 
520   // If we're not in --repl mode, add the commands to process the file
521   // arguments, and the commands specified to run afterwards.
522   if (!m_option_data.m_repl) {
523     const size_t num_args = m_option_data.m_args.size();
524     if (num_args > 0) {
525       char arch_name[64];
526       if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
527                                                    sizeof(arch_name)))
528         commands_stream.Printf("target create --arch=%s %s", arch_name,
529                                EscapeString(m_option_data.m_args[0]).c_str());
530       else
531         commands_stream.Printf("target create %s",
532                                EscapeString(m_option_data.m_args[0]).c_str());
533 
534       if (!m_option_data.m_core_file.empty()) {
535         commands_stream.Printf(" --core %s",
536                                EscapeString(m_option_data.m_core_file).c_str());
537       }
538       commands_stream.Printf("\n");
539 
540       if (num_args > 1) {
541         commands_stream.Printf("settings set -- target.run-args ");
542         for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
543           commands_stream.Printf(
544               " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
545         commands_stream.Printf("\n");
546       }
547     } else if (!m_option_data.m_core_file.empty()) {
548       commands_stream.Printf("target create --core %s\n",
549                              EscapeString(m_option_data.m_core_file).c_str());
550     } else if (!m_option_data.m_process_name.empty()) {
551       commands_stream.Printf(
552           "process attach --name %s",
553           EscapeString(m_option_data.m_process_name).c_str());
554 
555       if (m_option_data.m_wait_for)
556         commands_stream.Printf(" --waitfor");
557 
558       commands_stream.Printf("\n");
559 
560     } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
561       commands_stream.Printf("process attach --pid %" PRIu64 "\n",
562                              m_option_data.m_process_pid);
563     }
564 
565     WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
566   } else if (!m_option_data.m_after_file_commands.empty()) {
567     // We're in repl mode and after-file-load commands were specified.
568     WithColor::warning() << "commands specified to run after file load (via -o "
569                             "or -s) are ignored in REPL mode.\n";
570   }
571 
572   if (m_option_data.m_debug_mode) {
573     result.PutError(m_debugger.GetErrorFile());
574     result.PutOutput(m_debugger.GetOutputFile());
575   }
576 
577   const bool handle_events = true;
578   const bool spawn_thread = false;
579 
580   // Check if we have any data in the commands stream, and if so, save it to a
581   // temp file
582   // so we can then run the command interpreter using the file contents.
583   const char *commands_data = commands_stream.GetData();
584   const size_t commands_size = commands_stream.GetSize();
585 
586   bool go_interactive = true;
587   if ((commands_data != nullptr) && (commands_size != 0u)) {
588     FILE *commands_file =
589         PrepareCommandsForSourcing(commands_data, commands_size);
590 
591     if (commands_file == nullptr) {
592       // We should have already printed an error in PrepareCommandsForSourcing.
593       exit(1);
594     }
595 
596     m_debugger.SetInputFileHandle(commands_file, true);
597 
598     // Set the debugger into Sync mode when running the command file. Otherwise
599     // command files that run the target won't run in a sensible way.
600     bool old_async = m_debugger.GetAsync();
601     m_debugger.SetAsync(false);
602 
603     SBCommandInterpreterRunOptions options;
604     options.SetAutoHandleEvents(true);
605     options.SetSpawnThread(false);
606     options.SetStopOnError(true);
607     options.SetStopOnCrash(m_option_data.m_batch);
608 
609     SBCommandInterpreterRunResult results =
610         m_debugger.RunCommandInterpreter(options);
611     if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
612       go_interactive = false;
613     if (m_option_data.m_batch &&
614         results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
615       go_interactive = false;
616 
617     // When running in batch mode and stopped because of an error, exit with a
618     // non-zero exit status.
619     if (m_option_data.m_batch &&
620         results.GetResult() == lldb::eCommandInterpreterResultCommandError)
621       exit(1);
622 
623     if (m_option_data.m_batch &&
624         results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
625         !m_option_data.m_after_crash_commands.empty()) {
626       SBStream crash_commands_stream;
627       WriteCommandsForSourcing(eCommandPlacementAfterCrash,
628                                crash_commands_stream);
629       const char *crash_commands_data = crash_commands_stream.GetData();
630       const size_t crash_commands_size = crash_commands_stream.GetSize();
631       commands_file =
632           PrepareCommandsForSourcing(crash_commands_data, crash_commands_size);
633       if (commands_file != nullptr) {
634         m_debugger.SetInputFileHandle(commands_file, true);
635         SBCommandInterpreterRunResult local_results =
636             m_debugger.RunCommandInterpreter(options);
637         if (local_results.GetResult() ==
638             lldb::eCommandInterpreterResultQuitRequested)
639           go_interactive = false;
640 
641         // When running in batch mode and an error occurred while sourcing
642         // the crash commands, exit with a non-zero exit status.
643         if (m_option_data.m_batch &&
644             local_results.GetResult() ==
645                 lldb::eCommandInterpreterResultCommandError)
646           exit(1);
647       }
648     }
649     m_debugger.SetAsync(old_async);
650   }
651 
652   // Now set the input file handle to STDIN and run the command interpreter
653   // again in interactive mode or repl mode and let the debugger take ownership
654   // of stdin.
655   if (go_interactive) {
656     m_debugger.SetInputFileHandle(stdin, true);
657 
658     if (m_option_data.m_repl) {
659       const char *repl_options = nullptr;
660       if (!m_option_data.m_repl_options.empty())
661         repl_options = m_option_data.m_repl_options.c_str();
662       SBError error(
663           m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
664       if (error.Fail()) {
665         const char *error_cstr = error.GetCString();
666         if ((error_cstr != nullptr) && (error_cstr[0] != 0))
667           WithColor::error() << error_cstr << '\n';
668         else
669           WithColor::error() << error.GetError() << '\n';
670       }
671     } else {
672       m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
673     }
674   }
675 
676   reset_stdin_termios();
677   fclose(stdin);
678 
679   int exit_code = sb_interpreter.GetQuitStatus();
680   SBDebugger::Destroy(m_debugger);
681   return exit_code;
682 }
683 
684 void Driver::ResizeWindow(unsigned short col) {
685   GetDebugger().SetTerminalWidth(col);
686 }
687 
688 void sigwinch_handler(int signo) {
689   struct winsize window_size;
690   if ((isatty(STDIN_FILENO) != 0) &&
691       ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
692     if ((window_size.ws_col > 0) && g_driver != nullptr) {
693       g_driver->ResizeWindow(window_size.ws_col);
694     }
695   }
696 }
697 
698 void sigint_handler(int signo) {
699 #ifdef _WIN32 // Restore handler as it is not persistent on Windows
700   signal(SIGINT, sigint_handler);
701 #endif
702   static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
703   if (g_driver != nullptr) {
704     if (!g_interrupt_sent.test_and_set()) {
705       g_driver->GetDebugger().DispatchInputInterrupt();
706       g_interrupt_sent.clear();
707       return;
708     }
709   }
710 
711   _exit(signo);
712 }
713 
714 void sigtstp_handler(int signo) {
715   if (g_driver != nullptr)
716     g_driver->GetDebugger().SaveInputTerminalState();
717 
718   signal(signo, SIG_DFL);
719   kill(getpid(), signo);
720   signal(signo, sigtstp_handler);
721 }
722 
723 void sigcont_handler(int signo) {
724   if (g_driver != nullptr)
725     g_driver->GetDebugger().RestoreInputTerminalState();
726 
727   signal(signo, SIG_DFL);
728   kill(getpid(), signo);
729   signal(signo, sigcont_handler);
730 }
731 
732 void reproducer_handler(void *argv0) {
733   if (SBReproducer::Generate()) {
734     auto exe = static_cast<const char *>(argv0);
735     llvm::outs() << "********************\n";
736     llvm::outs() << "Crash reproducer for ";
737     llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
738     llvm::outs() << '\n';
739     llvm::outs() << "Reproducer written to '" << SBReproducer::GetPath()
740                  << "'\n";
741     llvm::outs() << '\n';
742     llvm::outs() << "Before attaching the reproducer to a bug report:\n";
743     llvm::outs() << " - Look at the directory to ensure you're willing to "
744                     "share its content.\n";
745     llvm::outs()
746         << " - Make sure the reproducer works by replaying the reproducer.\n";
747     llvm::outs() << '\n';
748     llvm::outs() << "Replay the reproducer with the following command:\n";
749     llvm::outs() << exe << " -replay " << SBReproducer::GetPath() << "\n";
750     llvm::outs() << "********************\n";
751   }
752 }
753 
754 static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
755   std::string usage_str = tool_name.str() + " [options]";
756   table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
757 
758   std::string examples = R"___(
759 EXAMPLES:
760   The debugger can be started in several modes.
761 
762   Passing an executable as a positional argument prepares lldb to debug the
763   given executable. To disambiguate between arguments passed to lldb and
764   arguments passed to the debugged executable, arguments starting with a - must
765   be passed after --.
766 
767     lldb --arch x86_64 /path/to/program program argument -- --arch arvm7
768 
769   For convenience, passing the executable after -- is also supported.
770 
771     lldb --arch x86_64 -- /path/to/program program argument --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(llvm::StringRef argv0,
801                                          opt::InputArgList &input_args) {
802   if (auto *replay_path = input_args.getLastArg(OPT_replay)) {
803     const bool no_version_check = input_args.hasArg(OPT_no_version_check);
804     if (const char *error =
805             SBReproducer::Replay(replay_path->getValue(), no_version_check)) {
806       WithColor::error() << "reproducer replay failed: " << error << '\n';
807       return 1;
808     }
809     return 0;
810   }
811 
812   bool capture = input_args.hasArg(OPT_capture);
813   bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit);
814   auto *capture_path = input_args.getLastArg(OPT_capture_path);
815 
816   if (generate_on_exit && !capture) {
817     WithColor::warning()
818         << "-reproducer-generate-on-exit specified without -capture\n";
819   }
820 
821   if (capture || capture_path) {
822     // Register the reproducer signal handler.
823     if (!input_args.hasArg(OPT_no_generate_on_signal)) {
824       llvm::sys::AddSignalHandler(reproducer_handler,
825                                   const_cast<char *>(argv0.data()));
826     }
827 
828     if (capture_path) {
829       if (!capture)
830         WithColor::warning() << "-capture-path specified without -capture\n";
831       if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
832         WithColor::error() << "reproducer capture failed: " << error << '\n';
833         return 1;
834       }
835     } else {
836       const char *error = SBReproducer::Capture();
837       if (error) {
838         WithColor::error() << "reproducer capture failed: " << error << '\n';
839         return 1;
840       }
841     }
842     if (generate_on_exit)
843       SBReproducer::SetAutoGenerate(true);
844   }
845 
846   return llvm::None;
847 }
848 
849 int main(int argc, char const *argv[]) {
850   // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
851   // destruction.
852   llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
853 
854   // Parse arguments.
855   LLDBOptTable T;
856   unsigned MAI;
857   unsigned MAC;
858   ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
859   opt::InputArgList input_args = T.ParseArgs(arg_arr, MAI, MAC);
860   llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
861 
862   if (input_args.hasArg(OPT_help)) {
863     printHelp(T, argv0);
864     return 0;
865   }
866 
867   // Error out on unknown options.
868   if (input_args.hasArg(OPT_UNKNOWN)) {
869     for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
870       WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
871     }
872     llvm::errs() << "Use '" << argv0
873                  << " --help' for a complete list of options.\n";
874     return 1;
875   }
876 
877   if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
878     return *exit_code;
879   }
880 
881   SBError error = SBDebugger::InitializeWithErrorHandling();
882   if (error.Fail()) {
883     WithColor::error() << "initialization failed: " << error.GetCString()
884                        << '\n';
885     return 1;
886   }
887   SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
888 
889   signal(SIGINT, sigint_handler);
890 #if !defined(_MSC_VER)
891   signal(SIGPIPE, SIG_IGN);
892   signal(SIGWINCH, sigwinch_handler);
893   signal(SIGTSTP, sigtstp_handler);
894   signal(SIGCONT, sigcont_handler);
895 #endif
896 
897   int exit_code = 0;
898   // Create a scope for driver so that the driver object will destroy itself
899   // before SBDebugger::Terminate() is called.
900   {
901     Driver driver;
902 
903     bool exiting = false;
904     SBError error(driver.ProcessArgs(input_args, exiting));
905     if (error.Fail()) {
906       exit_code = 1;
907       if (const char *error_cstr = error.GetCString())
908         WithColor::error() << error_cstr << '\n';
909     } else if (!exiting) {
910       exit_code = driver.MainLoop();
911     }
912   }
913 
914   SBDebugger::Terminate();
915   return exit_code;
916 }
917