]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Commands/CommandObjectBreakpointCommand.cpp
Import LLDB as of upstream SVN r216948 (git 50f7fe44)
[FreeBSD/FreeBSD.git] / source / Commands / CommandObjectBreakpointCommand.cpp
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                 bool stop_on_continue = true;
311                 bool echo_commands    = false;
312                 bool print_results    = true;
313
314                 debugger.GetCommandInterpreter().HandleCommands (commands, 
315                                                                  &exe_ctx,
316                                                                  stop_on_continue, 
317                                                                  data->stop_on_error, 
318                                                                  echo_commands, 
319                                                                  print_results,
320                                                                  eLazyBoolNo,
321                                                                  result);
322                 result.GetImmediateOutputStream()->Flush();
323                 result.GetImmediateErrorStream()->Flush();
324            }
325         }
326         return ret_value;
327     }    
328
329     class CommandOptions : public Options
330     {
331     public:
332
333         CommandOptions (CommandInterpreter &interpreter) :
334             Options (interpreter),
335             m_use_commands (false),
336             m_use_script_language (false),
337             m_script_language (eScriptLanguageNone),
338             m_use_one_liner (false),
339             m_one_liner(),
340             m_function_name()
341         {
342         }
343
344         virtual
345         ~CommandOptions () {}
346
347         virtual Error
348         SetOptionValue (uint32_t option_idx, const char *option_arg)
349         {
350             Error error;
351             const int short_option = m_getopt_table[option_idx].val;
352
353             switch (short_option)
354             {
355             case 'o':
356                 m_use_one_liner = true;
357                 m_one_liner = option_arg;
358                 break;
359
360             case 's':
361                 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 
362                                                                                      g_option_table[option_idx].enum_values, 
363                                                                                      eScriptLanguageNone,
364                                                                                      error);
365
366                 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
367                 {
368                     m_use_script_language = true;
369                 }
370                 else
371                 {
372                     m_use_script_language = false;
373                 }          
374                 break;
375
376             case 'e':
377                 {
378                     bool success = false;
379                     m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
380                     if (!success)
381                         error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
382                 }
383                 break;
384                     
385             case 'F':
386                 {
387                     m_use_one_liner = false;
388                     m_use_script_language = true;
389                     m_function_name.assign(option_arg);
390                 }
391                 break;
392
393             default:
394                 break;
395             }
396             return error;
397         }
398         void
399         OptionParsingStarting ()
400         {
401             m_use_commands = true;
402             m_use_script_language = false;
403             m_script_language = eScriptLanguageNone;
404
405             m_use_one_liner = false;
406             m_stop_on_error = true;
407             m_one_liner.clear();
408             m_function_name.clear();
409         }
410
411         const OptionDefinition*
412         GetDefinitions ()
413         {
414             return g_option_table;
415         }
416
417         // Options table: Required for subclasses of Options.
418
419         static OptionDefinition g_option_table[];
420
421         // Instance variables to hold the values for command options.
422
423         bool m_use_commands;
424         bool m_use_script_language;
425         lldb::ScriptLanguage m_script_language;
426
427         // Instance variables to hold the values for one_liner options.
428         bool m_use_one_liner;
429         std::string m_one_liner;
430         bool m_stop_on_error;
431         std::string m_function_name;
432     };
433
434 protected:
435     virtual bool
436     DoExecute (Args& command, CommandReturnObject &result)
437     {
438         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
439
440         if (target == NULL)
441         {
442             result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
443             result.SetStatus (eReturnStatusFailed);
444             return false;
445         }
446
447         const BreakpointList &breakpoints = target->GetBreakpointList();
448         size_t num_breakpoints = breakpoints.GetSize();
449
450         if (num_breakpoints == 0)
451         {
452             result.AppendError ("No breakpoints exist to have commands added");
453             result.SetStatus (eReturnStatusFailed);
454             return false;
455         }
456
457         if (m_options.m_use_script_language == false && m_options.m_function_name.size())
458         {
459             result.AppendError ("need to enable scripting to have a function run as a breakpoint command");
460             result.SetStatus (eReturnStatusFailed);
461             return false;
462         }
463         
464         BreakpointIDList valid_bp_ids;
465         CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
466
467         m_bp_options_vec.clear();
468         
469         if (result.Succeeded())
470         {
471             const size_t count = valid_bp_ids.GetSize();
472             
473             for (size_t i = 0; i < count; ++i)
474             {
475                 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
476                 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
477                 {
478                     Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
479                     BreakpointOptions *bp_options = NULL;
480                     if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
481                     {
482                         // This breakpoint does not have an associated location.
483                         bp_options = bp->GetOptions();
484                     }
485                     else                    
486                     {
487                         BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
488                         // This breakpoint does have an associated location.
489                         // Get its breakpoint options.
490                         if (bp_loc_sp)
491                             bp_options = bp_loc_sp->GetLocationOptions();
492                     }
493                     if (bp_options)
494                         m_bp_options_vec.push_back (bp_options);
495                 }
496             }
497
498             // If we are using script language, get the script interpreter
499             // in order to set or collect command callback.  Otherwise, call
500             // the methods associated with this object.
501             if (m_options.m_use_script_language)
502             {
503                 ScriptInterpreter *script_interp = m_interpreter.GetScriptInterpreter();
504                 // Special handling for one-liner specified inline.
505                 if (m_options.m_use_one_liner)
506                 {
507                     script_interp->SetBreakpointCommandCallback (m_bp_options_vec,
508                                                                  m_options.m_one_liner.c_str());
509                 }
510                 else if (m_options.m_function_name.size())
511                 {
512                     script_interp->SetBreakpointCommandCallbackFunction (m_bp_options_vec,
513                                                                          m_options.m_function_name.c_str());
514                 }
515                 else
516                 {
517                     script_interp->CollectDataForBreakpointCommandCallback (m_bp_options_vec,
518                                                                             result);
519                 }
520             }
521             else
522             {
523                 // Special handling for one-liner specified inline.
524                 if (m_options.m_use_one_liner)
525                     SetBreakpointCommandCallback (m_bp_options_vec,
526                                                   m_options.m_one_liner.c_str());
527                 else
528                     CollectDataForBreakpointCommandCallback (m_bp_options_vec,
529                                                              result);
530             }
531
532         }
533
534         return result.Succeeded();
535     }
536
537 private:
538     CommandOptions m_options;
539     std::vector<BreakpointOptions *> m_bp_options_vec;  // This stores the breakpoint options that we are currently
540                                                         // collecting commands for.  In the CollectData... calls we need
541                                                         // to hand this off to the IOHandler, which may run asynchronously.
542                                                         // So we have to have some way to keep it alive, and not leak it.
543                                                         // Making it an ivar of the command object, which never goes away
544                                                         // achieves this.  Note that if we were able to run
545                                                         // the same command concurrently in one interpreter we'd have to
546                                                         // make this "per invocation".  But there are many more reasons
547                                                         // why it is not in general safe to do that in lldb at present,
548                                                         // so it isn't worthwhile to come up with a more complex mechanism
549                                                         // to address this particular weakness right now.
550     static const char *g_reader_instructions;
551
552 };
553
554 const char *
555 CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s).  Type 'DONE' to end.\n";
556
557 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
558 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
559
560 static OptionEnumValueElement
561 g_script_option_enumeration[4] =
562 {
563     { eScriptLanguageNone,    "command",         "Commands are in the lldb command interpreter language"},
564     { eScriptLanguagePython,  "python",          "Commands are in the Python language."},
565     { eSortOrderByName,       "default-script",  "Commands are in the default scripting language."},
566     { 0,                      NULL,              NULL }
567 };
568
569 OptionDefinition
570 CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
571 {
572     { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner,
573         "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
574
575     { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,
576         "Specify whether breakpoint command execution should terminate on error." },
577
578     { LLDB_OPT_SET_ALL,   false, "script-type",     's', OptionParser::eRequiredArgument, NULL, g_script_option_enumeration, 0, eArgTypeNone,
579         "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
580
581     { LLDB_OPT_SET_2,   false, "python-function",     'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction,
582         "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."},
583     
584     { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
585 };
586
587 //-------------------------------------------------------------------------
588 // CommandObjectBreakpointCommandDelete
589 //-------------------------------------------------------------------------
590
591 class CommandObjectBreakpointCommandDelete : public CommandObjectParsed
592 {
593 public:
594     CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) :
595         CommandObjectParsed (interpreter, 
596                              "delete",
597                              "Delete the set of commands from a breakpoint.",
598                              NULL)
599     {
600         CommandArgumentEntry arg;
601         CommandArgumentData bp_id_arg;
602
603         // Define the first (and only) variant of this arg.
604         bp_id_arg.arg_type = eArgTypeBreakpointID;
605         bp_id_arg.arg_repetition = eArgRepeatPlain;
606
607         // There is only one variant this argument could be; put it into the argument entry.
608         arg.push_back (bp_id_arg);
609
610         // Push the data for the first argument into the m_arguments vector.
611         m_arguments.push_back (arg);
612     }
613
614
615     virtual
616     ~CommandObjectBreakpointCommandDelete () {}
617
618 protected:
619     virtual bool
620     DoExecute (Args& command, CommandReturnObject &result)
621     {
622         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
623
624         if (target == NULL)
625         {
626             result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands");
627             result.SetStatus (eReturnStatusFailed);
628             return false;
629         }
630
631         const BreakpointList &breakpoints = target->GetBreakpointList();
632         size_t num_breakpoints = breakpoints.GetSize();
633
634         if (num_breakpoints == 0)
635         {
636             result.AppendError ("No breakpoints exist to have commands deleted");
637             result.SetStatus (eReturnStatusFailed);
638             return false;
639         }
640
641         if (command.GetArgumentCount() == 0)
642         {
643             result.AppendError ("No breakpoint specified from which to delete the commands");
644             result.SetStatus (eReturnStatusFailed);
645             return false;
646         }
647
648         BreakpointIDList valid_bp_ids;
649         CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
650
651         if (result.Succeeded())
652         {
653             const size_t count = valid_bp_ids.GetSize();
654             for (size_t i = 0; i < count; ++i)
655             {
656                 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
657                 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
658                 {
659                     Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
660                     if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
661                     {
662                         BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
663                         if (bp_loc_sp)
664                             bp_loc_sp->ClearCallback();
665                         else
666                         {
667                             result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 
668                                                          cur_bp_id.GetBreakpointID(),
669                                                          cur_bp_id.GetLocationID());
670                             result.SetStatus (eReturnStatusFailed);
671                             return false;
672                         }
673                     }
674                     else
675                     {
676                         bp->ClearCallback();
677                     }
678                 }
679             }
680         }
681         return result.Succeeded();
682     }
683 };
684
685 //-------------------------------------------------------------------------
686 // CommandObjectBreakpointCommandList
687 //-------------------------------------------------------------------------
688
689 class CommandObjectBreakpointCommandList : public CommandObjectParsed
690 {
691 public:
692     CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
693         CommandObjectParsed (interpreter,
694                              "list",
695                              "List the script or set of commands to be executed when the breakpoint is hit.",
696                               NULL)
697     {
698         CommandArgumentEntry arg;
699         CommandArgumentData bp_id_arg;
700
701         // Define the first (and only) variant of this arg.
702         bp_id_arg.arg_type = eArgTypeBreakpointID;
703         bp_id_arg.arg_repetition = eArgRepeatPlain;
704
705         // There is only one variant this argument could be; put it into the argument entry.
706         arg.push_back (bp_id_arg);
707
708         // Push the data for the first argument into the m_arguments vector.
709         m_arguments.push_back (arg);
710     }
711
712     virtual
713     ~CommandObjectBreakpointCommandList () {}
714
715 protected:
716     virtual bool
717     DoExecute (Args& command,
718              CommandReturnObject &result)
719     {
720         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
721
722         if (target == NULL)
723         {
724             result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
725             result.SetStatus (eReturnStatusFailed);
726             return false;
727         }
728
729         const BreakpointList &breakpoints = target->GetBreakpointList();
730         size_t num_breakpoints = breakpoints.GetSize();
731
732         if (num_breakpoints == 0)
733         {
734             result.AppendError ("No breakpoints exist for which to list commands");
735             result.SetStatus (eReturnStatusFailed);
736             return false;
737         }
738
739         if (command.GetArgumentCount() == 0)
740         {
741             result.AppendError ("No breakpoint specified for which to list the commands");
742             result.SetStatus (eReturnStatusFailed);
743             return false;
744         }
745
746         BreakpointIDList valid_bp_ids;
747         CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
748
749         if (result.Succeeded())
750         {
751             const size_t count = valid_bp_ids.GetSize();
752             for (size_t i = 0; i < count; ++i)
753             {
754                 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
755                 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
756                 {
757                     Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
758                     
759                     if (bp)
760                     {
761                         const BreakpointOptions *bp_options = NULL;
762                         if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
763                         {
764                             BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
765                             if (bp_loc_sp)
766                                 bp_options = bp_loc_sp->GetOptionsNoCreate();
767                             else
768                             {
769                                 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 
770                                                              cur_bp_id.GetBreakpointID(),
771                                                              cur_bp_id.GetLocationID());
772                                 result.SetStatus (eReturnStatusFailed);
773                                 return false;
774                             }
775                         }
776                         else
777                         {
778                             bp_options = bp->GetOptions();
779                         }
780
781                         if (bp_options)
782                         {
783                             StreamString id_str;
784                             BreakpointID::GetCanonicalReference (&id_str, 
785                                                                  cur_bp_id.GetBreakpointID(), 
786                                                                  cur_bp_id.GetLocationID());
787                             const Baton *baton = bp_options->GetBaton();
788                             if (baton)
789                             {
790                                 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
791                                 result.GetOutputStream().IndentMore ();
792                                 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
793                                 result.GetOutputStream().IndentLess ();
794                             }
795                             else
796                             {
797                                 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", 
798                                                                 id_str.GetData());
799                             }
800                         }
801                         result.SetStatus (eReturnStatusSuccessFinishResult);
802                     }
803                     else
804                     {
805                         result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
806                         result.SetStatus (eReturnStatusFailed);
807                     }
808
809                 }
810             }
811         }
812
813         return result.Succeeded();
814     }
815 };
816
817 //-------------------------------------------------------------------------
818 // CommandObjectBreakpointCommand
819 //-------------------------------------------------------------------------
820
821 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
822     CommandObjectMultiword (interpreter,
823                             "command",
824                             "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commands').",
825                             "command <sub-command> [<sub-command-options>] <breakpoint-id>")
826 {
827     CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
828     CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter));
829     CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
830
831     add_command_object->SetCommandName ("breakpoint command add");
832     delete_command_object->SetCommandName ("breakpoint command delete");
833     list_command_object->SetCommandName ("breakpoint command list");
834
835     LoadSubCommand ("add",    add_command_object);
836     LoadSubCommand ("delete", delete_command_object);
837     LoadSubCommand ("list",   list_command_object);
838 }
839
840 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
841 {
842 }
843
844