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