Path: blob/main/contrib/llvm-project/lldb/tools/driver/Driver.cpp
34879 views
//===-- Driver.cpp ----------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Driver.h"910#include "lldb/API/SBCommandInterpreter.h"11#include "lldb/API/SBCommandInterpreterRunOptions.h"12#include "lldb/API/SBCommandReturnObject.h"13#include "lldb/API/SBDebugger.h"14#include "lldb/API/SBFile.h"15#include "lldb/API/SBHostOS.h"16#include "lldb/API/SBLanguageRuntime.h"17#include "lldb/API/SBStream.h"18#include "lldb/API/SBStringList.h"19#include "lldb/API/SBStructuredData.h"20#include "lldb/Host/Config.h"2122#include "llvm/ADT/StringRef.h"23#include "llvm/Support/Format.h"24#include "llvm/Support/InitLLVM.h"25#include "llvm/Support/Path.h"26#include "llvm/Support/Signals.h"27#include "llvm/Support/WithColor.h"28#include "llvm/Support/raw_ostream.h"2930#include <algorithm>31#include <atomic>32#include <bitset>33#include <clocale>34#include <csignal>35#include <future>36#include <string>37#include <thread>38#include <utility>3940#include <climits>41#include <cstdio>42#include <cstdlib>43#include <cstring>44#include <fcntl.h>4546#if !defined(__APPLE__)47#include "llvm/Support/DataTypes.h"48#endif4950using namespace lldb;51using namespace llvm;5253namespace {54using namespace llvm::opt;5556enum ID {57OPT_INVALID = 0, // This is not an option ID.58#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),59#include "Options.inc"60#undef OPTION61};6263#define PREFIX(NAME, VALUE) \64static constexpr StringLiteral NAME##_init[] = VALUE; \65static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \66std::size(NAME##_init) - 1);67#include "Options.inc"68#undef PREFIX6970static constexpr opt::OptTable::Info InfoTable[] = {71#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),72#include "Options.inc"73#undef OPTION74};7576class LLDBOptTable : public opt::GenericOptTable {77public:78LLDBOptTable() : opt::GenericOptTable(InfoTable) {}79};80} // namespace8182static void reset_stdin_termios();83static bool g_old_stdin_termios_is_valid = false;84static struct termios g_old_stdin_termios;8586static bool disable_color(const raw_ostream &OS) { return false; }8788static Driver *g_driver = nullptr;8990// In the Driver::MainLoop, we change the terminal settings. This function is91// added as an atexit handler to make sure we clean them up.92static void reset_stdin_termios() {93if (g_old_stdin_termios_is_valid) {94g_old_stdin_termios_is_valid = false;95::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios);96}97}9899Driver::Driver()100: SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {101// We want to be able to handle CTRL+D in the terminal to have it terminate102// certain input103m_debugger.SetCloseInputOnEOF(false);104g_driver = this;105}106107Driver::~Driver() {108SBDebugger::Destroy(m_debugger);109g_driver = nullptr;110}111112void Driver::OptionData::AddInitialCommand(std::string command,113CommandPlacement placement,114bool is_file, SBError &error) {115std::vector<InitialCmdEntry> *command_set;116switch (placement) {117case eCommandPlacementBeforeFile:118command_set = &(m_initial_commands);119break;120case eCommandPlacementAfterFile:121command_set = &(m_after_file_commands);122break;123case eCommandPlacementAfterCrash:124command_set = &(m_after_crash_commands);125break;126}127128if (is_file) {129SBFileSpec file(command.c_str());130if (file.Exists())131command_set->push_back(InitialCmdEntry(command, is_file));132else if (file.ResolveExecutableLocation()) {133char final_path[PATH_MAX];134file.GetPath(final_path, sizeof(final_path));135command_set->push_back(InitialCmdEntry(final_path, is_file));136} else137error.SetErrorStringWithFormat(138"file specified in --source (-s) option doesn't exist: '%s'",139command.c_str());140} else141command_set->push_back(InitialCmdEntry(command, is_file));142}143144void Driver::WriteCommandsForSourcing(CommandPlacement placement,145SBStream &strm) {146std::vector<OptionData::InitialCmdEntry> *command_set;147switch (placement) {148case eCommandPlacementBeforeFile:149command_set = &m_option_data.m_initial_commands;150break;151case eCommandPlacementAfterFile:152command_set = &m_option_data.m_after_file_commands;153break;154case eCommandPlacementAfterCrash:155command_set = &m_option_data.m_after_crash_commands;156break;157}158159for (const auto &command_entry : *command_set) {160const char *command = command_entry.contents.c_str();161if (command_entry.is_file) {162bool source_quietly =163m_option_data.m_source_quietly || command_entry.source_quietly;164strm.Printf("command source -s %i '%s'\n",165static_cast<int>(source_quietly), command);166} else167strm.Printf("%s\n", command);168}169}170171// Check the arguments that were passed to this program to make sure they are172// valid and to get their argument values (if any). Return a boolean value173// indicating whether or not to start up the full debugger (i.e. the Command174// Interpreter) or not. Return FALSE if the arguments were invalid OR if the175// user only wanted help or version information.176SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {177SBError error;178179// This is kind of a pain, but since we make the debugger in the Driver's180// constructor, we can't know at that point whether we should read in init181// files yet. So we don't read them in in the Driver constructor, then set182// the flags back to "read them in" here, and then if we see the "-n" flag,183// we'll turn it off again. Finally we have to read them in by hand later in184// the main loop.185m_debugger.SkipLLDBInitFiles(false);186m_debugger.SkipAppInitFiles(false);187188if (args.hasArg(OPT_no_use_colors)) {189m_debugger.SetUseColor(false);190WithColor::setAutoDetectFunction(disable_color);191}192193if (args.hasArg(OPT_version)) {194m_option_data.m_print_version = true;195}196197if (args.hasArg(OPT_python_path)) {198m_option_data.m_print_python_path = true;199}200if (args.hasArg(OPT_print_script_interpreter_info)) {201m_option_data.m_print_script_interpreter_info = true;202}203204if (args.hasArg(OPT_batch)) {205m_option_data.m_batch = true;206}207208if (auto *arg = args.getLastArg(OPT_core)) {209auto *arg_value = arg->getValue();210SBFileSpec file(arg_value);211if (!file.Exists()) {212error.SetErrorStringWithFormat(213"file specified in --core (-c) option doesn't exist: '%s'",214arg_value);215return error;216}217m_option_data.m_core_file = arg_value;218}219220if (args.hasArg(OPT_editor)) {221m_option_data.m_use_external_editor = true;222}223224if (args.hasArg(OPT_no_lldbinit)) {225m_debugger.SkipLLDBInitFiles(true);226m_debugger.SkipAppInitFiles(true);227}228229if (args.hasArg(OPT_local_lldbinit)) {230lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",231m_debugger.GetInstanceName());232}233234if (auto *arg = args.getLastArg(OPT_file)) {235auto *arg_value = arg->getValue();236SBFileSpec file(arg_value);237if (file.Exists()) {238m_option_data.m_args.emplace_back(arg_value);239} else if (file.ResolveExecutableLocation()) {240char path[PATH_MAX];241file.GetPath(path, sizeof(path));242m_option_data.m_args.emplace_back(path);243} else {244error.SetErrorStringWithFormat(245"file specified in --file (-f) option doesn't exist: '%s'",246arg_value);247return error;248}249}250251if (auto *arg = args.getLastArg(OPT_arch)) {252auto *arg_value = arg->getValue();253if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {254error.SetErrorStringWithFormat(255"invalid architecture in the -a or --arch option: '%s'", arg_value);256return error;257}258}259260if (auto *arg = args.getLastArg(OPT_script_language)) {261auto *arg_value = arg->getValue();262m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));263}264265if (args.hasArg(OPT_source_quietly)) {266m_option_data.m_source_quietly = true;267}268269if (auto *arg = args.getLastArg(OPT_attach_name)) {270auto *arg_value = arg->getValue();271m_option_data.m_process_name = arg_value;272}273274if (args.hasArg(OPT_wait_for)) {275m_option_data.m_wait_for = true;276}277278if (auto *arg = args.getLastArg(OPT_attach_pid)) {279auto *arg_value = arg->getValue();280char *remainder;281m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);282if (remainder == arg_value || *remainder != '\0') {283error.SetErrorStringWithFormat(284"Could not convert process PID: \"%s\" into a pid.", arg_value);285return error;286}287}288289if (auto *arg = args.getLastArg(OPT_repl_language)) {290auto *arg_value = arg->getValue();291m_option_data.m_repl_lang =292SBLanguageRuntime::GetLanguageTypeFromString(arg_value);293if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {294error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",295arg_value);296return error;297}298m_debugger.SetREPLLanguage(m_option_data.m_repl_lang);299}300301if (args.hasArg(OPT_repl)) {302m_option_data.m_repl = true;303}304305if (auto *arg = args.getLastArg(OPT_repl_)) {306m_option_data.m_repl = true;307if (auto *arg_value = arg->getValue())308m_option_data.m_repl_options = arg_value;309}310311// We need to process the options below together as their relative order312// matters.313for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,314OPT_source, OPT_source_before_file,315OPT_one_line, OPT_one_line_before_file)) {316auto *arg_value = arg->getValue();317if (arg->getOption().matches(OPT_source_on_crash)) {318m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,319true, error);320if (error.Fail())321return error;322}323324if (arg->getOption().matches(OPT_one_line_on_crash)) {325m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,326false, error);327if (error.Fail())328return error;329}330331if (arg->getOption().matches(OPT_source)) {332m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,333true, error);334if (error.Fail())335return error;336}337338if (arg->getOption().matches(OPT_source_before_file)) {339m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,340true, error);341if (error.Fail())342return error;343}344345if (arg->getOption().matches(OPT_one_line)) {346m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,347false, error);348if (error.Fail())349return error;350}351352if (arg->getOption().matches(OPT_one_line_before_file)) {353m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,354false, error);355if (error.Fail())356return error;357}358}359360if (m_option_data.m_process_name.empty() &&361m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {362363for (auto *arg : args.filtered(OPT_INPUT))364m_option_data.m_args.push_back(arg->getAsString((args)));365366// Any argument following -- is an argument for the inferior.367if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {368for (auto *value : arg->getValues())369m_option_data.m_args.emplace_back(value);370}371} else if (args.getLastArgNoClaim() != nullptr) {372WithColor::warning() << "program arguments are ignored when attaching.\n";373}374375if (m_option_data.m_print_version) {376llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';377exiting = true;378return error;379}380381if (m_option_data.m_print_python_path) {382SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();383if (python_file_spec.IsValid()) {384char python_path[PATH_MAX];385size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);386if (num_chars < PATH_MAX) {387llvm::outs() << python_path << '\n';388} else389llvm::outs() << "<PATH TOO LONG>\n";390} else391llvm::outs() << "<COULD NOT FIND PATH>\n";392exiting = true;393return error;394}395396if (m_option_data.m_print_script_interpreter_info) {397SBStructuredData info =398m_debugger.GetScriptInterpreterInfo(m_debugger.GetScriptLanguage());399if (!info) {400error.SetErrorString("no script interpreter.");401} else {402SBStream stream;403error = info.GetAsJSON(stream);404if (error.Success()) {405llvm::outs() << stream.GetData() << '\n';406}407}408exiting = true;409return error;410}411412return error;413}414415std::string EscapeString(std::string arg) {416std::string::size_type pos = 0;417while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {418arg.insert(pos, 1, '\\');419pos += 2;420}421return '"' + arg + '"';422}423424int Driver::MainLoop() {425if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {426g_old_stdin_termios_is_valid = true;427atexit(reset_stdin_termios);428}429430#ifndef _MSC_VER431// Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets432// which causes it to miss newlines depending on whether there have been an433// odd or even number of characters. Bug has been reported to MS via Connect.434::setbuf(stdin, nullptr);435#endif436::setbuf(stdout, nullptr);437438m_debugger.SetErrorFileHandle(stderr, false);439m_debugger.SetOutputFileHandle(stdout, false);440// Don't take ownership of STDIN yet...441m_debugger.SetInputFileHandle(stdin, false);442443m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);444445struct winsize window_size;446if ((isatty(STDIN_FILENO) != 0) &&447::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {448if (window_size.ws_col > 0)449m_debugger.SetTerminalWidth(window_size.ws_col);450}451452SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();453454// Process lldbinit files before handling any options from the command line.455SBCommandReturnObject result;456sb_interpreter.SourceInitFileInGlobalDirectory(result);457sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);458459// Source the local .lldbinit file if it exists and we're allowed to source.460// Here we want to always print the return object because it contains the461// warning and instructions to load local lldbinit files.462sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);463result.PutError(m_debugger.GetErrorFile());464result.PutOutput(m_debugger.GetOutputFile());465466// We allow the user to specify an exit code when calling quit which we will467// return when exiting.468m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);469470// Now we handle options we got from the command line471SBStream commands_stream;472473// First source in the commands specified to be run before the file arguments474// are processed.475WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);476477// If we're not in --repl mode, add the commands to process the file478// arguments, and the commands specified to run afterwards.479if (!m_option_data.m_repl) {480const size_t num_args = m_option_data.m_args.size();481if (num_args > 0) {482char arch_name[64];483if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,484sizeof(arch_name)))485commands_stream.Printf("target create --arch=%s %s", arch_name,486EscapeString(m_option_data.m_args[0]).c_str());487else488commands_stream.Printf("target create %s",489EscapeString(m_option_data.m_args[0]).c_str());490491if (!m_option_data.m_core_file.empty()) {492commands_stream.Printf(" --core %s",493EscapeString(m_option_data.m_core_file).c_str());494}495commands_stream.Printf("\n");496497if (num_args > 1) {498commands_stream.Printf("settings set -- target.run-args ");499for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)500commands_stream.Printf(501" %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());502commands_stream.Printf("\n");503}504} else if (!m_option_data.m_core_file.empty()) {505commands_stream.Printf("target create --core %s\n",506EscapeString(m_option_data.m_core_file).c_str());507} else if (!m_option_data.m_process_name.empty()) {508commands_stream.Printf(509"process attach --name %s",510EscapeString(m_option_data.m_process_name).c_str());511512if (m_option_data.m_wait_for)513commands_stream.Printf(" --waitfor");514515commands_stream.Printf("\n");516517} else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {518commands_stream.Printf("process attach --pid %" PRIu64 "\n",519m_option_data.m_process_pid);520}521522WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);523} else if (!m_option_data.m_after_file_commands.empty()) {524// We're in repl mode and after-file-load commands were specified.525WithColor::warning() << "commands specified to run after file load (via -o "526"or -s) are ignored in REPL mode.\n";527}528529const bool handle_events = true;530const bool spawn_thread = false;531532// Check if we have any data in the commands stream, and if so, save it to a533// temp file534// so we can then run the command interpreter using the file contents.535bool go_interactive = true;536if ((commands_stream.GetData() != nullptr) &&537(commands_stream.GetSize() != 0u)) {538SBError error = m_debugger.SetInputString(commands_stream.GetData());539if (error.Fail()) {540WithColor::error() << error.GetCString() << '\n';541return 1;542}543544// Set the debugger into Sync mode when running the command file. Otherwise545// command files that run the target won't run in a sensible way.546bool old_async = m_debugger.GetAsync();547m_debugger.SetAsync(false);548549SBCommandInterpreterRunOptions options;550options.SetAutoHandleEvents(true);551options.SetSpawnThread(false);552options.SetStopOnError(true);553options.SetStopOnCrash(m_option_data.m_batch);554options.SetEchoCommands(!m_option_data.m_source_quietly);555556SBCommandInterpreterRunResult results =557m_debugger.RunCommandInterpreter(options);558if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)559go_interactive = false;560if (m_option_data.m_batch &&561results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)562go_interactive = false;563564// When running in batch mode and stopped because of an error, exit with a565// non-zero exit status.566if (m_option_data.m_batch &&567results.GetResult() == lldb::eCommandInterpreterResultCommandError)568return 1;569570if (m_option_data.m_batch &&571results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&572!m_option_data.m_after_crash_commands.empty()) {573SBStream crash_commands_stream;574WriteCommandsForSourcing(eCommandPlacementAfterCrash,575crash_commands_stream);576SBError error =577m_debugger.SetInputString(crash_commands_stream.GetData());578if (error.Success()) {579SBCommandInterpreterRunResult local_results =580m_debugger.RunCommandInterpreter(options);581if (local_results.GetResult() ==582lldb::eCommandInterpreterResultQuitRequested)583go_interactive = false;584585// When running in batch mode and an error occurred while sourcing586// the crash commands, exit with a non-zero exit status.587if (m_option_data.m_batch &&588local_results.GetResult() ==589lldb::eCommandInterpreterResultCommandError)590return 1;591}592}593m_debugger.SetAsync(old_async);594}595596// Now set the input file handle to STDIN and run the command interpreter597// again in interactive mode or repl mode and let the debugger take ownership598// of stdin.599if (go_interactive) {600m_debugger.SetInputFileHandle(stdin, true);601602if (m_option_data.m_repl) {603const char *repl_options = nullptr;604if (!m_option_data.m_repl_options.empty())605repl_options = m_option_data.m_repl_options.c_str();606SBError error(607m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));608if (error.Fail()) {609const char *error_cstr = error.GetCString();610if ((error_cstr != nullptr) && (error_cstr[0] != 0))611WithColor::error() << error_cstr << '\n';612else613WithColor::error() << error.GetError() << '\n';614}615} else {616m_debugger.RunCommandInterpreter(handle_events, spawn_thread);617}618}619620reset_stdin_termios();621fclose(stdin);622623return sb_interpreter.GetQuitStatus();624}625626void Driver::ResizeWindow(unsigned short col) {627GetDebugger().SetTerminalWidth(col);628}629630void sigwinch_handler(int signo) {631struct winsize window_size;632if ((isatty(STDIN_FILENO) != 0) &&633::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {634if ((window_size.ws_col > 0) && g_driver != nullptr) {635g_driver->ResizeWindow(window_size.ws_col);636}637}638}639640void sigint_handler(int signo) {641#ifdef _WIN32 // Restore handler as it is not persistent on Windows642signal(SIGINT, sigint_handler);643#endif644static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;645if (g_driver != nullptr) {646if (!g_interrupt_sent.test_and_set()) {647g_driver->GetDebugger().DispatchInputInterrupt();648g_interrupt_sent.clear();649return;650}651}652653_exit(signo);654}655656#ifndef _WIN32657static void sigtstp_handler(int signo) {658if (g_driver != nullptr)659g_driver->GetDebugger().SaveInputTerminalState();660661// Unblock the signal and remove our handler.662sigset_t set;663sigemptyset(&set);664sigaddset(&set, signo);665pthread_sigmask(SIG_UNBLOCK, &set, nullptr);666signal(signo, SIG_DFL);667668// Now re-raise the signal. We will immediately suspend...669raise(signo);670// ... and resume after a SIGCONT.671672// Now undo the modifications.673pthread_sigmask(SIG_BLOCK, &set, nullptr);674signal(signo, sigtstp_handler);675676if (g_driver != nullptr)677g_driver->GetDebugger().RestoreInputTerminalState();678}679#endif680681static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {682std::string usage_str = tool_name.str() + " [options]";683table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);684685std::string examples = R"___(686EXAMPLES:687The debugger can be started in several modes.688689Passing an executable as a positional argument prepares lldb to debug the690given executable. To disambiguate between arguments passed to lldb and691arguments passed to the debugged executable, arguments starting with a - must692be passed after --.693694lldb --arch x86_64 /path/to/program program argument -- --arch armv7695696For convenience, passing the executable after -- is also supported.697698lldb --arch x86_64 -- /path/to/program program argument --arch armv7699700Passing one of the attach options causes lldb to immediately attach to the701given process.702703lldb -p <pid>704lldb -n <process-name>705706Passing --repl starts lldb in REPL mode.707708lldb -r709710Passing --core causes lldb to debug the core file.711712lldb -c /path/to/core713714Command options can be combined with these modes and cause lldb to run the715specified commands before or after events, like loading the file or crashing,716in the order provided on the command line.717718lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'719lldb -S /source/before/file -s /source/after/file720lldb -K /source/before/crash -k /source/after/crash721722Note: In REPL mode no file is loaded, so commands specified to run after723loading the file (via -o or -s) will be ignored.)___";724llvm::outs() << examples << '\n';725}726727int main(int argc, char const *argv[]) {728// Editline uses for example iswprint which is dependent on LC_CTYPE.729std::setlocale(LC_ALL, "");730std::setlocale(LC_CTYPE, "");731732// Setup LLVM signal handlers and make sure we call llvm_shutdown() on733// destruction.734llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);735#if !defined(__APPLE__)736llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL737" and include the crash backtrace.\n");738#else739llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL740" and include the crash report from "741"~/Library/Logs/DiagnosticReports/.\n");742#endif743744// Parse arguments.745LLDBOptTable T;746unsigned MissingArgIndex;747unsigned MissingArgCount;748ArrayRef<const char *> arg_arr = ArrayRef(argv + 1, argc - 1);749opt::InputArgList input_args =750T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);751llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);752753if (input_args.hasArg(OPT_help)) {754printHelp(T, argv0);755return 0;756}757758// Check for missing argument error.759if (MissingArgCount) {760WithColor::error() << "argument to '"761<< input_args.getArgString(MissingArgIndex)762<< "' is missing\n";763}764// Error out on unknown options.765if (input_args.hasArg(OPT_UNKNOWN)) {766for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {767WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';768}769}770if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {771llvm::errs() << "Use '" << argv0772<< " --help' for a complete list of options.\n";773return 1;774}775776SBError error = SBDebugger::InitializeWithErrorHandling();777if (error.Fail()) {778WithColor::error() << "initialization failed: " << error.GetCString()779<< '\n';780return 1;781}782783// Setup LLDB signal handlers once the debugger has been initialized.784SBDebugger::PrintDiagnosticsOnError();785786signal(SIGINT, sigint_handler);787#if !defined(_WIN32)788signal(SIGPIPE, SIG_IGN);789signal(SIGWINCH, sigwinch_handler);790signal(SIGTSTP, sigtstp_handler);791#endif792793int exit_code = 0;794// Create a scope for driver so that the driver object will destroy itself795// before SBDebugger::Terminate() is called.796{797Driver driver;798799bool exiting = false;800SBError error(driver.ProcessArgs(input_args, exiting));801if (error.Fail()) {802exit_code = 1;803if (const char *error_cstr = error.GetCString())804WithColor::error() << error_cstr << '\n';805} else if (!exiting) {806exit_code = driver.MainLoop();807}808}809810// When terminating the debugger we have to wait on all the background tasks811// to complete, which can take a while. Print a message when this takes longer812// than 1 second.813{814std::future<void> future =815std::async(std::launch::async, []() { SBDebugger::Terminate(); });816817if (future.wait_for(std::chrono::seconds(1)) == std::future_status::timeout)818fprintf(stderr, "Waiting for background tasks to complete...\n");819820future.wait();821}822823return exit_code;824}825826827