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