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