1 //===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Driver.h"
10 
11 #include "lldb/API/SBCommandInterpreter.h"
12 #include "lldb/API/SBCommandInterpreterRunOptions.h"
13 #include "lldb/API/SBCommandReturnObject.h"
14 #include "lldb/API/SBDebugger.h"
15 #include "lldb/API/SBFile.h"
16 #include "lldb/API/SBHostOS.h"
17 #include "lldb/API/SBLanguageRuntime.h"
18 #include "lldb/API/SBReproducer.h"
19 #include "lldb/API/SBStream.h"
20 #include "lldb/API/SBStringList.h"
21 
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/Process.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 <csignal>
35 #include <string>
36 #include <thread>
37 #include <utility>
38 
39 #include <fcntl.h>
40 #include <limits.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 
45 // Includes for pipe()
46 #if defined(_WIN32)
47 #include <fcntl.h>
48 #include <io.h>
49 #else
50 #include <unistd.h>
51 #endif
52 
53 #if !defined(__APPLE__)
54 #include "llvm/Support/DataTypes.h"
55 #endif
56 
57 using namespace lldb;
58 using namespace llvm;
59 
60 namespace {
61 enum ID {
62   OPT_INVALID = 0, // This is not an option ID.
63 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
64                HELPTEXT, METAVAR, VALUES)                                      \
65   OPT_##ID,
66 #include "Options.inc"
67 #undef OPTION
68 };
69 
70 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
71 #include "Options.inc"
72 #undef PREFIX
73 
74 const opt::OptTable::Info InfoTable[] = {
75 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
76                HELPTEXT, METAVAR, VALUES)                                      \
77   {                                                                            \
78       PREFIX,      NAME,      HELPTEXT,                                        \
79       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
80       PARAM,       FLAGS,     OPT_##GROUP,                                     \
81       OPT_##ALIAS, ALIASARGS, VALUES},
82 #include "Options.inc"
83 #undef OPTION
84 };
85 
86 class LLDBOptTable : public opt::OptTable {
87 public:
LLDBOptTable()88   LLDBOptTable() : OptTable(InfoTable) {}
89 };
90 } // namespace
91 
92 static void reset_stdin_termios();
93 static bool g_old_stdin_termios_is_valid = false;
94 static struct termios g_old_stdin_termios;
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.
reset_stdin_termios()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 
Driver()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 
~Driver()115 Driver::~Driver() {
116   SBDebugger::Destroy(m_debugger);
117   g_driver = nullptr;
118 }
119 
AddInitialCommand(std::string command,CommandPlacement placement,bool is_file,SBError & error)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 
WriteCommandsForSourcing(CommandPlacement placement,SBStream & strm)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.
ProcessArgs(const opt::InputArgList & args,bool & exiting)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_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 
204   if (args.hasArg(OPT_batch)) {
205     m_option_data.m_batch = true;
206   }
207 
208   if (auto *arg = args.getLastArg(OPT_core)) {
209     auto arg_value = arg->getValue();
210     SBFileSpec file(arg_value);
211     if (!file.Exists()) {
212       error.SetErrorStringWithFormat(
213           "file specified in --core (-c) option doesn't exist: '%s'",
214           arg_value);
215       return error;
216     }
217     m_option_data.m_core_file = arg_value;
218   }
219 
220   if (args.hasArg(OPT_editor)) {
221     m_option_data.m_use_external_editor = true;
222   }
223 
224   if (args.hasArg(OPT_no_lldbinit)) {
225     m_debugger.SkipLLDBInitFiles(true);
226     m_debugger.SkipAppInitFiles(true);
227   }
228 
229   if (args.hasArg(OPT_local_lldbinit)) {
230     lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
231                                           m_debugger.GetInstanceName());
232   }
233 
234   if (args.hasArg(OPT_no_use_colors)) {
235     m_debugger.SetUseColor(false);
236     m_option_data.m_debug_mode = true;
237   }
238 
239   if (auto *arg = args.getLastArg(OPT_file)) {
240     auto arg_value = arg->getValue();
241     SBFileSpec file(arg_value);
242     if (file.Exists()) {
243       m_option_data.m_args.emplace_back(arg_value);
244     } else if (file.ResolveExecutableLocation()) {
245       char path[PATH_MAX];
246       file.GetPath(path, sizeof(path));
247       m_option_data.m_args.emplace_back(path);
248     } else {
249       error.SetErrorStringWithFormat(
250           "file specified in --file (-f) option doesn't exist: '%s'",
251           arg_value);
252       return error;
253     }
254   }
255 
256   if (auto *arg = args.getLastArg(OPT_arch)) {
257     auto arg_value = arg->getValue();
258     if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
259       error.SetErrorStringWithFormat(
260           "invalid architecture in the -a or --arch option: '%s'", arg_value);
261       return error;
262     }
263   }
264 
265   if (auto *arg = args.getLastArg(OPT_script_language)) {
266     auto arg_value = arg->getValue();
267     m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
268   }
269 
270   if (args.hasArg(OPT_source_quietly)) {
271     m_option_data.m_source_quietly = true;
272   }
273 
274   if (auto *arg = args.getLastArg(OPT_attach_name)) {
275     auto arg_value = arg->getValue();
276     m_option_data.m_process_name = arg_value;
277   }
278 
279   if (args.hasArg(OPT_wait_for)) {
280     m_option_data.m_wait_for = true;
281   }
282 
283   if (auto *arg = args.getLastArg(OPT_attach_pid)) {
284     auto arg_value = arg->getValue();
285     char *remainder;
286     m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
287     if (remainder == arg_value || *remainder != '\0') {
288       error.SetErrorStringWithFormat(
289           "Could not convert process PID: \"%s\" into a pid.", arg_value);
290       return error;
291     }
292   }
293 
294   if (auto *arg = args.getLastArg(OPT_repl_language)) {
295     auto arg_value = arg->getValue();
296     m_option_data.m_repl_lang =
297         SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
298     if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
299       error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
300                                      arg_value);
301       return error;
302     }
303   }
304 
305   if (args.hasArg(OPT_repl)) {
306     m_option_data.m_repl = true;
307   }
308 
309   if (auto *arg = args.getLastArg(OPT_repl_)) {
310     m_option_data.m_repl = true;
311     if (auto arg_value = arg->getValue())
312       m_option_data.m_repl_options = arg_value;
313   }
314 
315   // We need to process the options below together as their relative order
316   // matters.
317   for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
318                                  OPT_source, OPT_source_before_file,
319                                  OPT_one_line, OPT_one_line_before_file)) {
320     auto arg_value = arg->getValue();
321     if (arg->getOption().matches(OPT_source_on_crash)) {
322       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
323                                       true, error);
324       if (error.Fail())
325         return error;
326     }
327 
328     if (arg->getOption().matches(OPT_one_line_on_crash)) {
329       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
330                                       false, error);
331       if (error.Fail())
332         return error;
333     }
334 
335     if (arg->getOption().matches(OPT_source)) {
336       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
337                                       true, error);
338       if (error.Fail())
339         return error;
340     }
341 
342     if (arg->getOption().matches(OPT_source_before_file)) {
343       m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
344                                       true, error);
345       if (error.Fail())
346         return error;
347     }
348 
349     if (arg->getOption().matches(OPT_one_line)) {
350       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
351                                       false, error);
352       if (error.Fail())
353         return error;
354     }
355 
356     if (arg->getOption().matches(OPT_one_line_before_file)) {
357       m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
358                                       false, error);
359       if (error.Fail())
360         return error;
361     }
362   }
363 
364   if (m_option_data.m_process_name.empty() &&
365       m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
366 
367     for (auto *arg : args.filtered(OPT_INPUT))
368       m_option_data.m_args.push_back(arg->getAsString((args)));
369 
370     // Any argument following -- is an argument for the inferior.
371     if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
372       for (auto value : arg->getValues())
373         m_option_data.m_args.emplace_back(value);
374     }
375   } else if (args.getLastArgNoClaim() != nullptr) {
376     WithColor::warning() << "program arguments are ignored when attaching.\n";
377   }
378 
379   if (m_option_data.m_print_version) {
380     llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
381     exiting = true;
382     return error;
383   }
384 
385   if (m_option_data.m_print_python_path) {
386     SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
387     if (python_file_spec.IsValid()) {
388       char python_path[PATH_MAX];
389       size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
390       if (num_chars < PATH_MAX) {
391         llvm::outs() << python_path << '\n';
392       } else
393         llvm::outs() << "<PATH TOO LONG>\n";
394     } else
395       llvm::outs() << "<COULD NOT FIND PATH>\n";
396     exiting = true;
397     return error;
398   }
399 
400   return error;
401 }
402 
OpenPipe(int fds[2],std::size_t size)403 static inline int OpenPipe(int fds[2], std::size_t size) {
404 #ifdef _WIN32
405   return _pipe(fds, size, O_BINARY);
406 #else
407   (void)size;
408   return pipe(fds);
409 #endif
410 }
411 
PrepareCommandsForSourcing(const char * commands_data,size_t commands_size)412 static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
413                                           size_t commands_size) {
414   enum PIPES { READ, WRITE }; // Indexes for the read and write fds
415   int fds[2] = {-1, -1};
416 
417   if (OpenPipe(fds, commands_size) != 0) {
418     WithColor::error()
419         << "can't create pipe file descriptors for LLDB commands\n";
420     return nullptr;
421   }
422 
423   ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
424   if (size_t(nrwr) != commands_size) {
425     WithColor::error()
426         << format(
427                "write(%i, %p, %" PRIu64
428                ") failed (errno = %i) when trying to open LLDB commands pipe",
429                fds[WRITE], static_cast<const void *>(commands_data),
430                static_cast<uint64_t>(commands_size), errno)
431         << '\n';
432     llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
433     llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
434     return nullptr;
435   }
436 
437   // Close the write end of the pipe, so that the command interpreter will exit
438   // when it consumes all the data.
439   llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
440 
441   // Open the read file descriptor as a FILE * that we can return as an input
442   // handle.
443   ::FILE *commands_file = fdopen(fds[READ], "rb");
444   if (commands_file == nullptr) {
445     WithColor::error() << format("fdopen(%i, \"rb\") failed (errno = %i) "
446                                  "when trying to open LLDB commands pipe",
447                                  fds[READ], errno)
448                        << '\n';
449     llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
450     return nullptr;
451   }
452 
453   // 'commands_file' now owns the read descriptor.
454   return commands_file;
455 }
456 
EscapeString(std::string arg)457 std::string EscapeString(std::string arg) {
458   std::string::size_type pos = 0;
459   while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
460     arg.insert(pos, 1, '\\');
461     pos += 2;
462   }
463   return '"' + arg + '"';
464 }
465 
MainLoop()466 int Driver::MainLoop() {
467   if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
468     g_old_stdin_termios_is_valid = true;
469     atexit(reset_stdin_termios);
470   }
471 
472 #ifndef _MSC_VER
473   // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
474   // which causes it to miss newlines depending on whether there have been an
475   // odd or even number of characters.  Bug has been reported to MS via Connect.
476   ::setbuf(stdin, nullptr);
477 #endif
478   ::setbuf(stdout, nullptr);
479 
480   m_debugger.SetErrorFileHandle(stderr, false);
481   m_debugger.SetOutputFileHandle(stdout, false);
482   // Don't take ownership of STDIN yet...
483   m_debugger.SetInputFileHandle(stdin, false);
484 
485   m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
486 
487   struct winsize window_size;
488   if ((isatty(STDIN_FILENO) != 0) &&
489       ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
490     if (window_size.ws_col > 0)
491       m_debugger.SetTerminalWidth(window_size.ws_col);
492   }
493 
494   SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
495 
496   // Before we handle any options from the command line, we parse the
497   // REPL init file or the default file in the user's home directory.
498   SBCommandReturnObject result;
499   sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
500   if (m_option_data.m_debug_mode) {
501     result.PutError(m_debugger.GetErrorFile());
502     result.PutOutput(m_debugger.GetOutputFile());
503   }
504 
505   // Source the local .lldbinit file if it exists and we're allowed to source.
506   // Here we want to always print the return object because it contains the
507   // warning and instructions to load local lldbinit files.
508   sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
509   result.PutError(m_debugger.GetErrorFile());
510   result.PutOutput(m_debugger.GetOutputFile());
511 
512   // We allow the user to specify an exit code when calling quit which we will
513   // return when exiting.
514   m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
515 
516   // Now we handle options we got from the command line
517   SBStream commands_stream;
518 
519   // First source in the commands specified to be run before the file arguments
520   // are processed.
521   WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
522 
523   // If we're not in --repl mode, add the commands to process the file
524   // arguments, and the commands specified to run afterwards.
525   if (!m_option_data.m_repl) {
526     const size_t num_args = m_option_data.m_args.size();
527     if (num_args > 0) {
528       char arch_name[64];
529       if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
530                                                    sizeof(arch_name)))
531         commands_stream.Printf("target create --arch=%s %s", arch_name,
532                                EscapeString(m_option_data.m_args[0]).c_str());
533       else
534         commands_stream.Printf("target create %s",
535                                EscapeString(m_option_data.m_args[0]).c_str());
536 
537       if (!m_option_data.m_core_file.empty()) {
538         commands_stream.Printf(" --core %s",
539                                EscapeString(m_option_data.m_core_file).c_str());
540       }
541       commands_stream.Printf("\n");
542 
543       if (num_args > 1) {
544         commands_stream.Printf("settings set -- target.run-args ");
545         for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
546           commands_stream.Printf(
547               " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
548         commands_stream.Printf("\n");
549       }
550     } else if (!m_option_data.m_core_file.empty()) {
551       commands_stream.Printf("target create --core %s\n",
552                              EscapeString(m_option_data.m_core_file).c_str());
553     } else if (!m_option_data.m_process_name.empty()) {
554       commands_stream.Printf(
555           "process attach --name %s",
556           EscapeString(m_option_data.m_process_name).c_str());
557 
558       if (m_option_data.m_wait_for)
559         commands_stream.Printf(" --waitfor");
560 
561       commands_stream.Printf("\n");
562 
563     } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
564       commands_stream.Printf("process attach --pid %" PRIu64 "\n",
565                              m_option_data.m_process_pid);
566     }
567 
568     WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
569   } else if (!m_option_data.m_after_file_commands.empty()) {
570     // We're in repl mode and after-file-load commands were specified.
571     WithColor::warning() << "commands specified to run after file load (via -o "
572                             "or -s) are ignored in REPL mode.\n";
573   }
574 
575   if (m_option_data.m_debug_mode) {
576     result.PutError(m_debugger.GetErrorFile());
577     result.PutOutput(m_debugger.GetOutputFile());
578   }
579 
580   const bool handle_events = true;
581   const bool spawn_thread = false;
582 
583   // Check if we have any data in the commands stream, and if so, save it to a
584   // temp file
585   // so we can then run the command interpreter using the file contents.
586   const char *commands_data = commands_stream.GetData();
587   const size_t commands_size = commands_stream.GetSize();
588 
589   bool go_interactive = true;
590   if ((commands_data != nullptr) && (commands_size != 0u)) {
591     FILE *commands_file =
592         PrepareCommandsForSourcing(commands_data, commands_size);
593 
594     if (commands_file == nullptr) {
595       // We should have already printed an error in PrepareCommandsForSourcing.
596       return 1;
597     }
598 
599     m_debugger.SetInputFileHandle(commands_file, true);
600 
601     // Set the debugger into Sync mode when running the command file. Otherwise
602     // command files that run the target won't run in a sensible way.
603     bool old_async = m_debugger.GetAsync();
604     m_debugger.SetAsync(false);
605 
606     SBCommandInterpreterRunOptions options;
607     options.SetAutoHandleEvents(true);
608     options.SetSpawnThread(false);
609     options.SetStopOnError(true);
610     options.SetStopOnCrash(m_option_data.m_batch);
611 
612     SBCommandInterpreterRunResult results =
613         m_debugger.RunCommandInterpreter(options);
614     if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
615       go_interactive = false;
616     if (m_option_data.m_batch &&
617         results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
618       go_interactive = false;
619 
620     // When running in batch mode and stopped because of an error, exit with a
621     // non-zero exit status.
622     if (m_option_data.m_batch &&
623         results.GetResult() == lldb::eCommandInterpreterResultCommandError)
624       return 1;
625 
626     if (m_option_data.m_batch &&
627         results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
628         !m_option_data.m_after_crash_commands.empty()) {
629       SBStream crash_commands_stream;
630       WriteCommandsForSourcing(eCommandPlacementAfterCrash,
631                                crash_commands_stream);
632       const char *crash_commands_data = crash_commands_stream.GetData();
633       const size_t crash_commands_size = crash_commands_stream.GetSize();
634       commands_file =
635           PrepareCommandsForSourcing(crash_commands_data, crash_commands_size);
636       if (commands_file != nullptr) {
637         m_debugger.SetInputFileHandle(commands_file, true);
638         SBCommandInterpreterRunResult local_results =
639             m_debugger.RunCommandInterpreter(options);
640         if (local_results.GetResult() ==
641             lldb::eCommandInterpreterResultQuitRequested)
642           go_interactive = false;
643 
644         // When running in batch mode and an error occurred while sourcing
645         // the crash commands, exit with a non-zero exit status.
646         if (m_option_data.m_batch &&
647             local_results.GetResult() ==
648                 lldb::eCommandInterpreterResultCommandError)
649           return 1;
650       }
651     }
652     m_debugger.SetAsync(old_async);
653   }
654 
655   // Now set the input file handle to STDIN and run the command interpreter
656   // again in interactive mode or repl mode and let the debugger take ownership
657   // of stdin.
658   if (go_interactive) {
659     m_debugger.SetInputFileHandle(stdin, true);
660 
661     if (m_option_data.m_repl) {
662       const char *repl_options = nullptr;
663       if (!m_option_data.m_repl_options.empty())
664         repl_options = m_option_data.m_repl_options.c_str();
665       SBError error(
666           m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
667       if (error.Fail()) {
668         const char *error_cstr = error.GetCString();
669         if ((error_cstr != nullptr) && (error_cstr[0] != 0))
670           WithColor::error() << error_cstr << '\n';
671         else
672           WithColor::error() << error.GetError() << '\n';
673       }
674     } else {
675       m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
676     }
677   }
678 
679   reset_stdin_termios();
680   fclose(stdin);
681 
682   return sb_interpreter.GetQuitStatus();
683 }
684 
ResizeWindow(unsigned short col)685 void Driver::ResizeWindow(unsigned short col) {
686   GetDebugger().SetTerminalWidth(col);
687 }
688 
sigwinch_handler(int signo)689 void sigwinch_handler(int signo) {
690   struct winsize window_size;
691   if ((isatty(STDIN_FILENO) != 0) &&
692       ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
693     if ((window_size.ws_col > 0) && g_driver != nullptr) {
694       g_driver->ResizeWindow(window_size.ws_col);
695     }
696   }
697 }
698 
sigint_handler(int signo)699 void sigint_handler(int signo) {
700 #ifdef _WIN32 // Restore handler as it is not persistent on Windows
701   signal(SIGINT, sigint_handler);
702 #endif
703   static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
704   if (g_driver != nullptr) {
705     if (!g_interrupt_sent.test_and_set()) {
706       g_driver->GetDebugger().DispatchInputInterrupt();
707       g_interrupt_sent.clear();
708       return;
709     }
710   }
711 
712   _exit(signo);
713 }
714 
sigtstp_handler(int signo)715 void sigtstp_handler(int signo) {
716   if (g_driver != nullptr)
717     g_driver->GetDebugger().SaveInputTerminalState();
718 
719   signal(signo, SIG_DFL);
720   kill(getpid(), signo);
721   signal(signo, sigtstp_handler);
722 }
723 
sigcont_handler(int signo)724 void sigcont_handler(int signo) {
725   if (g_driver != nullptr)
726     g_driver->GetDebugger().RestoreInputTerminalState();
727 
728   signal(signo, SIG_DFL);
729   kill(getpid(), signo);
730   signal(signo, sigcont_handler);
731 }
732 
reproducer_handler(void * finalize_cmd)733 void reproducer_handler(void *finalize_cmd) {
734   if (SBReproducer::Generate()) {
735     int result = std::system(static_cast<const char *>(finalize_cmd));
736     (void)result;
737     fflush(stdout);
738   }
739 }
740 
printHelp(LLDBOptTable & table,llvm::StringRef tool_name)741 static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
742   std::string usage_str = tool_name.str() + " [options]";
743   table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
744 
745   std::string examples = R"___(
746 EXAMPLES:
747   The debugger can be started in several modes.
748 
749   Passing an executable as a positional argument prepares lldb to debug the
750   given executable. To disambiguate between arguments passed to lldb and
751   arguments passed to the debugged executable, arguments starting with a - must
752   be passed after --.
753 
754     lldb --arch x86_64 /path/to/program program argument -- --arch armv7
755 
756   For convenience, passing the executable after -- is also supported.
757 
758     lldb --arch x86_64 -- /path/to/program program argument --arch armv7
759 
760   Passing one of the attach options causes lldb to immediately attach to the
761   given process.
762 
763     lldb -p <pid>
764     lldb -n <process-name>
765 
766   Passing --repl starts lldb in REPL mode.
767 
768     lldb -r
769 
770   Passing --core causes lldb to debug the core file.
771 
772     lldb -c /path/to/core
773 
774   Command options can be combined with these modes and cause lldb to run the
775   specified commands before or after events, like loading the file or crashing,
776   in the order provided on the command line.
777 
778     lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
779     lldb -S /source/before/file -s /source/after/file
780     lldb -K /source/before/crash -k /source/after/crash
781 
782   Note: In REPL mode no file is loaded, so commands specified to run after
783   loading the file (via -o or -s) will be ignored.)___";
784   llvm::outs() << examples << '\n';
785 }
786 
InitializeReproducer(llvm::StringRef argv0,opt::InputArgList & input_args)787 llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0,
788                                          opt::InputArgList &input_args) {
789   if (auto *finalize_path = input_args.getLastArg(OPT_reproducer_finalize)) {
790     if (const char *error = SBReproducer::Finalize(finalize_path->getValue())) {
791       WithColor::error() << "reproducer finalization failed: " << error << '\n';
792       return 1;
793     }
794 
795     llvm::outs() << "********************\n";
796     llvm::outs() << "Crash reproducer for ";
797     llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
798     llvm::outs() << '\n';
799     llvm::outs() << "Reproducer written to '" << SBReproducer::GetPath()
800                  << "'\n";
801     llvm::outs() << '\n';
802     llvm::outs() << "Before attaching the reproducer to a bug report:\n";
803     llvm::outs() << " - Look at the directory to ensure you're willing to "
804                     "share its content.\n";
805     llvm::outs()
806         << " - Make sure the reproducer works by replaying the reproducer.\n";
807     llvm::outs() << '\n';
808     llvm::outs() << "Replay the reproducer with the following command:\n";
809     llvm::outs() << argv0 << " -replay " << finalize_path->getValue() << "\n";
810     llvm::outs() << "********************\n";
811     return 0;
812   }
813 
814   if (auto *replay_path = input_args.getLastArg(OPT_replay)) {
815     SBReplayOptions replay_options;
816     replay_options.SetCheckVersion(!input_args.hasArg(OPT_no_version_check));
817     replay_options.SetVerify(!input_args.hasArg(OPT_no_verification));
818     if (const char *error =
819             SBReproducer::Replay(replay_path->getValue(), replay_options)) {
820       WithColor::error() << "reproducer replay failed: " << error << '\n';
821       return 1;
822     }
823     return 0;
824   }
825 
826   bool capture = input_args.hasArg(OPT_capture);
827   bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit);
828   auto *capture_path = input_args.getLastArg(OPT_capture_path);
829 
830   if (generate_on_exit && !capture) {
831     WithColor::warning()
832         << "-reproducer-generate-on-exit specified without -capture\n";
833   }
834 
835   if (capture || capture_path) {
836     if (capture_path) {
837       if (!capture)
838         WithColor::warning() << "-capture-path specified without -capture\n";
839       if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
840         WithColor::error() << "reproducer capture failed: " << error << '\n';
841         return 1;
842       }
843     } else {
844       const char *error = SBReproducer::Capture();
845       if (error) {
846         WithColor::error() << "reproducer capture failed: " << error << '\n';
847         return 1;
848       }
849     }
850     if (generate_on_exit)
851       SBReproducer::SetAutoGenerate(true);
852 
853     // Register the reproducer signal handler.
854     if (!input_args.hasArg(OPT_no_generate_on_signal)) {
855       if (const char *reproducer_path = SBReproducer::GetPath()) {
856         // Leaking the string on purpose.
857         std::string *finalize_cmd = new std::string(argv0);
858         finalize_cmd->append(" --reproducer-finalize '");
859         finalize_cmd->append(reproducer_path);
860         finalize_cmd->append("'");
861         llvm::sys::AddSignalHandler(reproducer_handler,
862                                     const_cast<char *>(finalize_cmd->c_str()));
863       }
864     }
865   }
866 
867   return llvm::None;
868 }
869 
main(int argc,char const * argv[])870 int main(int argc, char const *argv[]) {
871   // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
872   // destruction.
873   llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
874 
875   // Parse arguments.
876   LLDBOptTable T;
877   unsigned MissingArgIndex;
878   unsigned MissingArgCount;
879   ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
880   opt::InputArgList input_args =
881       T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
882   llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
883 
884   if (input_args.hasArg(OPT_help)) {
885     printHelp(T, argv0);
886     return 0;
887   }
888 
889   // Check for missing argument error.
890   if (MissingArgCount) {
891     WithColor::error() << "argument to '"
892                        << input_args.getArgString(MissingArgIndex)
893                        << "' is missing\n";
894   }
895   // Error out on unknown options.
896   if (input_args.hasArg(OPT_UNKNOWN)) {
897     for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
898       WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
899     }
900   }
901   if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {
902     llvm::errs() << "Use '" << argv0
903                  << " --help' for a complete list of options.\n";
904     return 1;
905   }
906 
907   if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
908     return *exit_code;
909   }
910 
911   SBError error = SBDebugger::InitializeWithErrorHandling();
912   if (error.Fail()) {
913     WithColor::error() << "initialization failed: " << error.GetCString()
914                        << '\n';
915     return 1;
916   }
917   SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
918 
919   signal(SIGINT, sigint_handler);
920 #if !defined(_MSC_VER)
921   signal(SIGPIPE, SIG_IGN);
922   signal(SIGWINCH, sigwinch_handler);
923   signal(SIGTSTP, sigtstp_handler);
924   signal(SIGCONT, sigcont_handler);
925 #endif
926 
927   int exit_code = 0;
928   // Create a scope for driver so that the driver object will destroy itself
929   // before SBDebugger::Terminate() is called.
930   {
931     Driver driver;
932 
933     bool exiting = false;
934     SBError error(driver.ProcessArgs(input_args, exiting));
935     if (error.Fail()) {
936       exit_code = 1;
937       if (const char *error_cstr = error.GetCString())
938         WithColor::error() << error_cstr << '\n';
939     } else if (!exiting) {
940       exit_code = driver.MainLoop();
941     }
942   }
943 
944   SBDebugger::Terminate();
945   return exit_code;
946 }
947