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