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,6 +21,7 @@ ${host_lib} LINK_COMPONENTS + Option Support ) @@ -24,4 +29,8 @@ add_definitions( -DIMPORT_LIBLLDB ) endif() -add_dependencies(lldb ${LLDB_SUITE_TARGET}) +add_dependencies(lldb + ${LLDB_SUITE_TARGET} + LLDBOptionsTableGen + ${tablegen_deps} +) Index: tools/driver/Driver.h =================================================================== --- tools/driver/Driver.h +++ tools/driver/Driver.h @@ -12,15 +12,19 @@ #include "Platform.h" -#include -#include -#include - #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 +#include +#include + 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 -#include -#include -#include -#include -#include -#include -#include -#include - -// Includes for pipe() -#if defined(_WIN32) -#include -#include -#else -#include -#endif - -#include - #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 +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include + +// Includes for pipe() +#if defined(_WIN32) +#include +#include +#else +#include +#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. 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 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 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 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. - // [options-for-level-0] - // - // [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, " [[--] [ ...]]"); - } - - fprintf(out, "\n\n"); - - // Now print out all the detailed information about the various options: long - // form, short form and help text: - // -- long_name - // - short - // 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 -- [ []]' 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