1 //===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
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"
44 // Includes for pipe()
52 #if !defined(__APPLE__)
53 #include "llvm/Support/DataTypes.h"
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) \
65 #include "Options.inc"
69 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
70 #include "Options.inc"
73 const opt::OptTable::Info InfoTable[] = {
74 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
75 HELPTEXT, METAVAR, VALUES) \
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"
85 class LLDBOptTable : public opt::OptTable {
87 LLDBOptTable() : OptTable(InfoTable) {}
91 static void reset_stdin_termios();
92 static bool g_old_stdin_termios_is_valid = false;
93 static struct termios g_old_stdin_termios;
95 static Driver *g_driver = nullptr;
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);
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
110 m_debugger.SetCloseInputOnEOF(false);
114 Driver::~Driver() { g_driver = nullptr; }
116 void Driver::OptionData::AddInitialCommand(std::string command,
117 CommandPlacement placement,
118 bool is_file, SBError &error) {
119 std::vector<InitialCmdEntry> *command_set;
121 case eCommandPlacementBeforeFile:
122 command_set = &(m_initial_commands);
124 case eCommandPlacementAfterFile:
125 command_set = &(m_after_file_commands);
127 case eCommandPlacementAfterCrash:
128 command_set = &(m_after_crash_commands);
133 SBFileSpec file(command.c_str());
135 command_set->push_back(InitialCmdEntry(command, is_file));
136 else if (file.ResolveExecutableLocation()) {
137 char final_path[PATH_MAX];
138 file.GetPath(final_path, sizeof(final_path));
139 command_set->push_back(InitialCmdEntry(final_path, is_file));
141 error.SetErrorStringWithFormat(
142 "file specified in --source (-s) option doesn't exist: '%s'",
145 command_set->push_back(InitialCmdEntry(command, is_file));
148 void Driver::WriteCommandsForSourcing(CommandPlacement placement,
150 std::vector<OptionData::InitialCmdEntry> *command_set;
152 case eCommandPlacementBeforeFile:
153 command_set = &m_option_data.m_initial_commands;
155 case eCommandPlacementAfterFile:
156 command_set = &m_option_data.m_after_file_commands;
158 case eCommandPlacementAfterCrash:
159 command_set = &m_option_data.m_after_crash_commands;
163 for (const auto &command_entry : *command_set) {
164 const char *command = command_entry.contents.c_str();
165 if (command_entry.is_file) {
166 bool source_quietly =
167 m_option_data.m_source_quietly || command_entry.source_quietly;
168 strm.Printf("command source -s %i '%s'\n",
169 static_cast<int>(source_quietly), command);
171 strm.Printf("%s\n", command);
175 // Check the arguments that were passed to this program to make sure they are
176 // valid and to get their argument values (if any). Return a boolean value
177 // indicating whether or not to start up the full debugger (i.e. the Command
178 // Interpreter) or not. Return FALSE if the arguments were invalid OR if the
179 // user only wanted help or version information.
180 SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
183 // This is kind of a pain, but since we make the debugger in the Driver's
184 // constructor, we can't know at that point whether we should read in init
185 // files yet. So we don't read them in in the Driver constructor, then set
186 // the flags back to "read them in" here, and then if we see the "-n" flag,
187 // we'll turn it off again. Finally we have to read them in by hand later in
189 m_debugger.SkipLLDBInitFiles(false);
190 m_debugger.SkipAppInitFiles(false);
192 if (args.hasArg(OPT_version)) {
193 m_option_data.m_print_version = true;
196 if (args.hasArg(OPT_python_path)) {
197 m_option_data.m_print_python_path = true;
200 if (args.hasArg(OPT_batch)) {
201 m_option_data.m_batch = true;
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'",
213 m_option_data.m_core_file = arg_value;
216 if (args.hasArg(OPT_editor)) {
217 m_option_data.m_use_external_editor = true;
220 if (args.hasArg(OPT_no_lldbinit)) {
221 m_debugger.SkipLLDBInitFiles(true);
222 m_debugger.SkipAppInitFiles(true);
225 if (args.hasArg(OPT_local_lldbinit)) {
226 lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
227 m_debugger.GetInstanceName());
230 if (args.hasArg(OPT_no_use_colors)) {
231 m_debugger.SetUseColor(false);
234 if (auto *arg = args.getLastArg(OPT_file)) {
235 auto arg_value = arg->getValue();
236 SBFileSpec file(arg_value);
238 m_option_data.m_args.emplace_back(arg_value);
239 } else if (file.ResolveExecutableLocation()) {
241 file.GetPath(path, sizeof(path));
242 m_option_data.m_args.emplace_back(path);
244 error.SetErrorStringWithFormat(
245 "file specified in --file (-f) option doesn't exist: '%s'",
251 if (auto *arg = args.getLastArg(OPT_arch)) {
252 auto arg_value = arg->getValue();
253 if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
254 error.SetErrorStringWithFormat(
255 "invalid architecture in the -a or --arch option: '%s'", arg_value);
260 if (auto *arg = args.getLastArg(OPT_script_language)) {
261 auto arg_value = arg->getValue();
262 m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
265 if (args.hasArg(OPT_no_use_colors)) {
266 m_option_data.m_debug_mode = true;
269 if (args.hasArg(OPT_no_use_colors)) {
270 m_debugger.SetUseColor(false);
273 if (args.hasArg(OPT_source_quietly)) {
274 m_option_data.m_source_quietly = true;
277 if (auto *arg = args.getLastArg(OPT_attach_name)) {
278 auto arg_value = arg->getValue();
279 m_option_data.m_process_name = arg_value;
282 if (args.hasArg(OPT_wait_for)) {
283 m_option_data.m_wait_for = true;
286 if (auto *arg = args.getLastArg(OPT_attach_pid)) {
287 auto arg_value = arg->getValue();
289 m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
290 if (remainder == arg_value || *remainder != '\0') {
291 error.SetErrorStringWithFormat(
292 "Could not convert process PID: \"%s\" into a pid.", arg_value);
297 if (auto *arg = args.getLastArg(OPT_repl_language)) {
298 auto arg_value = arg->getValue();
299 m_option_data.m_repl_lang =
300 SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
301 if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
302 error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
308 if (args.hasArg(OPT_repl)) {
309 m_option_data.m_repl = true;
312 if (auto *arg = args.getLastArg(OPT_repl_)) {
313 m_option_data.m_repl = true;
314 if (auto arg_value = arg->getValue())
315 m_option_data.m_repl_options = arg_value;
318 // We need to process the options below together as their relative order
320 for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
321 OPT_source, OPT_source_before_file,
322 OPT_one_line, OPT_one_line_before_file)) {
323 auto arg_value = arg->getValue();
324 if (arg->getOption().matches(OPT_source_on_crash)) {
325 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
331 if (arg->getOption().matches(OPT_one_line_on_crash)) {
332 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
338 if (arg->getOption().matches(OPT_source)) {
339 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
345 if (arg->getOption().matches(OPT_source_before_file)) {
346 m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
352 if (arg->getOption().matches(OPT_one_line)) {
353 m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
359 if (arg->getOption().matches(OPT_one_line_before_file)) {
360 m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
367 if (m_option_data.m_process_name.empty() &&
368 m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
370 // If the option data args array is empty that means the file was not
371 // specified with -f and we need to get it from the input args.
372 if (m_option_data.m_args.empty()) {
373 if (auto *arg = args.getLastArgNoClaim(OPT_INPUT)) {
374 m_option_data.m_args.push_back(arg->getAsString((args)));
378 // Any argument following -- is an argument for the inferior.
379 if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
380 for (auto value : arg->getValues())
381 m_option_data.m_args.emplace_back(value);
383 } else if (args.getLastArgNoClaim() != nullptr) {
384 WithColor::warning() << "program arguments are ignored when attaching.\n";
387 if (m_option_data.m_print_version) {
388 llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
393 if (m_option_data.m_print_python_path) {
394 SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
395 if (python_file_spec.IsValid()) {
396 char python_path[PATH_MAX];
397 size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
398 if (num_chars < PATH_MAX) {
399 llvm::outs() << python_path << '\n';
401 llvm::outs() << "<PATH TOO LONG>\n";
403 llvm::outs() << "<COULD NOT FIND PATH>\n";
411 static inline int OpenPipe(int fds[2], std::size_t size) {
413 return _pipe(fds, size, O_BINARY);
420 static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
421 size_t commands_size) {
422 enum PIPES { READ, WRITE }; // Indexes for the read and write fds
423 int fds[2] = {-1, -1};
425 if (OpenPipe(fds, commands_size) != 0) {
427 << "can't create pipe file descriptors for LLDB commands\n";
431 ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
432 if (size_t(nrwr) != commands_size) {
435 "write(%i, %p, %" PRIu64
436 ") failed (errno = %i) when trying to open LLDB commands pipe",
437 fds[WRITE], static_cast<const void *>(commands_data),
438 static_cast<uint64_t>(commands_size), errno)
440 llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
441 llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
445 // Close the write end of the pipe, so that the command interpreter will exit
446 // when it consumes all the data.
447 llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
449 // Open the read file descriptor as a FILE * that we can return as an input
451 ::FILE *commands_file = fdopen(fds[READ], "rb");
452 if (commands_file == nullptr) {
453 WithColor::error() << format("fdopen(%i, \"rb\") failed (errno = %i) "
454 "when trying to open LLDB commands pipe",
457 llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
461 // 'commands_file' now owns the read descriptor.
462 return commands_file;
465 std::string EscapeString(std::string arg) {
466 std::string::size_type pos = 0;
467 while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
468 arg.insert(pos, 1, '\\');
471 return '"' + arg + '"';
474 int Driver::MainLoop() {
475 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
476 g_old_stdin_termios_is_valid = true;
477 atexit(reset_stdin_termios);
481 // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
482 // which causes it to miss newlines depending on whether there have been an
483 // odd or even number of characters. Bug has been reported to MS via Connect.
484 ::setbuf(stdin, nullptr);
486 ::setbuf(stdout, nullptr);
488 m_debugger.SetErrorFileHandle(stderr, false);
489 m_debugger.SetOutputFileHandle(stdout, false);
490 // Don't take ownership of STDIN yet...
491 m_debugger.SetInputFileHandle(stdin, false);
493 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
495 struct winsize window_size;
496 if ((isatty(STDIN_FILENO) != 0) &&
497 ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
498 if (window_size.ws_col > 0)
499 m_debugger.SetTerminalWidth(window_size.ws_col);
502 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
504 // Before we handle any options from the command line, we parse the
505 // .lldbinit file in the user's home directory.
506 SBCommandReturnObject result;
507 sb_interpreter.SourceInitFileInHomeDirectory(result);
508 if (m_option_data.m_debug_mode) {
509 result.PutError(m_debugger.GetErrorFileHandle());
510 result.PutOutput(m_debugger.GetOutputFileHandle());
513 // Source the local .lldbinit file if it exists and we're allowed to source.
514 // Here we want to always print the return object because it contains the
515 // warning and instructions to load local lldbinit files.
516 sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
517 result.PutError(m_debugger.GetErrorFileHandle());
518 result.PutOutput(m_debugger.GetOutputFileHandle());
520 // We allow the user to specify an exit code when calling quit which we will
521 // return when exiting.
522 m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
524 // Now we handle options we got from the command line
525 SBStream commands_stream;
527 // First source in the commands specified to be run before the file arguments
529 WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
531 // If we're not in --repl mode, add the commands to process the file
532 // arguments, and the commands specified to run afterwards.
533 if (!m_option_data.m_repl) {
534 const size_t num_args = m_option_data.m_args.size();
537 if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
539 commands_stream.Printf("target create --arch=%s %s", arch_name,
540 EscapeString(m_option_data.m_args[0]).c_str());
542 commands_stream.Printf("target create %s",
543 EscapeString(m_option_data.m_args[0]).c_str());
545 if (!m_option_data.m_core_file.empty()) {
546 commands_stream.Printf(" --core %s",
547 EscapeString(m_option_data.m_core_file).c_str());
549 commands_stream.Printf("\n");
552 commands_stream.Printf("settings set -- target.run-args ");
553 for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
554 commands_stream.Printf(
555 " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
556 commands_stream.Printf("\n");
558 } else if (!m_option_data.m_core_file.empty()) {
559 commands_stream.Printf("target create --core %s\n",
560 EscapeString(m_option_data.m_core_file).c_str());
561 } else if (!m_option_data.m_process_name.empty()) {
562 commands_stream.Printf(
563 "process attach --name %s",
564 EscapeString(m_option_data.m_process_name).c_str());
566 if (m_option_data.m_wait_for)
567 commands_stream.Printf(" --waitfor");
569 commands_stream.Printf("\n");
571 } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
572 commands_stream.Printf("process attach --pid %" PRIu64 "\n",
573 m_option_data.m_process_pid);
576 WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
577 } else if (!m_option_data.m_after_file_commands.empty()) {
578 // We're in repl mode and after-file-load commands were specified.
579 WithColor::warning() << "commands specified to run after file load (via -o "
580 "or -s) are ignored in REPL mode.\n";
583 if (m_option_data.m_debug_mode) {
584 result.PutError(m_debugger.GetErrorFileHandle());
585 result.PutOutput(m_debugger.GetOutputFileHandle());
588 const bool handle_events = true;
589 const bool spawn_thread = false;
591 // Check if we have any data in the commands stream, and if so, save it to a
593 // so we can then run the command interpreter using the file contents.
594 const char *commands_data = commands_stream.GetData();
595 const size_t commands_size = commands_stream.GetSize();
597 // The command file might have requested that we quit, this variable will
599 bool quit_requested = false;
600 bool stopped_for_crash = false;
601 if ((commands_data != nullptr) && (commands_size != 0u)) {
603 FILE *commands_file =
604 PrepareCommandsForSourcing(commands_data, commands_size);
605 if (commands_file != nullptr) {
606 m_debugger.SetInputFileHandle(commands_file, true);
608 // Set the debugger into Sync mode when running the command file.
609 // Otherwise command files
610 // that run the target won't run in a sensible way.
611 bool old_async = m_debugger.GetAsync();
612 m_debugger.SetAsync(false);
615 SBCommandInterpreterRunOptions options;
616 options.SetStopOnError(true);
617 if (m_option_data.m_batch)
618 options.SetStopOnCrash(true);
620 m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options,
621 num_errors, quit_requested,
624 if (m_option_data.m_batch && stopped_for_crash &&
625 !m_option_data.m_after_crash_commands.empty()) {
626 SBStream crash_commands_stream;
627 WriteCommandsForSourcing(eCommandPlacementAfterCrash,
628 crash_commands_stream);
629 const char *crash_commands_data = crash_commands_stream.GetData();
630 const size_t crash_commands_size = crash_commands_stream.GetSize();
631 commands_file = PrepareCommandsForSourcing(crash_commands_data,
632 crash_commands_size);
633 if (commands_file != nullptr) {
634 bool local_quit_requested;
635 bool local_stopped_for_crash;
636 m_debugger.SetInputFileHandle(commands_file, true);
638 m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options,
639 num_errors, local_quit_requested,
640 local_stopped_for_crash);
641 if (local_quit_requested)
642 quit_requested = true;
645 m_debugger.SetAsync(old_async);
649 // Something went wrong with command pipe
655 // Now set the input file handle to STDIN and run the command
656 // interpreter again in interactive mode or repl mode and let the debugger
657 // take ownership of stdin
659 bool go_interactive = true;
661 go_interactive = false;
662 else if (m_option_data.m_batch && !stopped_for_crash)
663 go_interactive = false;
665 if (go_interactive) {
666 m_debugger.SetInputFileHandle(stdin, true);
668 if (m_option_data.m_repl) {
669 const char *repl_options = nullptr;
670 if (!m_option_data.m_repl_options.empty())
671 repl_options = m_option_data.m_repl_options.c_str();
673 m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
675 const char *error_cstr = error.GetCString();
676 if ((error_cstr != nullptr) && (error_cstr[0] != 0))
677 WithColor::error() << error_cstr << '\n';
679 WithColor::error() << error.GetError() << '\n';
682 m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
686 reset_stdin_termios();
689 int exit_code = sb_interpreter.GetQuitStatus();
690 SBDebugger::Destroy(m_debugger);
694 void Driver::ResizeWindow(unsigned short col) {
695 GetDebugger().SetTerminalWidth(col);
698 void sigwinch_handler(int signo) {
699 struct winsize window_size;
700 if ((isatty(STDIN_FILENO) != 0) &&
701 ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
702 if ((window_size.ws_col > 0) && g_driver != nullptr) {
703 g_driver->ResizeWindow(window_size.ws_col);
708 void sigint_handler(int signo) {
709 #ifdef _WIN32 // Restore handler as it is not persistent on Windows
710 signal(SIGINT, sigint_handler);
712 static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
713 if (g_driver != nullptr) {
714 if (!g_interrupt_sent.test_and_set()) {
715 g_driver->GetDebugger().DispatchInputInterrupt();
716 g_interrupt_sent.clear();
724 void sigtstp_handler(int signo) {
725 if (g_driver != nullptr)
726 g_driver->GetDebugger().SaveInputTerminalState();
728 signal(signo, SIG_DFL);
729 kill(getpid(), signo);
730 signal(signo, sigtstp_handler);
733 void sigcont_handler(int signo) {
734 if (g_driver != nullptr)
735 g_driver->GetDebugger().RestoreInputTerminalState();
737 signal(signo, SIG_DFL);
738 kill(getpid(), signo);
739 signal(signo, sigcont_handler);
742 static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
743 std::string usage_str = tool_name.str() + "options";
744 table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
746 std::string examples = R"___(
748 The debugger can be started in several modes.
750 Passing an executable as a positional argument prepares lldb to debug the
751 given executable. Arguments passed after -- are considered arguments to the
754 lldb --arch x86_64 /path/to/program -- --arch arvm7
756 Passing one of the attach options causes lldb to immediately attach to the
760 lldb -n <process-name>
762 Passing --repl starts lldb in REPL mode.
766 Passing --core causes lldb to debug the core file.
768 lldb -c /path/to/core
770 Command options can be combined with these modes and cause lldb to run the
771 specified commands before or after events, like loading the file or crashing,
772 in the order provided on the command line.
774 lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
775 lldb -S /source/before/file -s /source/after/file
776 lldb -K /source/before/crash -k /source/after/crash
778 Note: In REPL mode no file is loaded, so commands specified to run after
779 loading the file (via -o or -s) will be ignored.
781 llvm::outs() << examples;
784 llvm::Optional<int> InitializeReproducer(opt::InputArgList &input_args) {
785 if (auto *replay_path = input_args.getLastArg(OPT_replay)) {
786 if (const char *error = SBReproducer::Replay(replay_path->getValue())) {
787 WithColor::error() << "reproducer replay failed: " << error << '\n';
793 bool capture = input_args.hasArg(OPT_capture);
794 auto *capture_path = input_args.getLastArg(OPT_capture_path);
796 if (capture || capture_path) {
799 WithColor::warning() << "-capture-path specified without -capture\n";
800 if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
801 WithColor::error() << "reproducer capture failed: " << error << '\n';
805 const char *error = SBReproducer::Capture();
807 WithColor::error() << "reproducer capture failed: " << error << '\n';
818 wmain(int argc, wchar_t const *wargv[])
820 main(int argc, char const *argv[])
824 // Convert wide arguments to UTF-8
825 std::vector<std::string> argvStrings(argc);
826 std::vector<const char *> argvPointers(argc);
827 for (int i = 0; i != argc; ++i) {
828 llvm::convertWideToUTF8(wargv[i], argvStrings[i]);
829 argvPointers[i] = argvStrings[i].c_str();
831 const char **argv = argvPointers.data();
834 // Print stack trace on crash.
835 llvm::StringRef ToolName = llvm::sys::path::filename(argv[0]);
836 llvm::sys::PrintStackTraceOnErrorSignal(ToolName);
837 llvm::PrettyStackTraceProgram X(argc, argv);
843 ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
844 opt::InputArgList input_args = T.ParseArgs(arg_arr, MAI, MAC);
846 if (input_args.hasArg(OPT_help)) {
847 printHelp(T, ToolName);
851 for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
852 WithColor::warning() << "ignoring unknown option: " << arg->getSpelling()
856 if (auto exit_code = InitializeReproducer(input_args)) {
860 SBError error = SBDebugger::InitializeWithErrorHandling();
862 WithColor::error() << "initialization failed: " << error.GetCString()
866 SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
868 signal(SIGINT, sigint_handler);
869 #if !defined(_MSC_VER)
870 signal(SIGPIPE, SIG_IGN);
871 signal(SIGWINCH, sigwinch_handler);
872 signal(SIGTSTP, sigtstp_handler);
873 signal(SIGCONT, sigcont_handler);
877 // Create a scope for driver so that the driver object will destroy itself
878 // before SBDebugger::Terminate() is called.
882 bool exiting = false;
883 SBError error(driver.ProcessArgs(input_args, exiting));
886 if (const char *error_cstr = error.GetCString())
887 WithColor::error() << error_cstr << '\n';
888 } else if (!exiting) {
889 exit_code = driver.MainLoop();
893 SBDebugger::Terminate();