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