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