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