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