|  | //===-- CommandObjectWatchpointCommand.cpp ----------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "lldb/lldb-python.h" | 
|  |  | 
|  | // C Includes | 
|  | // C++ Includes | 
|  |  | 
|  |  | 
|  | #include "CommandObjectWatchpointCommand.h" | 
|  | #include "CommandObjectWatchpoint.h" | 
|  |  | 
|  | #include "lldb/Core/IOHandler.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" | 
|  |  | 
|  | #include <vector> | 
|  |  | 
|  | using namespace lldb; | 
|  | using namespace lldb_private; | 
|  |  | 
|  | //------------------------------------------------------------------------- | 
|  | // CommandObjectWatchpointCommandAdd | 
|  | //------------------------------------------------------------------------- | 
|  |  | 
|  |  | 
|  | class CommandObjectWatchpointCommandAdd : | 
|  | public CommandObjectParsed, | 
|  | public IOHandlerDelegateMultiline | 
|  | { | 
|  | public: | 
|  |  | 
|  | CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) : | 
|  | CommandObjectParsed (interpreter, | 
|  | "add", | 
|  | "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.", | 
|  | NULL), | 
|  | IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand), | 
|  | m_options (interpreter) | 
|  | { | 
|  | SetHelpLong ( | 
|  | "\nGeneral information about entering watchpoint commands \n\ | 
|  | ------------------------------------------------------ \n\ | 
|  | \n\ | 
|  | This command will cause you to be prompted to enter the command or set \n\ | 
|  | of commands you wish to be executed when the specified watchpoint is \n\ | 
|  | hit.  You will be told to enter your command(s), and will see a '> ' \n\ | 
|  | prompt. Because you can enter one or many commands to be executed when \n\ | 
|  | a watchpoint is hit, you will continue to be prompted after each \n\ | 
|  | new-line that you enter, until you enter the word 'DONE', which will \n\ | 
|  | cause the commands you have entered to be stored with the watchpoint \n\ | 
|  | and executed when the watchpoint is hit. \n\ | 
|  | \n\ | 
|  | Syntax checking is not necessarily done when watchpoint commands are \n\ | 
|  | entered.  An improperly written watchpoint command will attempt to get \n\ | 
|  | executed when the watchpoint gets hit, and usually silently fail.  If \n\ | 
|  | your watchpoint command does not appear to be getting executed, go \n\ | 
|  | back and check your syntax. \n\ | 
|  | \n\ | 
|  | \n\ | 
|  | Special information about PYTHON watchpoint commands                            \n\ | 
|  | ----------------------------------------------------                            \n\ | 
|  | \n\ | 
|  | You may enter either one line of Python or multiple lines of Python             \n\ | 
|  | (including defining whole functions, if desired).  If you enter a               \n\ | 
|  | single line of Python, that will be passed to the Python interpreter            \n\ | 
|  | 'as is' when the watchpoint gets hit.  If you enter function                    \n\ | 
|  | definitions, they will be passed to the Python interpreter as soon as           \n\ | 
|  | you finish entering the watchpoint command, and they can be called              \n\ | 
|  | later (don't forget to add calls to them, if you want them called when          \n\ | 
|  | the watchpoint is hit).  If you enter multiple lines of Python that             \n\ | 
|  | are not function definitions, they will be collected into a new,                \n\ | 
|  | automatically generated Python function, and a call to the newly                \n\ | 
|  | generated function will be attached to the watchpoint.                          \n\ | 
|  | \n\ | 
|  | This auto-generated function is passed in two arguments:                        \n\ | 
|  | \n\ | 
|  | frame:  an SBFrame object representing the frame which hit the watchpoint.  \n\ | 
|  | From the frame you can get back to the thread and process.          \n\ | 
|  | wp:     the watchpoint that was hit.                                        \n\ | 
|  | \n\ | 
|  | Important Note: Because loose Python code gets collected into functions,        \n\ | 
|  | if you want to access global variables in the 'loose' code, you need to         \n\ | 
|  | specify that they are global, using the 'global' keyword.  Be sure to           \n\ | 
|  | use correct Python syntax, including indentation, when entering Python          \n\ | 
|  | watchpoint commands.                                                            \n\ | 
|  | \n\ | 
|  | As a third option, you can pass the name of an already existing Python function \n\ | 
|  | and that function will be attached to the watchpoint. It will get passed the    \n\ | 
|  | frame and wp_loc arguments mentioned above.                                     \n\ | 
|  | \n\ | 
|  | Example Python one-line watchpoint command: \n\ | 
|  | \n\ | 
|  | (lldb) watchpoint command add -s python 1 \n\ | 
|  | Enter your Python command(s). Type 'DONE' to end. \n\ | 
|  | > print \"Hit this watchpoint!\" \n\ | 
|  | > DONE \n\ | 
|  | \n\ | 
|  | As a convenience, this also works for a short Python one-liner: \n\ | 
|  | (lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\ | 
|  | (lldb) run \n\ | 
|  | Launching '.../a.out'  (x86_64) \n\ | 
|  | (lldb) Fri Sep 10 12:17:45 2010 \n\ | 
|  | Process 21778 Stopped \n\ | 
|  | * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\ | 
|  | 36   	\n\ | 
|  | 37   	int c(int val)\n\ | 
|  | 38   	{\n\ | 
|  | 39 ->	    return val + 3;\n\ | 
|  | 40   	}\n\ | 
|  | 41   	\n\ | 
|  | 42   	int main (int argc, char const *argv[])\n\ | 
|  | (lldb) \n\ | 
|  | \n\ | 
|  | Example multiple line Python watchpoint command, using function definition: \n\ | 
|  | \n\ | 
|  | (lldb) watchpoint command add -s python 1 \n\ | 
|  | Enter your Python command(s). Type 'DONE' to end. \n\ | 
|  | > def watchpoint_output (wp_no): \n\ | 
|  | >     out_string = \"Hit watchpoint number \" + repr (wp_no) \n\ | 
|  | >     print out_string \n\ | 
|  | >     return True \n\ | 
|  | > watchpoint_output (1) \n\ | 
|  | > DONE \n\ | 
|  | \n\ | 
|  | \n\ | 
|  | Example multiple line Python watchpoint command, using 'loose' Python: \n\ | 
|  | \n\ | 
|  | (lldb) watchpoint command add -s p 1 \n\ | 
|  | Enter your Python command(s). Type 'DONE' to end. \n\ | 
|  | > global wp_count \n\ | 
|  | > wp_count = wp_count + 1 \n\ | 
|  | > print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\ | 
|  | > DONE \n\ | 
|  | \n\ | 
|  | In this case, since there is a reference to a global variable, \n\ | 
|  | 'wp_count', you will also need to make sure 'wp_count' exists and is \n\ | 
|  | initialized: \n\ | 
|  | \n\ | 
|  | (lldb) script \n\ | 
|  | >>> wp_count = 0 \n\ | 
|  | >>> quit() \n\ | 
|  | \n\ | 
|  | (lldb)  \n\ | 
|  | \n\ | 
|  | \n\ | 
|  | Final Note:  If you get a warning that no watchpoint command was generated, \n\ | 
|  | but you did not get any syntax errors, you probably forgot to add a call \n\ | 
|  | to your functions. \n\ | 
|  | \n\ | 
|  | Special information about debugger command watchpoint commands \n\ | 
|  | -------------------------------------------------------------- \n\ | 
|  | \n\ | 
|  | You may enter any debugger command, exactly as you would at the \n\ | 
|  | debugger prompt.  You may enter as many debugger commands as you like, \n\ | 
|  | but do NOT enter more than one command per line. \n" ); | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~CommandObjectWatchpointCommandAdd () {} | 
|  |  | 
|  | virtual Options * | 
|  | GetOptions () | 
|  | { | 
|  | return &m_options; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | IOHandlerActivated (IOHandler &io_handler) | 
|  | { | 
|  | 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(); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | virtual void | 
|  | IOHandlerInputComplete (IOHandler &io_handler, std::string &line) | 
|  | { | 
|  | 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.get()) | 
|  | { | 
|  | data_ap->user_source.SplitIntoLines(line); | 
|  | BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); | 
|  | 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 | 
|  | } | 
|  |  | 
|  | /// 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; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | WatchpointOptionsCallbackFunction (void *baton, | 
|  | StoppointCallbackContext *context, | 
|  | lldb::user_id_t watch_id) | 
|  | { | 
|  | bool ret_value = true; | 
|  | if (baton == NULL) | 
|  | 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() | 
|  | { | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~CommandOptions () {} | 
|  |  | 
|  | virtual Error | 
|  | SetOptionValue (uint32_t option_idx, const char *option_arg) | 
|  | { | 
|  | 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); | 
|  |  | 
|  | if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault) | 
|  | { | 
|  | m_use_script_language = true; | 
|  | } | 
|  | else | 
|  | { | 
|  | m_use_script_language = false; | 
|  | } | 
|  | 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 () | 
|  | { | 
|  | 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 () | 
|  | { | 
|  | return g_option_table; | 
|  | } | 
|  |  | 
|  | // Options table: Required for subclasses of Options. | 
|  |  | 
|  | static OptionDefinition g_option_table[]; | 
|  |  | 
|  | // Instance variables to hold the values for command options. | 
|  |  | 
|  | 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; | 
|  | }; | 
|  |  | 
|  | protected: | 
|  | virtual bool | 
|  | DoExecute (Args& command, CommandReturnObject &result) | 
|  | { | 
|  | Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); | 
|  |  | 
|  | if (target == NULL) | 
|  | { | 
|  | 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 == false && m_options.m_function_name.size()) | 
|  | { | 
|  | 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 == NULL) continue; | 
|  |  | 
|  | WatchpointOptions *wp_options = wp->GetOptions(); | 
|  | // Skip this watchpoint if wp_options is not good. | 
|  | if (wp_options == NULL) 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.size()) | 
|  | { | 
|  | 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(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | CommandOptions m_options; | 
|  | }; | 
|  |  | 
|  |  | 
|  | // 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,                      NULL,              NULL } | 
|  | }; | 
|  |  | 
|  | OptionDefinition | 
|  | CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] = | 
|  | { | 
|  | { LLDB_OPT_SET_1,   false, "one-liner",       'o', OptionParser::eRequiredArgument, NULL, NULL, 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, NULL, NULL, 0, eArgTypeBoolean, | 
|  | "Specify whether watchpoint command execution should terminate on error." }, | 
|  |  | 
|  | { LLDB_OPT_SET_ALL, false, "script-type",     's', OptionParser::eRequiredArgument, NULL, 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, NULL, NULL, 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, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } | 
|  | }; | 
|  |  | 
|  | //------------------------------------------------------------------------- | 
|  | // CommandObjectWatchpointCommandDelete | 
|  | //------------------------------------------------------------------------- | 
|  |  | 
|  | class CommandObjectWatchpointCommandDelete : public CommandObjectParsed | 
|  | { | 
|  | public: | 
|  | CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) : | 
|  | CommandObjectParsed (interpreter, | 
|  | "delete", | 
|  | "Delete the set of commands from a watchpoint.", | 
|  | NULL) | 
|  | { | 
|  | 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); | 
|  | } | 
|  |  | 
|  |  | 
|  | virtual | 
|  | ~CommandObjectWatchpointCommandDelete () {} | 
|  |  | 
|  | protected: | 
|  | virtual bool | 
|  | DoExecute (Args& command, CommandReturnObject &result) | 
|  | { | 
|  | Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); | 
|  |  | 
|  | if (target == NULL) | 
|  | { | 
|  | 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(); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | //------------------------------------------------------------------------- | 
|  | // CommandObjectWatchpointCommandList | 
|  | //------------------------------------------------------------------------- | 
|  |  | 
|  | 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.", | 
|  | NULL) | 
|  | { | 
|  | 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); | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~CommandObjectWatchpointCommandList () {} | 
|  |  | 
|  | protected: | 
|  | virtual bool | 
|  | DoExecute (Args& command, | 
|  | CommandReturnObject &result) | 
|  | { | 
|  | Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); | 
|  |  | 
|  | if (target == NULL) | 
|  | { | 
|  | 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(); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return result.Succeeded(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | //------------------------------------------------------------------------- | 
|  | // CommandObjectWatchpointCommand | 
|  | //------------------------------------------------------------------------- | 
|  |  | 
|  | CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) : | 
|  | CommandObjectMultiword (interpreter, | 
|  | "command", | 
|  | "A set of commands for adding, removing and examining bits of code to be 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 () | 
|  | { | 
|  | } | 
|  |  | 
|  |  |