CommandObjectBreakpointCommand.cpp revision 263363
1//===-- CommandObjectBreakpointCommand.cpp ----------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/lldb-python.h"
11
12// C Includes
13// C++ Includes
14
15
16#include "CommandObjectBreakpointCommand.h"
17#include "CommandObjectBreakpoint.h"
18
19#include "lldb/Interpreter/CommandInterpreter.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
21#include "lldb/Target/Target.h"
22#include "lldb/Target/Thread.h"
23#include "lldb/Breakpoint/BreakpointIDList.h"
24#include "lldb/Breakpoint/Breakpoint.h"
25#include "lldb/Breakpoint/BreakpointLocation.h"
26#include "lldb/Breakpoint/StoppointCallbackContext.h"
27#include "lldb/Core/State.h"
28
29using namespace lldb;
30using namespace lldb_private;
31
32//-------------------------------------------------------------------------
33// CommandObjectBreakpointCommandAdd
34//-------------------------------------------------------------------------
35
36
37class CommandObjectBreakpointCommandAdd : public CommandObjectParsed
38{
39public:
40
41    CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) :
42        CommandObjectParsed (interpreter,
43                             "add",
44                             "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.",
45                             NULL),
46        m_options (interpreter)
47    {
48        SetHelpLong (
49"\nGeneral information about entering breakpoint commands\n\
50------------------------------------------------------\n\
51\n\
52This command will cause you to be prompted to enter the command or set of\n\
53commands you wish to be executed when the specified breakpoint is hit. You\n\
54will be told to enter your command(s), and will see a '> 'prompt. Because\n\
55you can enter one or many commands to be executed when a breakpoint is hit,\n\
56you will continue to be prompted after each new-line that you enter, until you\n\
57enter the word 'DONE', which will cause the commands you have entered to be\n\
58stored with the breakpoint and executed when the breakpoint is hit.\n\
59\n\
60Syntax checking is not necessarily done when breakpoint commands are entered.\n\
61An improperly written breakpoint command will attempt to get executed when the\n\
62breakpoint gets hit, and usually silently fail.  If your breakpoint command does\n\
63not appear to be getting executed, go back and check your syntax.\n\
64\n\
65Special information about PYTHON breakpoint commands\n\
66----------------------------------------------------\n\
67\n\
68You may enter either one line of Python, multiple lines of Python (including\n\
69function definitions), or specify a Python function in a module that has already,\n\
70or will be imported.  If you enter a single line of Python, that will be passed\n\
71to the Python interpreter 'as is' when the breakpoint gets hit.  If you enter\n\
72function definitions, they will be passed to the Python interpreter as soon as\n\
73you finish entering the breakpoint command, and they can be called later (don't\n\
74forget to add calls to them, if you want them called when the breakpoint is\n\
75hit).  If you enter multiple lines of Python that are not function definitions,\n\
76they will be collected into a new, automatically generated Python function, and\n\
77a call to the newly generated function will be attached to the breakpoint.\n\
78\n\
79\n\
80This auto-generated function is passed in three arguments:\n\
81\n\
82    frame:  a lldb.SBFrame object for the frame which hit breakpoint.\n\
83    bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint\n\
84            location that was hit.\n\
85    dict:   the python session dictionary hit.\n\
86\n\
87When specifying a python function with the --python-function option, you need\n\
88to supply the function name prepended by the module name. So if you import a\n\
89module named 'myutils' that contains a 'breakpoint_callback' function, you would\n\
90specify the option as:\n\
91\n\
92    --python-function myutils.breakpoint_callback\n\
93\n\
94The function itself must have the following prototype:\n\
95\n\
96def breakpoint_callback(frame, bp_loc, dict):\n\
97  # Your code goes here\n\
98\n\
99The arguments are the same as the 3 auto generation function arguments listed\n\
100above. Note that the global variable 'lldb.frame' will NOT be setup when this\n\
101function is called, so be sure to use the 'frame' argument. The 'frame' argument\n\
102can get you to the thread (frame.GetThread()), the thread can get you to the\n\
103process (thread.GetProcess()), and the process can get you back to the target\n\
104(process.GetTarget()).\n\
105\n\
106Important Note: Because loose Python code gets collected into functions, if you\n\
107want to access global variables in the 'loose' code, you need to specify that\n\
108they are global, using the 'global' keyword.  Be sure to use correct Python\n\
109syntax, including indentation, when entering Python breakpoint commands.\n\
110\n\
111As a third option, you can pass the name of an already existing Python function\n\
112and that function will be attached to the breakpoint. It will get passed the\n\
113frame and bp_loc arguments mentioned above.\n\
114\n\
115Example Python one-line breakpoint command:\n\
116\n\
117(lldb) breakpoint command add -s python 1\n\
118Enter your Python command(s). Type 'DONE' to end.\n\
119> print \"Hit this breakpoint!\"\n\
120> DONE\n\
121\n\
122As a convenience, this also works for a short Python one-liner:\n\
123(lldb) breakpoint command add -s python 1 -o \"import time; print time.asctime()\"\n\
124(lldb) run\n\
125Launching '.../a.out'  (x86_64)\n\
126(lldb) Fri Sep 10 12:17:45 2010\n\
127Process 21778 Stopped\n\
128* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread\n\
129  36   	\n\
130  37   	int c(int val)\n\
131  38   	{\n\
132  39 ->	    return val + 3;\n\
133  40   	}\n\
134  41   	\n\
135  42   	int main (int argc, char const *argv[])\n\
136(lldb)\n\
137\n\
138Example multiple line Python breakpoint command, using function definition:\n\
139\n\
140(lldb) breakpoint command add -s python 1\n\
141Enter your Python command(s). Type 'DONE' to end.\n\
142> def breakpoint_output (bp_no):\n\
143>     out_string = \"Hit breakpoint number \" + repr (bp_no)\n\
144>     print out_string\n\
145>     return True\n\
146> breakpoint_output (1)\n\
147> DONE\n\
148\n\
149\n\
150Example multiple line Python breakpoint command, using 'loose' Python:\n\
151\n\
152(lldb) breakpoint command add -s p 1\n\
153Enter your Python command(s). Type 'DONE' to end.\n\
154> global bp_count\n\
155> bp_count = bp_count + 1\n\
156> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\"\n\
157> DONE\n\
158\n\
159In this case, since there is a reference to a global variable,\n\
160'bp_count', you will also need to make sure 'bp_count' exists and is\n\
161initialized:\n\
162\n\
163(lldb) script\n\
164>>> bp_count = 0\n\
165>>> quit()\n\
166\n\
167(lldb)\n\
168\n\
169\n\
170Your Python code, however organized, can optionally return a value.\n\
171If the returned value is False, that tells LLDB not to stop at the breakpoint\n\
172to which the code is associated. Returning anything other than False, or even\n\
173returning None, or even omitting a return statement entirely, will cause\n\
174LLDB to stop.\n\
175\n\
176Final Note:  If you get a warning that no breakpoint command was generated, but\n\
177you did not get any syntax errors, you probably forgot to add a call to your\n\
178functions.\n\
179\n\
180Special information about debugger command breakpoint commands\n\
181--------------------------------------------------------------\n\
182\n\
183You may enter any debugger command, exactly as you would at the debugger prompt.\n\
184You may enter as many debugger commands as you like, but do NOT enter more than\n\
185one command per line.\n" );
186
187        CommandArgumentEntry arg;
188        CommandArgumentData bp_id_arg;
189
190        // Define the first (and only) variant of this arg.
191        bp_id_arg.arg_type = eArgTypeBreakpointID;
192        bp_id_arg.arg_repetition = eArgRepeatPlain;
193
194        // There is only one variant this argument could be; put it into the argument entry.
195        arg.push_back (bp_id_arg);
196
197        // Push the data for the first argument into the m_arguments vector.
198        m_arguments.push_back (arg);
199    }
200
201    virtual
202    ~CommandObjectBreakpointCommandAdd () {}
203
204    virtual Options *
205    GetOptions ()
206    {
207        return &m_options;
208    }
209
210    void
211    CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
212                                             CommandReturnObject &result)
213    {
214        InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
215        std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
216        if (reader_sp && data_ap.get())
217        {
218            BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
219            bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
220
221            Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
222                                              bp_options,                   // baton
223                                              eInputReaderGranularityLine,  // token size, to pass to callback function
224                                              "DONE",                       // end token
225                                              "> ",                         // prompt
226                                              true));                       // echo input
227            if (err.Success())
228            {
229                m_interpreter.GetDebugger().PushInputReader (reader_sp);
230                result.SetStatus (eReturnStatusSuccessFinishNoResult);
231            }
232            else
233            {
234                result.AppendError (err.AsCString());
235                result.SetStatus (eReturnStatusFailed);
236            }
237        }
238        else
239        {
240            result.AppendError("out of memory");
241            result.SetStatus (eReturnStatusFailed);
242        }
243
244    }
245
246    /// Set a one-liner as the callback for the breakpoint.
247    void
248    SetBreakpointCommandCallback (BreakpointOptions *bp_options,
249                                  const char *oneliner)
250    {
251        std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
252
253        // It's necessary to set both user_source and script_source to the oneliner.
254        // The former is used to generate callback description (as in breakpoint command list)
255        // while the latter is used for Python to interpret during the actual callback.
256        data_ap->user_source.AppendString (oneliner);
257        data_ap->script_source.assign (oneliner);
258        data_ap->stop_on_error = m_options.m_stop_on_error;
259
260        BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
261        bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
262
263        return;
264    }
265
266    static size_t
267    GenerateBreakpointCommandCallback (void *baton,
268                                       InputReader &reader,
269                                       lldb::InputReaderAction notification,
270                                       const char *bytes,
271                                       size_t bytes_len)
272    {
273        StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
274        bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
275
276        switch (notification)
277        {
278        case eInputReaderActivate:
279            if (!batch_mode)
280            {
281                out_stream->Printf ("%s\n", g_reader_instructions);
282                if (reader.GetPrompt())
283                    out_stream->Printf ("%s", reader.GetPrompt());
284                out_stream->Flush();
285            }
286            break;
287
288        case eInputReaderDeactivate:
289            break;
290
291        case eInputReaderReactivate:
292            if (reader.GetPrompt() && !batch_mode)
293            {
294                out_stream->Printf ("%s", reader.GetPrompt());
295                out_stream->Flush();
296            }
297            break;
298
299        case eInputReaderAsynchronousOutputWritten:
300            break;
301
302        case eInputReaderGotToken:
303            if (bytes && bytes_len && baton)
304            {
305                BreakpointOptions *bp_options = (BreakpointOptions *) baton;
306                if (bp_options)
307                {
308                    Baton *bp_options_baton = bp_options->GetBaton();
309                    if (bp_options_baton)
310                        ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
311                }
312            }
313            if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
314            {
315                out_stream->Printf ("%s", reader.GetPrompt());
316                out_stream->Flush();
317            }
318            break;
319
320        case eInputReaderInterrupt:
321            {
322                // Finish, and cancel the breakpoint command.
323                reader.SetIsDone (true);
324                BreakpointOptions *bp_options = (BreakpointOptions *) baton;
325                if (bp_options)
326                {
327                    Baton *bp_options_baton = bp_options->GetBaton ();
328                    if (bp_options_baton)
329                    {
330                        ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear();
331                        ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.clear();
332                    }
333                }
334                if (!batch_mode)
335                {
336                    out_stream->Printf ("Warning: No command attached to breakpoint.\n");
337                    out_stream->Flush();
338                }
339            }
340            break;
341
342        case eInputReaderEndOfFile:
343            reader.SetIsDone (true);
344            break;
345
346        case eInputReaderDone:
347            break;
348        }
349
350        return bytes_len;
351    }
352
353    static bool
354    BreakpointOptionsCallbackFunction (void *baton,
355                                       StoppointCallbackContext *context,
356                                       lldb::user_id_t break_id,
357                                       lldb::user_id_t break_loc_id)
358    {
359        bool ret_value = true;
360        if (baton == NULL)
361            return true;
362
363
364        BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
365        StringList &commands = data->user_source;
366
367        if (commands.GetSize() > 0)
368        {
369            ExecutionContext exe_ctx (context->exe_ctx_ref);
370            Target *target = exe_ctx.GetTargetPtr();
371            if (target)
372            {
373                CommandReturnObject result;
374                Debugger &debugger = target->GetDebugger();
375                // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
376                // if the debugger is set up that way.
377
378                StreamSP output_stream (debugger.GetAsyncOutputStream());
379                StreamSP error_stream (debugger.GetAsyncErrorStream());
380                result.SetImmediateOutputStream (output_stream);
381                result.SetImmediateErrorStream (error_stream);
382
383                bool stop_on_continue = true;
384                bool echo_commands    = false;
385                bool print_results    = true;
386
387                debugger.GetCommandInterpreter().HandleCommands (commands,
388                                                                 &exe_ctx,
389                                                                 stop_on_continue,
390                                                                 data->stop_on_error,
391                                                                 echo_commands,
392                                                                 print_results,
393                                                                 eLazyBoolNo,
394                                                                 result);
395                result.GetImmediateOutputStream()->Flush();
396                result.GetImmediateErrorStream()->Flush();
397           }
398        }
399        return ret_value;
400    }
401
402    class CommandOptions : public Options
403    {
404    public:
405
406        CommandOptions (CommandInterpreter &interpreter) :
407            Options (interpreter),
408            m_use_commands (false),
409            m_use_script_language (false),
410            m_script_language (eScriptLanguageNone),
411            m_use_one_liner (false),
412            m_one_liner(),
413            m_function_name()
414        {
415        }
416
417        virtual
418        ~CommandOptions () {}
419
420        virtual Error
421        SetOptionValue (uint32_t option_idx, const char *option_arg)
422        {
423            Error error;
424            const int short_option = m_getopt_table[option_idx].val;
425
426            switch (short_option)
427            {
428            case 'o':
429                m_use_one_liner = true;
430                m_one_liner = option_arg;
431                break;
432
433            case 's':
434                m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
435                                                                                     g_option_table[option_idx].enum_values,
436                                                                                     eScriptLanguageNone,
437                                                                                     error);
438
439                if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
440                {
441                    m_use_script_language = true;
442                }
443                else
444                {
445                    m_use_script_language = false;
446                }
447                break;
448
449            case 'e':
450                {
451                    bool success = false;
452                    m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
453                    if (!success)
454                        error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
455                }
456                break;
457
458            case 'F':
459                {
460                    m_use_one_liner = false;
461                    m_use_script_language = true;
462                    m_function_name.assign(option_arg);
463                }
464                break;
465
466            default:
467                break;
468            }
469            return error;
470        }
471        void
472        OptionParsingStarting ()
473        {
474            m_use_commands = true;
475            m_use_script_language = false;
476            m_script_language = eScriptLanguageNone;
477
478            m_use_one_liner = false;
479            m_stop_on_error = true;
480            m_one_liner.clear();
481            m_function_name.clear();
482        }
483
484        const OptionDefinition*
485        GetDefinitions ()
486        {
487            return g_option_table;
488        }
489
490        // Options table: Required for subclasses of Options.
491
492        static OptionDefinition g_option_table[];
493
494        // Instance variables to hold the values for command options.
495
496        bool m_use_commands;
497        bool m_use_script_language;
498        lldb::ScriptLanguage m_script_language;
499
500        // Instance variables to hold the values for one_liner options.
501        bool m_use_one_liner;
502        std::string m_one_liner;
503        bool m_stop_on_error;
504        std::string m_function_name;
505    };
506
507protected:
508    virtual bool
509    DoExecute (Args& command, CommandReturnObject &result)
510    {
511        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
512
513        if (target == NULL)
514        {
515            result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
516            result.SetStatus (eReturnStatusFailed);
517            return false;
518        }
519
520        const BreakpointList &breakpoints = target->GetBreakpointList();
521        size_t num_breakpoints = breakpoints.GetSize();
522
523        if (num_breakpoints == 0)
524        {
525            result.AppendError ("No breakpoints exist to have commands added");
526            result.SetStatus (eReturnStatusFailed);
527            return false;
528        }
529
530        if (m_options.m_use_script_language == false && m_options.m_function_name.size())
531        {
532            result.AppendError ("need to enable scripting to have a function run as a breakpoint command");
533            result.SetStatus (eReturnStatusFailed);
534            return false;
535        }
536
537        BreakpointIDList valid_bp_ids;
538        CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
539
540        if (result.Succeeded())
541        {
542            const size_t count = valid_bp_ids.GetSize();
543            if (count > 1)
544            {
545                result.AppendError ("can only add commands to one breakpoint at a time.");
546                result.SetStatus (eReturnStatusFailed);
547                return false;
548            }
549
550            for (size_t i = 0; i < count; ++i)
551            {
552                BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
553                if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
554                {
555                    Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
556                    BreakpointOptions *bp_options = NULL;
557                    if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
558                    {
559                        // This breakpoint does not have an associated location.
560                        bp_options = bp->GetOptions();
561                    }
562                    else
563                    {
564                        BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
565                        // This breakpoint does have an associated location.
566                        // Get its breakpoint options.
567                        if (bp_loc_sp)
568                            bp_options = bp_loc_sp->GetLocationOptions();
569                    }
570
571                    // Skip this breakpoint if bp_options is not good.
572                    if (bp_options == NULL) continue;
573
574                    // If we are using script language, get the script interpreter
575                    // in order to set or collect command callback.  Otherwise, call
576                    // the methods associated with this object.
577                    if (m_options.m_use_script_language)
578                    {
579                        // Special handling for one-liner specified inline.
580                        if (m_options.m_use_one_liner)
581                        {
582                            m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
583                                                                                                m_options.m_one_liner.c_str());
584                        }
585                        // Special handling for using a Python function by name
586                        // instead of extending the breakpoint callback data structures, we just automatize
587                        // what the user would do manually: make their breakpoint command be a function call
588                        else if (m_options.m_function_name.size())
589                        {
590                            std::string oneliner("return ");
591                            oneliner += m_options.m_function_name;
592                            oneliner += "(frame, bp_loc, internal_dict)";
593                            m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
594                                                                                                oneliner.c_str());
595                        }
596                        else
597                        {
598                            m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
599                                                                                                           result);
600                        }
601                    }
602                    else
603                    {
604                        // Special handling for one-liner specified inline.
605                        if (m_options.m_use_one_liner)
606                            SetBreakpointCommandCallback (bp_options,
607                                                          m_options.m_one_liner.c_str());
608                        else
609                            CollectDataForBreakpointCommandCallback (bp_options,
610                                                                     result);
611                    }
612                }
613            }
614        }
615
616        return result.Succeeded();
617    }
618
619private:
620    CommandOptions m_options;
621    static const char *g_reader_instructions;
622
623};
624
625const char *
626CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s).  Type 'DONE' to end.";
627
628// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
629// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
630
631static OptionEnumValueElement
632g_script_option_enumeration[4] =
633{
634    { eScriptLanguageNone,    "command",         "Commands are in the lldb command interpreter language"},
635    { eScriptLanguagePython,  "python",          "Commands are in the Python language."},
636    { eSortOrderByName,       "default-script",  "Commands are in the default scripting language."},
637    { 0,                      NULL,              NULL }
638};
639
640OptionDefinition
641CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
642{
643    { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOneLiner,
644        "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
645
646    { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean,
647        "Specify whether breakpoint command execution should terminate on error." },
648
649    { LLDB_OPT_SET_ALL,   false, "script-type",     's', OptionParser::eRequiredArgument, g_script_option_enumeration, 0, eArgTypeNone,
650        "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
651
652    { LLDB_OPT_SET_2,   false, "python-function",     'F', OptionParser::eRequiredArgument, NULL, 0, eArgTypePythonFunction,
653        "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."},
654
655    { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
656};
657
658//-------------------------------------------------------------------------
659// CommandObjectBreakpointCommandDelete
660//-------------------------------------------------------------------------
661
662class CommandObjectBreakpointCommandDelete : public CommandObjectParsed
663{
664public:
665    CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) :
666        CommandObjectParsed (interpreter,
667                             "delete",
668                             "Delete the set of commands from a breakpoint.",
669                             NULL)
670    {
671        CommandArgumentEntry arg;
672        CommandArgumentData bp_id_arg;
673
674        // Define the first (and only) variant of this arg.
675        bp_id_arg.arg_type = eArgTypeBreakpointID;
676        bp_id_arg.arg_repetition = eArgRepeatPlain;
677
678        // There is only one variant this argument could be; put it into the argument entry.
679        arg.push_back (bp_id_arg);
680
681        // Push the data for the first argument into the m_arguments vector.
682        m_arguments.push_back (arg);
683    }
684
685
686    virtual
687    ~CommandObjectBreakpointCommandDelete () {}
688
689protected:
690    virtual bool
691    DoExecute (Args& command, CommandReturnObject &result)
692    {
693        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
694
695        if (target == NULL)
696        {
697            result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands");
698            result.SetStatus (eReturnStatusFailed);
699            return false;
700        }
701
702        const BreakpointList &breakpoints = target->GetBreakpointList();
703        size_t num_breakpoints = breakpoints.GetSize();
704
705        if (num_breakpoints == 0)
706        {
707            result.AppendError ("No breakpoints exist to have commands deleted");
708            result.SetStatus (eReturnStatusFailed);
709            return false;
710        }
711
712        if (command.GetArgumentCount() == 0)
713        {
714            result.AppendError ("No breakpoint specified from which to delete the commands");
715            result.SetStatus (eReturnStatusFailed);
716            return false;
717        }
718
719        BreakpointIDList valid_bp_ids;
720        CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
721
722        if (result.Succeeded())
723        {
724            const size_t count = valid_bp_ids.GetSize();
725            for (size_t i = 0; i < count; ++i)
726            {
727                BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
728                if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
729                {
730                    Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
731                    if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
732                    {
733                        BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
734                        if (bp_loc_sp)
735                            bp_loc_sp->ClearCallback();
736                        else
737                        {
738                            result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
739                                                         cur_bp_id.GetBreakpointID(),
740                                                         cur_bp_id.GetLocationID());
741                            result.SetStatus (eReturnStatusFailed);
742                            return false;
743                        }
744                    }
745                    else
746                    {
747                        bp->ClearCallback();
748                    }
749                }
750            }
751        }
752        return result.Succeeded();
753    }
754};
755
756//-------------------------------------------------------------------------
757// CommandObjectBreakpointCommandList
758//-------------------------------------------------------------------------
759
760class CommandObjectBreakpointCommandList : public CommandObjectParsed
761{
762public:
763    CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
764        CommandObjectParsed (interpreter,
765                             "list",
766                             "List the script or set of commands to be executed when the breakpoint is hit.",
767                              NULL)
768    {
769        CommandArgumentEntry arg;
770        CommandArgumentData bp_id_arg;
771
772        // Define the first (and only) variant of this arg.
773        bp_id_arg.arg_type = eArgTypeBreakpointID;
774        bp_id_arg.arg_repetition = eArgRepeatPlain;
775
776        // There is only one variant this argument could be; put it into the argument entry.
777        arg.push_back (bp_id_arg);
778
779        // Push the data for the first argument into the m_arguments vector.
780        m_arguments.push_back (arg);
781    }
782
783    virtual
784    ~CommandObjectBreakpointCommandList () {}
785
786protected:
787    virtual bool
788    DoExecute (Args& command,
789             CommandReturnObject &result)
790    {
791        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
792
793        if (target == NULL)
794        {
795            result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
796            result.SetStatus (eReturnStatusFailed);
797            return false;
798        }
799
800        const BreakpointList &breakpoints = target->GetBreakpointList();
801        size_t num_breakpoints = breakpoints.GetSize();
802
803        if (num_breakpoints == 0)
804        {
805            result.AppendError ("No breakpoints exist for which to list commands");
806            result.SetStatus (eReturnStatusFailed);
807            return false;
808        }
809
810        if (command.GetArgumentCount() == 0)
811        {
812            result.AppendError ("No breakpoint specified for which to list the commands");
813            result.SetStatus (eReturnStatusFailed);
814            return false;
815        }
816
817        BreakpointIDList valid_bp_ids;
818        CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
819
820        if (result.Succeeded())
821        {
822            const size_t count = valid_bp_ids.GetSize();
823            for (size_t i = 0; i < count; ++i)
824            {
825                BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
826                if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
827                {
828                    Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
829
830                    if (bp)
831                    {
832                        const BreakpointOptions *bp_options = NULL;
833                        if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
834                        {
835                            BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
836                            if (bp_loc_sp)
837                                bp_options = bp_loc_sp->GetOptionsNoCreate();
838                            else
839                            {
840                                result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
841                                                             cur_bp_id.GetBreakpointID(),
842                                                             cur_bp_id.GetLocationID());
843                                result.SetStatus (eReturnStatusFailed);
844                                return false;
845                            }
846                        }
847                        else
848                        {
849                            bp_options = bp->GetOptions();
850                        }
851
852                        if (bp_options)
853                        {
854                            StreamString id_str;
855                            BreakpointID::GetCanonicalReference (&id_str,
856                                                                 cur_bp_id.GetBreakpointID(),
857                                                                 cur_bp_id.GetLocationID());
858                            const Baton *baton = bp_options->GetBaton();
859                            if (baton)
860                            {
861                                result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
862                                result.GetOutputStream().IndentMore ();
863                                baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
864                                result.GetOutputStream().IndentLess ();
865                            }
866                            else
867                            {
868                                result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n",
869                                                                id_str.GetData());
870                            }
871                        }
872                        result.SetStatus (eReturnStatusSuccessFinishResult);
873                    }
874                    else
875                    {
876                        result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
877                        result.SetStatus (eReturnStatusFailed);
878                    }
879
880                }
881            }
882        }
883
884        return result.Succeeded();
885    }
886};
887
888//-------------------------------------------------------------------------
889// CommandObjectBreakpointCommand
890//-------------------------------------------------------------------------
891
892CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
893    CommandObjectMultiword (interpreter,
894                            "command",
895                            "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
896                            "command <sub-command> [<sub-command-options>] <breakpoint-id>")
897{
898    CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
899    CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter));
900    CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
901
902    add_command_object->SetCommandName ("breakpoint command add");
903    delete_command_object->SetCommandName ("breakpoint command delete");
904    list_command_object->SetCommandName ("breakpoint command list");
905
906    LoadSubCommand ("add",    add_command_object);
907    LoadSubCommand ("delete", delete_command_object);
908    LoadSubCommand ("list",   list_command_object);
909}
910
911CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
912{
913}
914
915
916