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