diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp | 924 |
1 files changed, 924 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp new file mode 100644 index 0000000..8f8404b --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -0,0 +1,924 @@ +//===-- CommandObjectBreakpointCommand.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 "CommandObjectBreakpointCommand.h" +#include "CommandObjectBreakpoint.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/BreakpointIDList.h" +#include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/State.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandAdd +//------------------------------------------------------------------------- + + +class CommandObjectBreakpointCommandAdd : + public CommandObjectParsed, + public IOHandlerDelegateMultiline +{ +public: + + CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "add", + "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit." + " If no breakpoint is specified, adds the commands to the last created breakpoint.", + NULL), + IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand), + m_options (interpreter) + { + SetHelpLong ( +"\nGeneral information about entering breakpoint commands\n\ +------------------------------------------------------\n\ +\n\ +This command will cause you to be prompted to enter the command or set of\n\ +commands you wish to be executed when the specified breakpoint is hit. You\n\ +will be told to enter your command(s), and will see a '> 'prompt. Because\n\ +you can enter one or many commands to be executed when a breakpoint is hit,\n\ +you will continue to be prompted after each new-line that you enter, until you\n\ +enter the word 'DONE', which will cause the commands you have entered to be\n\ +stored with the breakpoint and executed when the breakpoint is hit.\n\ +\n\ +Syntax checking is not necessarily done when breakpoint commands are entered.\n\ +An improperly written breakpoint command will attempt to get executed when the\n\ +breakpoint gets hit, and usually silently fail. If your breakpoint command does\n\ +not appear to be getting executed, go back and check your syntax.\n\ +\n\ +Special information about PYTHON breakpoint commands\n\ +----------------------------------------------------\n\ +\n\ +You may enter either one line of Python, multiple lines of Python (including\n\ +function definitions), or specify a Python function in a module that has already,\n\ +or will be imported. If you enter a single line of Python, that will be passed\n\ +to the Python interpreter 'as is' when the breakpoint gets hit. If you enter\n\ +function definitions, they will be passed to the Python interpreter as soon as\n\ +you finish entering the breakpoint command, and they can be called later (don't\n\ +forget to add calls to them, if you want them called when the breakpoint is\n\ +hit). If you enter multiple lines of Python that are not function definitions,\n\ +they will be collected into a new, automatically generated Python function, and\n\ +a call to the newly generated function will be attached to the breakpoint.\n\ +\n\ +\n\ +This auto-generated function is passed in three arguments:\n\ +\n\ + frame: a lldb.SBFrame object for the frame which hit breakpoint.\n\ + bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint\n\ + location that was hit.\n\ + dict: the python session dictionary hit.\n\ +\n\ +When specifying a python function with the --python-function option, you need\n\ +to supply the function name prepended by the module name. So if you import a\n\ +module named 'myutils' that contains a 'breakpoint_callback' function, you would\n\ +specify the option as:\n\ +\n\ + --python-function myutils.breakpoint_callback\n\ +\n\ +The function itself must have the following prototype:\n\ +\n\ +def breakpoint_callback(frame, bp_loc, dict):\n\ + # Your code goes here\n\ +\n\ +The arguments are the same as the 3 auto generation function arguments listed\n\ +above. Note that the global variable 'lldb.frame' will NOT be setup when this\n\ +function is called, so be sure to use the 'frame' argument. The 'frame' argument\n\ +can get you to the thread (frame.GetThread()), the thread can get you to the\n\ +process (thread.GetProcess()), and the process can get you back to the target\n\ +(process.GetTarget()).\n\ +\n\ +Important Note: Because loose Python code gets collected into functions, if you\n\ +want to access global variables in the 'loose' code, you need to specify that\n\ +they are global, using the 'global' keyword. Be sure to use correct Python\n\ +syntax, including indentation, when entering Python breakpoint 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 breakpoint. It will get passed the\n\ +frame and bp_loc arguments mentioned above.\n\ +\n\ +Example Python one-line breakpoint command:\n\ +\n\ +(lldb) breakpoint command add -s python 1\n\ +Enter your Python command(s). Type 'DONE' to end.\n\ +> print \"Hit this breakpoint!\"\n\ +> DONE\n\ +\n\ +As a convenience, this also works for a short Python one-liner:\n\ +(lldb) breakpoint 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 = breakpoint 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 breakpoint command, using function definition:\n\ +\n\ +(lldb) breakpoint command add -s python 1\n\ +Enter your Python command(s). Type 'DONE' to end.\n\ +> def breakpoint_output (bp_no):\n\ +> out_string = \"Hit breakpoint number \" + repr (bp_no)\n\ +> print out_string\n\ +> return True\n\ +> breakpoint_output (1)\n\ +> DONE\n\ +\n\ +\n\ +Example multiple line Python breakpoint command, using 'loose' Python:\n\ +\n\ +(lldb) breakpoint command add -s p 1\n\ +Enter your Python command(s). Type 'DONE' to end.\n\ +> global bp_count\n\ +> bp_count = bp_count + 1\n\ +> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\"\n\ +> DONE\n\ +\n\ +In this case, since there is a reference to a global variable,\n\ +'bp_count', you will also need to make sure 'bp_count' exists and is\n\ +initialized:\n\ +\n\ +(lldb) script\n\ +>>> bp_count = 0\n\ +>>> quit()\n\ +\n\ +(lldb)\n\ +\n\ +\n\ +Your Python code, however organized, can optionally return a value.\n\ +If the returned value is False, that tells LLDB not to stop at the breakpoint\n\ +to which the code is associated. Returning anything other than False, or even\n\ +returning None, or even omitting a return statement entirely, will cause\n\ +LLDB to stop.\n\ +\n\ +Final Note: If you get a warning that no breakpoint command was generated, but\n\ +you did not get any syntax errors, you probably forgot to add a call to your\n\ +functions.\n\ +\n\ +Special information about debugger command breakpoint commands\n\ +--------------------------------------------------------------\n\ +\n\ +You may enter any debugger command, exactly as you would at the debugger prompt.\n\ +You may enter as many debugger commands as you like, but do NOT enter more than\n\ +one command per line.\n" ); + + CommandArgumentEntry arg; + CommandArgumentData bp_id_arg; + + // Define the first (and only) variant of this arg. + bp_id_arg.arg_type = eArgTypeBreakpointID; + bp_id_arg.arg_repetition = eArgRepeatOptional; + + // There is only one variant this argument could be; put it into the argument entry. + arg.push_back (bp_id_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg); + } + + virtual + ~CommandObjectBreakpointCommandAdd () {} + + virtual Options * + GetOptions () + { + return &m_options; + } + + virtual void + IOHandlerActivated (IOHandler &io_handler) + { + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) + { + output_sp->PutCString(g_reader_instructions); + output_sp->Flush(); + } + } + + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &line) + { + io_handler.SetIsDone(true); + + std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData(); + for (BreakpointOptions *bp_options : *bp_options_vec) + { + if (!bp_options) + continue; + + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); + if (data_ap.get()) + { + data_ap->user_source.SplitIntoLines (line.c_str(), line.size()); + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); + } + } + } + + void + CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, + CommandReturnObject &result) + { + m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + &bp_options_vec); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + } + + /// Set a one-liner as the callback for the breakpoint. + void + SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, + const char *oneliner) + { + for (auto bp_options : bp_options_vec) + { + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::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 breakpoint 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 BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); + } + return; + } + + static bool + BreakpointOptionsCallbackFunction (void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) + { + bool ret_value = true; + if (baton == NULL) + return true; + + + BreakpointOptions::CommandData *data = (BreakpointOptions::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 (true); + 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; + + case 'D': + m_use_dummy = true; + 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(); + m_use_dummy = false; + } + + 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; + bool m_use_dummy; + }; + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); + + if (target == NULL) + { + result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints 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 breakpoint command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); + + m_bp_options_vec.clear(); + + if (result.Succeeded()) + { + const size_t count = valid_bp_ids.GetSize(); + + for (size_t i = 0; i < count; ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + BreakpointOptions *bp_options = NULL; + if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) + { + // This breakpoint does not have an associated location. + bp_options = bp->GetOptions(); + } + else + { + BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); + // This breakpoint does have an associated location. + // Get its breakpoint options. + if (bp_loc_sp) + bp_options = bp_loc_sp->GetLocationOptions(); + } + if (bp_options) + m_bp_options_vec.push_back (bp_options); + } + } + + // 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) + { + ScriptInterpreter *script_interp = m_interpreter.GetScriptInterpreter(); + // Special handling for one-liner specified inline. + if (m_options.m_use_one_liner) + { + script_interp->SetBreakpointCommandCallback (m_bp_options_vec, + m_options.m_one_liner.c_str()); + } + else if (m_options.m_function_name.size()) + { + script_interp->SetBreakpointCommandCallbackFunction (m_bp_options_vec, + m_options.m_function_name.c_str()); + } + else + { + script_interp->CollectDataForBreakpointCommandCallback (m_bp_options_vec, + result); + } + } + else + { + // Special handling for one-liner specified inline. + if (m_options.m_use_one_liner) + SetBreakpointCommandCallback (m_bp_options_vec, + m_options.m_one_liner.c_str()); + else + CollectDataForBreakpointCommandCallback (m_bp_options_vec, + result); + } + + } + + return result.Succeeded(); + } + +private: + CommandOptions m_options; + std::vector<BreakpointOptions *> m_bp_options_vec; // This stores the breakpoint options that we are currently + // collecting commands for. In the CollectData... calls we need + // to hand this off to the IOHandler, which may run asynchronously. + // So we have to have some way to keep it alive, and not leak it. + // Making it an ivar of the command object, which never goes away + // achieves this. Note that if we were able to run + // the same command concurrently in one interpreter we'd have to + // make this "per invocation". But there are many more reasons + // why it is not in general safe to do that in lldb at present, + // so it isn't worthwhile to come up with a more complex mechanism + // to address this particular weakness right now. + static const char *g_reader_instructions; + +}; + +const char * +CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.\n"; + +// 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 +CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner, + "Specify a one-line breakpoint 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 breakpoint 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 breakpoint. Be sure to give a module name if appropriate."}, + + { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandDelete +//------------------------------------------------------------------------- + +class CommandObjectBreakpointCommandDelete : public CommandObjectParsed +{ +public: + CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "delete", + "Delete the set of commands from a breakpoint.", + NULL), + m_options (interpreter) + { + CommandArgumentEntry arg; + CommandArgumentData bp_id_arg; + + // Define the first (and only) variant of this arg. + bp_id_arg.arg_type = eArgTypeBreakpointID; + bp_id_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg.push_back (bp_id_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg); + } + + + virtual + ~CommandObjectBreakpointCommandDelete () {} + + virtual Options * + GetOptions () + { + return &m_options; + } + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options (interpreter), + m_use_dummy (false) + { + } + + 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 'D': + m_use_dummy = true; + break; + + default: + error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); + break; + } + + return error; + } + + void + OptionParsingStarting () + { + m_use_dummy = false; + } + + 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_dummy; + }; + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); + + if (target == NULL) + { + result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints exist to have commands deleted"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() == 0) + { + result.AppendError ("No breakpoint specified from which to delete the commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + const size_t count = valid_bp_ids.GetSize(); + for (size_t i = 0; i < count; ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) + { + BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); + if (bp_loc_sp) + bp_loc_sp->ClearCallback(); + else + { + result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", + cur_bp_id.GetBreakpointID(), + cur_bp_id.GetLocationID()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + bp->ClearCallback(); + } + } + } + } + return result.Succeeded(); + } +private: + CommandOptions m_options; +}; + +OptionDefinition +CommandObjectBreakpointCommandDelete::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Delete commands from Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } +}; + + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandList +//------------------------------------------------------------------------- + +class CommandObjectBreakpointCommandList : public CommandObjectParsed +{ +public: + CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "list", + "List the script or set of commands to be executed when the breakpoint is hit.", + NULL) + { + CommandArgumentEntry arg; + CommandArgumentData bp_id_arg; + + // Define the first (and only) variant of this arg. + bp_id_arg.arg_type = eArgTypeBreakpointID; + bp_id_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg.push_back (bp_id_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg); + } + + virtual + ~CommandObjectBreakpointCommandList () {} + +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 breakpoints for which to list commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints exist for which to list commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() == 0) + { + result.AppendError ("No breakpoint specified for which to list the commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + const size_t count = valid_bp_ids.GetSize(); + for (size_t i = 0; i < count; ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + + if (bp) + { + const BreakpointOptions *bp_options = NULL; + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) + { + BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); + if (bp_loc_sp) + bp_options = bp_loc_sp->GetOptionsNoCreate(); + else + { + result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", + cur_bp_id.GetBreakpointID(), + cur_bp_id.GetLocationID()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + bp_options = bp->GetOptions(); + } + + if (bp_options) + { + StreamString id_str; + BreakpointID::GetCanonicalReference (&id_str, + cur_bp_id.GetBreakpointID(), + cur_bp_id.GetLocationID()); + const Baton *baton = bp_options->GetBaton(); + if (baton) + { + result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); + result.GetOutputStream().IndentMore (); + baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); + result.GetOutputStream().IndentLess (); + } + else + { + result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", + id_str.GetData()); + } + } + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); + result.SetStatus (eReturnStatusFailed); + } + + } + } + } + + return result.Succeeded(); + } +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommand +//------------------------------------------------------------------------- + +CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : + CommandObjectMultiword (interpreter, + "command", + "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commands').", + "command <sub-command> [<sub-command-options>] <breakpoint-id>") +{ + CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); + CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter)); + CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); + + add_command_object->SetCommandName ("breakpoint command add"); + delete_command_object->SetCommandName ("breakpoint command delete"); + list_command_object->SetCommandName ("breakpoint command list"); + + LoadSubCommand ("add", add_command_object); + LoadSubCommand ("delete", delete_command_object); + LoadSubCommand ("list", list_command_object); +} + +CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () +{ +} + + |