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/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/SBStream.h"
19 #include "lldb/API/SBStringList.h"
20 #include "lldb/API/SBStructuredData.h"
21 #include "lldb/Host/Config.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"
47 #if !defined(__APPLE__)
48 #include "llvm/Support/DataTypes.h"
55 using namespace llvm::opt
;
58 OPT_INVALID
= 0, // This is not an option ID.
59 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
60 #include "Options.inc"
64 #define PREFIX(NAME, VALUE) \
65 static constexpr StringLiteral NAME##_init[] = VALUE; \
66 static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
67 std::size(NAME##_init) - 1);
68 #include "Options.inc"
71 static constexpr opt::OptTable::Info InfoTable
[] = {
72 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
73 #include "Options.inc"
77 class LLDBOptTable
: public opt::GenericOptTable
{
79 LLDBOptTable() : opt::GenericOptTable(InfoTable
) {}
83 static void reset_stdin_termios();
84 static bool g_old_stdin_termios_is_valid
= false;
85 static struct termios g_old_stdin_termios
;
87 static bool disable_color(const raw_ostream
&OS
) { return false; }
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
);
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
104 m_debugger
.SetCloseInputOnEOF(false);
109 SBDebugger::Destroy(m_debugger
);
113 void Driver::OptionData::AddInitialCommand(std::string command
,
114 CommandPlacement placement
,
115 bool is_file
, SBError
&error
) {
116 std::vector
<InitialCmdEntry
> *command_set
;
118 case eCommandPlacementBeforeFile
:
119 command_set
= &(m_initial_commands
);
121 case eCommandPlacementAfterFile
:
122 command_set
= &(m_after_file_commands
);
124 case eCommandPlacementAfterCrash
:
125 command_set
= &(m_after_crash_commands
);
130 SBFileSpec
file(command
.c_str());
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
));
138 error
.SetErrorStringWithFormat(
139 "file specified in --source (-s) option doesn't exist: '%s'",
142 command_set
->push_back(InitialCmdEntry(command
, is_file
));
145 void Driver::WriteCommandsForSourcing(CommandPlacement placement
,
147 std::vector
<OptionData::InitialCmdEntry
> *command_set
;
149 case eCommandPlacementBeforeFile
:
150 command_set
= &m_option_data
.m_initial_commands
;
152 case eCommandPlacementAfterFile
:
153 command_set
= &m_option_data
.m_after_file_commands
;
155 case eCommandPlacementAfterCrash
:
156 command_set
= &m_option_data
.m_after_crash_commands
;
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
);
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
) {
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
186 m_debugger
.SkipLLDBInitFiles(false);
187 m_debugger
.SkipAppInitFiles(false);
189 if (args
.hasArg(OPT_no_use_colors
)) {
190 m_debugger
.SetUseColor(false);
191 WithColor::setAutoDetectFunction(disable_color
);
194 if (args
.hasArg(OPT_version
)) {
195 m_option_data
.m_print_version
= true;
198 if (args
.hasArg(OPT_python_path
)) {
199 m_option_data
.m_print_python_path
= true;
201 if (args
.hasArg(OPT_print_script_interpreter_info
)) {
202 m_option_data
.m_print_script_interpreter_info
= true;
205 if (args
.hasArg(OPT_batch
)) {
206 m_option_data
.m_batch
= true;
209 if (auto *arg
= args
.getLastArg(OPT_core
)) {
210 auto *arg_value
= arg
->getValue();
211 SBFileSpec
file(arg_value
);
212 if (!file
.Exists()) {
213 error
.SetErrorStringWithFormat(
214 "file specified in --core (-c) option doesn't exist: '%s'",
218 m_option_data
.m_core_file
= arg_value
;
221 if (args
.hasArg(OPT_editor
)) {
222 m_option_data
.m_use_external_editor
= true;
225 if (args
.hasArg(OPT_no_lldbinit
)) {
226 m_debugger
.SkipLLDBInitFiles(true);
227 m_debugger
.SkipAppInitFiles(true);
230 if (args
.hasArg(OPT_local_lldbinit
)) {
231 lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
232 m_debugger
.GetInstanceName());
235 if (auto *arg
= args
.getLastArg(OPT_file
)) {
236 auto *arg_value
= arg
->getValue();
237 SBFileSpec
file(arg_value
);
239 m_option_data
.m_args
.emplace_back(arg_value
);
240 } else if (file
.ResolveExecutableLocation()) {
242 file
.GetPath(path
, sizeof(path
));
243 m_option_data
.m_args
.emplace_back(path
);
245 error
.SetErrorStringWithFormat(
246 "file specified in --file (-f) option doesn't exist: '%s'",
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
);
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();
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
);
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\"",
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
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
,
325 if (arg
->getOption().matches(OPT_one_line_on_crash
)) {
326 m_option_data
.AddInitialCommand(arg_value
, eCommandPlacementAfterCrash
,
332 if (arg
->getOption().matches(OPT_source
)) {
333 m_option_data
.AddInitialCommand(arg_value
, eCommandPlacementAfterFile
,
339 if (arg
->getOption().matches(OPT_source_before_file
)) {
340 m_option_data
.AddInitialCommand(arg_value
, eCommandPlacementBeforeFile
,
346 if (arg
->getOption().matches(OPT_one_line
)) {
347 m_option_data
.AddInitialCommand(arg_value
, eCommandPlacementAfterFile
,
353 if (arg
->getOption().matches(OPT_one_line_before_file
)) {
354 m_option_data
.AddInitialCommand(arg_value
, eCommandPlacementBeforeFile
,
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';
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';
390 llvm::outs() << "<PATH TOO LONG>\n";
392 llvm::outs() << "<COULD NOT FIND PATH>\n";
397 if (m_option_data
.m_print_script_interpreter_info
) {
398 SBStructuredData info
=
399 m_debugger
.GetScriptInterpreterInfo(m_debugger
.GetScriptLanguage());
401 error
.SetErrorString("no script interpreter.");
404 error
= info
.GetAsJSON(stream
);
405 if (error
.Success()) {
406 llvm::outs() << stream
.GetData() << '\n';
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, '\\');
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
);
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);
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
);
445 m_debugger
.SetShowInlineDiagnostics(true);
447 struct winsize window_size
;
448 if ((isatty(STDIN_FILENO
) != 0) &&
449 ::ioctl(STDIN_FILENO
, TIOCGWINSZ
, &window_size
) == 0) {
450 if (window_size
.ws_col
> 0)
451 m_debugger
.SetTerminalWidth(window_size
.ws_col
);
454 SBCommandInterpreter sb_interpreter
= m_debugger
.GetCommandInterpreter();
456 // Process lldbinit files before handling any options from the command line.
457 SBCommandReturnObject result
;
458 sb_interpreter
.SourceInitFileInGlobalDirectory(result
);
459 sb_interpreter
.SourceInitFileInHomeDirectory(result
, m_option_data
.m_repl
);
461 // Source the local .lldbinit file if it exists and we're allowed to source.
462 // Here we want to always print the return object because it contains the
463 // warning and instructions to load local lldbinit files.
464 sb_interpreter
.SourceInitFileInCurrentWorkingDirectory(result
);
465 result
.PutError(m_debugger
.GetErrorFile());
466 result
.PutOutput(m_debugger
.GetOutputFile());
468 // We allow the user to specify an exit code when calling quit which we will
469 // return when exiting.
470 m_debugger
.GetCommandInterpreter().AllowExitCodeOnQuit(true);
472 // Now we handle options we got from the command line
473 SBStream commands_stream
;
475 // First source in the commands specified to be run before the file arguments
477 WriteCommandsForSourcing(eCommandPlacementBeforeFile
, commands_stream
);
479 // If we're not in --repl mode, add the commands to process the file
480 // arguments, and the commands specified to run afterwards.
481 if (!m_option_data
.m_repl
) {
482 const size_t num_args
= m_option_data
.m_args
.size();
485 if (lldb::SBDebugger::GetDefaultArchitecture(arch_name
,
487 commands_stream
.Printf("target create --arch=%s %s", arch_name
,
488 EscapeString(m_option_data
.m_args
[0]).c_str());
490 commands_stream
.Printf("target create %s",
491 EscapeString(m_option_data
.m_args
[0]).c_str());
493 if (!m_option_data
.m_core_file
.empty()) {
494 commands_stream
.Printf(" --core %s",
495 EscapeString(m_option_data
.m_core_file
).c_str());
497 commands_stream
.Printf("\n");
500 commands_stream
.Printf("settings set -- target.run-args ");
501 for (size_t arg_idx
= 1; arg_idx
< num_args
; ++arg_idx
)
502 commands_stream
.Printf(
503 " %s", EscapeString(m_option_data
.m_args
[arg_idx
]).c_str());
504 commands_stream
.Printf("\n");
506 } else if (!m_option_data
.m_core_file
.empty()) {
507 commands_stream
.Printf("target create --core %s\n",
508 EscapeString(m_option_data
.m_core_file
).c_str());
509 } else if (!m_option_data
.m_process_name
.empty()) {
510 commands_stream
.Printf(
511 "process attach --name %s",
512 EscapeString(m_option_data
.m_process_name
).c_str());
514 if (m_option_data
.m_wait_for
)
515 commands_stream
.Printf(" --waitfor");
517 commands_stream
.Printf("\n");
519 } else if (LLDB_INVALID_PROCESS_ID
!= m_option_data
.m_process_pid
) {
520 commands_stream
.Printf("process attach --pid %" PRIu64
"\n",
521 m_option_data
.m_process_pid
);
524 WriteCommandsForSourcing(eCommandPlacementAfterFile
, commands_stream
);
525 } else if (!m_option_data
.m_after_file_commands
.empty()) {
526 // We're in repl mode and after-file-load commands were specified.
527 WithColor::warning() << "commands specified to run after file load (via -o "
528 "or -s) are ignored in REPL mode.\n";
531 const bool handle_events
= true;
532 const bool spawn_thread
= false;
534 // Check if we have any data in the commands stream, and if so, save it to a
536 // so we can then run the command interpreter using the file contents.
537 bool go_interactive
= true;
538 if ((commands_stream
.GetData() != nullptr) &&
539 (commands_stream
.GetSize() != 0u)) {
540 SBError error
= m_debugger
.SetInputString(commands_stream
.GetData());
542 WithColor::error() << error
.GetCString() << '\n';
546 // Set the debugger into Sync mode when running the command file. Otherwise
547 // command files that run the target won't run in a sensible way.
548 bool old_async
= m_debugger
.GetAsync();
549 m_debugger
.SetAsync(false);
551 SBCommandInterpreterRunOptions options
;
552 options
.SetAutoHandleEvents(true);
553 options
.SetSpawnThread(false);
554 options
.SetStopOnError(true);
555 options
.SetStopOnCrash(m_option_data
.m_batch
);
556 options
.SetEchoCommands(!m_option_data
.m_source_quietly
);
558 SBCommandInterpreterRunResult results
=
559 m_debugger
.RunCommandInterpreter(options
);
560 if (results
.GetResult() == lldb::eCommandInterpreterResultQuitRequested
)
561 go_interactive
= false;
562 if (m_option_data
.m_batch
&&
563 results
.GetResult() != lldb::eCommandInterpreterResultInferiorCrash
)
564 go_interactive
= false;
566 // When running in batch mode and stopped because of an error, exit with a
567 // non-zero exit status.
568 if (m_option_data
.m_batch
&&
569 results
.GetResult() == lldb::eCommandInterpreterResultCommandError
)
572 if (m_option_data
.m_batch
&&
573 results
.GetResult() == lldb::eCommandInterpreterResultInferiorCrash
&&
574 !m_option_data
.m_after_crash_commands
.empty()) {
575 SBStream crash_commands_stream
;
576 WriteCommandsForSourcing(eCommandPlacementAfterCrash
,
577 crash_commands_stream
);
579 m_debugger
.SetInputString(crash_commands_stream
.GetData());
580 if (error
.Success()) {
581 SBCommandInterpreterRunResult local_results
=
582 m_debugger
.RunCommandInterpreter(options
);
583 if (local_results
.GetResult() ==
584 lldb::eCommandInterpreterResultQuitRequested
)
585 go_interactive
= false;
587 // When running in batch mode and an error occurred while sourcing
588 // the crash commands, exit with a non-zero exit status.
589 if (m_option_data
.m_batch
&&
590 local_results
.GetResult() ==
591 lldb::eCommandInterpreterResultCommandError
)
595 m_debugger
.SetAsync(old_async
);
598 // Now set the input file handle to STDIN and run the command interpreter
599 // again in interactive mode or repl mode and let the debugger take ownership
601 if (go_interactive
) {
602 m_debugger
.SetInputFileHandle(stdin
, true);
604 if (m_option_data
.m_repl
) {
605 const char *repl_options
= nullptr;
606 if (!m_option_data
.m_repl_options
.empty())
607 repl_options
= m_option_data
.m_repl_options
.c_str();
609 m_debugger
.RunREPL(m_option_data
.m_repl_lang
, repl_options
));
611 const char *error_cstr
= error
.GetCString();
612 if ((error_cstr
!= nullptr) && (error_cstr
[0] != 0))
613 WithColor::error() << error_cstr
<< '\n';
615 WithColor::error() << error
.GetError() << '\n';
618 m_debugger
.RunCommandInterpreter(handle_events
, spawn_thread
);
622 reset_stdin_termios();
625 return sb_interpreter
.GetQuitStatus();
628 void Driver::ResizeWindow(unsigned short col
) {
629 GetDebugger().SetTerminalWidth(col
);
632 void sigwinch_handler(int signo
) {
633 struct winsize window_size
;
634 if ((isatty(STDIN_FILENO
) != 0) &&
635 ::ioctl(STDIN_FILENO
, TIOCGWINSZ
, &window_size
) == 0) {
636 if ((window_size
.ws_col
> 0) && g_driver
!= nullptr) {
637 g_driver
->ResizeWindow(window_size
.ws_col
);
642 void sigint_handler(int signo
) {
643 #ifdef _WIN32 // Restore handler as it is not persistent on Windows
644 signal(SIGINT
, sigint_handler
);
646 static std::atomic_flag g_interrupt_sent
= ATOMIC_FLAG_INIT
;
647 if (g_driver
!= nullptr) {
648 if (!g_interrupt_sent
.test_and_set()) {
649 g_driver
->GetDebugger().DispatchInputInterrupt();
650 g_interrupt_sent
.clear();
659 static void sigtstp_handler(int signo
) {
660 if (g_driver
!= nullptr)
661 g_driver
->GetDebugger().SaveInputTerminalState();
663 // Unblock the signal and remove our handler.
666 sigaddset(&set
, signo
);
667 pthread_sigmask(SIG_UNBLOCK
, &set
, nullptr);
668 signal(signo
, SIG_DFL
);
670 // Now re-raise the signal. We will immediately suspend...
672 // ... and resume after a SIGCONT.
674 // Now undo the modifications.
675 pthread_sigmask(SIG_BLOCK
, &set
, nullptr);
676 signal(signo
, sigtstp_handler
);
678 if (g_driver
!= nullptr)
679 g_driver
->GetDebugger().RestoreInputTerminalState();
683 static void printHelp(LLDBOptTable
&table
, llvm::StringRef tool_name
) {
684 std::string usage_str
= tool_name
.str() + " [options]";
685 table
.printHelp(llvm::outs(), usage_str
.c_str(), "LLDB", false);
687 std::string examples
= R
"___(
689 The debugger can be started in several modes.
691 Passing an executable as a positional argument prepares lldb to debug the
692 given executable. To disambiguate between arguments passed to lldb and
693 arguments passed to the debugged executable, arguments starting with a - must
696 lldb --arch x86_64 /path/to/program program argument -- --arch armv7
698 For convenience, passing the executable after -- is also supported.
700 lldb --arch x86_64 -- /path/to/program program argument --arch armv7
702 Passing one of the attach options causes lldb to immediately attach to the
706 lldb -n <process-name>
708 Passing --repl starts lldb in REPL mode.
712 Passing --core causes lldb to debug the core file.
714 lldb -c /path/to/core
716 Command options can be combined with these modes and cause lldb to run the
717 specified commands before or after events, like loading the file or crashing,
718 in the order provided on the command line.
720 lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
721 lldb -S /source/before/file -s /source/after/file
722 lldb -K /source/before/crash -k /source/after/crash
724 Note: In REPL mode no file is loaded, so commands specified to run after
725 loading the file (via -o or -s) will be ignored.)___";
726 llvm::outs() << examples
<< '\n';
729 int main(int argc
, char const *argv
[]) {
730 // Editline uses for example iswprint which is dependent on LC_CTYPE.
731 std::setlocale(LC_ALL
, "");
732 std::setlocale(LC_CTYPE
, "");
734 // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
736 llvm::InitLLVM
IL(argc
, argv
, /*InstallPipeSignalExitHandler=*/false);
737 #if !defined(__APPLE__)
738 llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
739 " and include the crash backtrace.\n");
741 llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
742 " and include the crash report from "
743 "~/Library/Logs/DiagnosticReports/.\n");
748 unsigned MissingArgIndex
;
749 unsigned MissingArgCount
;
750 ArrayRef
<const char *> arg_arr
= ArrayRef(argv
+ 1, argc
- 1);
751 opt::InputArgList input_args
=
752 T
.ParseArgs(arg_arr
, MissingArgIndex
, MissingArgCount
);
753 llvm::StringRef argv0
= llvm::sys::path::filename(argv
[0]);
755 if (input_args
.hasArg(OPT_help
)) {
760 // Check for missing argument error.
761 if (MissingArgCount
) {
762 WithColor::error() << "argument to '"
763 << input_args
.getArgString(MissingArgIndex
)
766 // Error out on unknown options.
767 if (input_args
.hasArg(OPT_UNKNOWN
)) {
768 for (auto *arg
: input_args
.filtered(OPT_UNKNOWN
)) {
769 WithColor::error() << "unknown option: " << arg
->getSpelling() << '\n';
772 if (MissingArgCount
|| input_args
.hasArg(OPT_UNKNOWN
)) {
773 llvm::errs() << "Use '" << argv0
774 << " --help' for a complete list of options.\n";
778 SBError error
= SBDebugger::InitializeWithErrorHandling();
780 WithColor::error() << "initialization failed: " << error
.GetCString()
785 // Setup LLDB signal handlers once the debugger has been initialized.
786 SBDebugger::PrintDiagnosticsOnError();
788 signal(SIGINT
, sigint_handler
);
790 signal(SIGPIPE
, SIG_IGN
);
791 signal(SIGWINCH
, sigwinch_handler
);
792 signal(SIGTSTP
, sigtstp_handler
);
796 // Create a scope for driver so that the driver object will destroy itself
797 // before SBDebugger::Terminate() is called.
801 bool exiting
= false;
802 SBError
error(driver
.ProcessArgs(input_args
, exiting
));
805 if (const char *error_cstr
= error
.GetCString())
806 WithColor::error() << error_cstr
<< '\n';
807 } else if (!exiting
) {
808 exit_code
= driver
.MainLoop();
812 // When terminating the debugger we have to wait on all the background tasks
813 // to complete, which can take a while. Print a message when this takes longer
816 std::future
<void> future
=
817 std::async(std::launch::async
, []() { SBDebugger::Terminate(); });
819 if (future
.wait_for(std::chrono::seconds(1)) == std::future_status::timeout
)
820 fprintf(stderr
, "Waiting for background tasks to complete...\n");