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