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