aboutsummaryrefslogtreecommitdiff
path: root/source/Commands/CommandObjectWatchpointCommand.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Commands/CommandObjectWatchpointCommand.cpp')
-rw-r--r--source/Commands/CommandObjectWatchpointCommand.cpp1037
1 files changed, 499 insertions, 538 deletions
diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp
index 0ae1850b5e28..1860d4cca9fe 100644
--- a/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -13,16 +13,16 @@
// Other libraries and framework includes
// Project includes
-#include "CommandObjectWatchpointCommand.h"
#include "CommandObjectWatchpoint.h"
+#include "CommandObjectWatchpointCommand.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/IOHandler.h"
+#include "lldb/Core/State.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
-#include "lldb/Breakpoint/Watchpoint.h"
-#include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/State.h"
using namespace lldb;
using namespace lldb_private;
@@ -31,43 +31,72 @@ using namespace lldb_private;
// CommandObjectWatchpointCommandAdd
//-------------------------------------------------------------------------
-class CommandObjectWatchpointCommandAdd :
- public CommandObjectParsed,
- public IOHandlerDelegateMultiline
-{
+// FIXME: "script-type" needs to have its contents determined dynamically, so
+// somebody can add a new scripting
+// language to lldb and have it pickable here without having to change this
+// enumeration by hand and rebuild lldb proper.
+
+static OptionEnumValueElement g_script_option_enumeration[4] = {
+ {eScriptLanguageNone, "command",
+ "Commands are in the lldb command interpreter language"},
+ {eScriptLanguagePython, "python", "Commands are in the Python language."},
+ {eSortOrderByName, "default-script",
+ "Commands are in the default scripting language."},
+ {0, nullptr, nullptr}};
+
+static OptionDefinition g_watchpoint_command_add_options[] = {
+ // clang-format off
+ { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOneLiner, "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
+ { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Specify whether watchpoint command execution should terminate on error." },
+ { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, nullptr, g_script_option_enumeration, 0, eArgTypeNone, "Specify the language for the commands - if none is specified, the lldb command interpreter will be used." },
+ { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate." }
+ // clang-format on
+};
+
+class CommandObjectWatchpointCommandAdd : public CommandObjectParsed,
+ public IOHandlerDelegateMultiline {
public:
- CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter)
- : CommandObjectParsed(
- interpreter, "add",
- "Add a set of LLDB commands to a watchpoint, to be executed whenever the watchpoint is hit.", nullptr),
- IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand),
- m_options(interpreter)
- {
- SetHelpLong (
-R"(
+ CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "add",
+ "Add a set of LLDB commands to a watchpoint, to be "
+ "executed whenever the watchpoint is hit.",
+ nullptr),
+ IOHandlerDelegateMultiline("DONE",
+ IOHandlerDelegate::Completion::LLDBCommand),
+ m_options() {
+ SetHelpLong(
+ R"(
General information about entering watchpoint commands
------------------------------------------------------
-)" "This command will prompt for commands to be executed when the specified \
+)"
+ "This command will prompt for commands to be executed when the specified \
watchpoint is hit. Each command is typed on its own line following the '> ' \
-prompt until 'DONE' is entered." R"(
+prompt until 'DONE' is entered."
+ R"(
-)" "Syntactic errors may not be detected when initially entered, and many \
+)"
+ "Syntactic errors may not be detected when initially entered, and many \
malformed commands can silently fail when executed. If your watchpoint commands \
-do not appear to be executing, double-check the command syntax." R"(
+do not appear to be executing, double-check the command syntax."
+ R"(
-)" "Note: You may enter any debugger command exactly as you would at the debugger \
+)"
+ "Note: You may enter any debugger command exactly as you would at the debugger \
prompt. There is no limit to the number of commands supplied, but do NOT enter \
-more than one command per line." R"(
+more than one command per line."
+ R"(
Special information about PYTHON watchpoint commands
----------------------------------------------------
-)" "You may enter either one or more lines of Python, including function \
+)"
+ "You may enter either one or more lines of Python, including function \
definitions or calls to functions that will have been imported by the time \
the code executes. Single line watchpoint commands will be interpreted 'as is' \
when the watchpoint is hit. Multiple lines of Python will be wrapped in a \
-generated function, and a call to the function will be attached to the watchpoint." R"(
+generated function, and a call to the function will be attached to the watchpoint."
+ R"(
This auto-generated function is passed in three arguments:
@@ -75,8 +104,10 @@ This auto-generated function is passed in three arguments:
wp: the watchpoint that was hit.
-)" "When specifying a python function with the --python-function option, you need \
-to supply the function name prepended by the module name:" R"(
+)"
+ "When specifying a python function with the --python-function option, you need \
+to supply the function name prepended by the module name:"
+ R"(
--python-function myutils.watchpoint_callback
@@ -85,16 +116,20 @@ The function itself must have the following prototype:
def watchpoint_callback(frame, wp):
# Your code goes here
-)" "The arguments are the same as the arguments passed to generated functions as \
+)"
+ "The arguments are the same as the arguments passed to generated functions as \
described above. Note that the global variable 'lldb.frame' will NOT be updated when \
this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
can get you to the thread via frame.GetThread(), the thread can get you to the \
process via thread.GetProcess(), and the process can get you back to the target \
-via process.GetTarget()." R"(
+via process.GetTarget()."
+ R"(
-)" "Important Note: As Python code gets collected into functions, access to global \
+)"
+ "Important Note: As Python code gets collected into functions, access to global \
variables requires explicit scoping using the 'global' keyword. Be sure to use correct \
-Python syntax, including indentation, when entering Python watchpoint commands." R"(
+Python syntax, including indentation, when entering Python watchpoint commands."
+ R"(
Example Python one-line watchpoint command:
@@ -139,590 +174,516 @@ Enter your Python command(s). Type 'DONE' to end.
> print "Hit this watchpoint " + repr(wp_count) + " times!"
> DONE
-)" "In this case, since there is a reference to a global variable, \
+)"
+ "In this case, since there is a reference to a global variable, \
'wp_count', you will also need to make sure 'wp_count' exists and is \
-initialized:" R"(
+initialized:"
+ R"(
(lldb) script
>>> wp_count = 0
>>> quit()
-)" "Final Note: A warning that no watchpoint command was generated when there \
-are no syntax errors may indicate that a function was declared but never called."
- );
+)"
+ "Final Note: A warning that no watchpoint command was generated when there \
+are no syntax errors may indicate that a function was declared but never called.");
- CommandArgumentEntry arg;
- CommandArgumentData wp_id_arg;
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
- // Define the first (and only) variant of this arg.
- wp_id_arg.arg_type = eArgTypeWatchpointID;
- wp_id_arg.arg_repetition = eArgRepeatPlain;
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
- // There is only one variant this argument could be; put it into the argument entry.
- arg.push_back (wp_id_arg);
+ // There is only one variant this argument could be; put it into the
+ // argument entry.
+ arg.push_back(wp_id_arg);
- // Push the data for the first argument into the m_arguments vector.
- m_arguments.push_back (arg);
- }
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back(arg);
+ }
- ~CommandObjectWatchpointCommandAdd() override = default;
+ ~CommandObjectWatchpointCommandAdd() override = default;
- Options *
- GetOptions () override
- {
- return &m_options;
- }
+ Options *GetOptions() override { return &m_options; }
- void
- IOHandlerActivated (IOHandler &io_handler) override
- {
- StreamFileSP output_sp(io_handler.GetOutputStreamFile());
- if (output_sp)
- {
- output_sp->PutCString("Enter your debugger command(s). Type 'DONE' to end.\n");
- output_sp->Flush();
- }
+ void IOHandlerActivated(IOHandler &io_handler) override {
+ StreamFileSP output_sp(io_handler.GetOutputStreamFile());
+ if (output_sp) {
+ output_sp->PutCString(
+ "Enter your debugger command(s). Type 'DONE' to end.\n");
+ output_sp->Flush();
}
-
- void
- IOHandlerInputComplete (IOHandler &io_handler, std::string &line) override
- {
- io_handler.SetIsDone(true);
-
- // The WatchpointOptions object is owned by the watchpoint or watchpoint location
- WatchpointOptions *wp_options = (WatchpointOptions *) io_handler.GetUserData();
- if (wp_options)
- {
- std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
- if (data_ap)
- {
- data_ap->user_source.SplitIntoLines(line);
- BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
- wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
- }
- }
+ }
+
+ void IOHandlerInputComplete(IOHandler &io_handler,
+ std::string &line) override {
+ io_handler.SetIsDone(true);
+
+ // The WatchpointOptions object is owned by the watchpoint or watchpoint
+ // location
+ WatchpointOptions *wp_options =
+ (WatchpointOptions *)io_handler.GetUserData();
+ if (wp_options) {
+ std::unique_ptr<WatchpointOptions::CommandData> data_ap(
+ new WatchpointOptions::CommandData());
+ if (data_ap) {
+ data_ap->user_source.SplitIntoLines(line);
+ auto baton_sp = std::make_shared<WatchpointOptions::CommandBaton>(
+ std::move(data_ap));
+ wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
+ }
}
-
- void
- CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
- CommandReturnObject &result)
- {
- m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt
- *this, // IOHandlerDelegate
- true, // Run IOHandler in async mode
- wp_options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
+ }
+
+ void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
+ CommandReturnObject &result) {
+ m_interpreter.GetLLDBCommandsFromIOHandler(
+ "> ", // Prompt
+ *this, // IOHandlerDelegate
+ true, // Run IOHandler in async mode
+ wp_options); // Baton for the "io_handler" that will be passed back into
+ // our IOHandlerDelegate functions
+ }
+
+ /// Set a one-liner as the callback for the watchpoint.
+ void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
+ const char *oneliner) {
+ std::unique_ptr<WatchpointOptions::CommandData> data_ap(
+ new WatchpointOptions::CommandData());
+
+ // It's necessary to set both user_source and script_source to the oneliner.
+ // The former is used to generate callback description (as in watchpoint
+ // command list)
+ // while the latter is used for Python to interpret during the actual
+ // callback.
+ data_ap->user_source.AppendString(oneliner);
+ data_ap->script_source.assign(oneliner);
+ data_ap->stop_on_error = m_options.m_stop_on_error;
+
+ auto baton_sp =
+ std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_ap));
+ wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
+ }
+
+ static bool
+ WatchpointOptionsCallbackFunction(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t watch_id) {
+ bool ret_value = true;
+ if (baton == nullptr)
+ return true;
+
+ WatchpointOptions::CommandData *data =
+ (WatchpointOptions::CommandData *)baton;
+ StringList &commands = data->user_source;
+
+ if (commands.GetSize() > 0) {
+ ExecutionContext exe_ctx(context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ CommandReturnObject result;
+ Debugger &debugger = target->GetDebugger();
+ // Rig up the results secondary output stream to the debugger's, so the
+ // output will come out synchronously
+ // if the debugger is set up that way.
+
+ StreamSP output_stream(debugger.GetAsyncOutputStream());
+ StreamSP error_stream(debugger.GetAsyncErrorStream());
+ result.SetImmediateOutputStream(output_stream);
+ result.SetImmediateErrorStream(error_stream);
+
+ CommandInterpreterRunOptions options;
+ options.SetStopOnContinue(true);
+ options.SetStopOnError(data->stop_on_error);
+ options.SetEchoCommands(false);
+ options.SetPrintResults(true);
+ options.SetAddToHistory(false);
+
+ debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
+ options, result);
+ result.GetImmediateOutputStream()->Flush();
+ result.GetImmediateErrorStream()->Flush();
+ }
}
-
- /// Set a one-liner as the callback for the watchpoint.
- void
- SetWatchpointCommandCallback (WatchpointOptions *wp_options,
- const char *oneliner)
- {
- std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
-
- // It's necessary to set both user_source and script_source to the oneliner.
- // The former is used to generate callback description (as in watchpoint command list)
- // while the latter is used for Python to interpret during the actual callback.
- data_ap->user_source.AppendString (oneliner);
- data_ap->script_source.assign (oneliner);
- data_ap->stop_on_error = m_options.m_stop_on_error;
-
- BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
- wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
+ return ret_value;
+ }
+
+ class CommandOptions : public Options {
+ public:
+ CommandOptions()
+ : Options(), m_use_commands(false), m_use_script_language(false),
+ m_script_language(eScriptLanguageNone), m_use_one_liner(false),
+ m_one_liner(), m_function_name() {}
+
+ ~CommandOptions() override = default;
+
+ Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option) {
+ case 'o':
+ m_use_one_liner = true;
+ m_one_liner = option_arg;
+ break;
+
+ case 's':
+ m_script_language = (lldb::ScriptLanguage)Args::StringToOptionEnum(
+ option_arg, GetDefinitions()[option_idx].enum_values,
+ eScriptLanguageNone, error);
+
+ m_use_script_language = (m_script_language == eScriptLanguagePython ||
+ m_script_language == eScriptLanguageDefault);
+ break;
+
+ case 'e': {
+ bool success = false;
+ m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
+ if (!success)
+ error.SetErrorStringWithFormat(
+ "invalid value for stop-on-error: \"%s\"",
+ option_arg.str().c_str());
+ } break;
+
+ case 'F':
+ m_use_one_liner = false;
+ m_use_script_language = true;
+ m_function_name.assign(option_arg);
+ break;
+
+ default:
+ break;
+ }
+ return error;
}
-
- static bool
- WatchpointOptionsCallbackFunction (void *baton,
- StoppointCallbackContext *context,
- lldb::user_id_t watch_id)
- {
- bool ret_value = true;
- if (baton == nullptr)
- return true;
-
- WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton;
- StringList &commands = data->user_source;
-
- if (commands.GetSize() > 0)
- {
- ExecutionContext exe_ctx (context->exe_ctx_ref);
- Target *target = exe_ctx.GetTargetPtr();
- if (target)
- {
- CommandReturnObject result;
- Debugger &debugger = target->GetDebugger();
- // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
- // if the debugger is set up that way.
-
- StreamSP output_stream (debugger.GetAsyncOutputStream());
- StreamSP error_stream (debugger.GetAsyncErrorStream());
- result.SetImmediateOutputStream (output_stream);
- result.SetImmediateErrorStream (error_stream);
-
- CommandInterpreterRunOptions options;
- options.SetStopOnContinue (true);
- options.SetStopOnError (data->stop_on_error);
- options.SetEchoCommands (false);
- options.SetPrintResults (true);
- options.SetAddToHistory (false);
-
- debugger.GetCommandInterpreter().HandleCommands (commands,
- &exe_ctx,
- options,
- result);
- result.GetImmediateOutputStream()->Flush();
- result.GetImmediateErrorStream()->Flush();
- }
- }
- return ret_value;
- }
-
- class CommandOptions : public Options
- {
- public:
- CommandOptions (CommandInterpreter &interpreter) :
- Options (interpreter),
- m_use_commands (false),
- m_use_script_language (false),
- m_script_language (eScriptLanguageNone),
- m_use_one_liner (false),
- m_one_liner(),
- m_function_name()
- {
- }
- ~CommandOptions() override = default;
-
- Error
- SetOptionValue (uint32_t option_idx, const char *option_arg) override
- {
- Error error;
- const int short_option = m_getopt_table[option_idx].val;
-
- switch (short_option)
- {
- case 'o':
- m_use_one_liner = true;
- m_one_liner = option_arg;
- break;
-
- case 's':
- m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
- g_option_table[option_idx].enum_values,
- eScriptLanguageNone,
- error);
-
- m_use_script_language =
- (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault);
- break;
-
- case 'e':
- {
- bool success = false;
- m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
- if (!success)
- error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
- }
- break;
-
- case 'F':
- m_use_one_liner = false;
- m_use_script_language = true;
- m_function_name.assign(option_arg);
- break;
-
- default:
- break;
- }
- return error;
- }
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_use_commands = true;
+ m_use_script_language = false;
+ m_script_language = eScriptLanguageNone;
- void
- OptionParsingStarting () override
- {
- m_use_commands = true;
- m_use_script_language = false;
- m_script_language = eScriptLanguageNone;
-
- m_use_one_liner = false;
- m_stop_on_error = true;
- m_one_liner.clear();
- m_function_name.clear();
- }
-
- const OptionDefinition*
- GetDefinitions () override
- {
- return g_option_table;
- }
-
- // Options table: Required for subclasses of Options.
+ m_use_one_liner = false;
+ m_stop_on_error = true;
+ m_one_liner.clear();
+ m_function_name.clear();
+ }
- static OptionDefinition g_option_table[];
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::makeArrayRef(g_watchpoint_command_add_options);
+ }
- // Instance variables to hold the values for command options.
+ // Instance variables to hold the values for command options.
- bool m_use_commands;
- bool m_use_script_language;
- lldb::ScriptLanguage m_script_language;
+ bool m_use_commands;
+ bool m_use_script_language;
+ lldb::ScriptLanguage m_script_language;
- // Instance variables to hold the values for one_liner options.
- bool m_use_one_liner;
- std::string m_one_liner;
- bool m_stop_on_error;
- std::string m_function_name;
- };
+ // Instance variables to hold the values for one_liner options.
+ bool m_use_one_liner;
+ std::string m_one_liner;
+ bool m_stop_on_error;
+ std::string m_function_name;
+ };
protected:
- bool
- DoExecute (Args& command, CommandReturnObject &result) override
- {
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
-
- if (target == nullptr)
- {
- result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- const WatchpointList &watchpoints = target->GetWatchpointList();
- size_t num_watchpoints = watchpoints.GetSize();
-
- if (num_watchpoints == 0)
- {
- result.AppendError ("No watchpoints exist to have commands added");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- if (!m_options.m_use_script_language && !m_options.m_function_name.empty())
- {
- result.AppendError ("need to enable scripting to have a function run as a watchpoint command");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
-
- std::vector<uint32_t> valid_wp_ids;
- if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
- {
- result.AppendError("Invalid watchpoints specification.");
- result.SetStatus(eReturnStatusFailed);
- return false;
- }
-
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- const size_t count = valid_wp_ids.size();
- for (size_t i = 0; i < count; ++i)
- {
- uint32_t cur_wp_id = valid_wp_ids.at (i);
- if (cur_wp_id != LLDB_INVALID_WATCH_ID)
- {
- Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
- // Sanity check wp first.
- if (wp == nullptr) continue;
-
- WatchpointOptions *wp_options = wp->GetOptions();
- // Skip this watchpoint if wp_options is not good.
- if (wp_options == nullptr) continue;
-
- // If we are using script language, get the script interpreter
- // in order to set or collect command callback. Otherwise, call
- // the methods associated with this object.
- if (m_options.m_use_script_language)
- {
- // Special handling for one-liner specified inline.
- if (m_options.m_use_one_liner)
- {
- m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
- m_options.m_one_liner.c_str());
- }
- // Special handling for using a Python function by name
- // instead of extending the watchpoint callback data structures, we just automatize
- // what the user would do manually: make their watchpoint command be a function call
- else if (!m_options.m_function_name.empty())
- {
- std::string oneliner(m_options.m_function_name);
- oneliner += "(frame, wp, internal_dict)";
- m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
- oneliner.c_str());
- }
- else
- {
- m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options,
- result);
- }
- }
- else
- {
- // Special handling for one-liner specified inline.
- if (m_options.m_use_one_liner)
- SetWatchpointCommandCallback (wp_options,
- m_options.m_one_liner.c_str());
- else
- CollectDataForWatchpointCommandCallback (wp_options,
- result);
- }
- }
- }
-
- return result.Succeeded();
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == nullptr) {
+ result.AppendError("There is not a current executable; there are no "
+ "watchpoints to which to add commands");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
}
-private:
- CommandOptions m_options;
-};
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
-// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
-// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
+ if (num_watchpoints == 0) {
+ result.AppendError("No watchpoints exist to have commands added");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
-static OptionEnumValueElement
-g_script_option_enumeration[4] =
-{
- { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"},
- { eScriptLanguagePython, "python", "Commands are in the Python language."},
- { eSortOrderByName, "default-script", "Commands are in the default scripting language."},
- { 0, nullptr, nullptr }
-};
+ if (!m_options.m_use_script_language &&
+ !m_options.m_function_name.empty()) {
+ result.AppendError("need to enable scripting to have a function run as a "
+ "watchpoint command");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
-OptionDefinition
-CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
-{
- { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOneLiner,
- "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
+ valid_wp_ids)) {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean,
- "Specify whether watchpoint command execution should terminate on error." },
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i) {
+ uint32_t cur_wp_id = valid_wp_ids.at(i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
+ Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
+ // Sanity check wp first.
+ if (wp == nullptr)
+ continue;
+
+ WatchpointOptions *wp_options = wp->GetOptions();
+ // Skip this watchpoint if wp_options is not good.
+ if (wp_options == nullptr)
+ continue;
+
+ // If we are using script language, get the script interpreter
+ // in order to set or collect command callback. Otherwise, call
+ // the methods associated with this object.
+ if (m_options.m_use_script_language) {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner) {
+ m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback(
+ wp_options, m_options.m_one_liner.c_str());
+ }
+ // Special handling for using a Python function by name
+ // instead of extending the watchpoint callback data structures, we
+ // just automatize
+ // what the user would do manually: make their watchpoint command be a
+ // function call
+ else if (!m_options.m_function_name.empty()) {
+ std::string oneliner(m_options.m_function_name);
+ oneliner += "(frame, wp, internal_dict)";
+ m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback(
+ wp_options, oneliner.c_str());
+ } else {
+ m_interpreter.GetScriptInterpreter()
+ ->CollectDataForWatchpointCommandCallback(wp_options, result);
+ }
+ } else {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ SetWatchpointCommandCallback(wp_options,
+ m_options.m_one_liner.c_str());
+ else
+ CollectDataForWatchpointCommandCallback(wp_options, result);
+ }
+ }
+ }
- { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, nullptr, g_script_option_enumeration, 0, eArgTypeNone,
- "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
+ return result.Succeeded();
+ }
- { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction,
- "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
-
- { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
+private:
+ CommandOptions m_options;
};
//-------------------------------------------------------------------------
// CommandObjectWatchpointCommandDelete
//-------------------------------------------------------------------------
-class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
-{
+class CommandObjectWatchpointCommandDelete : public CommandObjectParsed {
public:
- CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) :
- CommandObjectParsed(interpreter,
- "delete",
+ CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "delete",
"Delete the set of commands from a watchpoint.",
- nullptr)
- {
- CommandArgumentEntry arg;
- CommandArgumentData wp_id_arg;
+ nullptr) {
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
- // Define the first (and only) variant of this arg.
- wp_id_arg.arg_type = eArgTypeWatchpointID;
- wp_id_arg.arg_repetition = eArgRepeatPlain;
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
- // There is only one variant this argument could be; put it into the argument entry.
- arg.push_back (wp_id_arg);
+ // There is only one variant this argument could be; put it into the
+ // argument entry.
+ arg.push_back(wp_id_arg);
- // Push the data for the first argument into the m_arguments vector.
- m_arguments.push_back (arg);
- }
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back(arg);
+ }
- ~CommandObjectWatchpointCommandDelete() override = default;
+ ~CommandObjectWatchpointCommandDelete() override = default;
protected:
- bool
- DoExecute (Args& command, CommandReturnObject &result) override
- {
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
-
- if (target == nullptr)
- {
- result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == nullptr) {
+ result.AppendError("There is not a current executable; there are no "
+ "watchpoints from which to delete commands");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- const WatchpointList &watchpoints = target->GetWatchpointList();
- size_t num_watchpoints = watchpoints.GetSize();
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
- if (num_watchpoints == 0)
- {
- result.AppendError ("No watchpoints exist to have commands deleted");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
+ if (num_watchpoints == 0) {
+ result.AppendError("No watchpoints exist to have commands deleted");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- if (command.GetArgumentCount() == 0)
- {
- result.AppendError ("No watchpoint specified from which to delete the commands");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
+ if (command.GetArgumentCount() == 0) {
+ result.AppendError(
+ "No watchpoint specified from which to delete the commands");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- std::vector<uint32_t> valid_wp_ids;
- if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
- {
- result.AppendError("Invalid watchpoints specification.");
- result.SetStatus(eReturnStatusFailed);
- return false;
- }
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
+ valid_wp_ids)) {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- const size_t count = valid_wp_ids.size();
- for (size_t i = 0; i < count; ++i)
- {
- uint32_t cur_wp_id = valid_wp_ids.at (i);
- if (cur_wp_id != LLDB_INVALID_WATCH_ID)
- {
- Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
- if (wp)
- wp->ClearCallback();
- }
- else
- {
- result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
- cur_wp_id);
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
- }
- return result.Succeeded();
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i) {
+ uint32_t cur_wp_id = valid_wp_ids.at(i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
+ Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
+ if (wp)
+ wp->ClearCallback();
+ } else {
+ result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
}
+ return result.Succeeded();
+ }
};
//-------------------------------------------------------------------------
// CommandObjectWatchpointCommandList
//-------------------------------------------------------------------------
-class CommandObjectWatchpointCommandList : public CommandObjectParsed
-{
+class CommandObjectWatchpointCommandList : public CommandObjectParsed {
public:
- CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) :
- CommandObjectParsed(interpreter,
- "list",
- "List the script or set of commands to be executed when the watchpoint is hit.",
- nullptr)
- {
- CommandArgumentEntry arg;
- CommandArgumentData wp_id_arg;
-
- // Define the first (and only) variant of this arg.
- wp_id_arg.arg_type = eArgTypeWatchpointID;
- wp_id_arg.arg_repetition = eArgRepeatPlain;
-
- // There is only one variant this argument could be; put it into the argument entry.
- arg.push_back (wp_id_arg);
-
- // Push the data for the first argument into the m_arguments vector.
- m_arguments.push_back (arg);
- }
+ CommandObjectWatchpointCommandList(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "list", "List the script or set of "
+ "commands to be executed when "
+ "the watchpoint is hit.",
+ nullptr) {
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
- ~CommandObjectWatchpointCommandList() override = default;
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the
+ // argument entry.
+ arg.push_back(wp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ ~CommandObjectWatchpointCommandList() override = default;
protected:
- bool
- DoExecute (Args& command, CommandReturnObject &result) override
- {
- Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
-
- if (target == nullptr)
- {
- result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == nullptr) {
+ result.AppendError("There is not a current executable; there are no "
+ "watchpoints for which to list commands");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- const WatchpointList &watchpoints = target->GetWatchpointList();
- size_t num_watchpoints = watchpoints.GetSize();
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
- if (num_watchpoints == 0)
- {
- result.AppendError ("No watchpoints exist for which to list commands");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
+ if (num_watchpoints == 0) {
+ result.AppendError("No watchpoints exist for which to list commands");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- if (command.GetArgumentCount() == 0)
- {
- result.AppendError ("No watchpoint specified for which to list the commands");
- result.SetStatus (eReturnStatusFailed);
- return false;
- }
+ if (command.GetArgumentCount() == 0) {
+ result.AppendError(
+ "No watchpoint specified for which to list the commands");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- std::vector<uint32_t> valid_wp_ids;
- if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
- {
- result.AppendError("Invalid watchpoints specification.");
- result.SetStatus(eReturnStatusFailed);
- return false;
- }
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
+ valid_wp_ids)) {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- const size_t count = valid_wp_ids.size();
- for (size_t i = 0; i < count; ++i)
- {
- uint32_t cur_wp_id = valid_wp_ids.at (i);
- if (cur_wp_id != LLDB_INVALID_WATCH_ID)
- {
- Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
-
- if (wp)
- {
- const WatchpointOptions *wp_options = wp->GetOptions();
- if (wp_options)
- {
- // Get the callback baton associated with the current watchpoint.
- const Baton *baton = wp_options->GetBaton();
- if (baton)
- {
- result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id);
- result.GetOutputStream().IndentMore ();
- baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
- result.GetOutputStream().IndentLess ();
- }
- else
- {
- result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n",
- cur_wp_id);
- }
- }
- result.SetStatus (eReturnStatusSuccessFinishResult);
- }
- else
- {
- result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
- result.SetStatus (eReturnStatusFailed);
- }
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i) {
+ uint32_t cur_wp_id = valid_wp_ids.at(i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
+ Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
+
+ if (wp) {
+ const WatchpointOptions *wp_options = wp->GetOptions();
+ if (wp_options) {
+ // Get the callback baton associated with the current watchpoint.
+ const Baton *baton = wp_options->GetBaton();
+ if (baton) {
+ result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id);
+ result.GetOutputStream().IndentMore();
+ baton->GetDescription(&result.GetOutputStream(),
+ eDescriptionLevelFull);
+ result.GetOutputStream().IndentLess();
+ } else {
+ result.AppendMessageWithFormat(
+ "Watchpoint %u does not have an associated command.\n",
+ cur_wp_id);
}
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
+ cur_wp_id);
+ result.SetStatus(eReturnStatusFailed);
}
-
- return result.Succeeded();
+ }
}
+
+ return result.Succeeded();
+ }
};
//-------------------------------------------------------------------------
// CommandObjectWatchpointCommand
//-------------------------------------------------------------------------
-CommandObjectWatchpointCommand::CommandObjectWatchpointCommand(CommandInterpreter &interpreter)
- : CommandObjectMultiword(interpreter, "command", "Commands for adding, removing and examining LLDB commands "
- "executed when the watchpoint is hit (watchpoint 'commmands').",
- "command <sub-command> [<sub-command-options>] <watchpoint-id>")
-{
- CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter));
- CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter));
- CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter));
-
- add_command_object->SetCommandName ("watchpoint command add");
- delete_command_object->SetCommandName ("watchpoint command delete");
- list_command_object->SetCommandName ("watchpoint command list");
-
- LoadSubCommand ("add", add_command_object);
- LoadSubCommand ("delete", delete_command_object);
- LoadSubCommand ("list", list_command_object);
+CommandObjectWatchpointCommand::CommandObjectWatchpointCommand(
+ CommandInterpreter &interpreter)
+ : CommandObjectMultiword(
+ interpreter, "command",
+ "Commands for adding, removing and examining LLDB commands "
+ "executed when the watchpoint is hit (watchpoint 'commmands').",
+ "command <sub-command> [<sub-command-options>] <watchpoint-id>") {
+ CommandObjectSP add_command_object(
+ new CommandObjectWatchpointCommandAdd(interpreter));
+ CommandObjectSP delete_command_object(
+ new CommandObjectWatchpointCommandDelete(interpreter));
+ CommandObjectSP list_command_object(
+ new CommandObjectWatchpointCommandList(interpreter));
+
+ add_command_object->SetCommandName("watchpoint command add");
+ delete_command_object->SetCommandName("watchpoint command delete");
+ list_command_object->SetCommandName("watchpoint command list");
+
+ LoadSubCommand("add", add_command_object);
+ LoadSubCommand("delete", delete_command_object);
+ LoadSubCommand("list", list_command_object);
}
CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default;