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