summaryrefslogtreecommitdiffstats
path: root/lldb/tools/driver/Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/tools/driver/Driver.cpp')
-rw-r--r--lldb/tools/driver/Driver.cpp979
1 files changed, 344 insertions, 635 deletions
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index 5b129e7559e..31425c1b963 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -9,26 +9,6 @@
#include "Driver.h"
-#include <algorithm>
-#include <atomic>
-#include <bitset>
-#include <csignal>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// Includes for pipe()
-#if defined(_WIN32)
-#include <fcntl.h>
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-#include <string>
-
#include "lldb/API/SBBreakpoint.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBCommandReturnObject.h"
@@ -43,18 +23,74 @@
#include "lldb/API/SBStringList.h"
#include "lldb/API/SBTarget.h"
#include "lldb/API/SBThread.h"
+
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <atomic>
+#include <bitset>
+#include <csignal>
+#include <string>
#include <thread>
#include <utility>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Includes for pipe()
+#if defined(_WIN32)
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
#if !defined(__APPLE__)
#include "llvm/Support/DataTypes.h"
#endif
using namespace lldb;
+using namespace llvm;
+
+namespace {
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ { \
+ PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
+#include "Options.inc"
+#undef OPTION
+};
+
+class LLDBOptTable : public opt::OptTable {
+public:
+ LLDBOptTable() : OptTable(InfoTable) {}
+};
+} // namespace
static void reset_stdin_termios();
static bool g_old_stdin_termios_is_valid = false;
@@ -71,110 +107,6 @@ static void reset_stdin_termios() {
}
}
-typedef struct {
- uint32_t usage_mask; // Used to mark options that can be used together. If (1
- // << n & usage_mask) != 0
- // then this option belongs to option set n.
- bool required; // This option is required (in the current usage level)
- const char *long_option; // Full name for this option.
- int short_option; // Single character for this option.
- int option_has_arg; // no_argument, required_argument or optional_argument
- uint32_t completion_type; // Cookie the option class can use to do define the
- // argument completion.
- lldb::CommandArgumentType argument_type; // Type of argument this option takes
- const char *usage_text; // Full text explaining what this options does and
- // what (if any) argument to
- // pass it.
-} OptionDefinition;
-
-#define LLDB_3_TO_5 LLDB_OPT_SET_3 | LLDB_OPT_SET_4 | LLDB_OPT_SET_5
-#define LLDB_4_TO_5 LLDB_OPT_SET_4 | LLDB_OPT_SET_5
-
-static constexpr OptionDefinition g_options[] = {
- {LLDB_OPT_SET_1, true, "help", 'h', no_argument, 0, eArgTypeNone,
- "Prints out the usage information for the LLDB debugger."},
- {LLDB_OPT_SET_2, true, "version", 'v', no_argument, 0, eArgTypeNone,
- "Prints out the current version number of the LLDB debugger."},
- {LLDB_OPT_SET_3, true, "arch", 'a', required_argument, 0,
- eArgTypeArchitecture,
- "Tells the debugger to use the specified architecture when starting and "
- "running the program. <architecture> must "
- "be one of the architectures for which the program was compiled."},
- {LLDB_OPT_SET_3, true, "file", 'f', required_argument, 0, eArgTypeFilename,
- "Tells the debugger to use the file <filename> as the program to be "
- "debugged."},
- {LLDB_OPT_SET_3, false, "core", 'c', required_argument, 0, eArgTypeFilename,
- "Tells the debugger to use the fullpath to <path> as the core file."},
- {LLDB_OPT_SET_5, true, "attach-pid", 'p', required_argument, 0, eArgTypePid,
- "Tells the debugger to attach to a process with the given pid."},
- {LLDB_OPT_SET_4, true, "attach-name", 'n', required_argument, 0,
- eArgTypeProcessName,
- "Tells the debugger to attach to a process with the given name."},
- {LLDB_OPT_SET_4, true, "wait-for", 'w', no_argument, 0, eArgTypeNone,
- "Tells the debugger to wait for a process with the given pid or name to "
- "launch before attaching."},
- {LLDB_3_TO_5, false, "source", 's', required_argument, 0, eArgTypeFilename,
- "Tells the debugger to read in and execute the lldb commands in the given "
- "file, after any file provided on the command line has been loaded."},
- {LLDB_3_TO_5, false, "one-line", 'o', required_argument, 0, eArgTypeNone,
- "Tells the debugger to execute this one-line lldb command after any file "
- "provided on the command line has been loaded."},
- {LLDB_3_TO_5, false, "source-before-file", 'S', required_argument, 0,
- eArgTypeFilename,
- "Tells the debugger to read in and execute the lldb "
- "commands in the given file, before any file provided "
- "on the command line has been loaded."},
- {LLDB_3_TO_5, false, "one-line-before-file", 'O', required_argument, 0,
- eArgTypeNone,
- "Tells the debugger to execute this one-line lldb command "
- "before any file provided on the command line has been "
- "loaded."},
- {LLDB_3_TO_5, false, "one-line-on-crash", 'k', required_argument, 0,
- eArgTypeNone,
- "When in batch mode, tells the debugger to execute this "
- "one-line lldb command if the target crashes."},
- {LLDB_3_TO_5, false, "source-on-crash", 'K', required_argument, 0,
- eArgTypeFilename,
- "When in batch mode, tells the debugger to source this "
- "file of lldb commands if the target crashes."},
- {LLDB_3_TO_5, false, "source-quietly", 'Q', no_argument, 0, eArgTypeNone,
- "Tells the debugger to execute this one-line lldb command before any file "
- "provided on the command line has been loaded."},
- {LLDB_3_TO_5, false, "batch", 'b', no_argument, 0, eArgTypeNone,
- "Tells the debugger to run the commands from -s, -S, -o & -O, and "
- "then quit. However if any run command stopped due to a signal or crash, "
- "the debugger will return to the interactive prompt at the place of the "
- "crash."},
- {LLDB_3_TO_5, false, "editor", 'e', no_argument, 0, eArgTypeNone,
- "Tells the debugger to open source files using the host's \"external "
- "editor\" mechanism."},
- {LLDB_3_TO_5, false, "no-lldbinit", 'x', no_argument, 0, eArgTypeNone,
- "Do not automatically parse any '.lldbinit' files."},
- {LLDB_3_TO_5, false, "no-use-colors", 'X', no_argument, 0, eArgTypeNone,
- "Do not use colors."},
- {LLDB_OPT_SET_6, true, "python-path", 'P', no_argument, 0, eArgTypeNone,
- "Prints out the path to the lldb.py file for this version of lldb."},
- {LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0,
- eArgTypeScriptLang,
- "Tells the debugger to use the specified scripting language for "
- "user-defined scripts, rather than the default. "
- "Valid scripting languages that can be specified include Python, Perl, "
- "Ruby and Tcl. Currently only the Python "
- "extensions have been implemented."},
- {LLDB_3_TO_5, false, "debug", 'd', no_argument, 0, eArgTypeNone,
- "Tells the debugger to print out extra information for debugging itself."},
- {LLDB_3_TO_5, false, "reproducer", 'z', required_argument, 0,
- eArgTypeFilename,
- "Tells the debugger to use the fullpath to <path> as a reproducer."},
- {LLDB_OPT_SET_7, true, "repl", 'r', optional_argument, 0, eArgTypeNone,
- "Runs lldb in REPL mode with a stub process."},
- {LLDB_OPT_SET_7, true, "repl-language", 'R', required_argument, 0,
- eArgTypeNone, "Chooses the language for the REPL."}};
-
-static constexpr auto g_num_options = sizeof(g_options)/sizeof(OptionDefinition);
-
-static const uint32_t last_option_set_with_args = 2;
-
Driver::Driver()
: SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)),
m_option_data() {
@@ -186,241 +118,14 @@ Driver::Driver()
Driver::~Driver() { g_driver = NULL; }
-// This function takes INDENT, which tells how many spaces to output at the
-// front
-// of each line; TEXT, which is the text that is to be output. It outputs the
-// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
-// front of each line. It breaks lines on spaces, tabs or newlines, shortening
-// the line if necessary to not break in the middle of a word. It assumes that
-// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
-
-void OutputFormattedUsageText(FILE *out, int indent, const char *text,
- int output_max_columns) {
- int len = strlen(text);
- std::string text_string(text);
-
- // Force indentation to be reasonable.
- if (indent >= output_max_columns)
- indent = 0;
-
- // Will it all fit on one line?
-
- if (len + indent < output_max_columns)
- // Output as a single line
- fprintf(out, "%*s%s\n", indent, "", text);
- else {
- // We need to break it up into multiple lines.
- int text_width = output_max_columns - indent - 1;
- int start = 0;
- int end = start;
- int final_end = len;
- int sub_len;
-
- while (end < final_end) {
- // Dont start the 'text' on a space, since we're already outputting the
- // indentation.
- while ((start < final_end) && (text[start] == ' '))
- start++;
-
- end = start + text_width;
- if (end > final_end)
- end = final_end;
- else {
- // If we're not at the end of the text, make sure we break the line on
- // white space.
- while (end > start && text[end] != ' ' && text[end] != '\t' &&
- text[end] != '\n')
- end--;
- }
- sub_len = end - start;
- std::string substring = text_string.substr(start, sub_len);
- fprintf(out, "%*s%s\n", indent, "", substring.c_str());
- start = end + 1;
- }
- }
-}
-
-static void ShowUsage(FILE *out, Driver::OptionData data) {
- uint32_t screen_width = 80;
- uint32_t indent_level = 0;
- const char *name = "lldb";
-
- fprintf(out, "\nUsage:\n\n");
-
- indent_level += 2;
-
- // First, show each usage level set of options, e.g. <cmd>
- // [options-for-level-0]
- // <cmd>
- // [options-for-level-1]
- // etc.
-
- uint32_t num_option_sets = 0;
-
- for (const auto &opt : g_options) {
- uint32_t this_usage_mask = opt.usage_mask;
- if (this_usage_mask == LLDB_OPT_SET_ALL) {
- if (num_option_sets == 0)
- num_option_sets = 1;
- } else {
- for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) {
- if (this_usage_mask & 1 << j) {
- if (num_option_sets <= j)
- num_option_sets = j + 1;
- }
- }
- }
- }
-
- for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++) {
- uint32_t opt_set_mask;
-
- opt_set_mask = 1 << opt_set;
-
- if (opt_set > 0)
- fprintf(out, "\n");
- fprintf(out, "%*s%s", indent_level, "", name);
- bool is_help_line = false;
-
- for (const auto &opt : g_options) {
- if (opt.usage_mask & opt_set_mask) {
- CommandArgumentType arg_type = opt.argument_type;
- const char *arg_name =
- SBCommandInterpreter::GetArgumentTypeAsCString(arg_type);
- // This is a bit of a hack, but there's no way to say certain options
- // don't have arguments yet...
- // so we do it by hand here.
- if (opt.short_option == 'h')
- is_help_line = true;
-
- if (opt.required) {
- if (opt.option_has_arg == required_argument)
- fprintf(out, " -%c <%s>", opt.short_option, arg_name);
- else if (opt.option_has_arg == optional_argument)
- fprintf(out, " -%c [<%s>]", opt.short_option, arg_name);
- else
- fprintf(out, " -%c", opt.short_option);
- } else {
- if (opt.option_has_arg == required_argument)
- fprintf(out, " [-%c <%s>]", opt.short_option, arg_name);
- else if (opt.option_has_arg == optional_argument)
- fprintf(out, " [-%c [<%s>]]", opt.short_option,
- arg_name);
- else
- fprintf(out, " [-%c]", opt.short_option);
- }
- }
- }
- if (!is_help_line && (opt_set <= last_option_set_with_args))
- fprintf(out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]");
- }
-
- fprintf(out, "\n\n");
-
- // Now print out all the detailed information about the various options: long
- // form, short form and help text:
- // -- long_name <argument>
- // - short <argument>
- // help text
-
- // This variable is used to keep track of which options' info we've printed
- // out, because some options can be in
- // more than one usage level, but we only want to print the long form of its
- // information once.
-
- Driver::OptionData::OptionSet options_seen;
- Driver::OptionData::OptionSet::iterator pos;
-
- indent_level += 5;
-
- for (const auto &opt : g_options) {
- // Only print this option if we haven't already seen it.
- pos = options_seen.find(opt.short_option);
- if (pos == options_seen.end()) {
- CommandArgumentType arg_type = opt.argument_type;
- const char *arg_name =
- SBCommandInterpreter::GetArgumentTypeAsCString(arg_type);
-
- options_seen.insert(opt.short_option);
- fprintf(out, "%*s-%c ", indent_level, "", opt.short_option);
- if (arg_type != eArgTypeNone)
- fprintf(out, "<%s>", arg_name);
- fprintf(out, "\n");
- fprintf(out, "%*s--%s ", indent_level, "", opt.long_option);
- if (arg_type != eArgTypeNone)
- fprintf(out, "<%s>", arg_name);
- fprintf(out, "\n");
- indent_level += 5;
- OutputFormattedUsageText(out, indent_level, opt.usage_text,
- screen_width);
- indent_level -= 5;
- fprintf(out, "\n");
- }
- }
-
- indent_level -= 5;
-
- fprintf(out, "\n%*sNotes:\n", indent_level, "");
- indent_level += 5;
-
- fprintf(out,
- "\n%*sMultiple \"-s\" and \"-o\" options can be provided. They will "
- "be processed"
- "\n%*sfrom left to right in order, with the source files and commands"
- "\n%*sinterleaved. The same is true of the \"-S\" and \"-O\" "
- "options. The before"
- "\n%*sfile and after file sets can intermixed freely, the command "
- "parser will"
- "\n%*ssort them out. The order of the file specifiers (\"-c\", "
- "\"-f\", etc.) is"
- "\n%*snot significant in this regard.\n\n",
- indent_level, "", indent_level, "", indent_level, "", indent_level,
- "", indent_level, "", indent_level, "");
-
- fprintf(
- out,
- "\n%*sIf you don't provide -f then the first argument will be the file "
- "to be"
- "\n%*sdebugged which means that '%s -- <filename> [<ARG1> [<ARG2>]]' also"
- "\n%*sworks. But remember to end the options with \"--\" if any of your"
- "\n%*sarguments have a \"-\" in them.\n\n",
- indent_level, "", indent_level, "", name, indent_level, "", indent_level,
- "");
-}
-
- static void BuildGetOptTable(std::vector<option> &getopt_table) {
- getopt_table.resize(g_num_options + 1);
-
- std::bitset<256> option_seen;
- uint32_t j = 0;
- for (const auto &opt : g_options) {
- char short_opt = opt.short_option;
-
- if (option_seen.test(short_opt) == false) {
- getopt_table[j].name = opt.long_option;
- getopt_table[j].has_arg = opt.option_has_arg;
- getopt_table[j].flag = NULL;
- getopt_table[j].val = opt.short_option;
- option_seen.set(short_opt);
- ++j;
- }
- }
-
- getopt_table[j].name = NULL;
- getopt_table[j].has_arg = 0;
- getopt_table[j].flag = NULL;
- getopt_table[j].val = 0;
-}
-
Driver::OptionData::OptionData()
: m_args(), m_script_lang(lldb::eScriptLanguageDefault), m_core_file(),
m_crash_log(), m_initial_commands(), m_after_file_commands(),
m_after_crash_commands(), m_debug_mode(false), m_source_quietly(false),
- m_print_version(false), m_print_python_path(false), m_print_help(false),
- m_wait_for(false), m_repl(false), m_repl_lang(eLanguageTypeUnknown),
- m_repl_options(), m_process_name(),
- m_process_pid(LLDB_INVALID_PROCESS_ID), m_use_external_editor(false),
- m_batch(false), m_seen_options() {}
+ m_print_version(false), m_print_python_path(false), m_wait_for(false),
+ m_repl(false), m_repl_lang(eLanguageTypeUnknown), m_repl_options(),
+ m_process_name(), m_process_pid(LLDB_INVALID_PROCESS_ID),
+ m_use_external_editor(false), m_batch(false), m_seen_options() {}
Driver::OptionData::~OptionData() {}
@@ -441,9 +146,8 @@ void Driver::OptionData::Clear() {
// Only read .lldbinit in the current working directory
// if it's not the same as the .lldbinit in the home
// directory (which is already being read in).
- if (local_lldbinit.Exists() &&
- strcmp(local_lldbinit.GetDirectory(), homedir_dot_lldb.GetDirectory()) !=
- 0) {
+ if (local_lldbinit.Exists() && strcmp(local_lldbinit.GetDirectory(),
+ homedir_dot_lldb.GetDirectory()) != 0) {
char path[2048];
local_lldbinit.GetPath(path, 2047);
InitialCmdEntry entry(path, true, true, true);
@@ -452,7 +156,6 @@ void Driver::OptionData::Clear() {
m_debug_mode = false;
m_source_quietly = false;
- m_print_help = false;
m_print_version = false;
m_print_python_path = false;
m_use_external_editor = false;
@@ -464,7 +167,7 @@ void Driver::OptionData::Clear() {
m_process_pid = LLDB_INVALID_PROCESS_ID;
}
-void Driver::OptionData::AddInitialCommand(const char *command,
+void Driver::OptionData::AddInitialCommand(std::string command,
CommandPlacement placement,
bool is_file, SBError &error) {
std::vector<InitialCmdEntry> *command_set;
@@ -481,7 +184,7 @@ void Driver::OptionData::AddInitialCommand(const char *command,
}
if (is_file) {
- SBFileSpec file(command);
+ SBFileSpec file(command.c_str());
if (file.Exists())
command_set->push_back(InitialCmdEntry(command, is_file, false));
else if (file.ResolveExecutableLocation()) {
@@ -490,7 +193,8 @@ void Driver::OptionData::AddInitialCommand(const char *command,
command_set->push_back(InitialCmdEntry(final_path, is_file, false));
} else
error.SetErrorStringWithFormat(
- "file specified in --source (-s) option doesn't exist: '%s'", optarg);
+ "file specified in --source (-s) option doesn't exist: '%s'",
+ command.c_str());
} else
command_set->push_back(InitialCmdEntry(command, is_file, false));
}
@@ -572,259 +276,239 @@ void Driver::WriteCommandsForSourcing(CommandPlacement placement,
bool Driver::GetDebugMode() const { return m_option_data.m_debug_mode; }
// Check the arguments that were passed to this program to make sure they are
-// valid and to get their
-// argument values (if any). Return a boolean value indicating whether or not
-// to start up the full
-// debugger (i.e. the Command Interpreter) or not. Return FALSE if the
-// arguments were invalid OR
-// if the user only wanted help or version information.
+// valid and to get their argument values (if any). Return a boolean value
+// indicating whether or not to start up the full debugger (i.e. the Command
+// Interpreter) or not. Return FALSE if the arguments were invalid OR if the
+// user only wanted help or version information.
+SBError Driver::ProcessArgs(const opt::InputArgList &args, FILE *out_fh,
+ bool &exiting) {
+ SBError error;
+ ResetOptionValues();
-SBError Driver::ParseArgs(int argc, const char *argv[], FILE *out_fh,
- bool &exiting) {
- static_assert(g_num_options > 0, "cannot handle arguments");
+ // This is kind of a pain, but since we make the debugger in the Driver's
+ // constructor, we can't know at that point whether we should read in init
+ // files yet. So we don't read them in in the Driver constructor, then set
+ // the flags back to "read them in" here, and then if we see the "-n" flag,
+ // we'll turn it off again. Finally we have to read them in by hand later in
+ // the main loop.
+ m_debugger.SkipLLDBInitFiles(false);
+ m_debugger.SkipAppInitFiles(false);
- ResetOptionValues();
+ if (args.hasArg(OPT_version)) {
+ m_option_data.m_print_version = true;
+ }
- SBError error;
- std::vector<option> long_options_vector;
- BuildGetOptTable(long_options_vector);
- if (long_options_vector.empty()) {
- error.SetErrorStringWithFormat("invalid long options");
- return error;
+ if (args.hasArg(OPT_python_path)) {
+ m_option_data.m_print_python_path = true;
}
- // Build the option_string argument for call to getopt_long_only.
- std::string option_string;
- auto sentinel_it = std::prev(std::end(long_options_vector));
- for (auto long_opt_it = std::begin(long_options_vector);
- long_opt_it != sentinel_it; ++long_opt_it) {
- if (long_opt_it->flag == nullptr) {
- option_string.push_back(static_cast<char>(long_opt_it->val));
- switch (long_opt_it->has_arg) {
- default:
- case no_argument:
- break;
- case required_argument:
- option_string.push_back(':');
- break;
- case optional_argument:
- option_string.append("::");
- break;
- }
+ if (args.hasArg(OPT_batch)) {
+ m_option_data.m_batch = true;
+ }
+
+ if (args.hasArg(OPT_core)) {
+ SBFileSpec file(optarg);
+ if (file.Exists()) {
+ m_option_data.m_core_file = optarg;
+ } else {
+ error.SetErrorStringWithFormat(
+ "file specified in --core (-c) option doesn't exist: '%s'", optarg);
+ return error;
}
}
- // This is kind of a pain, but since we make the debugger in the Driver's
- // constructor, we can't
- // know at that point whether we should read in init files yet. So we don't
- // read them in in the
- // Driver constructor, then set the flags back to "read them in" here, and
- // then if we see the
- // "-n" flag, we'll turn it off again. Finally we have to read them in by
- // hand later in the
- // main loop.
+ if (args.hasArg(OPT_editor)) {
+ m_option_data.m_use_external_editor = true;
+ }
- m_debugger.SkipLLDBInitFiles(false);
- m_debugger.SkipAppInitFiles(false);
+ if (args.hasArg(OPT_no_lldbinit)) {
+ m_debugger.SkipLLDBInitFiles(true);
+ m_debugger.SkipAppInitFiles(true);
+ }
-// Prepare for & make calls to getopt_long_only.
-#if __GLIBC__
- optind = 0;
-#else
- optreset = 1;
- optind = 1;
-#endif
- int val;
- while (1) {
- int long_options_index = -1;
- val = ::getopt_long_only(argc, const_cast<char **>(argv),
- option_string.c_str(), long_options_vector.data(),
- &long_options_index);
-
- if (val == -1)
- break;
- else if (val == '?') {
- m_option_data.m_print_help = true;
- error.SetErrorStringWithFormat("unknown or ambiguous option");
- break;
- } else if (val == 0)
- continue;
- else {
- m_option_data.m_seen_options.insert((char)val);
- if (long_options_index == -1) {
- auto long_opt_it = std::find_if(std::begin(long_options_vector), sentinel_it,
- [val](const option &long_option) { return long_option.val == val; });
- if (std::end(long_options_vector) != long_opt_it)
- long_options_index =
- std::distance(std::begin(long_options_vector), long_opt_it);
- }
+ if (args.hasArg(OPT_no_use_colors)) {
+ m_debugger.SetUseColor(false);
+ }
- if (long_options_index >= 0) {
- const int short_option = g_options[long_options_index].short_option;
-
- switch (short_option) {
- case 'h':
- m_option_data.m_print_help = true;
- break;
-
- case 'v':
- m_option_data.m_print_version = true;
- break;
-
- case 'P':
- m_option_data.m_print_python_path = true;
- break;
-
- case 'b':
- m_option_data.m_batch = true;
- break;
-
- case 'c': {
- SBFileSpec file(optarg);
- if (file.Exists()) {
- m_option_data.m_core_file = optarg;
- } else
- error.SetErrorStringWithFormat(
- "file specified in --core (-c) option doesn't exist: '%s'",
- optarg);
- } break;
-
- case 'e':
- m_option_data.m_use_external_editor = true;
- break;
-
- case 'x':
- m_debugger.SkipLLDBInitFiles(true);
- m_debugger.SkipAppInitFiles(true);
- break;
-
- case 'X':
- m_debugger.SetUseColor(false);
- break;
-
- case 'f': {
- SBFileSpec file(optarg);
- if (file.Exists()) {
- m_option_data.m_args.push_back(optarg);
- } else if (file.ResolveExecutableLocation()) {
- char path[PATH_MAX];
- file.GetPath(path, sizeof(path));
- m_option_data.m_args.push_back(path);
- } else
- error.SetErrorStringWithFormat(
- "file specified in --file (-f) option doesn't exist: '%s'",
- optarg);
- } break;
-
- case 'a':
- if (!m_debugger.SetDefaultArchitecture(optarg))
- error.SetErrorStringWithFormat(
- "invalid architecture in the -a or --arch option: '%s'",
- optarg);
- break;
-
- case 'l':
- m_option_data.m_script_lang = m_debugger.GetScriptingLanguage(optarg);
- break;
-
- case 'd':
- m_option_data.m_debug_mode = true;
- break;
-
- case 'z': {
- SBFileSpec file(optarg);
- if (file.Exists()) {
- m_debugger.SetReproducerPath(optarg);
- } else
- error.SetErrorStringWithFormat("file specified in --reproducer "
- "(-z) option doesn't exist: '%s'",
- optarg);
- } break;
-
- case 'Q':
- m_option_data.m_source_quietly = true;
- break;
-
- case 'K':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash,
- true, error);
- break;
- case 'k':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash,
- false, error);
- break;
-
- case 'n':
- m_option_data.m_process_name = optarg;
- break;
-
- case 'w':
- m_option_data.m_wait_for = true;
- break;
-
- case 'p': {
- char *remainder;
- m_option_data.m_process_pid = strtol(optarg, &remainder, 0);
- if (remainder == optarg || *remainder != '\0')
- error.SetErrorStringWithFormat(
- "Could not convert process PID: \"%s\" into a pid.", optarg);
- } break;
-
- case 'r':
- m_option_data.m_repl = true;
- if (optarg && optarg[0])
- m_option_data.m_repl_options = optarg;
- else
- m_option_data.m_repl_options.clear();
- break;
-
- case 'R':
- m_option_data.m_repl_lang =
- SBLanguageRuntime::GetLanguageTypeFromString(optarg);
- if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
- error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
- optarg);
- }
- break;
-
- case 's':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile,
- true, error);
- break;
- case 'o':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile,
- false, error);
- break;
- case 'S':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile,
- true, error);
- break;
- case 'O':
- m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile,
- false, error);
- break;
- default:
- m_option_data.m_print_help = true;
- error.SetErrorStringWithFormat("unrecognized option %c",
- short_option);
- break;
- }
- } else {
- error.SetErrorStringWithFormat("invalid option with value %i", val);
- }
- if (error.Fail()) {
+ if (auto *arg = args.getLastArg(OPT_file)) {
+ auto optarg = arg->getValue();
+ SBFileSpec file(optarg);
+ if (file.Exists()) {
+ m_option_data.m_args.push_back(optarg);
+ } else if (file.ResolveExecutableLocation()) {
+ char path[PATH_MAX];
+ file.GetPath(path, sizeof(path));
+ m_option_data.m_args.push_back(path);
+ } else {
+ error.SetErrorStringWithFormat(
+ "file specified in --file (-f) option doesn't exist: '%s'", optarg);
+ return error;
+ }
+ }
+
+ if (auto *arg = args.getLastArg(OPT_arch)) {
+ auto optarg = arg->getValue();
+ if (!m_debugger.SetDefaultArchitecture(optarg)) {
+ error.SetErrorStringWithFormat(
+ "invalid architecture in the -a or --arch option: '%s'", optarg);
+ return error;
+ }
+ }
+
+ if (auto *arg = args.getLastArg(OPT_script_language)) {
+ auto optarg = arg->getValue();
+ m_option_data.m_script_lang = m_debugger.GetScriptingLanguage(optarg);
+ }
+
+ if (args.hasArg(OPT_no_use_colors)) {
+ m_option_data.m_debug_mode = true;
+ }
+
+ if (auto *arg = args.getLastArg(OPT_reproducer)) {
+ auto optarg = arg->getValue();
+ SBFileSpec file(optarg);
+ if (file.Exists()) {
+ m_debugger.SetReproducerPath(optarg);
+ } else {
+ error.SetErrorStringWithFormat("file specified in --reproducer "
+ "(-z) option doesn't exist: '%s'",
+ optarg);
+ return error;
+ }
+ }
+
+ if (args.hasArg(OPT_no_use_colors)) {
+ m_debugger.SetUseColor(false);
+ }
+
+ if (args.hasArg(OPT_source_quietly)) {
+ m_option_data.m_source_quietly = true;
+ }
+
+ if (auto *arg = args.getLastArg(OPT_attach_name)) {
+ auto optarg = arg->getValue();
+ m_option_data.m_process_name = optarg;
+ }
+
+ if (args.hasArg(OPT_wait_for)) {
+ m_option_data.m_wait_for = true;
+ }
+
+ if (auto *arg = args.getLastArg(OPT_attach_pid)) {
+ auto optarg = arg->getValue();
+ char *remainder;
+ m_option_data.m_process_pid = strtol(optarg, &remainder, 0);
+ if (remainder == optarg || *remainder != '\0') {
+ error.SetErrorStringWithFormat(
+ "Could not convert process PID: \"%s\" into a pid.", optarg);
+ return error;
+ }
+ }
+
+ if (auto *arg = args.getLastArg(OPT_repl_language)) {
+ auto optarg = arg->getValue();
+ m_option_data.m_repl_lang =
+ SBLanguageRuntime::GetLanguageTypeFromString(optarg);
+ if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
+ error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
+ optarg);
+ return error;
+ }
+ }
+
+ if (auto *arg = args.getLastArg(OPT_repl)) {
+ auto optarg = arg->getValue();
+ m_option_data.m_repl = true;
+ if (optarg && optarg[0])
+ m_option_data.m_repl_options = optarg;
+ else
+ m_option_data.m_repl_options.clear();
+ }
+
+ // We need to process the options below together as their relative order
+ // matters.
+ for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
+ OPT_source, OPT_source_before_file,
+ OPT_one_line, OPT_one_line_before_file)) {
+ if (arg->getOption().matches(OPT_source_on_crash)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, true,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_one_line_on_crash)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash,
+ false, error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_source)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, true,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_source_before_file)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, true,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_one_line)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, false,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ if (arg->getOption().matches(OPT_one_line_before_file)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile,
+ false, error);
+ if (error.Fail())
return error;
+ }
+ }
+
+ if (m_option_data.m_process_name.empty() &&
+ m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
+
+ // If the option data args array is empty that means the file was not
+ // specified with -f and we need to get it from the input args.
+ if (m_option_data.m_args.empty()) {
+ if (auto *arg = args.getLastArgNoClaim(OPT_INPUT)) {
+ m_option_data.m_args.push_back(arg->getAsString((args)));
}
}
+
+ // Any argument following -- is an argument for the inferior.
+ if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
+ for (auto value : arg->getValues())
+ m_option_data.m_args.push_back(value);
+ }
+ } else {
+ if (args.getLastArgNoClaim()) {
+ ::fprintf(out_fh,
+ "Warning: program arguments are ignored when attaching.\n");
+ }
}
- if (error.Fail() || m_option_data.m_print_help) {
- ShowUsage(out_fh, m_option_data);
- exiting = true;
- } else if (m_option_data.m_print_version) {
+ if (m_option_data.m_print_version) {
::fprintf(out_fh, "%s\n", m_debugger.GetVersionString());
exiting = true;
- } else if (m_option_data.m_print_python_path) {
+ return error;
+ }
+
+ if (m_option_data.m_print_python_path) {
SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
if (python_file_spec.IsValid()) {
char python_path[PATH_MAX];
@@ -836,33 +520,7 @@ SBError Driver::ParseArgs(int argc, const char *argv[], FILE *out_fh,
} else
::fprintf(out_fh, "<COULD NOT FIND PATH>\n");
exiting = true;
- } else if (m_option_data.m_process_name.empty() &&
- m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
- // Any arguments that are left over after option parsing are for
- // the program. If a file was specified with -f then the filename
- // is already in the m_option_data.m_args array, and any remaining args
- // are arguments for the inferior program. If no file was specified with
- // -f, then what is left is the program name followed by any arguments.
-
- // Skip any options we consumed with getopt_long_only
- argc -= optind;
- argv += optind;
-
- if (argc > 0) {
- for (int arg_idx = 0; arg_idx < argc; ++arg_idx) {
- const char *arg = argv[arg_idx];
- if (arg)
- m_option_data.m_args.push_back(arg);
- }
- }
-
- } else {
- // Skip any options we consumed with getopt_long_only
- argc -= optind;
-
- if (argc > 0)
- ::fprintf(out_fh,
- "Warning: program arguments are ignored when attaching.\n");
+ return error;
}
return error;
@@ -884,8 +542,9 @@ static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
if (err == 0) {
ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
if (nrwr < 0) {
- fprintf(stderr, "error: write(%i, %p, %" PRIu64 ") failed (errno = %i) "
- "when trying to open LLDB commands pipe\n",
+ fprintf(stderr,
+ "error: write(%i, %p, %" PRIu64 ") failed (errno = %i) "
+ "when trying to open LLDB commands pipe\n",
fds[WRITE], static_cast<const void *>(commands_data),
static_cast<uint64_t>(commands_size), errno);
} else if (static_cast<size_t>(nrwr) == commands_size) {
@@ -903,13 +562,13 @@ static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
// the debugger as an input handle
commands_file = fdopen(fds[READ], "r");
if (commands_file) {
- fds[READ] =
- -1; // The FILE * 'commands_file' now owns the read descriptor
- // Hand ownership if the FILE * over to the debugger for
- // "commands_file".
+ fds[READ] = -1; // The FILE * 'commands_file' now owns the read
+ // descriptor Hand ownership if the FILE * over to the
+ // debugger for "commands_file".
} else {
- fprintf(stderr, "error: fdopen(%i, \"r\") failed (errno = %i) when "
- "trying to open LLDB commands pipe\n",
+ fprintf(stderr,
+ "error: fdopen(%i, \"r\") failed (errno = %i) when "
+ "trying to open LLDB commands pipe\n",
fds[READ], errno);
}
}
@@ -1206,6 +865,45 @@ void sigcont_handler(int signo) {
signal(signo, sigcont_handler);
}
+static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
+ std::string usage_str = tool_name.str() + "options";
+ table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
+
+ std::string examples = R"___(
+EXAMPLES:
+ The debugger can be started in several modes.
+
+ Passing an executable as a positional argument prepares lldb to debug the
+ given executable. Arguments passed after -- are considered arguments to the
+ debugged executable.
+
+ lldb --arch x86_64 /path/to/program -- --arch arvm7
+
+ Passing one of the attach options causes lldb to immediately attach to the
+ given process.
+
+ lldb -p <pid>
+ lldb -n <process-name>
+
+ Passing --repl starts lldb in REPL mode.
+
+ lldb -r
+
+ Passing --core causes lldb to debug the core file.
+
+ lldb -c /path/to/core
+
+ Command options can be combined with either mode and cause lldb to run the
+ specified commands before or after events, like loading the file or crashing,
+ in the order provided on the command line.
+
+ lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
+ lldb -S /source/before/file -s /source/after/file
+ lldb -K /source/before/crash -k /source/after/crash
+ )___";
+ llvm::outs() << examples;
+}
+
int
#ifdef _MSC_VER
wmain(int argc, wchar_t const *wargv[])
@@ -1224,12 +922,23 @@ main(int argc, char const *argv[])
const char **argv = argvPointers.data();
#endif
- llvm::StringRef ToolName = argv[0];
+ // Print stack trace on crash.
+ llvm::StringRef ToolName = llvm::sys::path::filename(argv[0]);
llvm::sys::PrintStackTraceOnErrorSignal(ToolName);
llvm::PrettyStackTraceProgram X(argc, argv);
- SBDebugger::Initialize();
+ // Parse arguments.
+ LLDBOptTable T;
+ unsigned MAI, MAC;
+ ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
+ opt::InputArgList input_args = T.ParseArgs(arg_arr, MAI, MAC);
+ if (input_args.hasArg(OPT_help)) {
+ printHelp(T, ToolName);
+ return 0;
+ }
+
+ SBDebugger::Initialize();
SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
signal(SIGINT, sigint_handler);
@@ -1247,7 +956,7 @@ main(int argc, char const *argv[])
Driver driver;
bool exiting = false;
- SBError error(driver.ParseArgs(argc, argv, stdout, exiting));
+ SBError error(driver.ProcessArgs(input_args, stdout, exiting));
if (error.Fail()) {
exit_code = 1;
const char *error_cstr = error.GetCString();
OpenPOWER on IntegriCloud