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
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/Support/Format.h"
24 #include "llvm/Support/InitLLVM.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/Process.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 <csignal>
35 #include <string>
36 #include <thread>
37 #include <utility>
38
39 #include <fcntl.h>
40 #include <limits.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 // Includes for pipe()
46 #if defined(_WIN32)
47 #include <fcntl.h>
48 #include <io.h>
49 #else
50 #include <unistd.h>
51 #endif
52
53 #if !defined(__APPLE__)
54 #include "llvm/Support/DataTypes.h"
55 #endif
56
57 using namespace lldb;
58 using namespace llvm;
59
60 namespace {
61 enum ID {
62 OPT_INVALID = 0, // This is not an option ID.
63 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
64 HELPTEXT, METAVAR, VALUES) \
65 OPT_##ID,
66 #include "Options.inc"
67 #undef OPTION
68 };
69
70 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
71 #include "Options.inc"
72 #undef PREFIX
73
74 const opt::OptTable::Info InfoTable[] = {
75 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
76 HELPTEXT, METAVAR, VALUES) \
77 { \
78 PREFIX, NAME, HELPTEXT, \
79 METAVAR, OPT_##ID, opt::Option::KIND##Class, \
80 PARAM, FLAGS, OPT_##GROUP, \
81 OPT_##ALIAS, ALIASARGS, VALUES},
82 #include "Options.inc"
83 #undef OPTION
84 };
85
86 class LLDBOptTable : public opt::OptTable {
87 public:
LLDBOptTable()88 LLDBOptTable() : OptTable(InfoTable) {}
89 };
90 } // namespace
91
92 static void reset_stdin_termios();
93 static bool g_old_stdin_termios_is_valid = false;
94 static struct termios g_old_stdin_termios;
95
96 static Driver *g_driver = nullptr;
97
98 // In the Driver::MainLoop, we change the terminal settings. This function is
99 // added as an atexit handler to make sure we clean them up.
reset_stdin_termios()100 static void reset_stdin_termios() {
101 if (g_old_stdin_termios_is_valid) {
102 g_old_stdin_termios_is_valid = false;
103 ::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
104 }
105 }
106
Driver()107 Driver::Driver()
108 : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {
109 // We want to be able to handle CTRL+D in the terminal to have it terminate
110 // certain input
111 m_debugger.SetCloseInputOnEOF(false);
112 g_driver = this;
113 }
114
~Driver()115 Driver::~Driver() {
116 SBDebugger::Destroy(m_debugger);
117 g_driver = nullptr;
118 }
119
AddInitialCommand(std::string command,CommandPlacement placement,bool is_file,SBError & error)120 void Driver::OptionData::AddInitialCommand(std::string command,
121 CommandPlacement placement,
122 bool is_file, SBError &error) {
123 std::vector<InitialCmdEntry> *command_set;
124 switch (placement) {
125 case eCommandPlacementBeforeFile:
126 command_set = &(m_initial_commands);
127 break;
128 case eCommandPlacementAfterFile:
129 command_set = &(m_after_file_commands);
130 break;
131 case eCommandPlacementAfterCrash:
132 command_set = &(m_after_crash_commands);
133 break;
134 }
135
136 if (is_file) {
137 SBFileSpec file(command.c_str());
138 if (file.Exists())
139 command_set->push_back(InitialCmdEntry(command, is_file));
140 else if (file.ResolveExecutableLocation()) {
141 char final_path[PATH_MAX];
142 file.GetPath(final_path, sizeof(final_path));
143 command_set->push_back(InitialCmdEntry(final_path, is_file));
144 } else
145 error.SetErrorStringWithFormat(
146 "file specified in --source (-s) option doesn't exist: '%s'",
147 command.c_str());
148 } else
149 command_set->push_back(InitialCmdEntry(command, is_file));
150 }
151
WriteCommandsForSourcing(CommandPlacement placement,SBStream & strm)152 void Driver::WriteCommandsForSourcing(CommandPlacement placement,
153 SBStream &strm) {
154 std::vector<OptionData::InitialCmdEntry> *command_set;
155 switch (placement) {
156 case eCommandPlacementBeforeFile:
157 command_set = &m_option_data.m_initial_commands;
158 break;
159 case eCommandPlacementAfterFile:
160 command_set = &m_option_data.m_after_file_commands;
161 break;
162 case eCommandPlacementAfterCrash:
163 command_set = &m_option_data.m_after_crash_commands;
164 break;
165 }
166
167 for (const auto &command_entry : *command_set) {
168 const char *command = command_entry.contents.c_str();
169 if (command_entry.is_file) {
170 bool source_quietly =
171 m_option_data.m_source_quietly || command_entry.source_quietly;
172 strm.Printf("command source -s %i '%s'\n",
173 static_cast<int>(source_quietly), command);
174 } else
175 strm.Printf("%s\n", command);
176 }
177 }
178
179 // Check the arguments that were passed to this program to make sure they are
180 // valid and to get their argument values (if any). Return a boolean value
181 // indicating whether or not to start up the full debugger (i.e. the Command
182 // Interpreter) or not. Return FALSE if the arguments were invalid OR if the
183 // user only wanted help or version information.
ProcessArgs(const opt::InputArgList & args,bool & exiting)184 SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
185 SBError error;
186
187 // This is kind of a pain, but since we make the debugger in the Driver's
188 // constructor, we can't know at that point whether we should read in init
189 // files yet. So we don't read them in in the Driver constructor, then set
190 // the flags back to "read them in" here, and then if we see the "-n" flag,
191 // we'll turn it off again. Finally we have to read them in by hand later in
192 // the main loop.
193 m_debugger.SkipLLDBInitFiles(false);
194 m_debugger.SkipAppInitFiles(false);
195
196 if (args.hasArg(OPT_version)) {
197 m_option_data.m_print_version = true;
198 }
199
200 if (args.hasArg(OPT_python_path)) {
201 m_option_data.m_print_python_path = true;
202 }
203
204 if (args.hasArg(OPT_batch)) {
205 m_option_data.m_batch = true;
206 }
207
208 if (auto *arg = args.getLastArg(OPT_core)) {
209 auto arg_value = arg->getValue();
210 SBFileSpec file(arg_value);
211 if (!file.Exists()) {
212 error.SetErrorStringWithFormat(
213 "file specified in --core (-c) option doesn't exist: '%s'",
214 arg_value);
215 return error;
216 }
217 m_option_data.m_core_file = arg_value;
218 }
219
220 if (args.hasArg(OPT_editor)) {
221 m_option_data.m_use_external_editor = true;
222 }
223
224 if (args.hasArg(OPT_no_lldbinit)) {
225 m_debugger.SkipLLDBInitFiles(true);
226 m_debugger.SkipAppInitFiles(true);
227 }
228
229 if (args.hasArg(OPT_local_lldbinit)) {
230 lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
231 m_debugger.GetInstanceName());
232 }
233
234 if (args.hasArg(OPT_no_use_colors)) {
235 m_debugger.SetUseColor(false);
236 m_option_data.m_debug_mode = true;
237 }
238
239 if (auto *arg = args.getLastArg(OPT_file)) {
240 auto arg_value = arg->getValue();
241 SBFileSpec file(arg_value);
242 if (file.Exists()) {
243 m_option_data.m_args.emplace_back(arg_value);
244 } else if (file.ResolveExecutableLocation()) {
245 char path[PATH_MAX];
246 file.GetPath(path, sizeof(path));
247 m_option_data.m_args.emplace_back(path);
248 } else {
249 error.SetErrorStringWithFormat(
250 "file specified in --file (-f) option doesn't exist: '%s'",
251 arg_value);
252 return error;
253 }
254 }
255
256 if (auto *arg = args.getLastArg(OPT_arch)) {
257 auto arg_value = arg->getValue();
258 if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
259 error.SetErrorStringWithFormat(
260 "invalid architecture in the -a or --arch option: '%s'", arg_value);
261 return error;
262 }
263 }
264
265 if (auto *arg = args.getLastArg(OPT_script_language)) {
266 auto arg_value = arg->getValue();
267 m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
268 }
269
270 if (args.hasArg(OPT_source_quietly)) {
271 m_option_data.m_source_quietly = true;
272 }
273
274 if (auto *arg = args.getLastArg(OPT_attach_name)) {
275 auto arg_value = arg->getValue();
276 m_option_data.m_process_name = arg_value;
277 }
278
279 if (args.hasArg(OPT_wait_for)) {
280 m_option_data.m_wait_for = true;
281 }
282
283 if (auto *arg = args.getLastArg(OPT_attach_pid)) {
284 auto arg_value = arg->getValue();
285 char *remainder;
286 m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
287 if (remainder == arg_value || *remainder != '\0') {
288 error.SetErrorStringWithFormat(
289 "Could not convert process PID: \"%s\" into a pid.", arg_value);
290 return error;
291 }
292 }
293
294 if (auto *arg = args.getLastArg(OPT_repl_language)) {
295 auto arg_value = arg->getValue();
296 m_option_data.m_repl_lang =
297 SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
298 if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
299 error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
300 arg_value);
301 return error;
302 }
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 return error;
401 }
402
OpenPipe(int fds[2],std::size_t size)403 static inline int OpenPipe(int fds[2], std::size_t size) {
404 #ifdef _WIN32
405 return _pipe(fds, size, O_BINARY);
406 #else
407 (void)size;
408 return pipe(fds);
409 #endif
410 }
411
PrepareCommandsForSourcing(const char * commands_data,size_t commands_size)412 static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
413 size_t commands_size) {
414 enum PIPES { READ, WRITE }; // Indexes for the read and write fds
415 int fds[2] = {-1, -1};
416
417 if (OpenPipe(fds, commands_size) != 0) {
418 WithColor::error()
419 << "can't create pipe file descriptors for LLDB commands\n";
420 return nullptr;
421 }
422
423 ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
424 if (size_t(nrwr) != commands_size) {
425 WithColor::error()
426 << format(
427 "write(%i, %p, %" PRIu64
428 ") failed (errno = %i) when trying to open LLDB commands pipe",
429 fds[WRITE], static_cast<const void *>(commands_data),
430 static_cast<uint64_t>(commands_size), errno)
431 << '\n';
432 llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
433 llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
434 return nullptr;
435 }
436
437 // Close the write end of the pipe, so that the command interpreter will exit
438 // when it consumes all the data.
439 llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
440
441 // Open the read file descriptor as a FILE * that we can return as an input
442 // handle.
443 ::FILE *commands_file = fdopen(fds[READ], "rb");
444 if (commands_file == nullptr) {
445 WithColor::error() << format("fdopen(%i, \"rb\") failed (errno = %i) "
446 "when trying to open LLDB commands pipe",
447 fds[READ], errno)
448 << '\n';
449 llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
450 return nullptr;
451 }
452
453 // 'commands_file' now owns the read descriptor.
454 return commands_file;
455 }
456
EscapeString(std::string arg)457 std::string EscapeString(std::string arg) {
458 std::string::size_type pos = 0;
459 while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
460 arg.insert(pos, 1, '\\');
461 pos += 2;
462 }
463 return '"' + arg + '"';
464 }
465
MainLoop()466 int Driver::MainLoop() {
467 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
468 g_old_stdin_termios_is_valid = true;
469 atexit(reset_stdin_termios);
470 }
471
472 #ifndef _MSC_VER
473 // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
474 // which causes it to miss newlines depending on whether there have been an
475 // odd or even number of characters. Bug has been reported to MS via Connect.
476 ::setbuf(stdin, nullptr);
477 #endif
478 ::setbuf(stdout, nullptr);
479
480 m_debugger.SetErrorFileHandle(stderr, false);
481 m_debugger.SetOutputFileHandle(stdout, false);
482 // Don't take ownership of STDIN yet...
483 m_debugger.SetInputFileHandle(stdin, false);
484
485 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
486
487 struct winsize window_size;
488 if ((isatty(STDIN_FILENO) != 0) &&
489 ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
490 if (window_size.ws_col > 0)
491 m_debugger.SetTerminalWidth(window_size.ws_col);
492 }
493
494 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
495
496 // Before we handle any options from the command line, we parse the
497 // REPL init file or the default file in the user's home directory.
498 SBCommandReturnObject result;
499 sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
500 if (m_option_data.m_debug_mode) {
501 result.PutError(m_debugger.GetErrorFile());
502 result.PutOutput(m_debugger.GetOutputFile());
503 }
504
505 // Source the local .lldbinit file if it exists and we're allowed to source.
506 // Here we want to always print the return object because it contains the
507 // warning and instructions to load local lldbinit files.
508 sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
509 result.PutError(m_debugger.GetErrorFile());
510 result.PutOutput(m_debugger.GetOutputFile());
511
512 // We allow the user to specify an exit code when calling quit which we will
513 // return when exiting.
514 m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
515
516 // Now we handle options we got from the command line
517 SBStream commands_stream;
518
519 // First source in the commands specified to be run before the file arguments
520 // are processed.
521 WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
522
523 // If we're not in --repl mode, add the commands to process the file
524 // arguments, and the commands specified to run afterwards.
525 if (!m_option_data.m_repl) {
526 const size_t num_args = m_option_data.m_args.size();
527 if (num_args > 0) {
528 char arch_name[64];
529 if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
530 sizeof(arch_name)))
531 commands_stream.Printf("target create --arch=%s %s", arch_name,
532 EscapeString(m_option_data.m_args[0]).c_str());
533 else
534 commands_stream.Printf("target create %s",
535 EscapeString(m_option_data.m_args[0]).c_str());
536
537 if (!m_option_data.m_core_file.empty()) {
538 commands_stream.Printf(" --core %s",
539 EscapeString(m_option_data.m_core_file).c_str());
540 }
541 commands_stream.Printf("\n");
542
543 if (num_args > 1) {
544 commands_stream.Printf("settings set -- target.run-args ");
545 for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
546 commands_stream.Printf(
547 " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
548 commands_stream.Printf("\n");
549 }
550 } else if (!m_option_data.m_core_file.empty()) {
551 commands_stream.Printf("target create --core %s\n",
552 EscapeString(m_option_data.m_core_file).c_str());
553 } else if (!m_option_data.m_process_name.empty()) {
554 commands_stream.Printf(
555 "process attach --name %s",
556 EscapeString(m_option_data.m_process_name).c_str());
557
558 if (m_option_data.m_wait_for)
559 commands_stream.Printf(" --waitfor");
560
561 commands_stream.Printf("\n");
562
563 } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
564 commands_stream.Printf("process attach --pid %" PRIu64 "\n",
565 m_option_data.m_process_pid);
566 }
567
568 WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
569 } else if (!m_option_data.m_after_file_commands.empty()) {
570 // We're in repl mode and after-file-load commands were specified.
571 WithColor::warning() << "commands specified to run after file load (via -o "
572 "or -s) are ignored in REPL mode.\n";
573 }
574
575 if (m_option_data.m_debug_mode) {
576 result.PutError(m_debugger.GetErrorFile());
577 result.PutOutput(m_debugger.GetOutputFile());
578 }
579
580 const bool handle_events = true;
581 const bool spawn_thread = false;
582
583 // Check if we have any data in the commands stream, and if so, save it to a
584 // temp file
585 // so we can then run the command interpreter using the file contents.
586 const char *commands_data = commands_stream.GetData();
587 const size_t commands_size = commands_stream.GetSize();
588
589 bool go_interactive = true;
590 if ((commands_data != nullptr) && (commands_size != 0u)) {
591 FILE *commands_file =
592 PrepareCommandsForSourcing(commands_data, commands_size);
593
594 if (commands_file == nullptr) {
595 // We should have already printed an error in PrepareCommandsForSourcing.
596 return 1;
597 }
598
599 m_debugger.SetInputFileHandle(commands_file, true);
600
601 // Set the debugger into Sync mode when running the command file. Otherwise
602 // command files that run the target won't run in a sensible way.
603 bool old_async = m_debugger.GetAsync();
604 m_debugger.SetAsync(false);
605
606 SBCommandInterpreterRunOptions options;
607 options.SetAutoHandleEvents(true);
608 options.SetSpawnThread(false);
609 options.SetStopOnError(true);
610 options.SetStopOnCrash(m_option_data.m_batch);
611
612 SBCommandInterpreterRunResult results =
613 m_debugger.RunCommandInterpreter(options);
614 if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
615 go_interactive = false;
616 if (m_option_data.m_batch &&
617 results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
618 go_interactive = false;
619
620 // When running in batch mode and stopped because of an error, exit with a
621 // non-zero exit status.
622 if (m_option_data.m_batch &&
623 results.GetResult() == lldb::eCommandInterpreterResultCommandError)
624 return 1;
625
626 if (m_option_data.m_batch &&
627 results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
628 !m_option_data.m_after_crash_commands.empty()) {
629 SBStream crash_commands_stream;
630 WriteCommandsForSourcing(eCommandPlacementAfterCrash,
631 crash_commands_stream);
632 const char *crash_commands_data = crash_commands_stream.GetData();
633 const size_t crash_commands_size = crash_commands_stream.GetSize();
634 commands_file =
635 PrepareCommandsForSourcing(crash_commands_data, crash_commands_size);
636 if (commands_file != nullptr) {
637 m_debugger.SetInputFileHandle(commands_file, true);
638 SBCommandInterpreterRunResult local_results =
639 m_debugger.RunCommandInterpreter(options);
640 if (local_results.GetResult() ==
641 lldb::eCommandInterpreterResultQuitRequested)
642 go_interactive = false;
643
644 // When running in batch mode and an error occurred while sourcing
645 // the crash commands, exit with a non-zero exit status.
646 if (m_option_data.m_batch &&
647 local_results.GetResult() ==
648 lldb::eCommandInterpreterResultCommandError)
649 return 1;
650 }
651 }
652 m_debugger.SetAsync(old_async);
653 }
654
655 // Now set the input file handle to STDIN and run the command interpreter
656 // again in interactive mode or repl mode and let the debugger take ownership
657 // of stdin.
658 if (go_interactive) {
659 m_debugger.SetInputFileHandle(stdin, true);
660
661 if (m_option_data.m_repl) {
662 const char *repl_options = nullptr;
663 if (!m_option_data.m_repl_options.empty())
664 repl_options = m_option_data.m_repl_options.c_str();
665 SBError error(
666 m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
667 if (error.Fail()) {
668 const char *error_cstr = error.GetCString();
669 if ((error_cstr != nullptr) && (error_cstr[0] != 0))
670 WithColor::error() << error_cstr << '\n';
671 else
672 WithColor::error() << error.GetError() << '\n';
673 }
674 } else {
675 m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
676 }
677 }
678
679 reset_stdin_termios();
680 fclose(stdin);
681
682 return sb_interpreter.GetQuitStatus();
683 }
684
ResizeWindow(unsigned short col)685 void Driver::ResizeWindow(unsigned short col) {
686 GetDebugger().SetTerminalWidth(col);
687 }
688
sigwinch_handler(int signo)689 void sigwinch_handler(int signo) {
690 struct winsize window_size;
691 if ((isatty(STDIN_FILENO) != 0) &&
692 ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
693 if ((window_size.ws_col > 0) && g_driver != nullptr) {
694 g_driver->ResizeWindow(window_size.ws_col);
695 }
696 }
697 }
698
sigint_handler(int signo)699 void sigint_handler(int signo) {
700 #ifdef _WIN32 // Restore handler as it is not persistent on Windows
701 signal(SIGINT, sigint_handler);
702 #endif
703 static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
704 if (g_driver != nullptr) {
705 if (!g_interrupt_sent.test_and_set()) {
706 g_driver->GetDebugger().DispatchInputInterrupt();
707 g_interrupt_sent.clear();
708 return;
709 }
710 }
711
712 _exit(signo);
713 }
714
sigtstp_handler(int signo)715 void sigtstp_handler(int signo) {
716 if (g_driver != nullptr)
717 g_driver->GetDebugger().SaveInputTerminalState();
718
719 signal(signo, SIG_DFL);
720 kill(getpid(), signo);
721 signal(signo, sigtstp_handler);
722 }
723
sigcont_handler(int signo)724 void sigcont_handler(int signo) {
725 if (g_driver != nullptr)
726 g_driver->GetDebugger().RestoreInputTerminalState();
727
728 signal(signo, SIG_DFL);
729 kill(getpid(), signo);
730 signal(signo, sigcont_handler);
731 }
732
reproducer_handler(void * finalize_cmd)733 void reproducer_handler(void *finalize_cmd) {
734 if (SBReproducer::Generate()) {
735 std::system(static_cast<const char *>(finalize_cmd));
736 fflush(stdout);
737 }
738 }
739
printHelp(LLDBOptTable & table,llvm::StringRef tool_name)740 static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
741 std::string usage_str = tool_name.str() + " [options]";
742 table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
743
744 std::string examples = R"___(
745 EXAMPLES:
746 The debugger can be started in several modes.
747
748 Passing an executable as a positional argument prepares lldb to debug the
749 given executable. To disambiguate between arguments passed to lldb and
750 arguments passed to the debugged executable, arguments starting with a - must
751 be passed after --.
752
753 lldb --arch x86_64 /path/to/program program argument -- --arch arvm7
754
755 For convenience, passing the executable after -- is also supported.
756
757 lldb --arch x86_64 -- /path/to/program program argument --arch arvm7
758
759 Passing one of the attach options causes lldb to immediately attach to the
760 given process.
761
762 lldb -p <pid>
763 lldb -n <process-name>
764
765 Passing --repl starts lldb in REPL mode.
766
767 lldb -r
768
769 Passing --core causes lldb to debug the core file.
770
771 lldb -c /path/to/core
772
773 Command options can be combined with these modes and cause lldb to run the
774 specified commands before or after events, like loading the file or crashing,
775 in the order provided on the command line.
776
777 lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
778 lldb -S /source/before/file -s /source/after/file
779 lldb -K /source/before/crash -k /source/after/crash
780
781 Note: In REPL mode no file is loaded, so commands specified to run after
782 loading the file (via -o or -s) will be ignored.)___";
783 llvm::outs() << examples << '\n';
784 }
785
InitializeReproducer(llvm::StringRef argv0,opt::InputArgList & input_args)786 llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0,
787 opt::InputArgList &input_args) {
788 if (auto *finalize_path = input_args.getLastArg(OPT_reproducer_finalize)) {
789 if (const char *error = SBReproducer::Finalize(finalize_path->getValue())) {
790 WithColor::error() << "reproducer finalization failed: " << error << '\n';
791 return 1;
792 }
793
794 llvm::outs() << "********************\n";
795 llvm::outs() << "Crash reproducer for ";
796 llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
797 llvm::outs() << '\n';
798 llvm::outs() << "Reproducer written to '" << SBReproducer::GetPath()
799 << "'\n";
800 llvm::outs() << '\n';
801 llvm::outs() << "Before attaching the reproducer to a bug report:\n";
802 llvm::outs() << " - Look at the directory to ensure you're willing to "
803 "share its content.\n";
804 llvm::outs()
805 << " - Make sure the reproducer works by replaying the reproducer.\n";
806 llvm::outs() << '\n';
807 llvm::outs() << "Replay the reproducer with the following command:\n";
808 llvm::outs() << argv0 << " -replay " << finalize_path->getValue() << "\n";
809 llvm::outs() << "********************\n";
810 return 0;
811 }
812
813 if (auto *replay_path = input_args.getLastArg(OPT_replay)) {
814 SBReplayOptions replay_options;
815 replay_options.SetCheckVersion(!input_args.hasArg(OPT_no_version_check));
816 replay_options.SetVerify(!input_args.hasArg(OPT_no_verification));
817 if (const char *error =
818 SBReproducer::Replay(replay_path->getValue(), replay_options)) {
819 WithColor::error() << "reproducer replay failed: " << error << '\n';
820 return 1;
821 }
822 return 0;
823 }
824
825 bool capture = input_args.hasArg(OPT_capture);
826 bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit);
827 auto *capture_path = input_args.getLastArg(OPT_capture_path);
828
829 if (generate_on_exit && !capture) {
830 WithColor::warning()
831 << "-reproducer-generate-on-exit specified without -capture\n";
832 }
833
834 if (capture || capture_path) {
835 if (capture_path) {
836 if (!capture)
837 WithColor::warning() << "-capture-path specified without -capture\n";
838 if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
839 WithColor::error() << "reproducer capture failed: " << error << '\n';
840 return 1;
841 }
842 } else {
843 const char *error = SBReproducer::Capture();
844 if (error) {
845 WithColor::error() << "reproducer capture failed: " << error << '\n';
846 return 1;
847 }
848 }
849 if (generate_on_exit)
850 SBReproducer::SetAutoGenerate(true);
851
852 // Register the reproducer signal handler.
853 if (!input_args.hasArg(OPT_no_generate_on_signal)) {
854 if (const char *reproducer_path = SBReproducer::GetPath()) {
855 // Leaking the string on purpose.
856 std::string *finalize_cmd = new std::string(argv0);
857 finalize_cmd->append(" --reproducer-finalize '");
858 finalize_cmd->append(reproducer_path);
859 finalize_cmd->append("'");
860 llvm::sys::AddSignalHandler(reproducer_handler,
861 const_cast<char *>(finalize_cmd->c_str()));
862 }
863 }
864 }
865
866 return llvm::None;
867 }
868
main(int argc,char const * argv[])869 int main(int argc, char const *argv[]) {
870 // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
871 // destruction.
872 llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
873
874 // Parse arguments.
875 LLDBOptTable T;
876 unsigned MissingArgIndex;
877 unsigned MissingArgCount;
878 ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
879 opt::InputArgList input_args =
880 T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
881 llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
882
883 if (input_args.hasArg(OPT_help)) {
884 printHelp(T, argv0);
885 return 0;
886 }
887
888 // Check for missing argument error.
889 if (MissingArgCount) {
890 WithColor::error() << "argument to '"
891 << input_args.getArgString(MissingArgIndex)
892 << "' is missing\n";
893 }
894 // Error out on unknown options.
895 if (input_args.hasArg(OPT_UNKNOWN)) {
896 for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
897 WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
898 }
899 }
900 if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {
901 llvm::errs() << "Use '" << argv0
902 << " --help' for a complete list of options.\n";
903 return 1;
904 }
905
906 if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
907 return *exit_code;
908 }
909
910 SBError error = SBDebugger::InitializeWithErrorHandling();
911 if (error.Fail()) {
912 WithColor::error() << "initialization failed: " << error.GetCString()
913 << '\n';
914 return 1;
915 }
916 SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
917
918 signal(SIGINT, sigint_handler);
919 #if !defined(_MSC_VER)
920 signal(SIGPIPE, SIG_IGN);
921 signal(SIGWINCH, sigwinch_handler);
922 signal(SIGTSTP, sigtstp_handler);
923 signal(SIGCONT, sigcont_handler);
924 #endif
925
926 int exit_code = 0;
927 // Create a scope for driver so that the driver object will destroy itself
928 // before SBDebugger::Terminate() is called.
929 {
930 Driver driver;
931
932 bool exiting = false;
933 SBError error(driver.ProcessArgs(input_args, exiting));
934 if (error.Fail()) {
935 exit_code = 1;
936 if (const char *error_cstr = error.GetCString())
937 WithColor::error() << error_cstr << '\n';
938 } else if (!exiting) {
939 exit_code = driver.MainLoop();
940 }
941 }
942
943 SBDebugger::Terminate();
944 return exit_code;
945 }
946