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