JDevlieghere created this revision.
JDevlieghere added a reviewer: zturner.
JDevlieghere added a project: LLDB.
Herald added subscribers: jfb, mgorny.
Alternative to https://reviews.llvm.org/D54682.
Repository:
rLLDB LLDB
https://reviews.llvm.org/D54692
Files:
tools/driver/CMakeLists.txt
tools/driver/Driver.cpp
tools/driver/Driver.h
tools/driver/Options.td
Index: tools/driver/Options.td
===================================================================
--- /dev/null
+++ tools/driver/Options.td
@@ -0,0 +1,106 @@
+include "llvm/Option/OptParser.td"
+
+class F<string name>: Flag<["--", "-"], name>;
+class S<string name>: Separate<["--", "-"], name>;
+
+def version: F<"version">,
+ HelpText<"Prints out the current version number of the LLDB debugger.">;
+def: Flag<["-"], "v">, Alias<version>, HelpText<"Alias for --version">;
+
+def help: F<"help">,
+ HelpText<"Prints out the usage information for the LLDB debugger.">;
+def: Flag<["-"], "h">, Alias<help>, HelpText<"Alias for --help">;
+
+def python_path: F<"python-path">,
+ HelpText<"Prints out the path to the lldb.py file for this version of lldb.">;
+def: Flag<["-"], "P">, Alias<python_path>, HelpText<"Alias for --python-path">;
+
+def batch: F<"batch">,
+ HelpText<"Tells the debugger to run the commands from -s, -S, -o & -O, and then quit.">;
+def: Flag<["-"], "b">, Alias<batch>, HelpText<"Alias for --batch">;
+
+def core: F<"core">,
+ HelpText<"Tells the debugger to use the full path to <core> as the core file.">;
+def: Flag<["-"], "c">, Alias<core>, HelpText<"Alias for --core">;
+
+def editor: F<"editor">,
+ HelpText<"Tells the debugger to open source files using the host's \"external editor\" mechanism.">;
+def: Flag<["-"], "e">, Alias<editor>, HelpText<"Alias for --editor">;
+
+def no_lldbinit: F<"no-lldbinit">,
+ HelpText<"Do not automatically parse any '.lldbinit' files.">;
+def: Flag<["-"], "x">, Alias<no_lldbinit>, HelpText<"Alias for --no-lldbinit">;
+
+def no_use_colors: F<"no-use-colors">,
+ HelpText<"Do not use colors.">;
+def: Flag<["-"], "X">, Alias<no_use_colors>, HelpText<"Alias for --no-use-color">;
+
+def file: Separate<["--", "-"], "file">, MetaVarName<"<filename>">,
+ HelpText<"Tells the debugger to use the file <filename> as the program to be debugged.">;
+def: Separate<["-"], "f">, Alias<file>, HelpText<"Alias for --file">;
+
+def arch: Separate<["--", "-"], "arch">, MetaVarName<"<architecture>">,
+ HelpText<"Tells the debugger to use the specified architecture when starting and running the program.">;
+def: Separate<["-"], "a">, Alias<arch>, HelpText<"Alias for --arch">;
+
+def script_language: Separate<["--", "-"], "script-language">, MetaVarName<"<language>">,
+ HelpText<"Tells the debugger to use the specified scripting language for user-defined scripts.">;
+def: Separate<["-"], "l">, Alias<script_language>, HelpText<"Alias for --script-language">;
+
+def debug: F<"debug">,
+ HelpText<"Tells the debugger to print out extra information for debugging itself.">;
+def: Flag<["-"], "d">, Alias<debug>, HelpText<"Alias for --debug">;
+
+def reproducer: Separate<["--", "-"], "reproducer">, MetaVarName<"<filename>">,
+ HelpText<"Tells the debugger to use the fullpath to <filename> as a reproducer.">;
+def: Separate<["-"], "z">, Alias<file>, HelpText<"Alias for --reproducer">;
+
+def source_quietly: F<"source-quietly">,
+ HelpText<"Tells the debugger to execute this one-line lldb command before any file has been loaded.">;
+def: Flag<["-"], "Q">, Alias<source_quietly>, HelpText<"Alias for --source-quietly">;
+
+def attach_name: Separate<["--", "-"], "attach-name">, MetaVarName<"<name>">,
+ HelpText<"Tells the debugger to attach to a process with the given name.">;
+def: Separate<["-"], "n">, Alias<attach_name>, HelpText<"Alias for --attach-name">;
+
+def wait_for: F<"wait-for">,
+ HelpText<"Tells the debugger to wait for a process with the given pid or name to launch before attaching.">;
+def: Flag<["-"], "w">, Alias<source_quietly>, HelpText<"Alias for --wait-for">;
+
+def attach_pid: Separate<["--", "-"], "attach-pid">, MetaVarName<"<pid>">,
+ HelpText<"Tells the debugger to attach to a process with the given pid.">;
+def: Separate<["-"], "p">, Alias<attach_pid>, HelpText<"Alias for --attach-pid">;
+
+def repl: Separate<["--", "-"], "repl">,
+ HelpText<"Runs lldb in REPL mode with a stub process.">;
+def: Separate<["-"], "r">, Alias<repl>, HelpText<"Alias for --repl">;
+
+def repl_language: Separate<["--", "-"], "repl-language">, MetaVarName<"<language>">,
+ HelpText<"Chooses the language for the REPL.">;
+def: Separate<["-"], "R">, Alias<repl_language>, HelpText<"Alias for --repl-language">;
+
+def source_on_crash: Separate<["--", "-"], "source-on-crash">, MetaVarName<"<file>">,
+ HelpText<"When in batch mode, tells the debugger to source this file of lldb commands if the target crashes.">;
+def: Separate<["-"], "K">, Alias<source_on_crash>, HelpText<"Alias for --source-on-crash">;
+
+def one_line_on_crash: Separate<["--", "-"], "one-line-on-crash">, MetaVarName<"<command>">,
+ HelpText<"When in batch mode, tells the debugger to source this file of lldb commands if the target crashes.">;
+def: Separate<["-"], "k">, Alias<one_line_on_crash>, HelpText<"Alias for --one-line-on-crash">;
+
+def source: Separate<["--", "-"], "source">, MetaVarName<"<file>">,
+ HelpText<"Tells the debugger to read in and execute the lldb commands in the given file, after any file has been loaded.">;
+def: Separate<["-"], "s">, Alias<source>, HelpText<"Alias for --source">;
+
+def source_before_file: Separate<["--", "-"], "source-before-file">, MetaVarName<"<file>">,
+ HelpText<"Tells the debugger to read in and execute the lldb commands in the given file, before any file has been loaded.">;
+def: Separate<["-"], "S">, Alias<source_before_file>, HelpText<"Alias for --source-before-file">;
+
+def one_line: Separate<["--", "-"], "one-line">, MetaVarName<"<command>">,
+ HelpText<"Tells the debugger to execute this one-line lldb command after any file provided on the command line has been loaded.">;
+def: Separate<["-"], "o">, Alias<one_line>, HelpText<"Alias for --one-line">;
+
+def one_line_before_file: Separate<["--", "-"], "one-line-before-file">, MetaVarName<"<command>">,
+ HelpText<"Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded.">;
+def: Separate<["-"], "O">, Alias<one_line_before_file>, HelpText<"Alias for --one-line-before-file">;
+
+def remaining : Flag<["--"], "">;
Index: tools/driver/Driver.h
===================================================================
--- tools/driver/Driver.h
+++ tools/driver/Driver.h
@@ -12,15 +12,19 @@
#include "Platform.h"
-#include <set>
-#include <string>
-#include <vector>
-
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBError.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
class Driver : public lldb::SBBroadcaster {
public:
typedef enum CommandPlacement {
@@ -38,8 +42,8 @@
/// @return The exit code that the process should return.
int MainLoop();
- lldb::SBError ParseArgs(int argc, const char *argv[], FILE *out_fh,
- bool &do_exit);
+ lldb::SBError ProcessArgs(const llvm::opt::InputArgList &args, FILE *out_fh,
+ bool &do_exit);
const char *GetFilename() const;
@@ -61,13 +65,13 @@
void Clear();
- void AddInitialCommand(const char *command, CommandPlacement placement,
+ void AddInitialCommand(std::string command, CommandPlacement placement,
bool is_file, lldb::SBError &error);
struct InitialCmdEntry {
- InitialCmdEntry(const char *in_contents, bool in_is_file,
+ InitialCmdEntry(std::string contents, bool in_is_file,
bool is_cwd_lldbinit_file_read, bool in_quiet = false)
- : contents(in_contents), is_file(in_is_file),
+ : contents(std::move(contents)), is_file(in_is_file),
is_cwd_lldbinit_file_read(is_cwd_lldbinit_file_read),
source_quietly(in_quiet) {}
@@ -89,7 +93,6 @@
bool m_source_quietly;
bool m_print_version;
bool m_print_python_path;
- bool m_print_help;
bool m_wait_for;
bool m_repl;
lldb::LanguageType m_repl_lang;
Index: tools/driver/Driver.cpp
===================================================================
--- tools/driver/Driver.cpp
+++ 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,73 @@
#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/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 +106,6 @@
}
}
-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() {
@@ -240,187 +171,14 @@
}
}
-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() {}
@@ -452,7 +210,6 @@
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 +221,7 @@
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,16 +238,17 @@
}
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()) {
char final_path[PATH_MAX];
file.GetPath(final_path, sizeof(final_path));
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 +330,228 @@
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();
+
+ // 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);
-SBError Driver::ParseArgs(int argc, const char *argv[], FILE *out_fh,
- bool &exiting) {
- static_assert(g_num_options > 0, "cannot handle arguments");
+ if (args.hasArg(OPT_version)) {
+ m_option_data.m_print_version = true;
+ }
- ResetOptionValues();
+ if (args.hasArg(OPT_python_path)) {
+ m_option_data.m_print_python_path = 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_batch)) {
+ m_option_data.m_batch = 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_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()) {
- return error;
+ 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_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();
+ }
+
+ for (auto *arg : args.filtered(OPT_source_on_crash)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, true,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ for (auto *arg : args.filtered(OPT_one_line_on_crash)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, false,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ for (auto *arg : args.filtered(OPT_source)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, true,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ for (auto *arg : args.filtered(OPT_source_before_file)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, true,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ for (auto *arg : args.filtered(OPT_one_line)) {
+ auto optarg = arg->getValue();
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, false,
+ error);
+ if (error.Fail())
+ return error;
+ }
+
+ for (auto *arg : args.filtered(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 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.
+ if (auto remaining = args.getLastArg(OPT_remaining)) {
+ auto index = remaining->getIndex() + 1;
+ auto end = args.getNumInputArgStrings();
+ while (index < end) {
+ m_option_data.m_args.push_back(args.getArgString(index++));
}
}
+
+ } 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 +563,7 @@
} 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;
@@ -1224,12 +925,24 @@
const char **argv = argvPointers.data();
#endif
+ // Print stack trace on crash.
llvm::StringRef ToolName = 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)) {
+ std::string usage = std::string(argv[0]) + " [options]";
+ T.PrintHelp(llvm::outs(), usage.c_str(), "LLDB", false);
+ return 0;
+ }
+
+ SBDebugger::Initialize();
SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
signal(SIGINT, sigint_handler);
@@ -1247,7 +960,7 @@
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();
Index: tools/driver/CMakeLists.txt
===================================================================
--- tools/driver/CMakeLists.txt
+++ tools/driver/CMakeLists.txt
@@ -1,3 +1,7 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(LLDBOptionsTableGen)
+
if ((CMAKE_SYSTEM_NAME MATCHES "Windows") OR
(CMAKE_SYSTEM_NAME MATCHES "NetBSD" ))
# These targets do not have getopt support, so they rely on the one provided by
@@ -17,11 +21,16 @@
${host_lib}
LINK_COMPONENTS
+ Option
Support
)
if ( CMAKE_SYSTEM_NAME MATCHES "Windows" )
add_definitions( -DIMPORT_LIBLLDB )
endif()
-add_dependencies(lldb ${LLDB_SUITE_TARGET})
+add_dependencies(lldb
+ ${LLDB_SUITE_TARGET}
+ LLDBOptionsTableGen
+ ${tablegen_deps}
+)
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits