xref: /freebsd-src/contrib/llvm-project/lldb/tools/driver/Driver.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "Driver.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/API/SBCommandInterpreter.h"
125ffd83dbSDimitry Andric #include "lldb/API/SBCommandInterpreterRunOptions.h"
130b57cec5SDimitry Andric #include "lldb/API/SBCommandReturnObject.h"
140b57cec5SDimitry Andric #include "lldb/API/SBDebugger.h"
159dba64beSDimitry Andric #include "lldb/API/SBFile.h"
160b57cec5SDimitry Andric #include "lldb/API/SBHostOS.h"
170b57cec5SDimitry Andric #include "lldb/API/SBLanguageRuntime.h"
180b57cec5SDimitry Andric #include "lldb/API/SBStream.h"
190b57cec5SDimitry Andric #include "lldb/API/SBStringList.h"
20349cc55cSDimitry Andric #include "lldb/API/SBStructuredData.h"
217a6dacacSDimitry Andric #include "lldb/Host/Config.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
240b57cec5SDimitry Andric #include "llvm/Support/Format.h"
259dba64beSDimitry Andric #include "llvm/Support/InitLLVM.h"
260b57cec5SDimitry Andric #include "llvm/Support/Path.h"
270b57cec5SDimitry Andric #include "llvm/Support/Signals.h"
280b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
290b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric #include <algorithm>
320b57cec5SDimitry Andric #include <atomic>
330b57cec5SDimitry Andric #include <bitset>
34fe6060f1SDimitry Andric #include <clocale>
350b57cec5SDimitry Andric #include <csignal>
36*0fca6ea1SDimitry Andric #include <future>
370b57cec5SDimitry Andric #include <string>
380b57cec5SDimitry Andric #include <thread>
390b57cec5SDimitry Andric #include <utility>
400b57cec5SDimitry Andric 
41fe6060f1SDimitry Andric #include <climits>
42fe6060f1SDimitry Andric #include <cstdio>
43fe6060f1SDimitry Andric #include <cstdlib>
44fe6060f1SDimitry Andric #include <cstring>
450b57cec5SDimitry Andric #include <fcntl.h>
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric #if !defined(__APPLE__)
480b57cec5SDimitry Andric #include "llvm/Support/DataTypes.h"
490b57cec5SDimitry Andric #endif
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric using namespace lldb;
520b57cec5SDimitry Andric using namespace llvm;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric namespace {
555f757f3fSDimitry Andric using namespace llvm::opt;
565f757f3fSDimitry Andric 
570b57cec5SDimitry Andric enum ID {
580b57cec5SDimitry Andric   OPT_INVALID = 0, // This is not an option ID.
595f757f3fSDimitry Andric #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
600b57cec5SDimitry Andric #include "Options.inc"
610b57cec5SDimitry Andric #undef OPTION
620b57cec5SDimitry Andric };
630b57cec5SDimitry Andric 
64bdd1243dSDimitry Andric #define PREFIX(NAME, VALUE)                                                    \
65bdd1243dSDimitry Andric   static constexpr StringLiteral NAME##_init[] = VALUE;                        \
66bdd1243dSDimitry Andric   static constexpr ArrayRef<StringLiteral> NAME(NAME##_init,                   \
67bdd1243dSDimitry Andric                                                 std::size(NAME##_init) - 1);
680b57cec5SDimitry Andric #include "Options.inc"
690b57cec5SDimitry Andric #undef PREFIX
700b57cec5SDimitry Andric 
71bdd1243dSDimitry Andric static constexpr opt::OptTable::Info InfoTable[] = {
725f757f3fSDimitry Andric #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
730b57cec5SDimitry Andric #include "Options.inc"
740b57cec5SDimitry Andric #undef OPTION
750b57cec5SDimitry Andric };
760b57cec5SDimitry Andric 
77bdd1243dSDimitry Andric class LLDBOptTable : public opt::GenericOptTable {
780b57cec5SDimitry Andric public:
79bdd1243dSDimitry Andric   LLDBOptTable() : opt::GenericOptTable(InfoTable) {}
800b57cec5SDimitry Andric };
810b57cec5SDimitry Andric } // namespace
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric static void reset_stdin_termios();
840b57cec5SDimitry Andric static bool g_old_stdin_termios_is_valid = false;
850b57cec5SDimitry Andric static struct termios g_old_stdin_termios;
860b57cec5SDimitry Andric 
8781ad6265SDimitry Andric static bool disable_color(const raw_ostream &OS) { return false; }
8881ad6265SDimitry Andric 
890b57cec5SDimitry Andric static Driver *g_driver = nullptr;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric // In the Driver::MainLoop, we change the terminal settings.  This function is
920b57cec5SDimitry Andric // added as an atexit handler to make sure we clean them up.
930b57cec5SDimitry Andric static void reset_stdin_termios() {
940b57cec5SDimitry Andric   if (g_old_stdin_termios_is_valid) {
950b57cec5SDimitry Andric     g_old_stdin_termios_is_valid = false;
960b57cec5SDimitry Andric     ::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric Driver::Driver()
1010b57cec5SDimitry Andric     : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {
1020b57cec5SDimitry Andric   // We want to be able to handle CTRL+D in the terminal to have it terminate
1030b57cec5SDimitry Andric   // certain input
1040b57cec5SDimitry Andric   m_debugger.SetCloseInputOnEOF(false);
1050b57cec5SDimitry Andric   g_driver = this;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
108e8d8bef9SDimitry Andric Driver::~Driver() {
109e8d8bef9SDimitry Andric   SBDebugger::Destroy(m_debugger);
110e8d8bef9SDimitry Andric   g_driver = nullptr;
111e8d8bef9SDimitry Andric }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric void Driver::OptionData::AddInitialCommand(std::string command,
1140b57cec5SDimitry Andric                                            CommandPlacement placement,
1150b57cec5SDimitry Andric                                            bool is_file, SBError &error) {
1160b57cec5SDimitry Andric   std::vector<InitialCmdEntry> *command_set;
1170b57cec5SDimitry Andric   switch (placement) {
1180b57cec5SDimitry Andric   case eCommandPlacementBeforeFile:
1190b57cec5SDimitry Andric     command_set = &(m_initial_commands);
1200b57cec5SDimitry Andric     break;
1210b57cec5SDimitry Andric   case eCommandPlacementAfterFile:
1220b57cec5SDimitry Andric     command_set = &(m_after_file_commands);
1230b57cec5SDimitry Andric     break;
1240b57cec5SDimitry Andric   case eCommandPlacementAfterCrash:
1250b57cec5SDimitry Andric     command_set = &(m_after_crash_commands);
1260b57cec5SDimitry Andric     break;
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   if (is_file) {
1300b57cec5SDimitry Andric     SBFileSpec file(command.c_str());
1310b57cec5SDimitry Andric     if (file.Exists())
1320b57cec5SDimitry Andric       command_set->push_back(InitialCmdEntry(command, is_file));
1330b57cec5SDimitry Andric     else if (file.ResolveExecutableLocation()) {
1340b57cec5SDimitry Andric       char final_path[PATH_MAX];
1350b57cec5SDimitry Andric       file.GetPath(final_path, sizeof(final_path));
1360b57cec5SDimitry Andric       command_set->push_back(InitialCmdEntry(final_path, is_file));
1370b57cec5SDimitry Andric     } else
1380b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
1390b57cec5SDimitry Andric           "file specified in --source (-s) option doesn't exist: '%s'",
1400b57cec5SDimitry Andric           command.c_str());
1410b57cec5SDimitry Andric   } else
1420b57cec5SDimitry Andric     command_set->push_back(InitialCmdEntry(command, is_file));
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric void Driver::WriteCommandsForSourcing(CommandPlacement placement,
1460b57cec5SDimitry Andric                                       SBStream &strm) {
1470b57cec5SDimitry Andric   std::vector<OptionData::InitialCmdEntry> *command_set;
1480b57cec5SDimitry Andric   switch (placement) {
1490b57cec5SDimitry Andric   case eCommandPlacementBeforeFile:
1500b57cec5SDimitry Andric     command_set = &m_option_data.m_initial_commands;
1510b57cec5SDimitry Andric     break;
1520b57cec5SDimitry Andric   case eCommandPlacementAfterFile:
1530b57cec5SDimitry Andric     command_set = &m_option_data.m_after_file_commands;
1540b57cec5SDimitry Andric     break;
1550b57cec5SDimitry Andric   case eCommandPlacementAfterCrash:
1560b57cec5SDimitry Andric     command_set = &m_option_data.m_after_crash_commands;
1570b57cec5SDimitry Andric     break;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   for (const auto &command_entry : *command_set) {
1610b57cec5SDimitry Andric     const char *command = command_entry.contents.c_str();
1620b57cec5SDimitry Andric     if (command_entry.is_file) {
1630b57cec5SDimitry Andric       bool source_quietly =
1640b57cec5SDimitry Andric           m_option_data.m_source_quietly || command_entry.source_quietly;
1650b57cec5SDimitry Andric       strm.Printf("command source -s %i '%s'\n",
1660b57cec5SDimitry Andric                   static_cast<int>(source_quietly), command);
1670b57cec5SDimitry Andric     } else
1680b57cec5SDimitry Andric       strm.Printf("%s\n", command);
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric // Check the arguments that were passed to this program to make sure they are
1730b57cec5SDimitry Andric // valid and to get their argument values (if any).  Return a boolean value
1740b57cec5SDimitry Andric // indicating whether or not to start up the full debugger (i.e. the Command
1750b57cec5SDimitry Andric // Interpreter) or not.  Return FALSE if the arguments were invalid OR if the
1760b57cec5SDimitry Andric // user only wanted help or version information.
1770b57cec5SDimitry Andric SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
1780b57cec5SDimitry Andric   SBError error;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   // This is kind of a pain, but since we make the debugger in the Driver's
1810b57cec5SDimitry Andric   // constructor, we can't know at that point whether we should read in init
1820b57cec5SDimitry Andric   // files yet.  So we don't read them in in the Driver constructor, then set
1830b57cec5SDimitry Andric   // the flags back to "read them in" here, and then if we see the "-n" flag,
1840b57cec5SDimitry Andric   // we'll turn it off again.  Finally we have to read them in by hand later in
1850b57cec5SDimitry Andric   // the main loop.
1860b57cec5SDimitry Andric   m_debugger.SkipLLDBInitFiles(false);
1870b57cec5SDimitry Andric   m_debugger.SkipAppInitFiles(false);
1880b57cec5SDimitry Andric 
18981ad6265SDimitry Andric   if (args.hasArg(OPT_no_use_colors)) {
19081ad6265SDimitry Andric     m_debugger.SetUseColor(false);
19181ad6265SDimitry Andric     WithColor::setAutoDetectFunction(disable_color);
19281ad6265SDimitry Andric   }
19381ad6265SDimitry Andric 
1940b57cec5SDimitry Andric   if (args.hasArg(OPT_version)) {
1950b57cec5SDimitry Andric     m_option_data.m_print_version = true;
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   if (args.hasArg(OPT_python_path)) {
1990b57cec5SDimitry Andric     m_option_data.m_print_python_path = true;
2000b57cec5SDimitry Andric   }
201349cc55cSDimitry Andric   if (args.hasArg(OPT_print_script_interpreter_info)) {
202349cc55cSDimitry Andric     m_option_data.m_print_script_interpreter_info = true;
203349cc55cSDimitry Andric   }
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric   if (args.hasArg(OPT_batch)) {
2060b57cec5SDimitry Andric     m_option_data.m_batch = true;
2070b57cec5SDimitry Andric   }
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_core)) {
2105f757f3fSDimitry Andric     auto *arg_value = arg->getValue();
2110b57cec5SDimitry Andric     SBFileSpec file(arg_value);
2120b57cec5SDimitry Andric     if (!file.Exists()) {
2130b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
2140b57cec5SDimitry Andric           "file specified in --core (-c) option doesn't exist: '%s'",
2150b57cec5SDimitry Andric           arg_value);
2160b57cec5SDimitry Andric       return error;
2170b57cec5SDimitry Andric     }
2180b57cec5SDimitry Andric     m_option_data.m_core_file = arg_value;
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   if (args.hasArg(OPT_editor)) {
2220b57cec5SDimitry Andric     m_option_data.m_use_external_editor = true;
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   if (args.hasArg(OPT_no_lldbinit)) {
2260b57cec5SDimitry Andric     m_debugger.SkipLLDBInitFiles(true);
2270b57cec5SDimitry Andric     m_debugger.SkipAppInitFiles(true);
2280b57cec5SDimitry Andric   }
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   if (args.hasArg(OPT_local_lldbinit)) {
2310b57cec5SDimitry Andric     lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
2320b57cec5SDimitry Andric                                           m_debugger.GetInstanceName());
2330b57cec5SDimitry Andric   }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_file)) {
2365f757f3fSDimitry Andric     auto *arg_value = arg->getValue();
2370b57cec5SDimitry Andric     SBFileSpec file(arg_value);
2380b57cec5SDimitry Andric     if (file.Exists()) {
2390b57cec5SDimitry Andric       m_option_data.m_args.emplace_back(arg_value);
2400b57cec5SDimitry Andric     } else if (file.ResolveExecutableLocation()) {
2410b57cec5SDimitry Andric       char path[PATH_MAX];
2420b57cec5SDimitry Andric       file.GetPath(path, sizeof(path));
2430b57cec5SDimitry Andric       m_option_data.m_args.emplace_back(path);
2440b57cec5SDimitry Andric     } else {
2450b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
2460b57cec5SDimitry Andric           "file specified in --file (-f) option doesn't exist: '%s'",
2470b57cec5SDimitry Andric           arg_value);
2480b57cec5SDimitry Andric       return error;
2490b57cec5SDimitry Andric     }
2500b57cec5SDimitry Andric   }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_arch)) {
2535f757f3fSDimitry Andric     auto *arg_value = arg->getValue();
2540b57cec5SDimitry Andric     if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
2550b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
2560b57cec5SDimitry Andric           "invalid architecture in the -a or --arch option: '%s'", arg_value);
2570b57cec5SDimitry Andric       return error;
2580b57cec5SDimitry Andric     }
2590b57cec5SDimitry Andric   }
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_script_language)) {
2625f757f3fSDimitry Andric     auto *arg_value = arg->getValue();
2630b57cec5SDimitry Andric     m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
2640b57cec5SDimitry Andric   }
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   if (args.hasArg(OPT_source_quietly)) {
2670b57cec5SDimitry Andric     m_option_data.m_source_quietly = true;
2680b57cec5SDimitry Andric   }
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_attach_name)) {
2715f757f3fSDimitry Andric     auto *arg_value = arg->getValue();
2720b57cec5SDimitry Andric     m_option_data.m_process_name = arg_value;
2730b57cec5SDimitry Andric   }
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric   if (args.hasArg(OPT_wait_for)) {
2760b57cec5SDimitry Andric     m_option_data.m_wait_for = true;
2770b57cec5SDimitry Andric   }
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_attach_pid)) {
2805f757f3fSDimitry Andric     auto *arg_value = arg->getValue();
2810b57cec5SDimitry Andric     char *remainder;
2820b57cec5SDimitry Andric     m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
2830b57cec5SDimitry Andric     if (remainder == arg_value || *remainder != '\0') {
2840b57cec5SDimitry Andric       error.SetErrorStringWithFormat(
2850b57cec5SDimitry Andric           "Could not convert process PID: \"%s\" into a pid.", arg_value);
2860b57cec5SDimitry Andric       return error;
2870b57cec5SDimitry Andric     }
2880b57cec5SDimitry Andric   }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_repl_language)) {
2915f757f3fSDimitry Andric     auto *arg_value = arg->getValue();
2920b57cec5SDimitry Andric     m_option_data.m_repl_lang =
2930b57cec5SDimitry Andric         SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
2940b57cec5SDimitry Andric     if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
2950b57cec5SDimitry Andric       error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
2960b57cec5SDimitry Andric                                      arg_value);
2970b57cec5SDimitry Andric       return error;
2980b57cec5SDimitry Andric     }
29904eeddc0SDimitry Andric     m_debugger.SetREPLLanguage(m_option_data.m_repl_lang);
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   if (args.hasArg(OPT_repl)) {
3030b57cec5SDimitry Andric     m_option_data.m_repl = true;
3040b57cec5SDimitry Andric   }
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric   if (auto *arg = args.getLastArg(OPT_repl_)) {
3070b57cec5SDimitry Andric     m_option_data.m_repl = true;
3085f757f3fSDimitry Andric     if (auto *arg_value = arg->getValue())
3090b57cec5SDimitry Andric       m_option_data.m_repl_options = arg_value;
3100b57cec5SDimitry Andric   }
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric   // We need to process the options below together as their relative order
3130b57cec5SDimitry Andric   // matters.
3140b57cec5SDimitry Andric   for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
3150b57cec5SDimitry Andric                                  OPT_source, OPT_source_before_file,
3160b57cec5SDimitry Andric                                  OPT_one_line, OPT_one_line_before_file)) {
3175f757f3fSDimitry Andric     auto *arg_value = arg->getValue();
3180b57cec5SDimitry Andric     if (arg->getOption().matches(OPT_source_on_crash)) {
3190b57cec5SDimitry Andric       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
3200b57cec5SDimitry Andric                                       true, error);
3210b57cec5SDimitry Andric       if (error.Fail())
3220b57cec5SDimitry Andric         return error;
3230b57cec5SDimitry Andric     }
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric     if (arg->getOption().matches(OPT_one_line_on_crash)) {
3260b57cec5SDimitry Andric       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
3270b57cec5SDimitry Andric                                       false, error);
3280b57cec5SDimitry Andric       if (error.Fail())
3290b57cec5SDimitry Andric         return error;
3300b57cec5SDimitry Andric     }
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric     if (arg->getOption().matches(OPT_source)) {
3330b57cec5SDimitry Andric       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
3340b57cec5SDimitry Andric                                       true, error);
3350b57cec5SDimitry Andric       if (error.Fail())
3360b57cec5SDimitry Andric         return error;
3370b57cec5SDimitry Andric     }
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     if (arg->getOption().matches(OPT_source_before_file)) {
3400b57cec5SDimitry Andric       m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
3410b57cec5SDimitry Andric                                       true, error);
3420b57cec5SDimitry Andric       if (error.Fail())
3430b57cec5SDimitry Andric         return error;
3440b57cec5SDimitry Andric     }
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric     if (arg->getOption().matches(OPT_one_line)) {
3470b57cec5SDimitry Andric       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
3480b57cec5SDimitry Andric                                       false, error);
3490b57cec5SDimitry Andric       if (error.Fail())
3500b57cec5SDimitry Andric         return error;
3510b57cec5SDimitry Andric     }
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric     if (arg->getOption().matches(OPT_one_line_before_file)) {
3540b57cec5SDimitry Andric       m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
3550b57cec5SDimitry Andric                                       false, error);
3560b57cec5SDimitry Andric       if (error.Fail())
3570b57cec5SDimitry Andric         return error;
3580b57cec5SDimitry Andric     }
3590b57cec5SDimitry Andric   }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   if (m_option_data.m_process_name.empty() &&
3620b57cec5SDimitry Andric       m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
3630b57cec5SDimitry Andric 
3645ffd83dbSDimitry Andric     for (auto *arg : args.filtered(OPT_INPUT))
3650b57cec5SDimitry Andric       m_option_data.m_args.push_back(arg->getAsString((args)));
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric     // Any argument following -- is an argument for the inferior.
3680b57cec5SDimitry Andric     if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
3695f757f3fSDimitry Andric       for (auto *value : arg->getValues())
3700b57cec5SDimitry Andric         m_option_data.m_args.emplace_back(value);
3710b57cec5SDimitry Andric     }
3720b57cec5SDimitry Andric   } else if (args.getLastArgNoClaim() != nullptr) {
3730b57cec5SDimitry Andric     WithColor::warning() << "program arguments are ignored when attaching.\n";
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric   if (m_option_data.m_print_version) {
3770b57cec5SDimitry Andric     llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
3780b57cec5SDimitry Andric     exiting = true;
3790b57cec5SDimitry Andric     return error;
3800b57cec5SDimitry Andric   }
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   if (m_option_data.m_print_python_path) {
3830b57cec5SDimitry Andric     SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
3840b57cec5SDimitry Andric     if (python_file_spec.IsValid()) {
3850b57cec5SDimitry Andric       char python_path[PATH_MAX];
3860b57cec5SDimitry Andric       size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
3870b57cec5SDimitry Andric       if (num_chars < PATH_MAX) {
3880b57cec5SDimitry Andric         llvm::outs() << python_path << '\n';
3890b57cec5SDimitry Andric       } else
3900b57cec5SDimitry Andric         llvm::outs() << "<PATH TOO LONG>\n";
3910b57cec5SDimitry Andric     } else
3920b57cec5SDimitry Andric       llvm::outs() << "<COULD NOT FIND PATH>\n";
3930b57cec5SDimitry Andric     exiting = true;
3940b57cec5SDimitry Andric     return error;
3950b57cec5SDimitry Andric   }
3960b57cec5SDimitry Andric 
397349cc55cSDimitry Andric   if (m_option_data.m_print_script_interpreter_info) {
398349cc55cSDimitry Andric     SBStructuredData info =
399349cc55cSDimitry Andric         m_debugger.GetScriptInterpreterInfo(m_debugger.GetScriptLanguage());
400349cc55cSDimitry Andric     if (!info) {
401349cc55cSDimitry Andric       error.SetErrorString("no script interpreter.");
402349cc55cSDimitry Andric     } else {
403349cc55cSDimitry Andric       SBStream stream;
404349cc55cSDimitry Andric       error = info.GetAsJSON(stream);
405349cc55cSDimitry Andric       if (error.Success()) {
406349cc55cSDimitry Andric         llvm::outs() << stream.GetData() << '\n';
407349cc55cSDimitry Andric       }
408349cc55cSDimitry Andric     }
409349cc55cSDimitry Andric     exiting = true;
410349cc55cSDimitry Andric     return error;
411349cc55cSDimitry Andric   }
412349cc55cSDimitry Andric 
4130b57cec5SDimitry Andric   return error;
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric std::string EscapeString(std::string arg) {
4170b57cec5SDimitry Andric   std::string::size_type pos = 0;
4180b57cec5SDimitry Andric   while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
4190b57cec5SDimitry Andric     arg.insert(pos, 1, '\\');
4200b57cec5SDimitry Andric     pos += 2;
4210b57cec5SDimitry Andric   }
4220b57cec5SDimitry Andric   return '"' + arg + '"';
4230b57cec5SDimitry Andric }
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric int Driver::MainLoop() {
4260b57cec5SDimitry Andric   if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
4270b57cec5SDimitry Andric     g_old_stdin_termios_is_valid = true;
4280b57cec5SDimitry Andric     atexit(reset_stdin_termios);
4290b57cec5SDimitry Andric   }
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric #ifndef _MSC_VER
4320b57cec5SDimitry Andric   // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
4330b57cec5SDimitry Andric   // which causes it to miss newlines depending on whether there have been an
4340b57cec5SDimitry Andric   // odd or even number of characters.  Bug has been reported to MS via Connect.
4350b57cec5SDimitry Andric   ::setbuf(stdin, nullptr);
4360b57cec5SDimitry Andric #endif
4370b57cec5SDimitry Andric   ::setbuf(stdout, nullptr);
4380b57cec5SDimitry Andric 
4390b57cec5SDimitry Andric   m_debugger.SetErrorFileHandle(stderr, false);
4400b57cec5SDimitry Andric   m_debugger.SetOutputFileHandle(stdout, false);
4410b57cec5SDimitry Andric   // Don't take ownership of STDIN yet...
4420b57cec5SDimitry Andric   m_debugger.SetInputFileHandle(stdin, false);
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric   m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric   struct winsize window_size;
4470b57cec5SDimitry Andric   if ((isatty(STDIN_FILENO) != 0) &&
4480b57cec5SDimitry Andric       ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
4490b57cec5SDimitry Andric     if (window_size.ws_col > 0)
4500b57cec5SDimitry Andric       m_debugger.SetTerminalWidth(window_size.ws_col);
4510b57cec5SDimitry Andric   }
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric   SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
4540b57cec5SDimitry Andric 
45581ad6265SDimitry Andric   // Process lldbinit files before handling any options from the command line.
4560b57cec5SDimitry Andric   SBCommandReturnObject result;
45781ad6265SDimitry Andric   sb_interpreter.SourceInitFileInGlobalDirectory(result);
458e8d8bef9SDimitry Andric   sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   // Source the local .lldbinit file if it exists and we're allowed to source.
4610b57cec5SDimitry Andric   // Here we want to always print the return object because it contains the
4620b57cec5SDimitry Andric   // warning and instructions to load local lldbinit files.
4630b57cec5SDimitry Andric   sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
4649dba64beSDimitry Andric   result.PutError(m_debugger.GetErrorFile());
4659dba64beSDimitry Andric   result.PutOutput(m_debugger.GetOutputFile());
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric   // We allow the user to specify an exit code when calling quit which we will
4680b57cec5SDimitry Andric   // return when exiting.
4690b57cec5SDimitry Andric   m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   // Now we handle options we got from the command line
4720b57cec5SDimitry Andric   SBStream commands_stream;
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric   // First source in the commands specified to be run before the file arguments
4750b57cec5SDimitry Andric   // are processed.
4760b57cec5SDimitry Andric   WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
4770b57cec5SDimitry Andric 
4780b57cec5SDimitry Andric   // If we're not in --repl mode, add the commands to process the file
4790b57cec5SDimitry Andric   // arguments, and the commands specified to run afterwards.
4800b57cec5SDimitry Andric   if (!m_option_data.m_repl) {
4810b57cec5SDimitry Andric     const size_t num_args = m_option_data.m_args.size();
4820b57cec5SDimitry Andric     if (num_args > 0) {
4830b57cec5SDimitry Andric       char arch_name[64];
4840b57cec5SDimitry Andric       if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
4850b57cec5SDimitry Andric                                                    sizeof(arch_name)))
4860b57cec5SDimitry Andric         commands_stream.Printf("target create --arch=%s %s", arch_name,
4870b57cec5SDimitry Andric                                EscapeString(m_option_data.m_args[0]).c_str());
4880b57cec5SDimitry Andric       else
4890b57cec5SDimitry Andric         commands_stream.Printf("target create %s",
4900b57cec5SDimitry Andric                                EscapeString(m_option_data.m_args[0]).c_str());
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric       if (!m_option_data.m_core_file.empty()) {
4930b57cec5SDimitry Andric         commands_stream.Printf(" --core %s",
4940b57cec5SDimitry Andric                                EscapeString(m_option_data.m_core_file).c_str());
4950b57cec5SDimitry Andric       }
4960b57cec5SDimitry Andric       commands_stream.Printf("\n");
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric       if (num_args > 1) {
4990b57cec5SDimitry Andric         commands_stream.Printf("settings set -- target.run-args ");
5000b57cec5SDimitry Andric         for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
5010b57cec5SDimitry Andric           commands_stream.Printf(
5020b57cec5SDimitry Andric               " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
5030b57cec5SDimitry Andric         commands_stream.Printf("\n");
5040b57cec5SDimitry Andric       }
5050b57cec5SDimitry Andric     } else if (!m_option_data.m_core_file.empty()) {
5060b57cec5SDimitry Andric       commands_stream.Printf("target create --core %s\n",
5070b57cec5SDimitry Andric                              EscapeString(m_option_data.m_core_file).c_str());
5080b57cec5SDimitry Andric     } else if (!m_option_data.m_process_name.empty()) {
5090b57cec5SDimitry Andric       commands_stream.Printf(
5100b57cec5SDimitry Andric           "process attach --name %s",
5110b57cec5SDimitry Andric           EscapeString(m_option_data.m_process_name).c_str());
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric       if (m_option_data.m_wait_for)
5140b57cec5SDimitry Andric         commands_stream.Printf(" --waitfor");
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric       commands_stream.Printf("\n");
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric     } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
5190b57cec5SDimitry Andric       commands_stream.Printf("process attach --pid %" PRIu64 "\n",
5200b57cec5SDimitry Andric                              m_option_data.m_process_pid);
5210b57cec5SDimitry Andric     }
5220b57cec5SDimitry Andric 
5230b57cec5SDimitry Andric     WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
5240b57cec5SDimitry Andric   } else if (!m_option_data.m_after_file_commands.empty()) {
5250b57cec5SDimitry Andric     // We're in repl mode and after-file-load commands were specified.
5260b57cec5SDimitry Andric     WithColor::warning() << "commands specified to run after file load (via -o "
5270b57cec5SDimitry Andric                             "or -s) are ignored in REPL mode.\n";
5280b57cec5SDimitry Andric   }
5290b57cec5SDimitry Andric 
5300b57cec5SDimitry Andric   const bool handle_events = true;
5310b57cec5SDimitry Andric   const bool spawn_thread = false;
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric   // Check if we have any data in the commands stream, and if so, save it to a
5340b57cec5SDimitry Andric   // temp file
5350b57cec5SDimitry Andric   // so we can then run the command interpreter using the file contents.
5365ffd83dbSDimitry Andric   bool go_interactive = true;
5374824e7fdSDimitry Andric   if ((commands_stream.GetData() != nullptr) &&
5384824e7fdSDimitry Andric       (commands_stream.GetSize() != 0u)) {
5394824e7fdSDimitry Andric     SBError error = m_debugger.SetInputString(commands_stream.GetData());
5404824e7fdSDimitry Andric     if (error.Fail()) {
5414824e7fdSDimitry Andric       WithColor::error() << error.GetCString() << '\n';
542e8d8bef9SDimitry Andric       return 1;
5435ffd83dbSDimitry Andric     }
5445ffd83dbSDimitry Andric 
5455ffd83dbSDimitry Andric     // Set the debugger into Sync mode when running the command file. Otherwise
5465ffd83dbSDimitry Andric     // command files that run the target won't run in a sensible way.
5470b57cec5SDimitry Andric     bool old_async = m_debugger.GetAsync();
5480b57cec5SDimitry Andric     m_debugger.SetAsync(false);
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric     SBCommandInterpreterRunOptions options;
5515ffd83dbSDimitry Andric     options.SetAutoHandleEvents(true);
5525ffd83dbSDimitry Andric     options.SetSpawnThread(false);
5530b57cec5SDimitry Andric     options.SetStopOnError(true);
5545ffd83dbSDimitry Andric     options.SetStopOnCrash(m_option_data.m_batch);
555349cc55cSDimitry Andric     options.SetEchoCommands(!m_option_data.m_source_quietly);
5560b57cec5SDimitry Andric 
5575ffd83dbSDimitry Andric     SBCommandInterpreterRunResult results =
5585ffd83dbSDimitry Andric         m_debugger.RunCommandInterpreter(options);
5595ffd83dbSDimitry Andric     if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
5605ffd83dbSDimitry Andric       go_interactive = false;
5615ffd83dbSDimitry Andric     if (m_option_data.m_batch &&
5625ffd83dbSDimitry Andric         results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
5635ffd83dbSDimitry Andric       go_interactive = false;
5640b57cec5SDimitry Andric 
5655ffd83dbSDimitry Andric     // When running in batch mode and stopped because of an error, exit with a
5665ffd83dbSDimitry Andric     // non-zero exit status.
5675ffd83dbSDimitry Andric     if (m_option_data.m_batch &&
5685ffd83dbSDimitry Andric         results.GetResult() == lldb::eCommandInterpreterResultCommandError)
569e8d8bef9SDimitry Andric       return 1;
5705ffd83dbSDimitry Andric 
5715ffd83dbSDimitry Andric     if (m_option_data.m_batch &&
5725ffd83dbSDimitry Andric         results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
5730b57cec5SDimitry Andric         !m_option_data.m_after_crash_commands.empty()) {
5740b57cec5SDimitry Andric       SBStream crash_commands_stream;
5750b57cec5SDimitry Andric       WriteCommandsForSourcing(eCommandPlacementAfterCrash,
5760b57cec5SDimitry Andric                                crash_commands_stream);
5774824e7fdSDimitry Andric       SBError error =
5784824e7fdSDimitry Andric           m_debugger.SetInputString(crash_commands_stream.GetData());
5794824e7fdSDimitry Andric       if (error.Success()) {
5805ffd83dbSDimitry Andric         SBCommandInterpreterRunResult local_results =
5815ffd83dbSDimitry Andric             m_debugger.RunCommandInterpreter(options);
5825ffd83dbSDimitry Andric         if (local_results.GetResult() ==
5835ffd83dbSDimitry Andric             lldb::eCommandInterpreterResultQuitRequested)
5845ffd83dbSDimitry Andric           go_interactive = false;
5850b57cec5SDimitry Andric 
5865ffd83dbSDimitry Andric         // When running in batch mode and an error occurred while sourcing
5875ffd83dbSDimitry Andric         // the crash commands, exit with a non-zero exit status.
5885ffd83dbSDimitry Andric         if (m_option_data.m_batch &&
5895ffd83dbSDimitry Andric             local_results.GetResult() ==
5905ffd83dbSDimitry Andric                 lldb::eCommandInterpreterResultCommandError)
591e8d8bef9SDimitry Andric           return 1;
5920b57cec5SDimitry Andric       }
5930b57cec5SDimitry Andric     }
5945ffd83dbSDimitry Andric     m_debugger.SetAsync(old_async);
5955ffd83dbSDimitry Andric   }
5960b57cec5SDimitry Andric 
5975ffd83dbSDimitry Andric   // Now set the input file handle to STDIN and run the command interpreter
5985ffd83dbSDimitry Andric   // again in interactive mode or repl mode and let the debugger take ownership
5995ffd83dbSDimitry Andric   // of stdin.
6000b57cec5SDimitry Andric   if (go_interactive) {
6010b57cec5SDimitry Andric     m_debugger.SetInputFileHandle(stdin, true);
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric     if (m_option_data.m_repl) {
6040b57cec5SDimitry Andric       const char *repl_options = nullptr;
6050b57cec5SDimitry Andric       if (!m_option_data.m_repl_options.empty())
6060b57cec5SDimitry Andric         repl_options = m_option_data.m_repl_options.c_str();
6070b57cec5SDimitry Andric       SBError error(
6080b57cec5SDimitry Andric           m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
6090b57cec5SDimitry Andric       if (error.Fail()) {
6100b57cec5SDimitry Andric         const char *error_cstr = error.GetCString();
6110b57cec5SDimitry Andric         if ((error_cstr != nullptr) && (error_cstr[0] != 0))
6120b57cec5SDimitry Andric           WithColor::error() << error_cstr << '\n';
6130b57cec5SDimitry Andric         else
6140b57cec5SDimitry Andric           WithColor::error() << error.GetError() << '\n';
6150b57cec5SDimitry Andric       }
6160b57cec5SDimitry Andric     } else {
6170b57cec5SDimitry Andric       m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
6180b57cec5SDimitry Andric     }
6190b57cec5SDimitry Andric   }
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric   reset_stdin_termios();
6220b57cec5SDimitry Andric   fclose(stdin);
6230b57cec5SDimitry Andric 
624e8d8bef9SDimitry Andric   return sb_interpreter.GetQuitStatus();
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric void Driver::ResizeWindow(unsigned short col) {
6280b57cec5SDimitry Andric   GetDebugger().SetTerminalWidth(col);
6290b57cec5SDimitry Andric }
6300b57cec5SDimitry Andric 
6310b57cec5SDimitry Andric void sigwinch_handler(int signo) {
6320b57cec5SDimitry Andric   struct winsize window_size;
6330b57cec5SDimitry Andric   if ((isatty(STDIN_FILENO) != 0) &&
6340b57cec5SDimitry Andric       ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
6350b57cec5SDimitry Andric     if ((window_size.ws_col > 0) && g_driver != nullptr) {
6360b57cec5SDimitry Andric       g_driver->ResizeWindow(window_size.ws_col);
6370b57cec5SDimitry Andric     }
6380b57cec5SDimitry Andric   }
6390b57cec5SDimitry Andric }
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric void sigint_handler(int signo) {
6420b57cec5SDimitry Andric #ifdef _WIN32 // Restore handler as it is not persistent on Windows
6430b57cec5SDimitry Andric   signal(SIGINT, sigint_handler);
6440b57cec5SDimitry Andric #endif
6450b57cec5SDimitry Andric   static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
6460b57cec5SDimitry Andric   if (g_driver != nullptr) {
6470b57cec5SDimitry Andric     if (!g_interrupt_sent.test_and_set()) {
6480b57cec5SDimitry Andric       g_driver->GetDebugger().DispatchInputInterrupt();
6490b57cec5SDimitry Andric       g_interrupt_sent.clear();
6500b57cec5SDimitry Andric       return;
6510b57cec5SDimitry Andric     }
6520b57cec5SDimitry Andric   }
6530b57cec5SDimitry Andric 
6540b57cec5SDimitry Andric   _exit(signo);
6550b57cec5SDimitry Andric }
6560b57cec5SDimitry Andric 
65781ad6265SDimitry Andric #ifndef _WIN32
65881ad6265SDimitry Andric static void sigtstp_handler(int signo) {
6590b57cec5SDimitry Andric   if (g_driver != nullptr)
6600b57cec5SDimitry Andric     g_driver->GetDebugger().SaveInputTerminalState();
6610b57cec5SDimitry Andric 
66281ad6265SDimitry Andric   // Unblock the signal and remove our handler.
66381ad6265SDimitry Andric   sigset_t set;
66481ad6265SDimitry Andric   sigemptyset(&set);
66581ad6265SDimitry Andric   sigaddset(&set, signo);
66681ad6265SDimitry Andric   pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
6670b57cec5SDimitry Andric   signal(signo, SIG_DFL);
6680b57cec5SDimitry Andric 
66981ad6265SDimitry Andric   // Now re-raise the signal. We will immediately suspend...
67081ad6265SDimitry Andric   raise(signo);
67181ad6265SDimitry Andric   // ... and resume after a SIGCONT.
67281ad6265SDimitry Andric 
67381ad6265SDimitry Andric   // Now undo the modifications.
67481ad6265SDimitry Andric   pthread_sigmask(SIG_BLOCK, &set, nullptr);
67581ad6265SDimitry Andric   signal(signo, sigtstp_handler);
67681ad6265SDimitry Andric 
6770b57cec5SDimitry Andric   if (g_driver != nullptr)
6780b57cec5SDimitry Andric     g_driver->GetDebugger().RestoreInputTerminalState();
6790b57cec5SDimitry Andric }
68081ad6265SDimitry Andric #endif
681480093f4SDimitry Andric 
6820b57cec5SDimitry Andric static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
683480093f4SDimitry Andric   std::string usage_str = tool_name.str() + " [options]";
684fe6060f1SDimitry Andric   table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
6850b57cec5SDimitry Andric 
6860b57cec5SDimitry Andric   std::string examples = R"___(
6870b57cec5SDimitry Andric EXAMPLES:
6880b57cec5SDimitry Andric   The debugger can be started in several modes.
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric   Passing an executable as a positional argument prepares lldb to debug the
6915ffd83dbSDimitry Andric   given executable. To disambiguate between arguments passed to lldb and
6925ffd83dbSDimitry Andric   arguments passed to the debugged executable, arguments starting with a - must
6935ffd83dbSDimitry Andric   be passed after --.
6940b57cec5SDimitry Andric 
69523408297SDimitry Andric     lldb --arch x86_64 /path/to/program program argument -- --arch armv7
6965ffd83dbSDimitry Andric 
6975ffd83dbSDimitry Andric   For convenience, passing the executable after -- is also supported.
6985ffd83dbSDimitry Andric 
69923408297SDimitry Andric     lldb --arch x86_64 -- /path/to/program program argument --arch armv7
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric   Passing one of the attach options causes lldb to immediately attach to the
7020b57cec5SDimitry Andric   given process.
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric     lldb -p <pid>
7050b57cec5SDimitry Andric     lldb -n <process-name>
7060b57cec5SDimitry Andric 
7070b57cec5SDimitry Andric   Passing --repl starts lldb in REPL mode.
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric     lldb -r
7100b57cec5SDimitry Andric 
7110b57cec5SDimitry Andric   Passing --core causes lldb to debug the core file.
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric     lldb -c /path/to/core
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric   Command options can be combined with these modes and cause lldb to run the
7160b57cec5SDimitry Andric   specified commands before or after events, like loading the file or crashing,
7170b57cec5SDimitry Andric   in the order provided on the command line.
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric     lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
7200b57cec5SDimitry Andric     lldb -S /source/before/file -s /source/after/file
7210b57cec5SDimitry Andric     lldb -K /source/before/crash -k /source/after/crash
7220b57cec5SDimitry Andric 
7230b57cec5SDimitry Andric   Note: In REPL mode no file is loaded, so commands specified to run after
724480093f4SDimitry Andric   loading the file (via -o or -s) will be ignored.)___";
725480093f4SDimitry Andric   llvm::outs() << examples << '\n';
7260b57cec5SDimitry Andric }
7270b57cec5SDimitry Andric 
728480093f4SDimitry Andric int main(int argc, char const *argv[]) {
729fe6060f1SDimitry Andric   // Editline uses for example iswprint which is dependent on LC_CTYPE.
730fe6060f1SDimitry Andric   std::setlocale(LC_ALL, "");
731fe6060f1SDimitry Andric   std::setlocale(LC_CTYPE, "");
732fe6060f1SDimitry Andric 
733480093f4SDimitry Andric   // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
734480093f4SDimitry Andric   // destruction.
735480093f4SDimitry Andric   llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
736*0fca6ea1SDimitry Andric #if !defined(__APPLE__)
7377a6dacacSDimitry Andric   llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
7387a6dacacSDimitry Andric                         " and include the crash backtrace.\n");
739*0fca6ea1SDimitry Andric #else
740*0fca6ea1SDimitry Andric   llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
741*0fca6ea1SDimitry Andric                         " and include the crash report from "
742*0fca6ea1SDimitry Andric                         "~/Library/Logs/DiagnosticReports/.\n");
743*0fca6ea1SDimitry Andric #endif
7440b57cec5SDimitry Andric 
7450b57cec5SDimitry Andric   // Parse arguments.
7460b57cec5SDimitry Andric   LLDBOptTable T;
747e8d8bef9SDimitry Andric   unsigned MissingArgIndex;
748e8d8bef9SDimitry Andric   unsigned MissingArgCount;
749bdd1243dSDimitry Andric   ArrayRef<const char *> arg_arr = ArrayRef(argv + 1, argc - 1);
750e8d8bef9SDimitry Andric   opt::InputArgList input_args =
751e8d8bef9SDimitry Andric       T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
7525ffd83dbSDimitry Andric   llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric   if (input_args.hasArg(OPT_help)) {
7555ffd83dbSDimitry Andric     printHelp(T, argv0);
7560b57cec5SDimitry Andric     return 0;
7570b57cec5SDimitry Andric   }
7580b57cec5SDimitry Andric 
759e8d8bef9SDimitry Andric   // Check for missing argument error.
760e8d8bef9SDimitry Andric   if (MissingArgCount) {
761e8d8bef9SDimitry Andric     WithColor::error() << "argument to '"
762e8d8bef9SDimitry Andric                        << input_args.getArgString(MissingArgIndex)
763e8d8bef9SDimitry Andric                        << "' is missing\n";
764e8d8bef9SDimitry Andric   }
7655ffd83dbSDimitry Andric   // Error out on unknown options.
7665ffd83dbSDimitry Andric   if (input_args.hasArg(OPT_UNKNOWN)) {
7670b57cec5SDimitry Andric     for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
7685ffd83dbSDimitry Andric       WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
7695ffd83dbSDimitry Andric     }
770e8d8bef9SDimitry Andric   }
771e8d8bef9SDimitry Andric   if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {
7725ffd83dbSDimitry Andric     llvm::errs() << "Use '" << argv0
7735ffd83dbSDimitry Andric                  << " --help' for a complete list of options.\n";
7745ffd83dbSDimitry Andric     return 1;
7750b57cec5SDimitry Andric   }
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   SBError error = SBDebugger::InitializeWithErrorHandling();
7780b57cec5SDimitry Andric   if (error.Fail()) {
7790b57cec5SDimitry Andric     WithColor::error() << "initialization failed: " << error.GetCString()
7800b57cec5SDimitry Andric                        << '\n';
7810b57cec5SDimitry Andric     return 1;
7820b57cec5SDimitry Andric   }
783bdd1243dSDimitry Andric 
784bdd1243dSDimitry Andric   // Setup LLDB signal handlers once the debugger has been initialized.
785bdd1243dSDimitry Andric   SBDebugger::PrintDiagnosticsOnError();
786bdd1243dSDimitry Andric 
7870b57cec5SDimitry Andric   signal(SIGINT, sigint_handler);
78881ad6265SDimitry Andric #if !defined(_WIN32)
7890b57cec5SDimitry Andric   signal(SIGPIPE, SIG_IGN);
7900b57cec5SDimitry Andric   signal(SIGWINCH, sigwinch_handler);
7910b57cec5SDimitry Andric   signal(SIGTSTP, sigtstp_handler);
7920b57cec5SDimitry Andric #endif
7930b57cec5SDimitry Andric 
7940b57cec5SDimitry Andric   int exit_code = 0;
7950b57cec5SDimitry Andric   // Create a scope for driver so that the driver object will destroy itself
7960b57cec5SDimitry Andric   // before SBDebugger::Terminate() is called.
7970b57cec5SDimitry Andric   {
7980b57cec5SDimitry Andric     Driver driver;
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric     bool exiting = false;
8010b57cec5SDimitry Andric     SBError error(driver.ProcessArgs(input_args, exiting));
8020b57cec5SDimitry Andric     if (error.Fail()) {
8030b57cec5SDimitry Andric       exit_code = 1;
8040b57cec5SDimitry Andric       if (const char *error_cstr = error.GetCString())
8050b57cec5SDimitry Andric         WithColor::error() << error_cstr << '\n';
8060b57cec5SDimitry Andric     } else if (!exiting) {
8070b57cec5SDimitry Andric       exit_code = driver.MainLoop();
8080b57cec5SDimitry Andric     }
8090b57cec5SDimitry Andric   }
8100b57cec5SDimitry Andric 
811*0fca6ea1SDimitry Andric   // When terminating the debugger we have to wait on all the background tasks
812*0fca6ea1SDimitry Andric   // to complete, which can take a while. Print a message when this takes longer
813*0fca6ea1SDimitry Andric   // than 1 second.
814*0fca6ea1SDimitry Andric   {
815*0fca6ea1SDimitry Andric     std::future<void> future =
816*0fca6ea1SDimitry Andric         std::async(std::launch::async, []() { SBDebugger::Terminate(); });
817*0fca6ea1SDimitry Andric 
818*0fca6ea1SDimitry Andric     if (future.wait_for(std::chrono::seconds(1)) == std::future_status::timeout)
819*0fca6ea1SDimitry Andric       fprintf(stderr, "Waiting for background tasks to complete...\n");
820*0fca6ea1SDimitry Andric 
821*0fca6ea1SDimitry Andric     future.wait();
822*0fca6ea1SDimitry Andric   }
823*0fca6ea1SDimitry Andric 
8240b57cec5SDimitry Andric   return exit_code;
8250b57cec5SDimitry Andric }
826