1061da546Spatrick //===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "Driver.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/API/SBCommandInterpreter.h"
12dda28197Spatrick #include "lldb/API/SBCommandInterpreterRunOptions.h"
13061da546Spatrick #include "lldb/API/SBCommandReturnObject.h"
14061da546Spatrick #include "lldb/API/SBDebugger.h"
15061da546Spatrick #include "lldb/API/SBFile.h"
16061da546Spatrick #include "lldb/API/SBHostOS.h"
17061da546Spatrick #include "lldb/API/SBLanguageRuntime.h"
18061da546Spatrick #include "lldb/API/SBStream.h"
19061da546Spatrick #include "lldb/API/SBStringList.h"
20*101d251dSrobert #include "lldb/API/SBStructuredData.h"
21061da546Spatrick
22061da546Spatrick #include "llvm/ADT/StringRef.h"
23061da546Spatrick #include "llvm/Support/Format.h"
24061da546Spatrick #include "llvm/Support/InitLLVM.h"
25061da546Spatrick #include "llvm/Support/Path.h"
26061da546Spatrick #include "llvm/Support/Signals.h"
27061da546Spatrick #include "llvm/Support/WithColor.h"
28061da546Spatrick #include "llvm/Support/raw_ostream.h"
29061da546Spatrick
30061da546Spatrick #include <algorithm>
31061da546Spatrick #include <atomic>
32061da546Spatrick #include <bitset>
33a0747c9fSpatrick #include <clocale>
34061da546Spatrick #include <csignal>
35061da546Spatrick #include <string>
36061da546Spatrick #include <thread>
37061da546Spatrick #include <utility>
38061da546Spatrick
39a0747c9fSpatrick #include <climits>
40a0747c9fSpatrick #include <cstdio>
41a0747c9fSpatrick #include <cstdlib>
42a0747c9fSpatrick #include <cstring>
43061da546Spatrick #include <fcntl.h>
44061da546Spatrick
45061da546Spatrick #if !defined(__APPLE__)
46061da546Spatrick #include "llvm/Support/DataTypes.h"
47061da546Spatrick #endif
48061da546Spatrick
49061da546Spatrick using namespace lldb;
50061da546Spatrick using namespace llvm;
51061da546Spatrick
52061da546Spatrick namespace {
53061da546Spatrick enum ID {
54061da546Spatrick OPT_INVALID = 0, // This is not an option ID.
55061da546Spatrick #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
56061da546Spatrick HELPTEXT, METAVAR, VALUES) \
57061da546Spatrick OPT_##ID,
58061da546Spatrick #include "Options.inc"
59061da546Spatrick #undef OPTION
60061da546Spatrick };
61061da546Spatrick
62*101d251dSrobert #define PREFIX(NAME, VALUE) \
63*101d251dSrobert static constexpr StringLiteral NAME##_init[] = VALUE; \
64*101d251dSrobert static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
65*101d251dSrobert std::size(NAME##_init) - 1);
66061da546Spatrick #include "Options.inc"
67061da546Spatrick #undef PREFIX
68061da546Spatrick
69*101d251dSrobert static constexpr opt::OptTable::Info InfoTable[] = {
70061da546Spatrick #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
71061da546Spatrick HELPTEXT, METAVAR, VALUES) \
72061da546Spatrick { \
73061da546Spatrick PREFIX, NAME, HELPTEXT, \
74061da546Spatrick METAVAR, OPT_##ID, opt::Option::KIND##Class, \
75061da546Spatrick PARAM, FLAGS, OPT_##GROUP, \
76061da546Spatrick OPT_##ALIAS, ALIASARGS, VALUES},
77061da546Spatrick #include "Options.inc"
78061da546Spatrick #undef OPTION
79061da546Spatrick };
80061da546Spatrick
81*101d251dSrobert class LLDBOptTable : public opt::GenericOptTable {
82061da546Spatrick public:
LLDBOptTable()83*101d251dSrobert LLDBOptTable() : opt::GenericOptTable(InfoTable) {}
84061da546Spatrick };
85061da546Spatrick } // namespace
86061da546Spatrick
87061da546Spatrick static void reset_stdin_termios();
88061da546Spatrick static bool g_old_stdin_termios_is_valid = false;
89061da546Spatrick static struct termios g_old_stdin_termios;
90061da546Spatrick
disable_color(const raw_ostream & OS)91*101d251dSrobert static bool disable_color(const raw_ostream &OS) { return false; }
92*101d251dSrobert
93061da546Spatrick static Driver *g_driver = nullptr;
94061da546Spatrick
95061da546Spatrick // In the Driver::MainLoop, we change the terminal settings. This function is
96061da546Spatrick // added as an atexit handler to make sure we clean them up.
reset_stdin_termios()97061da546Spatrick static void reset_stdin_termios() {
98061da546Spatrick if (g_old_stdin_termios_is_valid) {
99061da546Spatrick g_old_stdin_termios_is_valid = false;
100061da546Spatrick ::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
101061da546Spatrick }
102061da546Spatrick }
103061da546Spatrick
Driver()104061da546Spatrick Driver::Driver()
105061da546Spatrick : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {
106061da546Spatrick // We want to be able to handle CTRL+D in the terminal to have it terminate
107061da546Spatrick // certain input
108061da546Spatrick m_debugger.SetCloseInputOnEOF(false);
109061da546Spatrick g_driver = this;
110061da546Spatrick }
111061da546Spatrick
~Driver()112a0747c9fSpatrick Driver::~Driver() {
113a0747c9fSpatrick SBDebugger::Destroy(m_debugger);
114a0747c9fSpatrick g_driver = nullptr;
115a0747c9fSpatrick }
116061da546Spatrick
AddInitialCommand(std::string command,CommandPlacement placement,bool is_file,SBError & error)117061da546Spatrick void Driver::OptionData::AddInitialCommand(std::string command,
118061da546Spatrick CommandPlacement placement,
119061da546Spatrick bool is_file, SBError &error) {
120061da546Spatrick std::vector<InitialCmdEntry> *command_set;
121061da546Spatrick switch (placement) {
122061da546Spatrick case eCommandPlacementBeforeFile:
123061da546Spatrick command_set = &(m_initial_commands);
124061da546Spatrick break;
125061da546Spatrick case eCommandPlacementAfterFile:
126061da546Spatrick command_set = &(m_after_file_commands);
127061da546Spatrick break;
128061da546Spatrick case eCommandPlacementAfterCrash:
129061da546Spatrick command_set = &(m_after_crash_commands);
130061da546Spatrick break;
131061da546Spatrick }
132061da546Spatrick
133061da546Spatrick if (is_file) {
134061da546Spatrick SBFileSpec file(command.c_str());
135061da546Spatrick if (file.Exists())
136061da546Spatrick command_set->push_back(InitialCmdEntry(command, is_file));
137061da546Spatrick else if (file.ResolveExecutableLocation()) {
138061da546Spatrick char final_path[PATH_MAX];
139061da546Spatrick file.GetPath(final_path, sizeof(final_path));
140061da546Spatrick command_set->push_back(InitialCmdEntry(final_path, is_file));
141061da546Spatrick } else
142061da546Spatrick error.SetErrorStringWithFormat(
143061da546Spatrick "file specified in --source (-s) option doesn't exist: '%s'",
144061da546Spatrick command.c_str());
145061da546Spatrick } else
146061da546Spatrick command_set->push_back(InitialCmdEntry(command, is_file));
147061da546Spatrick }
148061da546Spatrick
WriteCommandsForSourcing(CommandPlacement placement,SBStream & strm)149061da546Spatrick void Driver::WriteCommandsForSourcing(CommandPlacement placement,
150061da546Spatrick SBStream &strm) {
151061da546Spatrick std::vector<OptionData::InitialCmdEntry> *command_set;
152061da546Spatrick switch (placement) {
153061da546Spatrick case eCommandPlacementBeforeFile:
154061da546Spatrick command_set = &m_option_data.m_initial_commands;
155061da546Spatrick break;
156061da546Spatrick case eCommandPlacementAfterFile:
157061da546Spatrick command_set = &m_option_data.m_after_file_commands;
158061da546Spatrick break;
159061da546Spatrick case eCommandPlacementAfterCrash:
160061da546Spatrick command_set = &m_option_data.m_after_crash_commands;
161061da546Spatrick break;
162061da546Spatrick }
163061da546Spatrick
164061da546Spatrick for (const auto &command_entry : *command_set) {
165061da546Spatrick const char *command = command_entry.contents.c_str();
166061da546Spatrick if (command_entry.is_file) {
167061da546Spatrick bool source_quietly =
168061da546Spatrick m_option_data.m_source_quietly || command_entry.source_quietly;
169061da546Spatrick strm.Printf("command source -s %i '%s'\n",
170061da546Spatrick static_cast<int>(source_quietly), command);
171061da546Spatrick } else
172061da546Spatrick strm.Printf("%s\n", command);
173061da546Spatrick }
174061da546Spatrick }
175061da546Spatrick
176061da546Spatrick // Check the arguments that were passed to this program to make sure they are
177061da546Spatrick // valid and to get their argument values (if any). Return a boolean value
178061da546Spatrick // indicating whether or not to start up the full debugger (i.e. the Command
179061da546Spatrick // Interpreter) or not. Return FALSE if the arguments were invalid OR if the
180061da546Spatrick // user only wanted help or version information.
ProcessArgs(const opt::InputArgList & args,bool & exiting)181061da546Spatrick SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
182061da546Spatrick SBError error;
183061da546Spatrick
184061da546Spatrick // This is kind of a pain, but since we make the debugger in the Driver's
185061da546Spatrick // constructor, we can't know at that point whether we should read in init
186061da546Spatrick // files yet. So we don't read them in in the Driver constructor, then set
187061da546Spatrick // the flags back to "read them in" here, and then if we see the "-n" flag,
188061da546Spatrick // we'll turn it off again. Finally we have to read them in by hand later in
189061da546Spatrick // the main loop.
190061da546Spatrick m_debugger.SkipLLDBInitFiles(false);
191061da546Spatrick m_debugger.SkipAppInitFiles(false);
192061da546Spatrick
193*101d251dSrobert if (args.hasArg(OPT_no_use_colors)) {
194*101d251dSrobert m_debugger.SetUseColor(false);
195*101d251dSrobert WithColor::setAutoDetectFunction(disable_color);
196*101d251dSrobert m_option_data.m_debug_mode = true;
197*101d251dSrobert }
198*101d251dSrobert
199061da546Spatrick if (args.hasArg(OPT_version)) {
200061da546Spatrick m_option_data.m_print_version = true;
201061da546Spatrick }
202061da546Spatrick
203061da546Spatrick if (args.hasArg(OPT_python_path)) {
204061da546Spatrick m_option_data.m_print_python_path = true;
205061da546Spatrick }
206*101d251dSrobert if (args.hasArg(OPT_print_script_interpreter_info)) {
207*101d251dSrobert m_option_data.m_print_script_interpreter_info = true;
208*101d251dSrobert }
209061da546Spatrick
210061da546Spatrick if (args.hasArg(OPT_batch)) {
211061da546Spatrick m_option_data.m_batch = true;
212061da546Spatrick }
213061da546Spatrick
214061da546Spatrick if (auto *arg = args.getLastArg(OPT_core)) {
215061da546Spatrick auto arg_value = arg->getValue();
216061da546Spatrick SBFileSpec file(arg_value);
217061da546Spatrick if (!file.Exists()) {
218061da546Spatrick error.SetErrorStringWithFormat(
219061da546Spatrick "file specified in --core (-c) option doesn't exist: '%s'",
220061da546Spatrick arg_value);
221061da546Spatrick return error;
222061da546Spatrick }
223061da546Spatrick m_option_data.m_core_file = arg_value;
224061da546Spatrick }
225061da546Spatrick
226061da546Spatrick if (args.hasArg(OPT_editor)) {
227061da546Spatrick m_option_data.m_use_external_editor = true;
228061da546Spatrick }
229061da546Spatrick
230061da546Spatrick if (args.hasArg(OPT_no_lldbinit)) {
231061da546Spatrick m_debugger.SkipLLDBInitFiles(true);
232061da546Spatrick m_debugger.SkipAppInitFiles(true);
233061da546Spatrick }
234061da546Spatrick
235061da546Spatrick if (args.hasArg(OPT_local_lldbinit)) {
236061da546Spatrick lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
237061da546Spatrick m_debugger.GetInstanceName());
238061da546Spatrick }
239061da546Spatrick
240061da546Spatrick if (auto *arg = args.getLastArg(OPT_file)) {
241061da546Spatrick auto arg_value = arg->getValue();
242061da546Spatrick SBFileSpec file(arg_value);
243061da546Spatrick if (file.Exists()) {
244061da546Spatrick m_option_data.m_args.emplace_back(arg_value);
245061da546Spatrick } else if (file.ResolveExecutableLocation()) {
246061da546Spatrick char path[PATH_MAX];
247061da546Spatrick file.GetPath(path, sizeof(path));
248061da546Spatrick m_option_data.m_args.emplace_back(path);
249061da546Spatrick } else {
250061da546Spatrick error.SetErrorStringWithFormat(
251061da546Spatrick "file specified in --file (-f) option doesn't exist: '%s'",
252061da546Spatrick arg_value);
253061da546Spatrick return error;
254061da546Spatrick }
255061da546Spatrick }
256061da546Spatrick
257061da546Spatrick if (auto *arg = args.getLastArg(OPT_arch)) {
258061da546Spatrick auto arg_value = arg->getValue();
259061da546Spatrick if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
260061da546Spatrick error.SetErrorStringWithFormat(
261061da546Spatrick "invalid architecture in the -a or --arch option: '%s'", arg_value);
262061da546Spatrick return error;
263061da546Spatrick }
264061da546Spatrick }
265061da546Spatrick
266061da546Spatrick if (auto *arg = args.getLastArg(OPT_script_language)) {
267061da546Spatrick auto arg_value = arg->getValue();
268061da546Spatrick m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
269061da546Spatrick }
270061da546Spatrick
271061da546Spatrick if (args.hasArg(OPT_source_quietly)) {
272061da546Spatrick m_option_data.m_source_quietly = true;
273061da546Spatrick }
274061da546Spatrick
275061da546Spatrick if (auto *arg = args.getLastArg(OPT_attach_name)) {
276061da546Spatrick auto arg_value = arg->getValue();
277061da546Spatrick m_option_data.m_process_name = arg_value;
278061da546Spatrick }
279061da546Spatrick
280061da546Spatrick if (args.hasArg(OPT_wait_for)) {
281061da546Spatrick m_option_data.m_wait_for = true;
282061da546Spatrick }
283061da546Spatrick
284061da546Spatrick if (auto *arg = args.getLastArg(OPT_attach_pid)) {
285061da546Spatrick auto arg_value = arg->getValue();
286061da546Spatrick char *remainder;
287061da546Spatrick m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
288061da546Spatrick if (remainder == arg_value || *remainder != '\0') {
289061da546Spatrick error.SetErrorStringWithFormat(
290061da546Spatrick "Could not convert process PID: \"%s\" into a pid.", arg_value);
291061da546Spatrick return error;
292061da546Spatrick }
293061da546Spatrick }
294061da546Spatrick
295061da546Spatrick if (auto *arg = args.getLastArg(OPT_repl_language)) {
296061da546Spatrick auto arg_value = arg->getValue();
297061da546Spatrick m_option_data.m_repl_lang =
298061da546Spatrick SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
299061da546Spatrick if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
300061da546Spatrick error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
301061da546Spatrick arg_value);
302061da546Spatrick return error;
303061da546Spatrick }
304*101d251dSrobert m_debugger.SetREPLLanguage(m_option_data.m_repl_lang);
305061da546Spatrick }
306061da546Spatrick
307061da546Spatrick if (args.hasArg(OPT_repl)) {
308061da546Spatrick m_option_data.m_repl = true;
309061da546Spatrick }
310061da546Spatrick
311061da546Spatrick if (auto *arg = args.getLastArg(OPT_repl_)) {
312061da546Spatrick m_option_data.m_repl = true;
313061da546Spatrick if (auto arg_value = arg->getValue())
314061da546Spatrick m_option_data.m_repl_options = arg_value;
315061da546Spatrick }
316061da546Spatrick
317061da546Spatrick // We need to process the options below together as their relative order
318061da546Spatrick // matters.
319061da546Spatrick for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
320061da546Spatrick OPT_source, OPT_source_before_file,
321061da546Spatrick OPT_one_line, OPT_one_line_before_file)) {
322061da546Spatrick auto arg_value = arg->getValue();
323061da546Spatrick if (arg->getOption().matches(OPT_source_on_crash)) {
324061da546Spatrick m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
325061da546Spatrick true, error);
326061da546Spatrick if (error.Fail())
327061da546Spatrick return error;
328061da546Spatrick }
329061da546Spatrick
330061da546Spatrick if (arg->getOption().matches(OPT_one_line_on_crash)) {
331061da546Spatrick m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
332061da546Spatrick false, error);
333061da546Spatrick if (error.Fail())
334061da546Spatrick return error;
335061da546Spatrick }
336061da546Spatrick
337061da546Spatrick if (arg->getOption().matches(OPT_source)) {
338061da546Spatrick m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
339061da546Spatrick true, error);
340061da546Spatrick if (error.Fail())
341061da546Spatrick return error;
342061da546Spatrick }
343061da546Spatrick
344061da546Spatrick if (arg->getOption().matches(OPT_source_before_file)) {
345061da546Spatrick m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
346061da546Spatrick true, error);
347061da546Spatrick if (error.Fail())
348061da546Spatrick return error;
349061da546Spatrick }
350061da546Spatrick
351061da546Spatrick if (arg->getOption().matches(OPT_one_line)) {
352061da546Spatrick m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
353061da546Spatrick false, error);
354061da546Spatrick if (error.Fail())
355061da546Spatrick return error;
356061da546Spatrick }
357061da546Spatrick
358061da546Spatrick if (arg->getOption().matches(OPT_one_line_before_file)) {
359061da546Spatrick m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
360061da546Spatrick false, error);
361061da546Spatrick if (error.Fail())
362061da546Spatrick return error;
363061da546Spatrick }
364061da546Spatrick }
365061da546Spatrick
366061da546Spatrick if (m_option_data.m_process_name.empty() &&
367061da546Spatrick m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
368061da546Spatrick
369dda28197Spatrick for (auto *arg : args.filtered(OPT_INPUT))
370061da546Spatrick m_option_data.m_args.push_back(arg->getAsString((args)));
371061da546Spatrick
372061da546Spatrick // Any argument following -- is an argument for the inferior.
373061da546Spatrick if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
374061da546Spatrick for (auto value : arg->getValues())
375061da546Spatrick m_option_data.m_args.emplace_back(value);
376061da546Spatrick }
377061da546Spatrick } else if (args.getLastArgNoClaim() != nullptr) {
378061da546Spatrick WithColor::warning() << "program arguments are ignored when attaching.\n";
379061da546Spatrick }
380061da546Spatrick
381061da546Spatrick if (m_option_data.m_print_version) {
382061da546Spatrick llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
383061da546Spatrick exiting = true;
384061da546Spatrick return error;
385061da546Spatrick }
386061da546Spatrick
387061da546Spatrick if (m_option_data.m_print_python_path) {
388061da546Spatrick SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
389061da546Spatrick if (python_file_spec.IsValid()) {
390061da546Spatrick char python_path[PATH_MAX];
391061da546Spatrick size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
392061da546Spatrick if (num_chars < PATH_MAX) {
393061da546Spatrick llvm::outs() << python_path << '\n';
394061da546Spatrick } else
395061da546Spatrick llvm::outs() << "<PATH TOO LONG>\n";
396061da546Spatrick } else
397061da546Spatrick llvm::outs() << "<COULD NOT FIND PATH>\n";
398061da546Spatrick exiting = true;
399061da546Spatrick return error;
400061da546Spatrick }
401061da546Spatrick
402*101d251dSrobert if (m_option_data.m_print_script_interpreter_info) {
403*101d251dSrobert SBStructuredData info =
404*101d251dSrobert m_debugger.GetScriptInterpreterInfo(m_debugger.GetScriptLanguage());
405*101d251dSrobert if (!info) {
406*101d251dSrobert error.SetErrorString("no script interpreter.");
407*101d251dSrobert } else {
408*101d251dSrobert SBStream stream;
409*101d251dSrobert error = info.GetAsJSON(stream);
410*101d251dSrobert if (error.Success()) {
411*101d251dSrobert llvm::outs() << stream.GetData() << '\n';
412*101d251dSrobert }
413*101d251dSrobert }
414*101d251dSrobert exiting = true;
415061da546Spatrick return error;
416061da546Spatrick }
417061da546Spatrick
418*101d251dSrobert return error;
419061da546Spatrick }
420061da546Spatrick
EscapeString(std::string arg)421061da546Spatrick std::string EscapeString(std::string arg) {
422061da546Spatrick std::string::size_type pos = 0;
423061da546Spatrick while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
424061da546Spatrick arg.insert(pos, 1, '\\');
425061da546Spatrick pos += 2;
426061da546Spatrick }
427061da546Spatrick return '"' + arg + '"';
428061da546Spatrick }
429061da546Spatrick
MainLoop()430061da546Spatrick int Driver::MainLoop() {
431061da546Spatrick if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
432061da546Spatrick g_old_stdin_termios_is_valid = true;
433061da546Spatrick atexit(reset_stdin_termios);
434061da546Spatrick }
435061da546Spatrick
436061da546Spatrick #ifndef _MSC_VER
437061da546Spatrick // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
438061da546Spatrick // which causes it to miss newlines depending on whether there have been an
439061da546Spatrick // odd or even number of characters. Bug has been reported to MS via Connect.
440061da546Spatrick ::setbuf(stdin, nullptr);
441061da546Spatrick #endif
442061da546Spatrick ::setbuf(stdout, nullptr);
443061da546Spatrick
444061da546Spatrick m_debugger.SetErrorFileHandle(stderr, false);
445061da546Spatrick m_debugger.SetOutputFileHandle(stdout, false);
446061da546Spatrick // Don't take ownership of STDIN yet...
447061da546Spatrick m_debugger.SetInputFileHandle(stdin, false);
448061da546Spatrick
449061da546Spatrick m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
450061da546Spatrick
451061da546Spatrick struct winsize window_size;
452061da546Spatrick if ((isatty(STDIN_FILENO) != 0) &&
453061da546Spatrick ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
454061da546Spatrick if (window_size.ws_col > 0)
455061da546Spatrick m_debugger.SetTerminalWidth(window_size.ws_col);
456061da546Spatrick }
457061da546Spatrick
458061da546Spatrick SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
459061da546Spatrick
460*101d251dSrobert // Process lldbinit files before handling any options from the command line.
461061da546Spatrick SBCommandReturnObject result;
462*101d251dSrobert sb_interpreter.SourceInitFileInGlobalDirectory(result);
463*101d251dSrobert if (m_option_data.m_debug_mode) {
464*101d251dSrobert result.PutError(m_debugger.GetErrorFile());
465*101d251dSrobert result.PutOutput(m_debugger.GetOutputFile());
466*101d251dSrobert }
467*101d251dSrobert
468a0747c9fSpatrick sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
469061da546Spatrick if (m_option_data.m_debug_mode) {
470061da546Spatrick result.PutError(m_debugger.GetErrorFile());
471061da546Spatrick result.PutOutput(m_debugger.GetOutputFile());
472061da546Spatrick }
473061da546Spatrick
474061da546Spatrick // Source the local .lldbinit file if it exists and we're allowed to source.
475061da546Spatrick // Here we want to always print the return object because it contains the
476061da546Spatrick // warning and instructions to load local lldbinit files.
477061da546Spatrick sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
478061da546Spatrick result.PutError(m_debugger.GetErrorFile());
479061da546Spatrick result.PutOutput(m_debugger.GetOutputFile());
480061da546Spatrick
481061da546Spatrick // We allow the user to specify an exit code when calling quit which we will
482061da546Spatrick // return when exiting.
483061da546Spatrick m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
484061da546Spatrick
485061da546Spatrick // Now we handle options we got from the command line
486061da546Spatrick SBStream commands_stream;
487061da546Spatrick
488061da546Spatrick // First source in the commands specified to be run before the file arguments
489061da546Spatrick // are processed.
490061da546Spatrick WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
491061da546Spatrick
492061da546Spatrick // If we're not in --repl mode, add the commands to process the file
493061da546Spatrick // arguments, and the commands specified to run afterwards.
494061da546Spatrick if (!m_option_data.m_repl) {
495061da546Spatrick const size_t num_args = m_option_data.m_args.size();
496061da546Spatrick if (num_args > 0) {
497061da546Spatrick char arch_name[64];
498061da546Spatrick if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
499061da546Spatrick sizeof(arch_name)))
500061da546Spatrick commands_stream.Printf("target create --arch=%s %s", arch_name,
501061da546Spatrick EscapeString(m_option_data.m_args[0]).c_str());
502061da546Spatrick else
503061da546Spatrick commands_stream.Printf("target create %s",
504061da546Spatrick EscapeString(m_option_data.m_args[0]).c_str());
505061da546Spatrick
506061da546Spatrick if (!m_option_data.m_core_file.empty()) {
507061da546Spatrick commands_stream.Printf(" --core %s",
508061da546Spatrick EscapeString(m_option_data.m_core_file).c_str());
509061da546Spatrick }
510061da546Spatrick commands_stream.Printf("\n");
511061da546Spatrick
512061da546Spatrick if (num_args > 1) {
513061da546Spatrick commands_stream.Printf("settings set -- target.run-args ");
514061da546Spatrick for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
515061da546Spatrick commands_stream.Printf(
516061da546Spatrick " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
517061da546Spatrick commands_stream.Printf("\n");
518061da546Spatrick }
519061da546Spatrick } else if (!m_option_data.m_core_file.empty()) {
520061da546Spatrick commands_stream.Printf("target create --core %s\n",
521061da546Spatrick EscapeString(m_option_data.m_core_file).c_str());
522061da546Spatrick } else if (!m_option_data.m_process_name.empty()) {
523061da546Spatrick commands_stream.Printf(
524061da546Spatrick "process attach --name %s",
525061da546Spatrick EscapeString(m_option_data.m_process_name).c_str());
526061da546Spatrick
527061da546Spatrick if (m_option_data.m_wait_for)
528061da546Spatrick commands_stream.Printf(" --waitfor");
529061da546Spatrick
530061da546Spatrick commands_stream.Printf("\n");
531061da546Spatrick
532061da546Spatrick } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
533061da546Spatrick commands_stream.Printf("process attach --pid %" PRIu64 "\n",
534061da546Spatrick m_option_data.m_process_pid);
535061da546Spatrick }
536061da546Spatrick
537061da546Spatrick WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
538061da546Spatrick } else if (!m_option_data.m_after_file_commands.empty()) {
539061da546Spatrick // We're in repl mode and after-file-load commands were specified.
540061da546Spatrick WithColor::warning() << "commands specified to run after file load (via -o "
541061da546Spatrick "or -s) are ignored in REPL mode.\n";
542061da546Spatrick }
543061da546Spatrick
544061da546Spatrick if (m_option_data.m_debug_mode) {
545061da546Spatrick result.PutError(m_debugger.GetErrorFile());
546061da546Spatrick result.PutOutput(m_debugger.GetOutputFile());
547061da546Spatrick }
548061da546Spatrick
549061da546Spatrick const bool handle_events = true;
550061da546Spatrick const bool spawn_thread = false;
551061da546Spatrick
552061da546Spatrick // Check if we have any data in the commands stream, and if so, save it to a
553061da546Spatrick // temp file
554061da546Spatrick // so we can then run the command interpreter using the file contents.
555dda28197Spatrick bool go_interactive = true;
556*101d251dSrobert if ((commands_stream.GetData() != nullptr) &&
557*101d251dSrobert (commands_stream.GetSize() != 0u)) {
558*101d251dSrobert SBError error = m_debugger.SetInputString(commands_stream.GetData());
559*101d251dSrobert if (error.Fail()) {
560*101d251dSrobert WithColor::error() << error.GetCString() << '\n';
561a0747c9fSpatrick return 1;
562dda28197Spatrick }
563dda28197Spatrick
564dda28197Spatrick // Set the debugger into Sync mode when running the command file. Otherwise
565dda28197Spatrick // command files that run the target won't run in a sensible way.
566061da546Spatrick bool old_async = m_debugger.GetAsync();
567061da546Spatrick m_debugger.SetAsync(false);
568061da546Spatrick
569061da546Spatrick SBCommandInterpreterRunOptions options;
570dda28197Spatrick options.SetAutoHandleEvents(true);
571dda28197Spatrick options.SetSpawnThread(false);
572061da546Spatrick options.SetStopOnError(true);
573dda28197Spatrick options.SetStopOnCrash(m_option_data.m_batch);
574*101d251dSrobert options.SetEchoCommands(!m_option_data.m_source_quietly);
575061da546Spatrick
576dda28197Spatrick SBCommandInterpreterRunResult results =
577dda28197Spatrick m_debugger.RunCommandInterpreter(options);
578dda28197Spatrick if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
579dda28197Spatrick go_interactive = false;
580dda28197Spatrick if (m_option_data.m_batch &&
581dda28197Spatrick results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
582dda28197Spatrick go_interactive = false;
583061da546Spatrick
584dda28197Spatrick // When running in batch mode and stopped because of an error, exit with a
585dda28197Spatrick // non-zero exit status.
586dda28197Spatrick if (m_option_data.m_batch &&
587dda28197Spatrick results.GetResult() == lldb::eCommandInterpreterResultCommandError)
588a0747c9fSpatrick return 1;
589dda28197Spatrick
590dda28197Spatrick if (m_option_data.m_batch &&
591dda28197Spatrick results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
592061da546Spatrick !m_option_data.m_after_crash_commands.empty()) {
593061da546Spatrick SBStream crash_commands_stream;
594061da546Spatrick WriteCommandsForSourcing(eCommandPlacementAfterCrash,
595061da546Spatrick crash_commands_stream);
596*101d251dSrobert SBError error =
597*101d251dSrobert m_debugger.SetInputString(crash_commands_stream.GetData());
598*101d251dSrobert if (error.Success()) {
599dda28197Spatrick SBCommandInterpreterRunResult local_results =
600dda28197Spatrick m_debugger.RunCommandInterpreter(options);
601dda28197Spatrick if (local_results.GetResult() ==
602dda28197Spatrick lldb::eCommandInterpreterResultQuitRequested)
603dda28197Spatrick go_interactive = false;
604061da546Spatrick
605dda28197Spatrick // When running in batch mode and an error occurred while sourcing
606dda28197Spatrick // the crash commands, exit with a non-zero exit status.
607dda28197Spatrick if (m_option_data.m_batch &&
608dda28197Spatrick local_results.GetResult() ==
609dda28197Spatrick lldb::eCommandInterpreterResultCommandError)
610a0747c9fSpatrick return 1;
611061da546Spatrick }
612061da546Spatrick }
613dda28197Spatrick m_debugger.SetAsync(old_async);
614dda28197Spatrick }
615061da546Spatrick
616dda28197Spatrick // Now set the input file handle to STDIN and run the command interpreter
617dda28197Spatrick // again in interactive mode or repl mode and let the debugger take ownership
618dda28197Spatrick // of stdin.
619061da546Spatrick if (go_interactive) {
620061da546Spatrick m_debugger.SetInputFileHandle(stdin, true);
621061da546Spatrick
622061da546Spatrick if (m_option_data.m_repl) {
623061da546Spatrick const char *repl_options = nullptr;
624061da546Spatrick if (!m_option_data.m_repl_options.empty())
625061da546Spatrick repl_options = m_option_data.m_repl_options.c_str();
626061da546Spatrick SBError error(
627061da546Spatrick m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
628061da546Spatrick if (error.Fail()) {
629061da546Spatrick const char *error_cstr = error.GetCString();
630061da546Spatrick if ((error_cstr != nullptr) && (error_cstr[0] != 0))
631061da546Spatrick WithColor::error() << error_cstr << '\n';
632061da546Spatrick else
633061da546Spatrick WithColor::error() << error.GetError() << '\n';
634061da546Spatrick }
635061da546Spatrick } else {
636061da546Spatrick m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
637061da546Spatrick }
638061da546Spatrick }
639061da546Spatrick
640061da546Spatrick reset_stdin_termios();
641061da546Spatrick fclose(stdin);
642061da546Spatrick
643a0747c9fSpatrick return sb_interpreter.GetQuitStatus();
644061da546Spatrick }
645061da546Spatrick
ResizeWindow(unsigned short col)646061da546Spatrick void Driver::ResizeWindow(unsigned short col) {
647061da546Spatrick GetDebugger().SetTerminalWidth(col);
648061da546Spatrick }
649061da546Spatrick
sigwinch_handler(int signo)650061da546Spatrick void sigwinch_handler(int signo) {
651061da546Spatrick struct winsize window_size;
652061da546Spatrick if ((isatty(STDIN_FILENO) != 0) &&
653061da546Spatrick ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
654061da546Spatrick if ((window_size.ws_col > 0) && g_driver != nullptr) {
655061da546Spatrick g_driver->ResizeWindow(window_size.ws_col);
656061da546Spatrick }
657061da546Spatrick }
658061da546Spatrick }
659061da546Spatrick
sigint_handler(int signo)660061da546Spatrick void sigint_handler(int signo) {
661061da546Spatrick #ifdef _WIN32 // Restore handler as it is not persistent on Windows
662061da546Spatrick signal(SIGINT, sigint_handler);
663061da546Spatrick #endif
664061da546Spatrick static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
665061da546Spatrick if (g_driver != nullptr) {
666061da546Spatrick if (!g_interrupt_sent.test_and_set()) {
667061da546Spatrick g_driver->GetDebugger().DispatchInputInterrupt();
668061da546Spatrick g_interrupt_sent.clear();
669061da546Spatrick return;
670061da546Spatrick }
671061da546Spatrick }
672061da546Spatrick
673061da546Spatrick _exit(signo);
674061da546Spatrick }
675061da546Spatrick
676*101d251dSrobert #ifndef _WIN32
sigtstp_handler(int signo)677*101d251dSrobert static void sigtstp_handler(int signo) {
678061da546Spatrick if (g_driver != nullptr)
679061da546Spatrick g_driver->GetDebugger().SaveInputTerminalState();
680061da546Spatrick
681*101d251dSrobert // Unblock the signal and remove our handler.
682*101d251dSrobert sigset_t set;
683*101d251dSrobert sigemptyset(&set);
684*101d251dSrobert sigaddset(&set, signo);
685*101d251dSrobert pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
686061da546Spatrick signal(signo, SIG_DFL);
687061da546Spatrick
688*101d251dSrobert // Now re-raise the signal. We will immediately suspend...
689*101d251dSrobert raise(signo);
690*101d251dSrobert // ... and resume after a SIGCONT.
691*101d251dSrobert
692*101d251dSrobert // Now undo the modifications.
693*101d251dSrobert pthread_sigmask(SIG_BLOCK, &set, nullptr);
694*101d251dSrobert signal(signo, sigtstp_handler);
695*101d251dSrobert
696061da546Spatrick if (g_driver != nullptr)
697061da546Spatrick g_driver->GetDebugger().RestoreInputTerminalState();
698061da546Spatrick }
699*101d251dSrobert #endif
700061da546Spatrick
printHelp(LLDBOptTable & table,llvm::StringRef tool_name)701061da546Spatrick static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
702061da546Spatrick std::string usage_str = tool_name.str() + " [options]";
703a0747c9fSpatrick table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
704061da546Spatrick
705061da546Spatrick std::string examples = R"___(
706061da546Spatrick EXAMPLES:
707061da546Spatrick The debugger can be started in several modes.
708061da546Spatrick
709061da546Spatrick Passing an executable as a positional argument prepares lldb to debug the
710dda28197Spatrick given executable. To disambiguate between arguments passed to lldb and
711dda28197Spatrick arguments passed to the debugged executable, arguments starting with a - must
712dda28197Spatrick be passed after --.
713061da546Spatrick
714b3094f69Sjsg lldb --arch x86_64 /path/to/program program argument -- --arch armv7
715dda28197Spatrick
716dda28197Spatrick For convenience, passing the executable after -- is also supported.
717dda28197Spatrick
718b3094f69Sjsg lldb --arch x86_64 -- /path/to/program program argument --arch armv7
719061da546Spatrick
720061da546Spatrick Passing one of the attach options causes lldb to immediately attach to the
721061da546Spatrick given process.
722061da546Spatrick
723061da546Spatrick lldb -p <pid>
724061da546Spatrick lldb -n <process-name>
725061da546Spatrick
726061da546Spatrick Passing --repl starts lldb in REPL mode.
727061da546Spatrick
728061da546Spatrick lldb -r
729061da546Spatrick
730061da546Spatrick Passing --core causes lldb to debug the core file.
731061da546Spatrick
732061da546Spatrick lldb -c /path/to/core
733061da546Spatrick
734061da546Spatrick Command options can be combined with these modes and cause lldb to run the
735061da546Spatrick specified commands before or after events, like loading the file or crashing,
736061da546Spatrick in the order provided on the command line.
737061da546Spatrick
738061da546Spatrick lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
739061da546Spatrick lldb -S /source/before/file -s /source/after/file
740061da546Spatrick lldb -K /source/before/crash -k /source/after/crash
741061da546Spatrick
742061da546Spatrick Note: In REPL mode no file is loaded, so commands specified to run after
743061da546Spatrick loading the file (via -o or -s) will be ignored.)___";
744061da546Spatrick llvm::outs() << examples << '\n';
745061da546Spatrick }
746061da546Spatrick
main(int argc,char const * argv[])747061da546Spatrick int main(int argc, char const *argv[]) {
748a0747c9fSpatrick // Editline uses for example iswprint which is dependent on LC_CTYPE.
749a0747c9fSpatrick std::setlocale(LC_ALL, "");
750a0747c9fSpatrick std::setlocale(LC_CTYPE, "");
751a0747c9fSpatrick
752061da546Spatrick // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
753061da546Spatrick // destruction.
754061da546Spatrick llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
755061da546Spatrick
756061da546Spatrick // Parse arguments.
757061da546Spatrick LLDBOptTable T;
758a0747c9fSpatrick unsigned MissingArgIndex;
759a0747c9fSpatrick unsigned MissingArgCount;
760*101d251dSrobert ArrayRef<const char *> arg_arr = ArrayRef(argv + 1, argc - 1);
761a0747c9fSpatrick opt::InputArgList input_args =
762a0747c9fSpatrick T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
763dda28197Spatrick llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
764061da546Spatrick
765061da546Spatrick if (input_args.hasArg(OPT_help)) {
766dda28197Spatrick printHelp(T, argv0);
767061da546Spatrick return 0;
768061da546Spatrick }
769061da546Spatrick
770a0747c9fSpatrick // Check for missing argument error.
771a0747c9fSpatrick if (MissingArgCount) {
772a0747c9fSpatrick WithColor::error() << "argument to '"
773a0747c9fSpatrick << input_args.getArgString(MissingArgIndex)
774a0747c9fSpatrick << "' is missing\n";
775a0747c9fSpatrick }
776dda28197Spatrick // Error out on unknown options.
777dda28197Spatrick if (input_args.hasArg(OPT_UNKNOWN)) {
778061da546Spatrick for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
779dda28197Spatrick WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
780dda28197Spatrick }
781a0747c9fSpatrick }
782a0747c9fSpatrick if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {
783dda28197Spatrick llvm::errs() << "Use '" << argv0
784dda28197Spatrick << " --help' for a complete list of options.\n";
785dda28197Spatrick return 1;
786061da546Spatrick }
787061da546Spatrick
788061da546Spatrick SBError error = SBDebugger::InitializeWithErrorHandling();
789061da546Spatrick if (error.Fail()) {
790061da546Spatrick WithColor::error() << "initialization failed: " << error.GetCString()
791061da546Spatrick << '\n';
792061da546Spatrick return 1;
793061da546Spatrick }
794*101d251dSrobert
795*101d251dSrobert // Setup LLDB signal handlers once the debugger has been initialized.
796*101d251dSrobert SBDebugger::PrintDiagnosticsOnError();
797*101d251dSrobert
798061da546Spatrick SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
799061da546Spatrick
800061da546Spatrick signal(SIGINT, sigint_handler);
801*101d251dSrobert #if !defined(_WIN32)
802061da546Spatrick signal(SIGPIPE, SIG_IGN);
803061da546Spatrick signal(SIGWINCH, sigwinch_handler);
804061da546Spatrick signal(SIGTSTP, sigtstp_handler);
805061da546Spatrick #endif
806061da546Spatrick
807061da546Spatrick int exit_code = 0;
808061da546Spatrick // Create a scope for driver so that the driver object will destroy itself
809061da546Spatrick // before SBDebugger::Terminate() is called.
810061da546Spatrick {
811061da546Spatrick Driver driver;
812061da546Spatrick
813061da546Spatrick bool exiting = false;
814061da546Spatrick SBError error(driver.ProcessArgs(input_args, exiting));
815061da546Spatrick if (error.Fail()) {
816061da546Spatrick exit_code = 1;
817061da546Spatrick if (const char *error_cstr = error.GetCString())
818061da546Spatrick WithColor::error() << error_cstr << '\n';
819061da546Spatrick } else if (!exiting) {
820061da546Spatrick exit_code = driver.MainLoop();
821061da546Spatrick }
822061da546Spatrick }
823061da546Spatrick
824061da546Spatrick SBDebugger::Terminate();
825061da546Spatrick return exit_code;
826061da546Spatrick }
827