[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / lldb / tools / driver / Driver.cpp
blob233e0dd977d34c29f44318ebb5ff94ea18880c3b
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 //===----------------------------------------------------------------------===//
9 #include "Driver.h"
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"
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"
31 #include <algorithm>
32 #include <atomic>
33 #include <bitset>
34 #include <clocale>
35 #include <csignal>
36 #include <string>
37 #include <thread>
38 #include <utility>
40 #include <climits>
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
44 #include <fcntl.h>
46 #if !defined(__APPLE__)
47 #include "llvm/Support/DataTypes.h"
48 #endif
50 using namespace lldb;
51 using namespace llvm;
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
63 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
64 #include "Options.inc"
65 #undef PREFIX
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
79 class LLDBOptTable : public opt::OptTable {
80 public:
81 LLDBOptTable() : OptTable(InfoTable) {}
83 } // namespace
85 static void reset_stdin_termios();
86 static bool g_old_stdin_termios_is_valid = false;
87 static struct termios g_old_stdin_termios;
89 static Driver *g_driver = nullptr;
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);
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;
108 Driver::~Driver() {
109 SBDebugger::Destroy(m_debugger);
110 g_driver = nullptr;
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;
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));
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;
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);
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;
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);
189 if (args.hasArg(OPT_version)) {
190 m_option_data.m_print_version = true;
193 if (args.hasArg(OPT_python_path)) {
194 m_option_data.m_print_python_path = true;
196 if (args.hasArg(OPT_print_script_interpreter_info)) {
197 m_option_data.m_print_script_interpreter_info = 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'",
210 arg_value);
211 return error;
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);
232 m_option_data.m_debug_mode = true;
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;
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;
261 if (auto *arg = args.getLastArg(OPT_script_language)) {
262 auto arg_value = arg->getValue();
263 m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
266 if (args.hasArg(OPT_source_quietly)) {
267 m_option_data.m_source_quietly = true;
270 if (auto *arg = args.getLastArg(OPT_attach_name)) {
271 auto arg_value = arg->getValue();
272 m_option_data.m_process_name = arg_value;
275 if (args.hasArg(OPT_wait_for)) {
276 m_option_data.m_wait_for = true;
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;
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;
299 m_debugger.SetREPLLanguage(m_option_data.m_repl_lang);
302 if (args.hasArg(OPT_repl)) {
303 m_option_data.m_repl = true;
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;
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;
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;
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;
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;
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;
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;
361 if (m_option_data.m_process_name.empty() &&
362 m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
364 for (auto *arg : args.filtered(OPT_INPUT))
365 m_option_data.m_args.push_back(arg->getAsString((args)));
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);
372 } else if (args.getLastArgNoClaim() != nullptr) {
373 WithColor::warning() << "program arguments are ignored when attaching.\n";
376 if (m_option_data.m_print_version) {
377 llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
378 exiting = true;
379 return error;
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;
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';
409 exiting = true;
410 return error;
413 return error;
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;
422 return '"' + arg + '"';
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);
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);
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);
444 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
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);
453 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
455 // Before we handle any options from the command line, we parse the
456 // REPL init file or the default file in the user's home directory.
457 SBCommandReturnObject result;
458 sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
459 if (m_option_data.m_debug_mode) {
460 result.PutError(m_debugger.GetErrorFile());
461 result.PutOutput(m_debugger.GetOutputFile());
464 // Source the local .lldbinit file if it exists and we're allowed to source.
465 // Here we want to always print the return object because it contains the
466 // warning and instructions to load local lldbinit files.
467 sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
468 result.PutError(m_debugger.GetErrorFile());
469 result.PutOutput(m_debugger.GetOutputFile());
471 // We allow the user to specify an exit code when calling quit which we will
472 // return when exiting.
473 m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
475 // Now we handle options we got from the command line
476 SBStream commands_stream;
478 // First source in the commands specified to be run before the file arguments
479 // are processed.
480 WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
482 // If we're not in --repl mode, add the commands to process the file
483 // arguments, and the commands specified to run afterwards.
484 if (!m_option_data.m_repl) {
485 const size_t num_args = m_option_data.m_args.size();
486 if (num_args > 0) {
487 char arch_name[64];
488 if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
489 sizeof(arch_name)))
490 commands_stream.Printf("target create --arch=%s %s", arch_name,
491 EscapeString(m_option_data.m_args[0]).c_str());
492 else
493 commands_stream.Printf("target create %s",
494 EscapeString(m_option_data.m_args[0]).c_str());
496 if (!m_option_data.m_core_file.empty()) {
497 commands_stream.Printf(" --core %s",
498 EscapeString(m_option_data.m_core_file).c_str());
500 commands_stream.Printf("\n");
502 if (num_args > 1) {
503 commands_stream.Printf("settings set -- target.run-args ");
504 for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
505 commands_stream.Printf(
506 " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
507 commands_stream.Printf("\n");
509 } else if (!m_option_data.m_core_file.empty()) {
510 commands_stream.Printf("target create --core %s\n",
511 EscapeString(m_option_data.m_core_file).c_str());
512 } else if (!m_option_data.m_process_name.empty()) {
513 commands_stream.Printf(
514 "process attach --name %s",
515 EscapeString(m_option_data.m_process_name).c_str());
517 if (m_option_data.m_wait_for)
518 commands_stream.Printf(" --waitfor");
520 commands_stream.Printf("\n");
522 } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
523 commands_stream.Printf("process attach --pid %" PRIu64 "\n",
524 m_option_data.m_process_pid);
527 WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
528 } else if (!m_option_data.m_after_file_commands.empty()) {
529 // We're in repl mode and after-file-load commands were specified.
530 WithColor::warning() << "commands specified to run after file load (via -o "
531 "or -s) are ignored in REPL mode.\n";
534 if (m_option_data.m_debug_mode) {
535 result.PutError(m_debugger.GetErrorFile());
536 result.PutOutput(m_debugger.GetOutputFile());
539 const bool handle_events = true;
540 const bool spawn_thread = false;
542 // Check if we have any data in the commands stream, and if so, save it to a
543 // temp file
544 // so we can then run the command interpreter using the file contents.
545 bool go_interactive = true;
546 if ((commands_stream.GetData() != nullptr) &&
547 (commands_stream.GetSize() != 0u)) {
548 SBError error = m_debugger.SetInputString(commands_stream.GetData());
549 if (error.Fail()) {
550 WithColor::error() << error.GetCString() << '\n';
551 return 1;
554 // Set the debugger into Sync mode when running the command file. Otherwise
555 // command files that run the target won't run in a sensible way.
556 bool old_async = m_debugger.GetAsync();
557 m_debugger.SetAsync(false);
559 SBCommandInterpreterRunOptions options;
560 options.SetAutoHandleEvents(true);
561 options.SetSpawnThread(false);
562 options.SetStopOnError(true);
563 options.SetStopOnCrash(m_option_data.m_batch);
564 options.SetEchoCommands(!m_option_data.m_source_quietly);
566 SBCommandInterpreterRunResult results =
567 m_debugger.RunCommandInterpreter(options);
568 if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
569 go_interactive = false;
570 if (m_option_data.m_batch &&
571 results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
572 go_interactive = false;
574 // When running in batch mode and stopped because of an error, exit with a
575 // non-zero exit status.
576 if (m_option_data.m_batch &&
577 results.GetResult() == lldb::eCommandInterpreterResultCommandError)
578 return 1;
580 if (m_option_data.m_batch &&
581 results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
582 !m_option_data.m_after_crash_commands.empty()) {
583 SBStream crash_commands_stream;
584 WriteCommandsForSourcing(eCommandPlacementAfterCrash,
585 crash_commands_stream);
586 SBError error =
587 m_debugger.SetInputString(crash_commands_stream.GetData());
588 if (error.Success()) {
589 SBCommandInterpreterRunResult local_results =
590 m_debugger.RunCommandInterpreter(options);
591 if (local_results.GetResult() ==
592 lldb::eCommandInterpreterResultQuitRequested)
593 go_interactive = false;
595 // When running in batch mode and an error occurred while sourcing
596 // the crash commands, exit with a non-zero exit status.
597 if (m_option_data.m_batch &&
598 local_results.GetResult() ==
599 lldb::eCommandInterpreterResultCommandError)
600 return 1;
603 m_debugger.SetAsync(old_async);
606 // Now set the input file handle to STDIN and run the command interpreter
607 // again in interactive mode or repl mode and let the debugger take ownership
608 // of stdin.
609 if (go_interactive) {
610 m_debugger.SetInputFileHandle(stdin, true);
612 if (m_option_data.m_repl) {
613 const char *repl_options = nullptr;
614 if (!m_option_data.m_repl_options.empty())
615 repl_options = m_option_data.m_repl_options.c_str();
616 SBError error(
617 m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
618 if (error.Fail()) {
619 const char *error_cstr = error.GetCString();
620 if ((error_cstr != nullptr) && (error_cstr[0] != 0))
621 WithColor::error() << error_cstr << '\n';
622 else
623 WithColor::error() << error.GetError() << '\n';
625 } else {
626 m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
630 reset_stdin_termios();
631 fclose(stdin);
633 return sb_interpreter.GetQuitStatus();
636 void Driver::ResizeWindow(unsigned short col) {
637 GetDebugger().SetTerminalWidth(col);
640 void sigwinch_handler(int signo) {
641 struct winsize window_size;
642 if ((isatty(STDIN_FILENO) != 0) &&
643 ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
644 if ((window_size.ws_col > 0) && g_driver != nullptr) {
645 g_driver->ResizeWindow(window_size.ws_col);
650 void sigint_handler(int signo) {
651 #ifdef _WIN32 // Restore handler as it is not persistent on Windows
652 signal(SIGINT, sigint_handler);
653 #endif
654 static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
655 if (g_driver != nullptr) {
656 if (!g_interrupt_sent.test_and_set()) {
657 g_driver->GetDebugger().DispatchInputInterrupt();
658 g_interrupt_sent.clear();
659 return;
663 _exit(signo);
666 void sigtstp_handler(int signo) {
667 if (g_driver != nullptr)
668 g_driver->GetDebugger().SaveInputTerminalState();
670 signal(signo, SIG_DFL);
671 kill(getpid(), signo);
672 signal(signo, sigtstp_handler);
675 void sigcont_handler(int signo) {
676 if (g_driver != nullptr)
677 g_driver->GetDebugger().RestoreInputTerminalState();
679 signal(signo, SIG_DFL);
680 kill(getpid(), signo);
681 signal(signo, sigcont_handler);
684 void reproducer_handler(void *finalize_cmd) {
685 if (SBReproducer::Generate()) {
686 int result = std::system(static_cast<const char *>(finalize_cmd));
687 (void)result;
688 fflush(stdout);
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);
696 std::string examples = R"___(
697 EXAMPLES:
698 The debugger can be started in several modes.
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 --.
705 lldb --arch x86_64 /path/to/program program argument -- --arch armv7
707 For convenience, passing the executable after -- is also supported.
709 lldb --arch x86_64 -- /path/to/program program argument --arch armv7
711 Passing one of the attach options causes lldb to immediately attach to the
712 given process.
714 lldb -p <pid>
715 lldb -n <process-name>
717 Passing --repl starts lldb in REPL mode.
719 lldb -r
721 Passing --core causes lldb to debug the core file.
723 lldb -c /path/to/core
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.
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
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';
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);
744 if (generate_on_exit && !capture) {
745 WithColor::warning()
746 << "-reproducer-generate-on-exit specified without -capture\n";
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;
757 } else {
758 const char *error = SBReproducer::Capture();
759 if (error) {
760 WithColor::error() << "reproducer capture failed: " << error << '\n';
761 return 1;
764 if (generate_on_exit)
765 SBReproducer::SetAutoGenerate(true);
768 return llvm::None;
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, "");
776 // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
777 // destruction.
778 llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
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]);
789 if (input_args.hasArg(OPT_help)) {
790 printHelp(T, argv0);
791 return 0;
794 // Check for missing argument error.
795 if (MissingArgCount) {
796 WithColor::error() << "argument to '"
797 << input_args.getArgString(MissingArgIndex)
798 << "' is missing\n";
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';
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;
812 if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
813 return *exit_code;
816 SBError error = SBDebugger::InitializeWithErrorHandling();
817 if (error.Fail()) {
818 WithColor::error() << "initialization failed: " << error.GetCString()
819 << '\n';
820 return 1;
822 SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
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
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.
836 Driver driver;
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();
849 SBDebugger::Terminate();
850 return exit_code;