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