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 #ifndef _WIN32 675 static void sigtstp_handler(int signo) { 676 if (g_driver != nullptr) 677 g_driver->GetDebugger().SaveInputTerminalState(); 678 679 // Unblock the signal and remove our handler. 680 sigset_t set; 681 sigemptyset(&set); 682 sigaddset(&set, signo); 683 pthread_sigmask(SIG_UNBLOCK, &set, nullptr); 684 signal(signo, SIG_DFL); 685 686 // Now re-raise the signal. We will immediately suspend... 687 raise(signo); 688 // ... and resume after a SIGCONT. 689 690 // Now undo the modifications. 691 pthread_sigmask(SIG_BLOCK, &set, nullptr); 692 signal(signo, sigtstp_handler); 693 694 if (g_driver != nullptr) 695 g_driver->GetDebugger().RestoreInputTerminalState(); 696 } 697 #endif 698 699 static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { 700 std::string usage_str = tool_name.str() + " [options]"; 701 table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false); 702 703 std::string examples = R"___( 704 EXAMPLES: 705 The debugger can be started in several modes. 706 707 Passing an executable as a positional argument prepares lldb to debug the 708 given executable. To disambiguate between arguments passed to lldb and 709 arguments passed to the debugged executable, arguments starting with a - must 710 be passed after --. 711 712 lldb --arch x86_64 /path/to/program program argument -- --arch armv7 713 714 For convenience, passing the executable after -- is also supported. 715 716 lldb --arch x86_64 -- /path/to/program program argument --arch armv7 717 718 Passing one of the attach options causes lldb to immediately attach to the 719 given process. 720 721 lldb -p <pid> 722 lldb -n <process-name> 723 724 Passing --repl starts lldb in REPL mode. 725 726 lldb -r 727 728 Passing --core causes lldb to debug the core file. 729 730 lldb -c /path/to/core 731 732 Command options can be combined with these modes and cause lldb to run the 733 specified commands before or after events, like loading the file or crashing, 734 in the order provided on the command line. 735 736 lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt' 737 lldb -S /source/before/file -s /source/after/file 738 lldb -K /source/before/crash -k /source/after/crash 739 740 Note: In REPL mode no file is loaded, so commands specified to run after 741 loading the file (via -o or -s) will be ignored.)___"; 742 llvm::outs() << examples << '\n'; 743 } 744 745 static llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0, 746 opt::InputArgList &input_args) { 747 bool capture = input_args.hasArg(OPT_capture); 748 bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit); 749 auto *capture_path = input_args.getLastArg(OPT_capture_path); 750 751 if (generate_on_exit && !capture) { 752 WithColor::warning() 753 << "-reproducer-generate-on-exit specified without -capture\n"; 754 } 755 756 if (capture || capture_path) { 757 if (capture_path) { 758 if (!capture) 759 WithColor::warning() << "-capture-path specified without -capture\n"; 760 if (const char *error = SBReproducer::Capture(capture_path->getValue())) { 761 WithColor::error() << "reproducer capture failed: " << error << '\n'; 762 return 1; 763 } 764 } else { 765 const char *error = SBReproducer::Capture(); 766 if (error) { 767 WithColor::error() << "reproducer capture failed: " << error << '\n'; 768 return 1; 769 } 770 } 771 if (generate_on_exit) 772 SBReproducer::SetAutoGenerate(true); 773 } 774 775 return llvm::None; 776 } 777 778 int main(int argc, char const *argv[]) { 779 // Editline uses for example iswprint which is dependent on LC_CTYPE. 780 std::setlocale(LC_ALL, ""); 781 std::setlocale(LC_CTYPE, ""); 782 783 // Setup LLVM signal handlers and make sure we call llvm_shutdown() on 784 // destruction. 785 llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false); 786 787 // Parse arguments. 788 LLDBOptTable T; 789 unsigned MissingArgIndex; 790 unsigned MissingArgCount; 791 ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1); 792 opt::InputArgList input_args = 793 T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount); 794 llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]); 795 796 if (input_args.hasArg(OPT_help)) { 797 printHelp(T, argv0); 798 return 0; 799 } 800 801 // Check for missing argument error. 802 if (MissingArgCount) { 803 WithColor::error() << "argument to '" 804 << input_args.getArgString(MissingArgIndex) 805 << "' is missing\n"; 806 } 807 // Error out on unknown options. 808 if (input_args.hasArg(OPT_UNKNOWN)) { 809 for (auto *arg : input_args.filtered(OPT_UNKNOWN)) { 810 WithColor::error() << "unknown option: " << arg->getSpelling() << '\n'; 811 } 812 } 813 if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) { 814 llvm::errs() << "Use '" << argv0 815 << " --help' for a complete list of options.\n"; 816 return 1; 817 } 818 819 if (auto exit_code = InitializeReproducer(argv[0], input_args)) { 820 return *exit_code; 821 } 822 823 SBError error = SBDebugger::InitializeWithErrorHandling(); 824 if (error.Fail()) { 825 WithColor::error() << "initialization failed: " << error.GetCString() 826 << '\n'; 827 return 1; 828 } 829 SBHostOS::ThreadCreated("<lldb.driver.main-thread>"); 830 831 signal(SIGINT, sigint_handler); 832 #if !defined(_WIN32) 833 signal(SIGPIPE, SIG_IGN); 834 signal(SIGWINCH, sigwinch_handler); 835 signal(SIGTSTP, sigtstp_handler); 836 #endif 837 838 int exit_code = 0; 839 // Create a scope for driver so that the driver object will destroy itself 840 // before SBDebugger::Terminate() is called. 841 { 842 Driver driver; 843 844 bool exiting = false; 845 SBError error(driver.ProcessArgs(input_args, exiting)); 846 if (error.Fail()) { 847 exit_code = 1; 848 if (const char *error_cstr = error.GetCString()) 849 WithColor::error() << error_cstr << '\n'; 850 } else if (!exiting) { 851 exit_code = driver.MainLoop(); 852 } 853 } 854 855 SBDebugger::Terminate(); 856 return exit_code; 857 } 858