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