Index: packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py =================================================================== --- packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py +++ packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py @@ -167,4 +167,56 @@ index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT]) self.assertTrue(index == 0, "lldb didn't close on successful batch completion.") - + @no_debug_info_test + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + def test_command_order(self): + """Test that we handle --source and --one-line commands in the correct order.""" + self.setTearDownCleanup() + + import pexpect + prompt = "(lldb) " + + # Now do it again, and make sure if we don't crash, we quit: + run_commands = ' -b --one-line "settings show use-color" --source source.file --one-line "settings show tab-size"' + self.child = pexpect.spawn('%s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, run_commands)) + child = self.child + # Turn on logging for what the child sends back. + if self.TraceOn(): + child.logfile_read = sys.stdout + + # We should see the "use-color" from --one-line: + self.expect_string ("use-color") + # Then "auto-confirm" from --source: + self.expect_string ("auto-confirm") + # And then "tab-size" from the second --one-line: + self.expect_string ("tab-size") + + index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT]) + self.assertTrue(index == 0, "lldb didn't close on successful batch completion.") + + @skipIfRemote # test not remote-ready llvm.org/pr24813 + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + @no_debug_info_test + def test_batch_mode_file (self): + """Test that we can specify the executable with the --file argument""" + self.build() + self.setTearDownCleanup() + + import pexpect + exe = os.path.join(os.getcwd(), "a.out") + prompt = "(lldb) " + + run_commands = ' -b -o "target list" ' + self.child = pexpect.spawn('%s %s %s --file %s' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) + child = self.child + # Turn on logging for what the child sends back. + if self.TraceOn(): + child.logfile_read = sys.stdout + + # We should see the "target list": + self.expect_string ("target list") + # And then the actual target: + self.expect_string ("* target #0:") + + index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT]) + self.assertTrue(index == 0, "lldb didn't close on successful batch completion.") Index: packages/Python/lldbsuite/test/driver/batch_mode/source.file =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/driver/batch_mode/source.file @@ -0,0 +1 @@ +settings show auto-confirm Index: packages/Python/lldbsuite/test/functionalities/format/TestFormats.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/format/TestFormats.py +++ packages/Python/lldbsuite/test/functionalities/format/TestFormats.py @@ -22,7 +22,7 @@ self.build() import pexpect prompt = "(lldb) " - child = pexpect.spawn('%s %s -x -o "b main" -o r a.out' % (lldbtest_config.lldbExec, self.lldbOption)) + child = pexpect.spawn('%s %s -o "b main" -o r a.out' % (lldbtest_config.lldbExec, self.lldbOption)) # Turn on logging for what the child sends back. if self.TraceOn(): child.logfile_read = sys.stdout Index: tools/driver/Driver.h =================================================================== --- tools/driver/Driver.h +++ tools/driver/Driver.h @@ -18,6 +18,8 @@ #include #include +#include "llvm/Support/CommandLine.h" + #include "lldb/API/SBDefines.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBDebugger.h" @@ -47,24 +49,11 @@ ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &do_exit); const char * - GetFilename() const; - - const char * - GetCrashLogFilename() const; - - const char * GetArchName() const; - lldb::ScriptLanguage - GetScriptLanguage() const; - void WriteCommandsForSourcing (CommandPlacement placement, lldb::SBStream &strm); - bool - GetDebugMode() const; - - class OptionData { public: @@ -75,13 +64,13 @@ Clear(); void - AddInitialCommand (const char *command, CommandPlacement placement, bool is_file, lldb::SBError &error); - + AddInitialCommand(const std::string &command, CommandPlacement placement, bool is_file, lldb::SBError &error); + //static OptionDefinition m_cmd_option_table[]; struct InitialCmdEntry { - InitialCmdEntry (const char *in_contents, bool in_is_file, bool is_cwd_lldbinit_file_read, bool in_quiet = false) : + InitialCmdEntry (const std::string &in_contents, bool in_is_file, bool is_cwd_lldbinit_file_read, bool in_quiet = false) : contents (in_contents), is_file (in_is_file), is_cwd_lldbinit_file_read (is_cwd_lldbinit_file_read), @@ -94,28 +83,10 @@ bool source_quietly; }; - std::vector m_args; - lldb::ScriptLanguage m_script_lang; - std::string m_core_file; - std::string m_crash_log; std::vector m_initial_commands; std::vector m_after_file_commands; std::vector m_after_crash_commands; - bool m_debug_mode; - 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; - std::string m_repl_options; - std::string m_process_name; - lldb::pid_t m_process_pid; - bool m_use_external_editor; // FIXME: When we have set/show variables we can remove this from here. - bool m_batch; - typedef std::set OptionSet; - OptionSet m_seen_options; }; @@ -143,6 +114,9 @@ void ReadyForCommand (); + + lldb::SBError + ParsePositionalArgPair(const llvm::cl::list &source, const llvm::cl::list &one_line, CommandPlacement placement); }; #endif // lldb_Driver_h_ Index: tools/driver/Driver.cpp =================================================================== --- tools/driver/Driver.cpp +++ tools/driver/Driver.cpp @@ -47,6 +47,7 @@ #include "llvm/Support/DataTypes.h" #endif +using namespace llvm; using namespace lldb; static void reset_stdin_termios (); @@ -67,6 +68,12 @@ } } +static void print_version() +{ + assert(g_driver); + puts(g_driver->GetDebugger().GetVersionString()); +} + typedef struct { uint32_t usage_mask; // Used to mark options that can be used together. If (1 << n & usage_mask) != 0 @@ -84,64 +91,107 @@ #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 OptionDefinition g_options[] = +namespace 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 running 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_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." }, - { 0, false, NULL , 0 , 0 , 0, eArgTypeNone, NULL } -}; - -static const uint32_t last_option_set_with_args = 2; +// These will be created at runtime in: Driver::ParseArgs +std::unique_ptr v; +std::unique_ptr h; +std::unique_ptr> debug; +std::unique_ptr d; + + +cl::opt arch("arch", cl::desc("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.")); +cl::alias a("a", cl::desc("Alias for -arch."), cl::aliasopt(arch)); + +cl::opt file("file", cl::desc("Tells the debugger to use the file as the program to be debugged.")); +cl::alias f("f", cl::desc("Alias for -file."), cl::aliasopt(file)); + +cl::opt core("core", cl::desc("Tells the debugger to use the file as the core file.")); +cl::alias c("c", cl::desc("Alias for -core."), cl::aliasopt(core)); + +cl::opt attach_pid("attach-pid", + cl::desc("Tells the debugger to attach to a process with the given pid"), + cl::init(LLDB_INVALID_PROCESS_ID)); +cl::alias p("p", cl::desc("Alias for -attach-pid."), cl::aliasopt(attach_pid)); + +cl::opt attach_name("attach-name", + cl::desc("Tells the debugger to attach to a process with the given name.")); +cl::alias n("n", cl::desc("Alias for -attach-name."), cl::aliasopt(attach_name)); + +cl::opt wait_for("wait-for", cl::desc("Tells the debugger to wait for a process with the given pid or name to launch before attaching."), cl::ValueDisallowed); +cl::alias w("w", cl::desc("Alias for -wait-for."), cl::aliasopt(wait_for)); + +cl::list source("source", + cl::desc("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.")); +cl::alias s("s", cl::desc("Alias for -source"), cl::aliasopt(source)); + +cl::list one_line("one-line", cl::desc("Tells the debugger to execute this one-line lldb command after " + "any file provided on the command line has been loaded.")); +cl::alias o("o", cl::desc("Alias for -one-line."), cl::aliasopt(one_line)); + +cl::list + source_before_file("source-before-file", + cl::desc("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.")); +cl::alias S("S", cl::desc("Alias for -source-before-file."), cl::aliasopt(source_before_file)); + +cl::list one_line_before_file("one-line-before-file", + cl::desc("Tells the debugger to execute this one-line lldb command before " + "any file provided on the command line has been loaded.")); +cl::alias O("O", cl::desc("Alias for -one-line-before-file."), cl::aliasopt(one_line_before_file)); + +cl::list one_line_on_crash( + "one-line-on-crash", + cl::desc("When in batch mode, tells the debugger to execute this one-line lldb command if the target crashes.")); +cl::alias k("k", cl::desc("Alias for -one-line-on-crash."), cl::aliasopt(one_line_on_crash)); + +cl::list source_on_crash( + "source-on-crash", + cl::desc("When in batch mode, tells the debugger to source this file of lldb commands if the target crashes.")); +cl::alias K("K", cl::desc("Alias for -source-on-crash."), cl::aliasopt(source_on_crash)); + +cl::opt source_quietly("source-quietly", cl::desc("Don't echo the commands when executing them.")); +cl::alias Q("Q", cl::desc("Alias for -source-quietly."), cl::aliasopt(source_quietly)); + +cl::opt batch("batch", cl::desc("Tells the debugger to running 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.")); +cl::alias b("b", cl::desc("Alias for -batch."), cl::aliasopt(batch)); + +cl::opt editor("editor", cl::desc( + "Tells the debugger to open source files using the host's \"external editor\" mechanism.")); +cl::alias e("e", cl::desc("Alias for -editor."), cl::aliasopt(editor)); + +cl::opt no_lldbinit("no-lldbinit", cl::desc("Do not automatically parse any '.lldbinit' files.")); +cl::alias x("x", cl::desc("Alias for -no-lldbinit."), cl::aliasopt(no_lldbinit)); + +cl::opt no_use_colors("no-use-colors", cl::desc("Do not use colors.")); +cl::alias X("X", cl::desc("Alias for -no-use-colors."), cl::aliasopt(no_use_colors)); + +cl::opt python_path("python-path", cl::desc( + "Prints out the path to the lldb.py file for this version of lldb."), cl::Hidden); +cl::alias P("P", cl::desc("Alias for -python-path."), cl::aliasopt(python_path)); + +cl::opt repl("repl", cl::desc("Runs lldb in REPL mode with a stub process."), cl::ValueOptional); +cl::alias r("r", cl::desc("Alias for -repl."), cl::aliasopt(repl)); + +cl::opt repl_language("repl-langauge", cl::desc("Chooses the language for the REPL.")); +cl::alias R("R", cl::desc("Alias for -repl-language."), cl::aliasopt(repl_language)); + +cl::list args(cl::Positional, cl::desc(""), cl::ZeroOrMore); + +cl::extrahelp help("\nIf you don't provide -file then the first argument will be the file to be" + "\ndebugged which means that 'lldb -- [ []]' also" + "\nworks. But remember to end the options with \"--\" if any of your" + "\narguments begin with \"-\"." + "\n" + "\nMultiple \"-source\" and \"-one-line\" options can be provided. They will be" + "\nprocessed from left to right in order, with the source files and commands" + "\ninterleaved.\n\n"); +} Driver::Driver () : SBBroadcaster ("Driver"), @@ -215,219 +265,11 @@ } } -void -ShowUsage (FILE *out, OptionDefinition *option_table, 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_options; - uint32_t num_option_sets = 0; - - for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options) - { - uint32_t this_usage_mask = option_table[num_options].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 (uint32_t i = 0; i < num_options; ++i) - { - if (option_table[i].usage_mask & opt_set_mask) - { - CommandArgumentType arg_type = option_table[i].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 (option_table[i].short_option == 'h') - is_help_line = true; - - if (option_table[i].required) - { - if (option_table[i].option_has_arg == required_argument) - fprintf (out, " -%c <%s>", option_table[i].short_option, arg_name); - else if (option_table[i].option_has_arg == optional_argument) - fprintf (out, " -%c [<%s>]", option_table[i].short_option, arg_name); - else - fprintf (out, " -%c", option_table[i].short_option); - } - else - { - if (option_table[i].option_has_arg == required_argument) - fprintf (out, " [-%c <%s>]", option_table[i].short_option, arg_name); - else if (option_table[i].option_has_arg == optional_argument) - fprintf (out, " [-%c [<%s>]]", option_table[i].short_option, arg_name); - else - fprintf (out, " [-%c]", option_table[i].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 (uint32_t i = 0; i < num_options; ++i) - { - // Only print this option if we haven't already seen it. - pos = options_seen.find (option_table[i].short_option); - if (pos == options_seen.end()) - { - CommandArgumentType arg_type = option_table[i].argument_type; - const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type); - - options_seen.insert (option_table[i].short_option); - fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option); - if (arg_type != eArgTypeNone) - fprintf (out, "<%s>", arg_name); - fprintf (out, "\n"); - fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option); - if (arg_type != eArgTypeNone) - fprintf (out, "<%s>", arg_name); - fprintf (out, "\n"); - indent_level += 5; - OutputFormattedUsageText (out, indent_level, option_table[i].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, ""); -} - -void -BuildGetOptTable (OptionDefinition *expanded_option_table, std::vector &getopt_table, - uint32_t num_options) -{ - if (num_options == 0) - return; - - uint32_t i; - uint32_t j; - std::bitset<256> option_seen; - - getopt_table.resize (num_options + 1); - - for (i = 0, j = 0; i < num_options; ++i) - { - char short_opt = expanded_option_table[i].short_option; - - if (option_seen.test(short_opt) == false) - { - getopt_table[j].name = expanded_option_table[i].long_option; - getopt_table[j].has_arg = expanded_option_table[i].option_has_arg; - getopt_table[j].flag = NULL; - getopt_table[j].val = expanded_option_table[i].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_repl_lang (eLanguageTypeUnknown) { } @@ -438,8 +280,6 @@ void Driver::OptionData::Clear () { - m_args.clear (); - m_script_lang = lldb::eScriptLanguageDefault; m_initial_commands.clear (); m_after_file_commands.clear (); @@ -463,22 +303,11 @@ m_after_file_commands.push_back (entry); } - 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; - m_wait_for = false; - m_process_name.erase(); - m_batch = false; m_after_crash_commands.clear(); - - m_process_pid = LLDB_INVALID_PROCESS_ID; } void -Driver::OptionData::AddInitialCommand (const char *command, CommandPlacement placement, bool is_file, SBError &error) +Driver::OptionData::AddInitialCommand (const std::string &command, CommandPlacement placement, bool is_file, SBError &error) { std::vector *command_set; switch (placement) @@ -496,7 +325,7 @@ 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()) @@ -518,28 +347,6 @@ m_option_data.Clear (); } -const char * -Driver::GetFilename() const -{ - if (m_option_data.m_args.empty()) - return NULL; - return m_option_data.m_args.front().c_str(); -} - -const char * -Driver::GetCrashLogFilename() const -{ - if (m_option_data.m_crash_log.empty()) - return NULL; - return m_option_data.m_crash_log.c_str(); -} - -lldb::ScriptLanguage -Driver::GetScriptLanguage() const -{ - return m_option_data.m_script_lang; -} - void Driver::WriteCommandsForSourcing (CommandPlacement placement, SBStream &strm) { @@ -586,7 +393,7 @@ return; } } - bool source_quietly = m_option_data.m_source_quietly || command_entry.source_quietly; + bool source_quietly = options::source_quietly || command_entry.source_quietly; strm.Printf("command source -s %i '%s'\n", source_quietly, command); } else @@ -594,12 +401,28 @@ } } -bool -Driver::GetDebugMode() const +// This loop makes sure we process -s and -o options in the order they were specified. +lldb::SBError +Driver::ParsePositionalArgPair(const llvm::cl::list &source, const llvm::cl::list &one_line, CommandPlacement placement) { - return m_option_data.m_debug_mode; -} + unsigned source_ind = 0, one_line_ind = 0; + while (source_ind < source.size() || one_line_ind < one_line.size()) + { + unsigned source_pos = + source_ind < source.size() ? source.getPosition(source_ind) : std::numeric_limits::max(); + unsigned one_line_pos = + one_line_ind < one_line.size() ? one_line.getPosition(one_line_ind) : std::numeric_limits::max(); + SBError error; + if (source_pos < one_line_pos) + m_option_data.AddInitialCommand(source[source_ind++], placement, true, error); + else + m_option_data.AddInitialCommand(one_line[one_line_ind++], placement, false, error); + if (error.Fail()) + return error; + } + return SBError(); +} // 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 @@ -611,271 +434,96 @@ { ResetOptionValues (); - SBCommandReturnObject result; + cl::SetVersionPrinter(print_version); + StringMap &option_map = cl::getRegisteredOptions(); - SBError error; - std::string option_string; - struct option *long_options = NULL; - std::vector long_options_vector; - uint32_t num_options; + // LLVM already adds a -debug option in Debug builds. We need to remove that one before + // inserting our option. + auto debug_it = option_map.find("debug"); + if (debug_it != option_map.end()) + option_map.erase(debug_it); - for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options) - /* Do Nothing. */; + options::debug.reset(new cl::opt( + "debug", cl::desc("Tells the debugger to print out extra information for debugging itself."))); + options::d.reset(new cl::alias("d", cl::desc("Alias for -debug."), cl::aliasopt(*options::debug))); - if (num_options == 0) - { - if (argc > 1) - error.SetErrorStringWithFormat ("invalid number of options"); - return error; - } + // Add short-hand aliases for -help and -version. + cl::Option& version = *option_map.lookup("version"); + options::v.reset( + new cl::alias("v", cl::desc("Alias for -version."), cl::aliasopt(version), cl::cat(*version.Category))); - BuildGetOptTable (g_options, long_options_vector, num_options); + cl::Option& help = *option_map.lookup("help"); + options::h.reset( + new cl::alias("h", cl::desc("Alias for -help."), cl::aliasopt(help), cl::cat(*help.Category))); - if (long_options_vector.empty()) - long_options = NULL; - else - long_options = &long_options_vector.front(); + cl::ParseCommandLineOptions(argc, argv); - if (long_options == NULL) - { - error.SetErrorStringWithFormat ("invalid long options"); - return error; - } + SBCommandReturnObject result; + + SBError error; - // Build the option_string argument for call to getopt_long_only. + // 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. So we don't read them in in the + // Driver constructor, then set the flags back to "read them in" here, if the command-line + // flag was *not* provided. Finally we have to read them in by hand later in the main loop. + m_debugger.SkipLLDBInitFiles(options::no_lldbinit); + m_debugger.SkipAppInitFiles(options::no_lldbinit); - for (int i = 0; long_options[i].name != NULL; ++i) + if (options::arch.getNumOccurrences() > 0) { - if (long_options[i].flag == NULL) + if (!m_debugger.SetDefaultArchitecture(options::arch.c_str())) { - option_string.push_back ((char) long_options[i].val); - switch (long_options[i].has_arg) - { - default: - case no_argument: - break; - case required_argument: - option_string.push_back (':'); - break; - case optional_argument: - option_string.append ("::"); - break; - } + error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", + options::arch.c_str()); + 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. - - m_debugger.SkipLLDBInitFiles (false); - m_debugger.SkipAppInitFiles (false); - - // Prepare for & make calls to getopt_long_only. -#if __GLIBC__ - optind = 0; -#else - optreset = 1; - optind = 1; -#endif - int val; - while (1) + if (options::file.getNumOccurrences() > 0) { - int long_options_index = -1; - val = ::getopt_long_only (argc, const_cast(argv), option_string.c_str(), long_options, &long_options_index); - - if (val == -1) - break; - else if (val == '?') + SBFileSpec file(options::file.c_str()); + if (! file.Exists() && !file.ResolveExecutableLocation()) { - m_option_data.m_print_help = true; - error.SetErrorStringWithFormat ("unknown or ambiguous option"); - break; + error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", + options::file.c_str()); + return error; } - else if (val == 0) - continue; - else + char path[PATH_MAX]; + file.GetPath(path, sizeof(path)); + // Store program path as the first argument + options::args.insert(options::args.begin(), path); + } + + if (options::core.getNumOccurrences() > 0) + { + SBFileSpec file(options::core.c_str()); + if (! file.Exists()) { - m_option_data.m_seen_options.insert ((char) val); - if (long_options_index == -1) - { - for (int i = 0; - long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val; - ++i) - { - if (long_options[i].val == val) - { - long_options_index = i; - break; - } - } - } + error.SetErrorStringWithFormat("file specified in --core (-c) option doesn't exist: '%s'", + options::core.c_str()); + return error; + } + } - if (long_options_index >= 0) - { - const int short_option = g_options[long_options_index].short_option; + ParsePositionalArgPair(options::source, options::one_line, eCommandPlacementAfterFile); + ParsePositionalArgPair(options::source_before_file, options::one_line_before_file, eCommandPlacementBeforeFile); + ParsePositionalArgPair(options::source_on_crash, options::one_line_on_crash, eCommandPlacementAfterCrash); - 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 '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(options::no_use_colors) + m_debugger.SetUseColor (false); + + if (options::repl_language.getNumOccurrences() > 0) + { + 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 (error.Fail() || m_option_data.m_print_help) - { - ShowUsage (out_fh, g_options, m_option_data); - exiting = true; - } - else 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) + if (options::python_path.getNumOccurrences() > 0) { SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath(); if (python_file_spec.IsValid()) @@ -892,39 +540,12 @@ else ::fprintf (out_fh, "\n"); exiting = true; + return error; } - 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 0) - ::fprintf (out_fh, "Warning: program arguments are ignored when attaching.\n"); - } + if ((options::attach_name.getNumOccurrences() > 0 || options::attach_pid.getNumOccurrences() > 0) && + options::args.size() > 0) + ::fprintf(out_fh, "Warning: program arguments are ignored when attaching.\n"); return error; } @@ -1043,7 +664,7 @@ m_debugger.SetOutputFileHandle (stdout, false); m_debugger.SetInputFileHandle (stdin, false); // Don't take ownership of STDIN yet... - m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); + m_debugger.SetUseExternalEditor(options::editor); struct winsize window_size; if (isatty (STDIN_FILENO) @@ -1059,7 +680,7 @@ // .lldbinit file in the user's home directory. SBCommandReturnObject result; sb_interpreter.SourceInitFileInHomeDirectory(result); - if (GetDebugMode()) + if (options::debug) { result.PutError (m_debugger.GetErrorFileHandle()); result.PutOutput (m_debugger.GetOutputFileHandle()); @@ -1071,51 +692,46 @@ // First source in the commands specified to be run before the file arguments are processed. WriteCommandsForSourcing (eCommandPlacementBeforeFile, commands_stream); - const size_t num_args = m_option_data.m_args.size(); - if (num_args > 0) + if (options::args.size() > 0) { char arch_name[64]; if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) - commands_stream.Printf("target create --arch=%s %s", arch_name, EscapeString(m_option_data.m_args[0]).c_str()); + commands_stream.Printf("target create --arch=%s %s", arch_name, EscapeString(options::args[0]).c_str()); else - commands_stream.Printf("target create %s", EscapeString(m_option_data.m_args[0]).c_str()); + commands_stream.Printf("target create %s", EscapeString(options::args[0]).c_str()); - if (!m_option_data.m_core_file.empty()) + if (options::core.getNumOccurrences() > 0) { - commands_stream.Printf(" --core %s", EscapeString(m_option_data.m_core_file).c_str()); + commands_stream.Printf(" --core %s", EscapeString(options::core).c_str()); } commands_stream.Printf("\n"); - if (num_args > 1) + if (options::args.size() > 1) { commands_stream.Printf ("settings set -- target.run-args "); - for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) - commands_stream.Printf(" %s", EscapeString(m_option_data.m_args[arg_idx]).c_str()); + for (const std::string &arg : options::args) + commands_stream.Printf(" %s", EscapeString(arg).c_str()); commands_stream.Printf("\n"); } } - else if (!m_option_data.m_core_file.empty()) + else if (options::core.getNumOccurrences() > 0) + commands_stream.Printf("target create --core %s\n", EscapeString(options::core).c_str()); + else if (options::attach_name.getNumOccurrences() > 0) { - commands_stream.Printf("target create --core %s\n", EscapeString(m_option_data.m_core_file).c_str()); - } - else if (!m_option_data.m_process_name.empty()) - { - commands_stream.Printf ("process attach --name %s", EscapeString(m_option_data.m_process_name).c_str()); + commands_stream.Printf ("process attach --name %s", EscapeString(options::attach_name).c_str()); - if (m_option_data.m_wait_for) + if (options::wait_for) commands_stream.Printf(" --waitfor"); commands_stream.Printf("\n"); } - else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) - { - commands_stream.Printf ("process attach --pid %" PRIu64 "\n", m_option_data.m_process_pid); - } + else if (options::attach_pid.getNumOccurrences() > 0) + commands_stream.Printf ("process attach --pid %" PRIu64 "\n", uint64_t(options::attach_pid)); WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream); - if (GetDebugMode()) + if (options::debug) { result.PutError(m_debugger.GetErrorFileHandle()); result.PutOutput(m_debugger.GetOutputFileHandle()); @@ -1124,11 +740,11 @@ bool handle_events = true; bool spawn_thread = false; - if (m_option_data.m_repl) + if (options::repl.getNumOccurrences() > 0) { const char *repl_options = NULL; - if (!m_option_data.m_repl_options.empty()) - repl_options = m_option_data.m_repl_options.c_str(); + if (!options::repl.empty()) + repl_options = options::repl.c_str(); SBError error (m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options)); if (error.Fail()) { @@ -1166,7 +782,7 @@ SBCommandInterpreterRunOptions options; options.SetStopOnError (true); - if (m_option_data.m_batch) + if (options::batch) options.SetStopOnCrash (true); m_debugger.RunCommandInterpreter(handle_events, @@ -1176,7 +792,7 @@ quit_requested, stopped_for_crash); - if (m_option_data.m_batch && stopped_for_crash && !m_option_data.m_after_crash_commands.empty()) + if (options::batch && stopped_for_crash && !m_option_data.m_after_crash_commands.empty()) { int crash_command_fds[2]; SBStream crash_commands_stream; @@ -1224,7 +840,7 @@ bool go_interactive = true; if (quit_requested) go_interactive = false; - else if (m_option_data.m_batch && !stopped_for_crash) + else if (options::batch && !stopped_for_crash) go_interactive = false; if (go_interactive) @@ -1301,11 +917,10 @@ main (int argc, char const *argv[], const char *envp[]) { #ifdef _MSC_VER - // disable buffering on windows - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stdin , NULL, _IONBF, 0); + // disable buffering on windows + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stdin , NULL, _IONBF, 0); #endif - SBDebugger::Initialize(); SBHostOS::ThreadCreated (""); Index: tools/driver/Platform.h =================================================================== --- tools/driver/Platform.h +++ tools/driver/Platform.h @@ -12,9 +12,6 @@ #if defined( _WIN32 ) - // this will stop signal.h being included - #define _INC_SIGNAL - #include "lldb/Host/HostGetOpt.h" #include #if defined( _MSC_VER ) #include