956 lines · cpp
1//===-- Driver.cpp ----------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Driver.h"10 11#include "lldb/API/SBCommandInterpreter.h"12#include "lldb/API/SBCommandInterpreterRunOptions.h"13#include "lldb/API/SBCommandReturnObject.h"14#include "lldb/API/SBDebugger.h"15#include "lldb/API/SBFile.h"16#include "lldb/API/SBHostOS.h"17#include "lldb/API/SBLanguageRuntime.h"18#include "lldb/API/SBStream.h"19#include "lldb/API/SBStringList.h"20#include "lldb/API/SBStructuredData.h"21#include "lldb/Host/Config.h"22#include "lldb/Host/MainLoop.h"23#include "lldb/Host/MainLoopBase.h"24#include "lldb/Utility/Status.h"25#include "llvm/ADT/SmallString.h"26#include "llvm/ADT/StringRef.h"27#include "llvm/Support/ConvertUTF.h"28#include "llvm/Support/FileSystem.h"29#include "llvm/Support/Format.h"30#include "llvm/Support/InitLLVM.h"31#include "llvm/Support/Path.h"32#include "llvm/Support/Signals.h"33#include "llvm/Support/WithColor.h"34#include "llvm/Support/raw_ostream.h"35 36#ifdef _WIN3237#include "llvm/Support/Windows/WindowsSupport.h"38#endif39 40#include <algorithm>41#include <atomic>42#include <bitset>43#include <clocale>44#include <csignal>45#include <future>46#include <string>47#include <thread>48#include <utility>49 50#include <climits>51#include <cstdio>52#include <cstdlib>53#include <cstring>54#include <fcntl.h>55 56#if !defined(__APPLE__)57#include "llvm/Support/DataTypes.h"58#endif59 60using namespace lldb;61using namespace llvm;62using lldb_private::MainLoop;63using lldb_private::MainLoopBase;64using lldb_private::Status;65 66namespace {67using namespace llvm::opt;68 69enum ID {70 OPT_INVALID = 0, // This is not an option ID.71#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),72#include "Options.inc"73#undef OPTION74};75 76#define OPTTABLE_STR_TABLE_CODE77#include "Options.inc"78#undef OPTTABLE_STR_TABLE_CODE79 80#define OPTTABLE_PREFIXES_TABLE_CODE81#include "Options.inc"82#undef OPTTABLE_PREFIXES_TABLE_CODE83 84static constexpr opt::OptTable::Info InfoTable[] = {85#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),86#include "Options.inc"87#undef OPTION88};89 90class LLDBOptTable : public opt::GenericOptTable {91public:92 LLDBOptTable()93 : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}94};95} // namespace96 97static void reset_stdin_termios();98static bool g_old_stdin_termios_is_valid = false;99static struct termios g_old_stdin_termios;100 101static bool disable_color(const raw_ostream &OS) { return false; }102 103static Driver *g_driver = nullptr;104 105// In the Driver::MainLoop, we change the terminal settings. This function is106// added as an atexit handler to make sure we clean them up.107static void reset_stdin_termios() {108 if (g_old_stdin_termios_is_valid) {109 g_old_stdin_termios_is_valid = false;110 ::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios);111 }112}113 114Driver::Driver()115 : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {116 // We want to be able to handle CTRL+D in the terminal to have it terminate117 // certain input118 m_debugger.SetCloseInputOnEOF(false);119 g_driver = this;120}121 122Driver::~Driver() {123 SBDebugger::Destroy(m_debugger);124 g_driver = nullptr;125}126 127void Driver::OptionData::AddInitialCommand(std::string command,128 CommandPlacement placement,129 bool is_file, SBError &error) {130 std::vector<InitialCmdEntry> *command_set;131 switch (placement) {132 case eCommandPlacementBeforeFile:133 command_set = &(m_initial_commands);134 break;135 case eCommandPlacementAfterFile:136 command_set = &(m_after_file_commands);137 break;138 case eCommandPlacementAfterCrash:139 command_set = &(m_after_crash_commands);140 break;141 }142 143 if (is_file) {144 SBFileSpec file(command.c_str());145 if (file.Exists())146 command_set->push_back(InitialCmdEntry(command, is_file));147 else if (file.ResolveExecutableLocation()) {148 char final_path[PATH_MAX];149 file.GetPath(final_path, sizeof(final_path));150 command_set->push_back(InitialCmdEntry(final_path, is_file));151 } else152 error.SetErrorStringWithFormat(153 "file specified in --source (-s) option doesn't exist: '%s'",154 command.c_str());155 } else156 command_set->push_back(InitialCmdEntry(command, is_file));157}158 159void Driver::WriteCommandsForSourcing(CommandPlacement placement,160 SBStream &strm) {161 std::vector<OptionData::InitialCmdEntry> *command_set;162 switch (placement) {163 case eCommandPlacementBeforeFile:164 command_set = &m_option_data.m_initial_commands;165 break;166 case eCommandPlacementAfterFile:167 command_set = &m_option_data.m_after_file_commands;168 break;169 case eCommandPlacementAfterCrash:170 command_set = &m_option_data.m_after_crash_commands;171 break;172 }173 174 for (const auto &command_entry : *command_set) {175 const char *command = command_entry.contents.c_str();176 if (command_entry.is_file) {177 bool source_quietly =178 m_option_data.m_source_quietly || command_entry.source_quietly;179 strm.Printf("command source -s %i '%s'\n",180 static_cast<int>(source_quietly), command);181 } else182 strm.Printf("%s\n", command);183 }184}185 186// Check the arguments that were passed to this program to make sure they are187// valid and to get their argument values (if any). Return a boolean value188// indicating whether or not to start up the full debugger (i.e. the Command189// Interpreter) or not. Return FALSE if the arguments were invalid OR if the190// user only wanted help or version information.191SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {192 SBError error;193 194 // This is kind of a pain, but since we make the debugger in the Driver's195 // constructor, we can't know at that point whether we should read in init196 // files yet. So we don't read them in in the Driver constructor, then set197 // the flags back to "read them in" here, and then if we see the "-n" flag,198 // we'll turn it off again. Finally we have to read them in by hand later in199 // the main loop.200 m_debugger.SkipLLDBInitFiles(false);201 m_debugger.SkipAppInitFiles(false);202 203 if (args.hasArg(OPT_no_use_colors)) {204 m_debugger.SetUseColor(false);205 WithColor::setAutoDetectFunction(disable_color);206 }207 208 if (args.hasArg(OPT_version)) {209 m_option_data.m_print_version = true;210 }211 212 if (args.hasArg(OPT_python_path)) {213 m_option_data.m_print_python_path = true;214 }215 if (args.hasArg(OPT_print_script_interpreter_info)) {216 m_option_data.m_print_script_interpreter_info = true;217 }218 219 if (args.hasArg(OPT_batch)) {220 m_option_data.m_batch = true;221 }222 223 if (auto *arg = args.getLastArg(OPT_core)) {224 auto *arg_value = arg->getValue();225 SBFileSpec file(arg_value);226 if (!file.Exists()) {227 error.SetErrorStringWithFormat(228 "file specified in --core (-c) option doesn't exist: '%s'",229 arg_value);230 return error;231 }232 m_option_data.m_core_file = arg_value;233 }234 235 if (args.hasArg(OPT_editor)) {236 m_option_data.m_use_external_editor = true;237 }238 239 if (args.hasArg(OPT_no_lldbinit)) {240 m_debugger.SkipLLDBInitFiles(true);241 m_debugger.SkipAppInitFiles(true);242 }243 244 if (args.hasArg(OPT_local_lldbinit)) {245 lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",246 m_debugger.GetInstanceName());247 }248 249 if (auto *arg = args.getLastArg(OPT_file)) {250 auto *arg_value = arg->getValue();251 SBFileSpec file(arg_value);252 if (file.Exists()) {253 m_option_data.m_args.emplace_back(arg_value);254 } else if (file.ResolveExecutableLocation()) {255 char path[PATH_MAX];256 file.GetPath(path, sizeof(path));257 m_option_data.m_args.emplace_back(path);258 } else {259 error.SetErrorStringWithFormat(260 "file specified in --file (-f) option doesn't exist: '%s'",261 arg_value);262 return error;263 }264 }265 266 if (auto *arg = args.getLastArg(OPT_arch)) {267 auto *arg_value = arg->getValue();268 if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {269 error.SetErrorStringWithFormat(270 "invalid architecture in the -a or --arch option: '%s'", arg_value);271 return error;272 }273 }274 275 if (auto *arg = args.getLastArg(OPT_script_language)) {276 auto *arg_value = arg->getValue();277 m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));278 }279 280 if (args.hasArg(OPT_source_quietly)) {281 m_option_data.m_source_quietly = true;282 }283 284 if (auto *arg = args.getLastArg(OPT_attach_name)) {285 auto *arg_value = arg->getValue();286 m_option_data.m_process_name = arg_value;287 }288 289 if (args.hasArg(OPT_wait_for)) {290 if (!args.hasArg(OPT_attach_name)) {291 error.SetErrorStringWithFormat(292 "--wait-for requires a name (--attach-name)");293 return error;294 }295 296 m_option_data.m_wait_for = true;297 }298 299 if (auto *arg = args.getLastArg(OPT_attach_pid)) {300 auto *arg_value = arg->getValue();301 char *remainder;302 m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);303 if (remainder == arg_value || *remainder != '\0') {304 error.SetErrorStringWithFormat(305 "Could not convert process PID: \"%s\" into a pid.", arg_value);306 return error;307 }308 }309 310 if (auto *arg = args.getLastArg(OPT_repl_language)) {311 auto *arg_value = arg->getValue();312 m_option_data.m_repl_lang =313 SBLanguageRuntime::GetLanguageTypeFromString(arg_value);314 if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {315 error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",316 arg_value);317 return error;318 }319 m_debugger.SetREPLLanguage(m_option_data.m_repl_lang);320 }321 322 if (args.hasArg(OPT_repl)) {323 m_option_data.m_repl = true;324 }325 326 if (auto *arg = args.getLastArg(OPT_repl_)) {327 m_option_data.m_repl = true;328 if (auto *arg_value = arg->getValue())329 m_option_data.m_repl_options = arg_value;330 }331 332 // We need to process the options below together as their relative order333 // matters.334 for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,335 OPT_source, OPT_source_before_file,336 OPT_one_line, OPT_one_line_before_file)) {337 auto *arg_value = arg->getValue();338 if (arg->getOption().matches(OPT_source_on_crash)) {339 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,340 true, error);341 if (error.Fail())342 return error;343 }344 345 if (arg->getOption().matches(OPT_one_line_on_crash)) {346 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,347 false, error);348 if (error.Fail())349 return error;350 }351 352 if (arg->getOption().matches(OPT_source)) {353 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,354 true, error);355 if (error.Fail())356 return error;357 }358 359 if (arg->getOption().matches(OPT_source_before_file)) {360 m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,361 true, error);362 if (error.Fail())363 return error;364 }365 366 if (arg->getOption().matches(OPT_one_line)) {367 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,368 false, error);369 if (error.Fail())370 return error;371 }372 373 if (arg->getOption().matches(OPT_one_line_before_file)) {374 m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,375 false, error);376 if (error.Fail())377 return error;378 }379 }380 381 if (m_option_data.m_process_name.empty() &&382 m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {383 384 for (auto *arg : args.filtered(OPT_INPUT))385 m_option_data.m_args.push_back(arg->getAsString((args)));386 387 // Any argument following -- is an argument for the inferior.388 if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {389 for (auto *value : arg->getValues())390 m_option_data.m_args.emplace_back(value);391 }392 } else if (args.getLastArgNoClaim() != nullptr) {393 WithColor::warning() << "program arguments are ignored when attaching.\n";394 }395 396 if (m_option_data.m_print_version) {397 llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';398 exiting = true;399 return error;400 }401 402 if (m_option_data.m_print_python_path) {403 SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();404 if (python_file_spec.IsValid()) {405 char python_path[PATH_MAX];406 size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);407 if (num_chars < PATH_MAX) {408 llvm::outs() << python_path << '\n';409 } else410 llvm::outs() << "<PATH TOO LONG>\n";411 } else412 llvm::outs() << "<COULD NOT FIND PATH>\n";413 exiting = true;414 return error;415 }416 417 if (m_option_data.m_print_script_interpreter_info) {418 SBStructuredData info =419 m_debugger.GetScriptInterpreterInfo(m_debugger.GetScriptLanguage());420 if (!info) {421 error.SetErrorString("no script interpreter.");422 } else {423 SBStream stream;424 error = info.GetAsJSON(stream);425 if (error.Success()) {426 llvm::outs() << stream.GetData() << '\n';427 }428 }429 exiting = true;430 return error;431 }432 433 return error;434}435 436#ifdef _WIN32437#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH438/// Returns the full path to the lldb.exe executable.439inline std::wstring GetPathToExecutableW() {440 // Iterate until we reach the Windows API maximum path length (32,767).441 std::vector<WCHAR> buffer;442 buffer.resize(MAX_PATH /*=260*/);443 while (buffer.size() < 32767) {444 if (GetModuleFileNameW(NULL, buffer.data(), buffer.size()) < buffer.size())445 return std::wstring(buffer.begin(), buffer.end());446 buffer.resize(buffer.size() * 2);447 }448 return L"";449}450 451/// \brief Resolve the full path of the directory defined by452/// LLDB_PYTHON_DLL_RELATIVE_PATH. If it exists, add it to the list of DLL453/// search directories.454/// \return `true` if the library was added to the search path.455/// `false` otherwise.456bool AddPythonDLLToSearchPath() {457 std::wstring modulePath = GetPathToExecutableW();458 if (modulePath.empty())459 return false;460 461 SmallVector<char, MAX_PATH> utf8Path;462 if (sys::windows::UTF16ToUTF8(modulePath.c_str(), modulePath.length(),463 utf8Path))464 return false;465 sys::path::remove_filename(utf8Path);466 sys::path::append(utf8Path, LLDB_PYTHON_DLL_RELATIVE_PATH);467 sys::fs::make_absolute(utf8Path);468 469 SmallVector<wchar_t, 1> widePath;470 if (sys::windows::widenPath(utf8Path.data(), widePath))471 return false;472 473 if (sys::fs::exists(utf8Path))474 return SetDllDirectoryW(widePath.data());475 return false;476}477#endif478 479#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME480/// Returns true if `python3x.dll` can be loaded.481bool IsPythonDLLInPath() {482#define WIDEN2(x) L##x483#define WIDEN(x) WIDEN2(x)484 HMODULE h = LoadLibraryW(WIDEN(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME));485 if (!h)486 return false;487 FreeLibrary(h);488 return true;489#undef WIDEN2490#undef WIDEN491}492#endif493 494/// Try to setup the DLL search path for the Python Runtime Library495/// (python3xx.dll).496///497/// If `LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME` is set, we first check if498/// python3xx.dll is in the search path. If it's not, we try to add it and499/// check for it a second time.500/// If only `LLDB_PYTHON_DLL_RELATIVE_PATH` is set, we try to add python3xx.dll501/// to the search path python.dll is already in the search path or not.502void SetupPythonRuntimeLibrary() {503#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME504 if (IsPythonDLLInPath())505 return;506#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH507 if (AddPythonDLLToSearchPath() && IsPythonDLLInPath())508 return;509#endif510 WithColor::error() << "unable to find '"511 << LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME << "'.\n";512 return;513#elif defined(LLDB_PYTHON_DLL_RELATIVE_PATH)514 if (!AddPythonDLLToSearchPath())515 WithColor::error() << "unable to find the Python runtime library.\n";516#endif517}518#endif519 520std::string EscapeString(std::string arg) {521 std::string::size_type pos = 0;522 while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {523 arg.insert(pos, 1, '\\');524 pos += 2;525 }526 return '"' + arg + '"';527}528 529int Driver::MainLoop() {530 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {531 g_old_stdin_termios_is_valid = true;532 atexit(reset_stdin_termios);533 }534 535#ifndef _MSC_VER536 // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets537 // which causes it to miss newlines depending on whether there have been an538 // odd or even number of characters. Bug has been reported to MS via Connect.539 ::setbuf(stdin, nullptr);540#endif541 ::setbuf(stdout, nullptr);542 543 m_debugger.SetErrorFileHandle(stderr, false);544 m_debugger.SetOutputFileHandle(stdout, false);545 // Don't take ownership of STDIN yet...546 m_debugger.SetInputFileHandle(stdin, false);547 548 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);549 m_debugger.SetShowInlineDiagnostics(true);550 551 // Set the terminal dimensions.552 UpdateWindowSize();553 554 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();555 556 // Process lldbinit files before handling any options from the command line.557 SBCommandReturnObject result;558 sb_interpreter.SourceInitFileInGlobalDirectory(result);559 sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);560 561 // Source the local .lldbinit file if it exists and we're allowed to source.562 // Here we want to always print the return object because it contains the563 // warning and instructions to load local lldbinit files.564 sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);565 result.PutError(m_debugger.GetErrorFile());566 result.PutOutput(m_debugger.GetOutputFile());567 568 // We allow the user to specify an exit code when calling quit which we will569 // return when exiting.570 m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);571 572 // Now we handle options we got from the command line573 SBStream commands_stream;574 575 // First source in the commands specified to be run before the file arguments576 // are processed.577 WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);578 579 // If we're not in --repl mode, add the commands to process the file580 // arguments, and the commands specified to run afterwards.581 if (!m_option_data.m_repl) {582 const size_t num_args = m_option_data.m_args.size();583 if (num_args > 0) {584 char arch_name[64];585 if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,586 sizeof(arch_name)))587 commands_stream.Printf("target create --arch=%s %s", arch_name,588 EscapeString(m_option_data.m_args[0]).c_str());589 else590 commands_stream.Printf("target create %s",591 EscapeString(m_option_data.m_args[0]).c_str());592 593 if (!m_option_data.m_core_file.empty()) {594 commands_stream.Printf(" --core %s",595 EscapeString(m_option_data.m_core_file).c_str());596 }597 commands_stream.Printf("\n");598 599 if (num_args > 1) {600 commands_stream.Printf("settings set -- target.run-args ");601 for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)602 commands_stream.Printf(603 " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());604 commands_stream.Printf("\n");605 }606 } else if (!m_option_data.m_core_file.empty()) {607 commands_stream.Printf("target create --core %s\n",608 EscapeString(m_option_data.m_core_file).c_str());609 } else if (!m_option_data.m_process_name.empty()) {610 commands_stream.Printf(611 "process attach --name %s",612 EscapeString(m_option_data.m_process_name).c_str());613 614 if (m_option_data.m_wait_for)615 commands_stream.Printf(" --waitfor");616 617 commands_stream.Printf("\n");618 619 } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {620 commands_stream.Printf("process attach --pid %" PRIu64 "\n",621 m_option_data.m_process_pid);622 }623 624 WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);625 } else if (!m_option_data.m_after_file_commands.empty()) {626 // We're in repl mode and after-file-load commands were specified.627 WithColor::warning() << "commands specified to run after file load (via -o "628 "or -s) are ignored in REPL mode.\n";629 }630 631 const bool handle_events = true;632 const bool spawn_thread = false;633 634 // Check if we have any data in the commands stream, and if so, save it to a635 // temp file636 // so we can then run the command interpreter using the file contents.637 bool go_interactive = true;638 if ((commands_stream.GetData() != nullptr) &&639 (commands_stream.GetSize() != 0u)) {640 SBError error = m_debugger.SetInputString(commands_stream.GetData());641 if (error.Fail()) {642 WithColor::error() << error.GetCString() << '\n';643 return 1;644 }645 646 // Set the debugger into Sync mode when running the command file. Otherwise647 // command files that run the target won't run in a sensible way.648 bool old_async = m_debugger.GetAsync();649 m_debugger.SetAsync(false);650 651 SBCommandInterpreterRunOptions options;652 options.SetAutoHandleEvents(true);653 options.SetSpawnThread(false);654 options.SetStopOnError(true);655 options.SetStopOnCrash(m_option_data.m_batch);656 options.SetEchoCommands(!m_option_data.m_source_quietly);657 658 SBCommandInterpreterRunResult results =659 m_debugger.RunCommandInterpreter(options);660 if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)661 go_interactive = false;662 if (m_option_data.m_batch &&663 results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)664 go_interactive = false;665 666 // When running in batch mode and stopped because of an error, exit with a667 // non-zero exit status.668 if (m_option_data.m_batch &&669 results.GetResult() == lldb::eCommandInterpreterResultCommandError)670 return 1;671 672 if (m_option_data.m_batch &&673 results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&674 !m_option_data.m_after_crash_commands.empty()) {675 SBStream crash_commands_stream;676 WriteCommandsForSourcing(eCommandPlacementAfterCrash,677 crash_commands_stream);678 SBError error =679 m_debugger.SetInputString(crash_commands_stream.GetData());680 if (error.Success()) {681 SBCommandInterpreterRunResult local_results =682 m_debugger.RunCommandInterpreter(options);683 if (local_results.GetResult() ==684 lldb::eCommandInterpreterResultQuitRequested)685 go_interactive = false;686 687 // When running in batch mode and an error occurred while sourcing688 // the crash commands, exit with a non-zero exit status.689 if (m_option_data.m_batch &&690 local_results.GetResult() ==691 lldb::eCommandInterpreterResultCommandError)692 return 1;693 }694 }695 m_debugger.SetAsync(old_async);696 }697 698 // Now set the input file handle to STDIN and run the command interpreter699 // again in interactive mode or repl mode and let the debugger take ownership700 // of stdin.701 if (go_interactive) {702 m_debugger.SetInputFileHandle(stdin, true);703 704 if (m_option_data.m_repl) {705 const char *repl_options = nullptr;706 if (!m_option_data.m_repl_options.empty())707 repl_options = m_option_data.m_repl_options.c_str();708 SBError error(709 m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));710 if (error.Fail()) {711 const char *error_cstr = error.GetCString();712 if ((error_cstr != nullptr) && (error_cstr[0] != 0))713 WithColor::error() << error_cstr << '\n';714 else715 WithColor::error() << error.GetError() << '\n';716 }717 } else {718 m_debugger.RunCommandInterpreter(handle_events, spawn_thread);719 }720 }721 722 reset_stdin_termios();723 fclose(stdin);724 725 return sb_interpreter.GetQuitStatus();726}727 728void Driver::UpdateWindowSize() {729 struct winsize window_size;730 if ((isatty(STDIN_FILENO) != 0) &&731 ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {732 if (window_size.ws_col > 0)733 m_debugger.SetTerminalWidth(window_size.ws_col);734#ifndef _WIN32735 if (window_size.ws_row > 0)736 m_debugger.SetTerminalHeight(window_size.ws_row);737#endif738 }739}740 741void sigint_handler(int signo) {742#ifdef _WIN32743 // Restore handler as it is not persistent on Windows.744 signal(SIGINT, sigint_handler);745#endif746 747 static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;748 if (g_driver != nullptr) {749 if (!g_interrupt_sent.test_and_set()) {750 g_driver->GetDebugger().DispatchInputInterrupt();751 g_interrupt_sent.clear();752 return;753 }754 }755 756 _exit(signo);757}758 759static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {760 std::string usage_str = tool_name.str() + " [options]";761 table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);762 763 std::string examples = R"___(764EXAMPLES:765 The debugger can be started in several modes.766 767 Passing an executable as a positional argument prepares lldb to debug the768 given executable. To disambiguate between arguments passed to lldb and769 arguments passed to the debugged executable, arguments starting with a - must770 be passed after --.771 772 lldb --arch x86_64 /path/to/program program argument -- --arch armv7773 774 For convenience, passing the executable after -- is also supported.775 776 lldb --arch x86_64 -- /path/to/program program argument --arch armv7777 778 Passing one of the attach options causes lldb to immediately attach to the779 given process.780 781 lldb -p <pid>782 lldb -n <process-name>783 784 Passing --repl starts lldb in REPL mode.785 786 lldb -r787 788 Passing --core causes lldb to debug the core file.789 790 lldb -c /path/to/core791 792 Command options can be combined with these modes and cause lldb to run the793 specified commands before or after events, like loading the file or crashing,794 in the order provided on the command line.795 796 lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'797 lldb -S /source/before/file -s /source/after/file798 lldb -K /source/before/crash -k /source/after/crash799 800 Note: In REPL mode no file is loaded, so commands specified to run after801 loading the file (via -o or -s) will be ignored.)___";802 llvm::outs() << examples << '\n';803}804 805int main(int argc, char const *argv[]) {806 // Editline uses for example iswprint which is dependent on LC_CTYPE.807 std::setlocale(LC_ALL, "");808 std::setlocale(LC_CTYPE, "");809 810 // Setup LLVM signal handlers and make sure we call llvm_shutdown() on811 // destruction.812 llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);813#if !defined(__APPLE__)814 llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL815 " and include the crash backtrace.\n");816#else817 llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL818 " and include the crash report from "819 "~/Library/Logs/DiagnosticReports/.\n");820#endif821 822#ifdef _WIN32823 SetupPythonRuntimeLibrary();824#endif825 826 // Parse arguments.827 LLDBOptTable T;828 unsigned MissingArgIndex;829 unsigned MissingArgCount;830 ArrayRef<const char *> arg_arr = ArrayRef(argv + 1, argc - 1);831 opt::InputArgList input_args =832 T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);833 llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);834 835 if (input_args.hasArg(OPT_help)) {836 printHelp(T, argv0);837 return 0;838 }839 840 // Check for missing argument error.841 if (MissingArgCount) {842 WithColor::error() << "argument to '"843 << input_args.getArgString(MissingArgIndex)844 << "' is missing\n";845 }846 // Error out on unknown options.847 if (input_args.hasArg(OPT_UNKNOWN)) {848 for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {849 WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';850 }851 }852 if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {853 llvm::errs() << "Use '" << argv0854 << " --help' for a complete list of options.\n";855 return 1;856 }857 858 SBError error = SBDebugger::InitializeWithErrorHandling();859 if (error.Fail()) {860 WithColor::error() << "initialization failed: " << error.GetCString()861 << '\n';862 return 1;863 }864 865 // Setup LLDB signal handlers once the debugger has been initialized.866 SBDebugger::PrintDiagnosticsOnError();867 868 // FIXME: Migrate the SIGINT handler to be handled by the signal loop below.869 signal(SIGINT, sigint_handler);870#if !defined(_WIN32)871 signal(SIGPIPE, SIG_IGN);872 873 // Handle signals in a MainLoop running on a separate thread.874 MainLoop signal_loop;875 Status signal_status;876 877 auto sigwinch_handler = signal_loop.RegisterSignal(878 SIGWINCH,879 [&](MainLoopBase &) {880 if (g_driver)881 g_driver->UpdateWindowSize();882 },883 signal_status);884 assert(sigwinch_handler && signal_status.Success());885 886 auto sigtstp_handler = signal_loop.RegisterSignal(887 SIGTSTP,888 [&](MainLoopBase &) {889 if (g_driver)890 g_driver->GetDebugger().SaveInputTerminalState();891 892 struct sigaction old_action;893 struct sigaction new_action = {};894 new_action.sa_handler = SIG_DFL;895 sigemptyset(&new_action.sa_mask);896 sigaddset(&new_action.sa_mask, SIGTSTP);897 898 int ret = sigaction(SIGTSTP, &new_action, &old_action);899 UNUSED_IF_ASSERT_DISABLED(ret);900 assert(ret == 0 && "sigaction failed");901 902 raise(SIGTSTP);903 904 ret = sigaction(SIGTSTP, &old_action, nullptr);905 UNUSED_IF_ASSERT_DISABLED(ret);906 assert(ret == 0 && "sigaction failed");907 908 if (g_driver)909 g_driver->GetDebugger().RestoreInputTerminalState();910 },911 signal_status);912 assert(sigtstp_handler && signal_status.Success());913 914 std::thread signal_thread([&] { signal_loop.Run(); });915#endif916 917 int exit_code = 0;918 // Create a scope for driver so that the driver object will destroy itself919 // before SBDebugger::Terminate() is called.920 {921 Driver driver;922 923 bool exiting = false;924 SBError error(driver.ProcessArgs(input_args, exiting));925 if (error.Fail()) {926 exit_code = 1;927 if (const char *error_cstr = error.GetCString())928 WithColor::error() << error_cstr << '\n';929 } else if (!exiting) {930 exit_code = driver.MainLoop();931 }932 }933 934 // When terminating the debugger we have to wait on all the background tasks935 // to complete, which can take a while. Print a message when this takes longer936 // than 1 second.937 {938 std::future<void> future =939 std::async(std::launch::async, []() { SBDebugger::Terminate(); });940 941 if (future.wait_for(std::chrono::seconds(1)) == std::future_status::timeout)942 fprintf(stderr, "Waiting for background tasks to complete...\n");943 944 future.wait();945 }946 947#if !defined(_WIN32)948 // Try to interrupt the signal thread. If that succeeds, wait for it to exit.949 if (signal_loop.AddPendingCallback(950 [](MainLoopBase &loop) { loop.RequestTermination(); }))951 signal_thread.join();952#endif953 954 return exit_code;955}956