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