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