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             ::fflush (out_fh);
439         }
440         break;
441 
442     case eInputReaderDeactivate:
443         break;
444 
445     case eInputReaderReactivate:
446         if (out_fh && reader.GetPrompt())
447         {
448             ::fprintf (out_fh, "%s", reader.GetPrompt());
449             ::fflush (out_fh);
450         }
451         break;
452 
453     case eInputReaderGotToken:
454         if (bytes && bytes_len && baton)
455         {
456             BreakpointOptions *bp_options = (BreakpointOptions *) baton;
457             if (bp_options)
458             {
459                 Baton *bp_options_baton = bp_options->GetBaton();
460                 if (bp_options_baton)
461                     ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
462             }
463         }
464         if (out_fh && !reader.IsDone() && reader.GetPrompt())
465         {
466             ::fprintf (out_fh, "%s", reader.GetPrompt());
467             ::fflush (out_fh);
468         }
469         break;
470 
471     case eInputReaderDone:
472         break;
473     }
474 
475     return bytes_len;
476 }
477 
478 
479 //-------------------------------------------------------------------------
480 // CommandObjectBreakpointCommandRemove
481 //-------------------------------------------------------------------------
482 
483 CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) :
484     CommandObject (interpreter,
485                    "remove",
486                    "Remove the set of commands from a breakpoint.",
487                    NULL)
488 {
489     CommandArgumentEntry arg;
490     CommandArgumentData bp_id_arg;
491 
492     // Define the first (and only) variant of this arg.
493     bp_id_arg.arg_type = eArgTypeBreakpointID;
494     bp_id_arg.arg_repetition = eArgRepeatPlain;
495 
496     // There is only one variant this argument could be; put it into the argument entry.
497     arg.push_back (bp_id_arg);
498 
499     // Push the data for the first argument into the m_arguments vector.
500     m_arguments.push_back (arg);
501 }
502 
503 CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
504 {
505 }
506 
507 bool
508 CommandObjectBreakpointCommandRemove::Execute
509 (
510     Args& command,
511     CommandReturnObject &result
512 )
513 {
514     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
515 
516     if (target == NULL)
517     {
518         result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
519         result.SetStatus (eReturnStatusFailed);
520         return false;
521     }
522 
523     const BreakpointList &breakpoints = target->GetBreakpointList();
524     size_t num_breakpoints = breakpoints.GetSize();
525 
526     if (num_breakpoints == 0)
527     {
528         result.AppendError ("No breakpoints exist to have commands removed");
529         result.SetStatus (eReturnStatusFailed);
530         return false;
531     }
532 
533     if (command.GetArgumentCount() == 0)
534     {
535         result.AppendError ("No breakpoint specified from which to remove the commands");
536         result.SetStatus (eReturnStatusFailed);
537         return false;
538     }
539 
540     BreakpointIDList valid_bp_ids;
541     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
542 
543     if (result.Succeeded())
544     {
545         const size_t count = valid_bp_ids.GetSize();
546         for (size_t i = 0; i < count; ++i)
547         {
548             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
549             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
550             {
551                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
552                 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
553                 {
554                     BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
555                     if (bp_loc_sp)
556                         bp_loc_sp->ClearCallback();
557                     else
558                     {
559                         result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
560                                                      cur_bp_id.GetBreakpointID(),
561                                                      cur_bp_id.GetLocationID());
562                         result.SetStatus (eReturnStatusFailed);
563                         return false;
564                     }
565                 }
566                 else
567                 {
568                     bp->ClearCallback();
569                 }
570             }
571         }
572     }
573     return result.Succeeded();
574 }
575 
576 
577 //-------------------------------------------------------------------------
578 // CommandObjectBreakpointCommandList
579 //-------------------------------------------------------------------------
580 
581 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
582     CommandObject (interpreter,
583                    "list",
584                    "List the script or set of commands to be executed when the breakpoint is hit.",
585                     NULL)
586 {
587     CommandArgumentEntry arg;
588     CommandArgumentData bp_id_arg;
589 
590     // Define the first (and only) variant of this arg.
591     bp_id_arg.arg_type = eArgTypeBreakpointID;
592     bp_id_arg.arg_repetition = eArgRepeatPlain;
593 
594     // There is only one variant this argument could be; put it into the argument entry.
595     arg.push_back (bp_id_arg);
596 
597     // Push the data for the first argument into the m_arguments vector.
598     m_arguments.push_back (arg);
599 }
600 
601 CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
602 {
603 }
604 
605 bool
606 CommandObjectBreakpointCommandList::Execute
607 (
608     Args& command,
609     CommandReturnObject &result
610 )
611 {
612     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
613 
614     if (target == NULL)
615     {
616         result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
617         result.SetStatus (eReturnStatusFailed);
618         return false;
619     }
620 
621     const BreakpointList &breakpoints = target->GetBreakpointList();
622     size_t num_breakpoints = breakpoints.GetSize();
623 
624     if (num_breakpoints == 0)
625     {
626         result.AppendError ("No breakpoints exist for which to list commands");
627         result.SetStatus (eReturnStatusFailed);
628         return false;
629     }
630 
631     if (command.GetArgumentCount() == 0)
632     {
633         result.AppendError ("No breakpoint specified for which to list the commands");
634         result.SetStatus (eReturnStatusFailed);
635         return false;
636     }
637 
638     BreakpointIDList valid_bp_ids;
639     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
640 
641     if (result.Succeeded())
642     {
643         const size_t count = valid_bp_ids.GetSize();
644         for (size_t i = 0; i < count; ++i)
645         {
646             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
647             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
648             {
649                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
650 
651                 if (bp)
652                 {
653                     const BreakpointOptions *bp_options = NULL;
654                     if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
655                     {
656                         BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
657                         if (bp_loc_sp)
658                             bp_options = bp_loc_sp->GetOptionsNoCreate();
659                         else
660                         {
661                             result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
662                                                          cur_bp_id.GetBreakpointID(),
663                                                          cur_bp_id.GetLocationID());
664                             result.SetStatus (eReturnStatusFailed);
665                             return false;
666                         }
667                     }
668                     else
669                     {
670                         bp_options = bp->GetOptions();
671                     }
672 
673                     if (bp_options)
674                     {
675                         StreamString id_str;
676                         BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
677                         const Baton *baton = bp_options->GetBaton();
678                         if (baton)
679                         {
680                             result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
681                             result.GetOutputStream().IndentMore ();
682                             baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
683                             result.GetOutputStream().IndentLess ();
684                         }
685                         else
686                         {
687                             result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
688                         }
689                     }
690                     result.SetStatus (eReturnStatusSuccessFinishResult);
691                 }
692                 else
693                 {
694                     result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
695                     result.SetStatus (eReturnStatusFailed);
696                 }
697 
698             }
699         }
700     }
701 
702     return result.Succeeded();
703 }
704 
705 //-------------------------------------------------------------------------
706 // CommandObjectBreakpointCommand
707 //-------------------------------------------------------------------------
708 
709 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
710     CommandObjectMultiword (interpreter,
711                             "command",
712                             "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
713                             "command <sub-command> [<sub-command-options>] <breakpoint-id>")
714 {
715     bool status;
716     CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
717     CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter));
718     CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
719 
720     add_command_object->SetCommandName ("breakpoint command add");
721     remove_command_object->SetCommandName ("breakpoint command remove");
722     list_command_object->SetCommandName ("breakpoint command list");
723 
724     status = LoadSubCommand ("add",    add_command_object);
725     status = LoadSubCommand ("remove", remove_command_object);
726     status = LoadSubCommand ("list",   list_command_object);
727 }
728 
729 
730 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
731 {
732 }
733 
734 bool
735 CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
736 (
737     void *baton,
738     StoppointCallbackContext *context,
739     lldb::user_id_t break_id,
740     lldb::user_id_t break_loc_id
741 )
742 {
743     bool ret_value = true;
744     if (baton == NULL)
745         return true;
746 
747 
748     BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
749     StringList &commands = data->user_source;
750 
751     if (commands.GetSize() > 0)
752     {
753         uint32_t num_commands = commands.GetSize();
754         CommandReturnObject result;
755         if (context->exe_ctx.target)
756         {
757 
758             Debugger &debugger = context->exe_ctx.target->GetDebugger();
759             CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
760 
761             FILE *out_fh = debugger.GetOutputFileHandle();
762             FILE *err_fh = debugger.GetErrorFileHandle();
763 
764             uint32_t i;
765             for (i = 0; i < num_commands; ++i)
766             {
767 
768                 // First time through we use the context from the stoppoint, after that we use whatever
769                 // has been set by the previous command.
770 
771                 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
772                     break;
773 
774                 // FIXME: This isn't really the right way to do this.  We should be able to peek at the public
775                 // to see if there is any new events, but that is racey, since the internal process thread has to run and
776                 // deliver the event to the public queue before a run will show up.  So for now we check
777                 // the internal thread state.
778 
779                 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
780                 if (internal_state != eStateStopped)
781                 {
782                     if (i < num_commands - 1)
783                     {
784                         if (out_fh)
785                             ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
786                                                " last command: \"%s\"\n", StateAsCString(internal_state),
787                                                commands.GetStringAtIndex(i));
788                     }
789                     break;
790                 }
791 
792                 if (out_fh)
793                     ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
794                 if (err_fh)
795                     ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
796                 result.Clear();
797                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
798             }
799 
800             if (err_fh && !result.Succeeded() && i < num_commands)
801                 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
802 
803             if (out_fh)
804                 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
805 
806             if (err_fh)
807                 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
808         }
809     }
810     return ret_value;
811 }
812 
813