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