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