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