diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp | 435 |
1 files changed, 309 insertions, 126 deletions
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp index f98eac0..f56d089 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectCommands.h" // C Includes @@ -29,7 +27,6 @@ #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" using namespace lldb; using namespace lldb_private; @@ -85,7 +82,7 @@ protected: switch (short_option) { case 'c': - error = m_count.SetValueFromCString(option_arg,eVarSetOperationAssign); + error = m_count.SetValueFromString(option_arg,eVarSetOperationAssign); break; case 's': if (option_arg && strcmp("end", option_arg) == 0) @@ -94,10 +91,10 @@ protected: m_start_idx.SetOptionWasSet(); } else - error = m_start_idx.SetValueFromCString(option_arg,eVarSetOperationAssign); + error = m_start_idx.SetValueFromString(option_arg,eVarSetOperationAssign); break; case 'e': - error = m_stop_idx.SetValueFromCString(option_arg,eVarSetOperationAssign); + error = m_stop_idx.SetValueFromString(option_arg,eVarSetOperationAssign); break; case 'C': m_clear.SetCurrentValue(true); @@ -326,15 +323,15 @@ protected: switch (short_option) { case 'e': - error = m_stop_on_error.SetValueFromCString(option_arg); + error = m_stop_on_error.SetValueFromString(option_arg); break; case 'c': - error = m_stop_on_continue.SetValueFromCString(option_arg); + error = m_stop_on_continue.SetValueFromString(option_arg); break; case 's': - error = m_silent_run.SetValueFromCString(option_arg); + error = m_silent_run.SetValueFromString(option_arg); break; default: @@ -453,60 +450,74 @@ public: NULL) { SetHelpLong( - "'alias' allows the user to create a short-cut or abbreviation for long \n\ - commands, multi-word commands, and commands that take particular options. \n\ - Below are some simple examples of how one might use the 'alias' command: \n\ - \n 'command alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\ - // command. \n\ - 'command alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\ - // command. Since breakpoint commands are two-word \n\ - // commands, the user will still need to enter the \n\ - // second word after 'bp', e.g. 'bp enable' or \n\ - // 'bp delete'. \n\ - 'command alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\ - // two-word command 'breakpoint list'. \n\ - \nAn alias can include some options for the command, with the values either \n\ - filled in at the time the alias is created, or specified as positional \n\ - arguments, to be filled in when the alias is invoked. The following example \n\ - shows how to create aliases with options: \n\ - \n\ - 'command alias bfl breakpoint set -f %1 -l %2' \n\ - \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\ - options already part of the alias. So if the user wants to set a breakpoint \n\ - by file and line without explicitly having to use the -f and -l options, the \n\ - user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\ - for the actual arguments that will be passed when the alias command is used. \n\ - The number in the placeholder refers to the position/order the actual value \n\ - occupies when the alias is used. All the occurrences of '%1' in the alias \n\ - will be replaced with the first argument, all the occurrences of '%2' in the \n\ - alias will be replaced with the second argument, and so on. This also allows \n\ - actual arguments to be used multiple times within an alias (see 'process \n\ - launch' example below). \n\ - Note: the positional arguments must substitute as whole words in the resultant\n\ - command, so you can't at present do something like:\n\ - \n\ - command alias bcppfl breakpoint set -f %1.cpp -l %2\n\ - \n\ - to get the file extension \".cpp\" automatically appended. For more complex\n\ - aliasing, use the \"command regex\" command instead.\n\ - \nSo in the 'bfl' case, the actual file value will be \n\ - filled in with the first argument following 'bfl' and the actual line number \n\ - value will be filled in with the second argument. The user would use this \n\ - alias as follows: \n\ - \n (lldb) command alias bfl breakpoint set -f %1 -l %2 \n\ - <... some time later ...> \n\ - (lldb) bfl my-file.c 137 \n\ - \nThis would be the same as if the user had entered \n\ - 'breakpoint set -f my-file.c -l 137'. \n\ - \nAnother example: \n\ - \n (lldb) command alias pltty process launch -s -o %1 -e %1 \n\ - (lldb) pltty /dev/tty0 \n\ - // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\ - \nIf the user always wanted to pass the same value to a particular option, the \n\ - alias could be defined with that value directly in the alias as a constant, \n\ - rather than using a positional placeholder: \n\ - \n command alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\ - // 3 of whatever file is indicated. \n"); +"'alias' allows the user to create a short-cut or abbreviation for long \ +commands, multi-word commands, and commands that take particular options. \ +Below are some simple examples of how one might use the 'alias' command:" R"( + +(lldb) command alias sc script + + Creates the abbreviation 'sc' for the 'script' command. + +(lldb) command alias bp breakpoint + +)" " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ +breakpoint commands are two-word commands, the user would still need to \ +enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." R"( + +(lldb) command alias bpl breakpoint list + + Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'. + +)" "An alias can include some options for the command, with the values either \ +filled in at the time the alias is created, or specified as positional \ +arguments, to be filled in when the alias is invoked. The following example \ +shows how to create aliases with options:" R"( + +(lldb) command alias bfl breakpoint set -f %1 -l %2 + +)" " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ +options already part of the alias. So if the user wants to set a breakpoint \ +by file and line without explicitly having to use the -f and -l options, the \ +user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ +for the actual arguments that will be passed when the alias command is used. \ +The number in the placeholder refers to the position/order the actual value \ +occupies when the alias is used. All the occurrences of '%1' in the alias \ +will be replaced with the first argument, all the occurrences of '%2' in the \ +alias will be replaced with the second argument, and so on. This also allows \ +actual arguments to be used multiple times within an alias (see 'process \ +launch' example below)." R"( + +)" "Note: the positional arguments must substitute as whole words in the resultant \ +command, so you can't at present do something like this to append the file extension \ +\".cpp\":" R"( + +(lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2 + +)" "For more complex aliasing, use the \"command regex\" command instead. In the \ +'bfl' case above, the actual file value will be filled in with the first argument \ +following 'bfl' and the actual line number value will be filled in with the second \ +argument. The user would use this alias as follows:" R"( + +(lldb) command alias bfl breakpoint set -f %1 -l %2 +(lldb) bfl my-file.c 137 + +This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'. + +Another example: + +(lldb) command alias pltty process launch -s -o %1 -e %1 +(lldb) pltty /dev/tty0 + + Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0' + +)" "If the user always wanted to pass the same value to a particular option, the \ +alias could be defined with that value directly in the alias as a constant, \ +rather than using a positional placeholder:" R"( + +(lldb) command alias bl3 breakpoint set -f %1 -l 3 + + Always sets a breakpoint on line 3 of whatever file is indicated.)" + ); CommandArgumentEntry arg1; CommandArgumentEntry arg2; @@ -963,31 +974,30 @@ public: IOHandlerDelegateMultiline ("", IOHandlerDelegate::Completion::LLDBCommand), m_options (interpreter) { - SetHelpLong( -"This command allows the user to create powerful regular expression commands\n" -"with substitutions. The regular expressions and substitutions are specified\n" -"using the regular expression substitution format of:\n" -"\n" -" s/<regex>/<subst>/\n" -"\n" -"<regex> is a regular expression that can use parenthesis to capture regular\n" -"expression input and substitute the captured matches in the output using %1\n" -"for the first match, %2 for the second, and so on.\n" -"\n" -"The regular expressions can all be specified on the command line if more than\n" -"one argument is provided. If just the command name is provided on the command\n" -"line, then the regular expressions and substitutions can be entered on separate\n" -" lines, followed by an empty line to terminate the command definition.\n" -"\n" -"EXAMPLES\n" -"\n" -"The following example will define a regular expression command named 'f' that\n" -"will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n" -"a number follows 'f':\n" -"\n" -" (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n" -"\n" - ); + SetHelpLong(R"( +)" "This command allows the user to create powerful regular expression commands \ +with substitutions. The regular expressions and substitutions are specified \ +using the regular expression substitution format of:" R"( + + s/<regex>/<subst>/ + +)" "<regex> is a regular expression that can use parenthesis to capture regular \ +expression input and substitute the captured matches in the output using %1 \ +for the first match, %2 for the second, and so on." R"( + +)" "The regular expressions can all be specified on the command line if more than \ +one argument is provided. If just the command name is provided on the command \ +line, then the regular expressions and substitutions can be entered on separate \ +lines, followed by an empty line to terminate the command definition." R"( + +EXAMPLES + +)" "The following example will define a regular expression command named 'f' that \ +will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ +a number follows 'f':" R"( + + (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')" + ); } ~CommandObjectCommandsAddRegex() @@ -1430,6 +1440,130 @@ protected: }; +class CommandObjectScriptingObject : public CommandObjectRaw +{ +private: + StructuredData::GenericSP m_cmd_obj_sp; + ScriptedCommandSynchronicity m_synchro; + bool m_fetched_help_short:1; + bool m_fetched_help_long:1; + +public: + + CommandObjectScriptingObject (CommandInterpreter &interpreter, + std::string name, + StructuredData::GenericSP cmd_obj_sp, + ScriptedCommandSynchronicity synch) : + CommandObjectRaw (interpreter, + name.c_str(), + NULL, + NULL), + m_cmd_obj_sp(cmd_obj_sp), + m_synchro(synch), + m_fetched_help_short(false), + m_fetched_help_long(false) + { + StreamString stream; + stream.Printf("For more information run 'help %s'",name.c_str()); + SetHelp(stream.GetData()); + if (ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter()) + GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); + } + + virtual + ~CommandObjectScriptingObject () + { + } + + virtual bool + IsRemovable () const + { + return true; + } + + StructuredData::GenericSP + GetImplementingObject () + { + return m_cmd_obj_sp; + } + + ScriptedCommandSynchronicity + GetSynchronicity () + { + return m_synchro; + } + + virtual const char * + GetHelp () + { + if (!m_fetched_help_short) + { + ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); + if (scripter) + { + std::string docstring; + m_fetched_help_short = scripter->GetShortHelpForCommandObject(m_cmd_obj_sp,docstring); + if (!docstring.empty()) + SetHelp(docstring); + } + } + return CommandObjectRaw::GetHelp(); + } + + virtual const char * + GetHelpLong () + { + if (!m_fetched_help_long) + { + ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); + if (scripter) + { + std::string docstring; + m_fetched_help_long = scripter->GetLongHelpForCommandObject(m_cmd_obj_sp,docstring); + if (!docstring.empty()) + SetHelpLong(docstring); + } + } + return CommandObjectRaw::GetHelpLong(); + } + +protected: + virtual bool + DoExecute (const char *raw_command_line, CommandReturnObject &result) + { + ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); + + Error error; + + result.SetStatus(eReturnStatusInvalid); + + if (!scripter || scripter->RunScriptBasedCommand(m_cmd_obj_sp, + raw_command_line, + m_synchro, + result, + error, + m_exe_ctx) == false) + { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } + else + { + // Don't change the status if the command already set it... + if (result.GetStatus() == eReturnStatusInvalid) + { + if (result.GetOutputData() == NULL || result.GetOutputData()[0] == '\0') + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusSuccessFinishResult); + } + } + + return result.Succeeded(); + } + +}; + //------------------------------------------------------------------------- // CommandObjectCommandsScriptImport //------------------------------------------------------------------------- @@ -1449,7 +1583,7 @@ public: // Define the first (and only) variant of this arg. cmd_arg.arg_type = eArgTypeFilename; - cmd_arg.arg_repetition = eArgRepeatPlain; + cmd_arg.arg_repetition = eArgRepeatPlus; // There is only one variant this argument could be; put it into the argument entry. arg1.push_back (cmd_arg); @@ -1549,7 +1683,6 @@ protected: bool DoExecute (Args& command, CommandReturnObject &result) { - if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { result.AppendError ("only scripting language supported for module importing is currently Python"); @@ -1558,36 +1691,40 @@ protected: } size_t argc = command.GetArgumentCount(); - - if (argc != 1) + if (0 == argc) { - result.AppendError ("'command script import' requires one argument"); + result.AppendError("command script import needs one or more arguments"); result.SetStatus (eReturnStatusFailed); return false; } - std::string path = command.GetArgumentAtIndex(0); - Error error; - - const bool init_session = true; - // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that - // commands won't ever be recursively invoked, but it's actually possible to craft - // a Python script that does other "command script imports" in __lldb_init_module - // the real fix is to have recursive commands possible with a CommandInvocation object - // separate from the CommandObject itself, so that recursive command invocations - // won't stomp on each other (wrt to execution contents, options, and more) - m_exe_ctx.Clear(); - if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(), - m_options.m_allow_reload, - init_session, - error)) - { - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else + for (size_t i = 0; + i < argc; + i++) { - result.AppendErrorWithFormat("module importing failed: %s", error.AsCString()); - result.SetStatus (eReturnStatusFailed); + std::string path = command.GetArgumentAtIndex(i); + Error error; + + const bool init_session = true; + // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that + // commands won't ever be recursively invoked, but it's actually possible to craft + // a Python script that does other "command script imports" in __lldb_init_module + // the real fix is to have recursive commands possible with a CommandInvocation object + // separate from the CommandObject itself, so that recursive command invocations + // won't stomp on each other (wrt to execution contents, options, and more) + m_exe_ctx.Clear(); + if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(), + m_options.m_allow_reload, + init_session, + error)) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat("module importing failed: %s", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } } return result.Succeeded(); @@ -1652,7 +1789,11 @@ protected: public: CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter) + Options (interpreter), + m_class_name(), + m_funct_name(), + m_short_help(), + m_synchronicity(eScriptedCommandSynchronicitySynchronous) { } @@ -1671,6 +1812,10 @@ protected: if (option_arg) m_funct_name.assign(option_arg); break; + case 'c': + if (option_arg) + m_class_name.assign(option_arg); + break; case 'h': if (option_arg) m_short_help.assign(option_arg); @@ -1691,6 +1836,7 @@ protected: void OptionParsingStarting () { + m_class_name.clear(); m_funct_name.clear(); m_short_help.clear(); m_synchronicity = eScriptedCommandSynchronicitySynchronous; @@ -1708,6 +1854,7 @@ protected: // Instance variables to hold the values for command options. + std::string m_class_name; std::string m_funct_name; std::string m_short_help; ScriptedCommandSynchronicity m_synchronicity; @@ -1812,20 +1959,55 @@ protected: m_short_help.assign(m_options.m_short_help); m_synchronicity = m_options.m_synchronicity; - if (m_options.m_funct_name.empty()) + if (m_options.m_class_name.empty()) { - m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt - *this, // IOHandlerDelegate - true, // Run IOHandler in async mode - NULL); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + if (m_options.m_funct_name.empty()) + { + m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + NULL); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + } + else + { + CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter, + m_cmd_name, + m_options.m_funct_name, + m_options.m_short_help, + m_synchronicity)); + if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError("cannot add command"); + result.SetStatus (eReturnStatusFailed); + } + } } else { - CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter, - m_cmd_name, - m_options.m_funct_name, - m_options.m_short_help, - m_synchronicity)); + ScriptInterpreter *interpreter = GetCommandInterpreter().GetScriptInterpreter(); + if (!interpreter) + { + result.AppendError("cannot find ScriptInterpreter"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + auto cmd_obj_sp = interpreter->CreateScriptCommandObject(m_options.m_class_name.c_str()); + if (!cmd_obj_sp) + { + result.AppendError("cannot create helper object"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + CommandObjectSP new_cmd(new CommandObjectScriptingObject(m_interpreter, + m_cmd_name, + cmd_obj_sp, + m_synchronicity)); if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { result.SetStatus (eReturnStatusSuccessFinishNoResult); @@ -1859,8 +2041,9 @@ OptionDefinition CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."}, + { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name."}, { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeHelpText, "The help text to display for this command."}, - { LLDB_OPT_SET_1, false, "synchronicity", 's', OptionParser::eRequiredArgument, NULL, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."}, + { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, NULL, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; |