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