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