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