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