Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/tools/driver/Driver.cpp
34879 views
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 <future>
37
#include <string>
38
#include <thread>
39
#include <utility>
40
41
#include <climits>
42
#include <cstdio>
43
#include <cstdlib>
44
#include <cstring>
45
#include <fcntl.h>
46
47
#if !defined(__APPLE__)
48
#include "llvm/Support/DataTypes.h"
49
#endif
50
51
using namespace lldb;
52
using namespace llvm;
53
54
namespace {
55
using namespace llvm::opt;
56
57
enum ID {
58
OPT_INVALID = 0, // This is not an option ID.
59
#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
60
#include "Options.inc"
61
#undef OPTION
62
};
63
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"
69
#undef PREFIX
70
71
static constexpr opt::OptTable::Info InfoTable[] = {
72
#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
73
#include "Options.inc"
74
#undef OPTION
75
};
76
77
class LLDBOptTable : public opt::GenericOptTable {
78
public:
79
LLDBOptTable() : opt::GenericOptTable(InfoTable) {}
80
};
81
} // namespace
82
83
static void reset_stdin_termios();
84
static bool g_old_stdin_termios_is_valid = false;
85
static struct termios g_old_stdin_termios;
86
87
static bool disable_color(const raw_ostream &OS) { return false; }
88
89
static Driver *g_driver = nullptr;
90
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);
97
}
98
}
99
100
Driver::Driver()
101
: SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {
102
// We want to be able to handle CTRL+D in the terminal to have it terminate
103
// certain input
104
m_debugger.SetCloseInputOnEOF(false);
105
g_driver = this;
106
}
107
108
Driver::~Driver() {
109
SBDebugger::Destroy(m_debugger);
110
g_driver = nullptr;
111
}
112
113
void Driver::OptionData::AddInitialCommand(std::string command,
114
CommandPlacement placement,
115
bool is_file, SBError &error) {
116
std::vector<InitialCmdEntry> *command_set;
117
switch (placement) {
118
case eCommandPlacementBeforeFile:
119
command_set = &(m_initial_commands);
120
break;
121
case eCommandPlacementAfterFile:
122
command_set = &(m_after_file_commands);
123
break;
124
case eCommandPlacementAfterCrash:
125
command_set = &(m_after_crash_commands);
126
break;
127
}
128
129
if (is_file) {
130
SBFileSpec file(command.c_str());
131
if (file.Exists())
132
command_set->push_back(InitialCmdEntry(command, is_file));
133
else if (file.ResolveExecutableLocation()) {
134
char final_path[PATH_MAX];
135
file.GetPath(final_path, sizeof(final_path));
136
command_set->push_back(InitialCmdEntry(final_path, is_file));
137
} else
138
error.SetErrorStringWithFormat(
139
"file specified in --source (-s) option doesn't exist: '%s'",
140
command.c_str());
141
} else
142
command_set->push_back(InitialCmdEntry(command, is_file));
143
}
144
145
void Driver::WriteCommandsForSourcing(CommandPlacement placement,
146
SBStream &strm) {
147
std::vector<OptionData::InitialCmdEntry> *command_set;
148
switch (placement) {
149
case eCommandPlacementBeforeFile:
150
command_set = &m_option_data.m_initial_commands;
151
break;
152
case eCommandPlacementAfterFile:
153
command_set = &m_option_data.m_after_file_commands;
154
break;
155
case eCommandPlacementAfterCrash:
156
command_set = &m_option_data.m_after_crash_commands;
157
break;
158
}
159
160
for (const auto &command_entry : *command_set) {
161
const char *command = command_entry.contents.c_str();
162
if (command_entry.is_file) {
163
bool source_quietly =
164
m_option_data.m_source_quietly || command_entry.source_quietly;
165
strm.Printf("command source -s %i '%s'\n",
166
static_cast<int>(source_quietly), command);
167
} else
168
strm.Printf("%s\n", command);
169
}
170
}
171
172
// Check the arguments that were passed to this program to make sure they are
173
// valid and to get their argument values (if any). Return a boolean value
174
// indicating whether or not to start up the full debugger (i.e. the Command
175
// Interpreter) or not. Return FALSE if the arguments were invalid OR if the
176
// user only wanted help or version information.
177
SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
178
SBError error;
179
180
// This is kind of a pain, but since we make the debugger in the Driver's
181
// constructor, we can't know at that point whether we should read in init
182
// files yet. So we don't read them in in the Driver constructor, then set
183
// the flags back to "read them in" here, and then if we see the "-n" flag,
184
// we'll turn it off again. Finally we have to read them in by hand later in
185
// the main loop.
186
m_debugger.SkipLLDBInitFiles(false);
187
m_debugger.SkipAppInitFiles(false);
188
189
if (args.hasArg(OPT_no_use_colors)) {
190
m_debugger.SetUseColor(false);
191
WithColor::setAutoDetectFunction(disable_color);
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
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
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
sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
459
460
// Source the local .lldbinit file if it exists and we're allowed to source.
461
// Here we want to always print the return object because it contains the
462
// warning and instructions to load local lldbinit files.
463
sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
464
result.PutError(m_debugger.GetErrorFile());
465
result.PutOutput(m_debugger.GetOutputFile());
466
467
// We allow the user to specify an exit code when calling quit which we will
468
// return when exiting.
469
m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
470
471
// Now we handle options we got from the command line
472
SBStream commands_stream;
473
474
// First source in the commands specified to be run before the file arguments
475
// are processed.
476
WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
477
478
// If we're not in --repl mode, add the commands to process the file
479
// arguments, and the commands specified to run afterwards.
480
if (!m_option_data.m_repl) {
481
const size_t num_args = m_option_data.m_args.size();
482
if (num_args > 0) {
483
char arch_name[64];
484
if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
485
sizeof(arch_name)))
486
commands_stream.Printf("target create --arch=%s %s", arch_name,
487
EscapeString(m_option_data.m_args[0]).c_str());
488
else
489
commands_stream.Printf("target create %s",
490
EscapeString(m_option_data.m_args[0]).c_str());
491
492
if (!m_option_data.m_core_file.empty()) {
493
commands_stream.Printf(" --core %s",
494
EscapeString(m_option_data.m_core_file).c_str());
495
}
496
commands_stream.Printf("\n");
497
498
if (num_args > 1) {
499
commands_stream.Printf("settings set -- target.run-args ");
500
for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
501
commands_stream.Printf(
502
" %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
503
commands_stream.Printf("\n");
504
}
505
} else if (!m_option_data.m_core_file.empty()) {
506
commands_stream.Printf("target create --core %s\n",
507
EscapeString(m_option_data.m_core_file).c_str());
508
} else if (!m_option_data.m_process_name.empty()) {
509
commands_stream.Printf(
510
"process attach --name %s",
511
EscapeString(m_option_data.m_process_name).c_str());
512
513
if (m_option_data.m_wait_for)
514
commands_stream.Printf(" --waitfor");
515
516
commands_stream.Printf("\n");
517
518
} else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
519
commands_stream.Printf("process attach --pid %" PRIu64 "\n",
520
m_option_data.m_process_pid);
521
}
522
523
WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
524
} else if (!m_option_data.m_after_file_commands.empty()) {
525
// We're in repl mode and after-file-load commands were specified.
526
WithColor::warning() << "commands specified to run after file load (via -o "
527
"or -s) are ignored in REPL mode.\n";
528
}
529
530
const bool handle_events = true;
531
const bool spawn_thread = false;
532
533
// Check if we have any data in the commands stream, and if so, save it to a
534
// temp file
535
// so we can then run the command interpreter using the file contents.
536
bool go_interactive = true;
537
if ((commands_stream.GetData() != nullptr) &&
538
(commands_stream.GetSize() != 0u)) {
539
SBError error = m_debugger.SetInputString(commands_stream.GetData());
540
if (error.Fail()) {
541
WithColor::error() << error.GetCString() << '\n';
542
return 1;
543
}
544
545
// Set the debugger into Sync mode when running the command file. Otherwise
546
// command files that run the target won't run in a sensible way.
547
bool old_async = m_debugger.GetAsync();
548
m_debugger.SetAsync(false);
549
550
SBCommandInterpreterRunOptions options;
551
options.SetAutoHandleEvents(true);
552
options.SetSpawnThread(false);
553
options.SetStopOnError(true);
554
options.SetStopOnCrash(m_option_data.m_batch);
555
options.SetEchoCommands(!m_option_data.m_source_quietly);
556
557
SBCommandInterpreterRunResult results =
558
m_debugger.RunCommandInterpreter(options);
559
if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
560
go_interactive = false;
561
if (m_option_data.m_batch &&
562
results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
563
go_interactive = false;
564
565
// When running in batch mode and stopped because of an error, exit with a
566
// non-zero exit status.
567
if (m_option_data.m_batch &&
568
results.GetResult() == lldb::eCommandInterpreterResultCommandError)
569
return 1;
570
571
if (m_option_data.m_batch &&
572
results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
573
!m_option_data.m_after_crash_commands.empty()) {
574
SBStream crash_commands_stream;
575
WriteCommandsForSourcing(eCommandPlacementAfterCrash,
576
crash_commands_stream);
577
SBError error =
578
m_debugger.SetInputString(crash_commands_stream.GetData());
579
if (error.Success()) {
580
SBCommandInterpreterRunResult local_results =
581
m_debugger.RunCommandInterpreter(options);
582
if (local_results.GetResult() ==
583
lldb::eCommandInterpreterResultQuitRequested)
584
go_interactive = false;
585
586
// When running in batch mode and an error occurred while sourcing
587
// the crash commands, exit with a non-zero exit status.
588
if (m_option_data.m_batch &&
589
local_results.GetResult() ==
590
lldb::eCommandInterpreterResultCommandError)
591
return 1;
592
}
593
}
594
m_debugger.SetAsync(old_async);
595
}
596
597
// Now set the input file handle to STDIN and run the command interpreter
598
// again in interactive mode or repl mode and let the debugger take ownership
599
// of stdin.
600
if (go_interactive) {
601
m_debugger.SetInputFileHandle(stdin, true);
602
603
if (m_option_data.m_repl) {
604
const char *repl_options = nullptr;
605
if (!m_option_data.m_repl_options.empty())
606
repl_options = m_option_data.m_repl_options.c_str();
607
SBError error(
608
m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
609
if (error.Fail()) {
610
const char *error_cstr = error.GetCString();
611
if ((error_cstr != nullptr) && (error_cstr[0] != 0))
612
WithColor::error() << error_cstr << '\n';
613
else
614
WithColor::error() << error.GetError() << '\n';
615
}
616
} else {
617
m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
618
}
619
}
620
621
reset_stdin_termios();
622
fclose(stdin);
623
624
return sb_interpreter.GetQuitStatus();
625
}
626
627
void Driver::ResizeWindow(unsigned short col) {
628
GetDebugger().SetTerminalWidth(col);
629
}
630
631
void sigwinch_handler(int signo) {
632
struct winsize window_size;
633
if ((isatty(STDIN_FILENO) != 0) &&
634
::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
635
if ((window_size.ws_col > 0) && g_driver != nullptr) {
636
g_driver->ResizeWindow(window_size.ws_col);
637
}
638
}
639
}
640
641
void sigint_handler(int signo) {
642
#ifdef _WIN32 // Restore handler as it is not persistent on Windows
643
signal(SIGINT, sigint_handler);
644
#endif
645
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
646
if (g_driver != nullptr) {
647
if (!g_interrupt_sent.test_and_set()) {
648
g_driver->GetDebugger().DispatchInputInterrupt();
649
g_interrupt_sent.clear();
650
return;
651
}
652
}
653
654
_exit(signo);
655
}
656
657
#ifndef _WIN32
658
static void sigtstp_handler(int signo) {
659
if (g_driver != nullptr)
660
g_driver->GetDebugger().SaveInputTerminalState();
661
662
// Unblock the signal and remove our handler.
663
sigset_t set;
664
sigemptyset(&set);
665
sigaddset(&set, signo);
666
pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
667
signal(signo, SIG_DFL);
668
669
// Now re-raise the signal. We will immediately suspend...
670
raise(signo);
671
// ... and resume after a SIGCONT.
672
673
// Now undo the modifications.
674
pthread_sigmask(SIG_BLOCK, &set, nullptr);
675
signal(signo, sigtstp_handler);
676
677
if (g_driver != nullptr)
678
g_driver->GetDebugger().RestoreInputTerminalState();
679
}
680
#endif
681
682
static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
683
std::string usage_str = tool_name.str() + " [options]";
684
table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
685
686
std::string examples = R"___(
687
EXAMPLES:
688
The debugger can be started in several modes.
689
690
Passing an executable as a positional argument prepares lldb to debug the
691
given executable. To disambiguate between arguments passed to lldb and
692
arguments passed to the debugged executable, arguments starting with a - must
693
be passed after --.
694
695
lldb --arch x86_64 /path/to/program program argument -- --arch armv7
696
697
For convenience, passing the executable after -- is also supported.
698
699
lldb --arch x86_64 -- /path/to/program program argument --arch armv7
700
701
Passing one of the attach options causes lldb to immediately attach to the
702
given process.
703
704
lldb -p <pid>
705
lldb -n <process-name>
706
707
Passing --repl starts lldb in REPL mode.
708
709
lldb -r
710
711
Passing --core causes lldb to debug the core file.
712
713
lldb -c /path/to/core
714
715
Command options can be combined with these modes and cause lldb to run the
716
specified commands before or after events, like loading the file or crashing,
717
in the order provided on the command line.
718
719
lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
720
lldb -S /source/before/file -s /source/after/file
721
lldb -K /source/before/crash -k /source/after/crash
722
723
Note: In REPL mode no file is loaded, so commands specified to run after
724
loading the file (via -o or -s) will be ignored.)___";
725
llvm::outs() << examples << '\n';
726
}
727
728
int main(int argc, char const *argv[]) {
729
// Editline uses for example iswprint which is dependent on LC_CTYPE.
730
std::setlocale(LC_ALL, "");
731
std::setlocale(LC_CTYPE, "");
732
733
// Setup LLVM signal handlers and make sure we call llvm_shutdown() on
734
// destruction.
735
llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
736
#if !defined(__APPLE__)
737
llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
738
" and include the crash backtrace.\n");
739
#else
740
llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL
741
" and include the crash report from "
742
"~/Library/Logs/DiagnosticReports/.\n");
743
#endif
744
745
// Parse arguments.
746
LLDBOptTable T;
747
unsigned MissingArgIndex;
748
unsigned MissingArgCount;
749
ArrayRef<const char *> arg_arr = ArrayRef(argv + 1, argc - 1);
750
opt::InputArgList input_args =
751
T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
752
llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
753
754
if (input_args.hasArg(OPT_help)) {
755
printHelp(T, argv0);
756
return 0;
757
}
758
759
// Check for missing argument error.
760
if (MissingArgCount) {
761
WithColor::error() << "argument to '"
762
<< input_args.getArgString(MissingArgIndex)
763
<< "' is missing\n";
764
}
765
// Error out on unknown options.
766
if (input_args.hasArg(OPT_UNKNOWN)) {
767
for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
768
WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
769
}
770
}
771
if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {
772
llvm::errs() << "Use '" << argv0
773
<< " --help' for a complete list of options.\n";
774
return 1;
775
}
776
777
SBError error = SBDebugger::InitializeWithErrorHandling();
778
if (error.Fail()) {
779
WithColor::error() << "initialization failed: " << error.GetCString()
780
<< '\n';
781
return 1;
782
}
783
784
// Setup LLDB signal handlers once the debugger has been initialized.
785
SBDebugger::PrintDiagnosticsOnError();
786
787
signal(SIGINT, sigint_handler);
788
#if !defined(_WIN32)
789
signal(SIGPIPE, SIG_IGN);
790
signal(SIGWINCH, sigwinch_handler);
791
signal(SIGTSTP, sigtstp_handler);
792
#endif
793
794
int exit_code = 0;
795
// Create a scope for driver so that the driver object will destroy itself
796
// before SBDebugger::Terminate() is called.
797
{
798
Driver driver;
799
800
bool exiting = false;
801
SBError error(driver.ProcessArgs(input_args, exiting));
802
if (error.Fail()) {
803
exit_code = 1;
804
if (const char *error_cstr = error.GetCString())
805
WithColor::error() << error_cstr << '\n';
806
} else if (!exiting) {
807
exit_code = driver.MainLoop();
808
}
809
}
810
811
// When terminating the debugger we have to wait on all the background tasks
812
// to complete, which can take a while. Print a message when this takes longer
813
// than 1 second.
814
{
815
std::future<void> future =
816
std::async(std::launch::async, []() { SBDebugger::Terminate(); });
817
818
if (future.wait_for(std::chrono::seconds(1)) == std::future_status::timeout)
819
fprintf(stderr, "Waiting for background tasks to complete...\n");
820
821
future.wait();
822
}
823
824
return exit_code;
825
}
826
827