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     BreakpointIDList valid_bp_ids;
286     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
287 
288     if (result.Succeeded())
289     {
290         const size_t count = valid_bp_ids.GetSize();
291         for (size_t i = 0; i < count; ++i)
292         {
293             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
294             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
295             {
296                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
297                 BreakpointOptions *bp_options = NULL;
298                 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
299                 {
300                     // This breakpoint does not have an associated location.
301                     bp_options = bp->GetOptions();
302                 }
303                 else
304                 {
305                     BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
306                     // This breakpoint does have an associated location.
307                     // Get its breakpoint options.
308                     if (bp_loc_sp)
309                         bp_options = bp_loc_sp->GetLocationOptions();
310                 }
311 
312                 // Skip this breakpoiont if bp_options is not good.
313                 if (bp_options == NULL) continue;
314 
315                 // If we are using script language, get the script interpreter
316                 // in order to set or collect command callback.  Otherwise, call
317                 // the methods associated with this object.
318                 if (m_options.m_use_script_language)
319                 {
320                     // Special handling for one-liner specified inline.
321                     if (m_options.m_use_one_liner)
322                         m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
323                                                                                             m_options.m_one_liner.c_str());
324                     else
325                         m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
326                                                                                                        result);
327                 }
328                 else
329                 {
330                     // Special handling for one-liner specified inline.
331                     if (m_options.m_use_one_liner)
332                         SetBreakpointCommandCallback (bp_options,
333                                                       m_options.m_one_liner.c_str());
334                     else
335                         CollectDataForBreakpointCommandCallback (bp_options,
336                                                                  result);
337                 }
338             }
339         }
340     }
341 
342     return result.Succeeded();
343 }
344 
345 Options *
346 CommandObjectBreakpointCommandAdd::GetOptions ()
347 {
348     return &m_options;
349 }
350 
351 const char *g_reader_instructions = "Enter your debugger command(s).  Type 'DONE' to end.";
352 
353 void
354 CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
355 (
356     BreakpointOptions *bp_options,
357     CommandReturnObject &result
358 )
359 {
360     InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
361     std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
362     if (reader_sp && data_ap.get())
363     {
364         BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
365         bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
366 
367         Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
368                                           bp_options,                   // baton
369                                           eInputReaderGranularityLine,  // token size, to pass to callback function
370                                           "DONE",                       // end token
371                                           "> ",                         // prompt
372                                           true));                       // echo input
373         if (err.Success())
374         {
375             m_interpreter.GetDebugger().PushInputReader (reader_sp);
376             result.SetStatus (eReturnStatusSuccessFinishNoResult);
377         }
378         else
379         {
380             result.AppendError (err.AsCString());
381             result.SetStatus (eReturnStatusFailed);
382         }
383     }
384     else
385     {
386         result.AppendError("out of memory");
387         result.SetStatus (eReturnStatusFailed);
388     }
389 
390 }
391 
392 // Set a one-liner as the callback for the breakpoint.
393 void
394 CommandObjectBreakpointCommandAdd::SetBreakpointCommandCallback (BreakpointOptions *bp_options,
395                                                                  const char *oneliner)
396 {
397     std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
398 
399     // It's necessary to set both user_source and script_source to the oneliner.
400     // The former is used to generate callback description (as in breakpoint command list)
401     // while the latter is used for Python to interpret during the actual callback.
402     data_ap->user_source.AppendString (oneliner);
403     data_ap->script_source.AppendString (oneliner);
404 
405     BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
406     bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
407 
408     return;
409 }
410 
411 size_t
412 CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
413 (
414     void *baton,
415     InputReader &reader,
416     lldb::InputReaderAction notification,
417     const char *bytes,
418     size_t bytes_len
419 )
420 {
421     File &out_file = reader.GetDebugger().GetOutputFile();
422 
423     switch (notification)
424     {
425     case eInputReaderActivate:
426         out_file.Printf ("%s\n", g_reader_instructions);
427         if (reader.GetPrompt())
428             out_file.Printf ("%s", reader.GetPrompt());
429         out_file.Flush();
430         break;
431 
432     case eInputReaderDeactivate:
433         break;
434 
435     case eInputReaderReactivate:
436         if (reader.GetPrompt())
437         {
438             out_file.Printf ("%s", reader.GetPrompt());
439             out_file.Flush();
440         }
441         break;
442 
443     case eInputReaderGotToken:
444         if (bytes && bytes_len && baton)
445         {
446             BreakpointOptions *bp_options = (BreakpointOptions *) baton;
447             if (bp_options)
448             {
449                 Baton *bp_options_baton = bp_options->GetBaton();
450                 if (bp_options_baton)
451                     ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
452             }
453         }
454         if (!reader.IsDone() && reader.GetPrompt())
455         {
456             out_file.Printf ("%s", reader.GetPrompt());
457             out_file.Flush();
458         }
459         break;
460 
461     case eInputReaderInterrupt:
462         {
463             // Finish, and cancel the breakpoint command.
464             reader.SetIsDone (true);
465             BreakpointOptions *bp_options = (BreakpointOptions *) baton;
466             if (bp_options)
467             {
468                 Baton *bp_options_baton = bp_options->GetBaton ();
469                 if (bp_options_baton)
470                 {
471                     ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear();
472                     ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.Clear();
473                 }
474             }
475             out_file.Printf ("Warning: No command attached to breakpoint.\n");
476             out_file.Flush();
477         }
478         break;
479 
480     case eInputReaderEndOfFile:
481         reader.SetIsDone (true);
482         break;
483 
484     case eInputReaderDone:
485         break;
486     }
487 
488     return bytes_len;
489 }
490 
491 
492 //-------------------------------------------------------------------------
493 // CommandObjectBreakpointCommandRemove
494 //-------------------------------------------------------------------------
495 
496 CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) :
497     CommandObject (interpreter,
498                    "remove",
499                    "Remove the set of commands from a breakpoint.",
500                    NULL)
501 {
502     CommandArgumentEntry arg;
503     CommandArgumentData bp_id_arg;
504 
505     // Define the first (and only) variant of this arg.
506     bp_id_arg.arg_type = eArgTypeBreakpointID;
507     bp_id_arg.arg_repetition = eArgRepeatPlain;
508 
509     // There is only one variant this argument could be; put it into the argument entry.
510     arg.push_back (bp_id_arg);
511 
512     // Push the data for the first argument into the m_arguments vector.
513     m_arguments.push_back (arg);
514 }
515 
516 CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
517 {
518 }
519 
520 bool
521 CommandObjectBreakpointCommandRemove::Execute
522 (
523     Args& command,
524     CommandReturnObject &result
525 )
526 {
527     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
528 
529     if (target == NULL)
530     {
531         result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
532         result.SetStatus (eReturnStatusFailed);
533         return false;
534     }
535 
536     const BreakpointList &breakpoints = target->GetBreakpointList();
537     size_t num_breakpoints = breakpoints.GetSize();
538 
539     if (num_breakpoints == 0)
540     {
541         result.AppendError ("No breakpoints exist to have commands removed");
542         result.SetStatus (eReturnStatusFailed);
543         return false;
544     }
545 
546     if (command.GetArgumentCount() == 0)
547     {
548         result.AppendError ("No breakpoint specified from which to remove the commands");
549         result.SetStatus (eReturnStatusFailed);
550         return false;
551     }
552 
553     BreakpointIDList valid_bp_ids;
554     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
555 
556     if (result.Succeeded())
557     {
558         const size_t count = valid_bp_ids.GetSize();
559         for (size_t i = 0; i < count; ++i)
560         {
561             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
562             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
563             {
564                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
565                 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
566                 {
567                     BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
568                     if (bp_loc_sp)
569                         bp_loc_sp->ClearCallback();
570                     else
571                     {
572                         result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
573                                                      cur_bp_id.GetBreakpointID(),
574                                                      cur_bp_id.GetLocationID());
575                         result.SetStatus (eReturnStatusFailed);
576                         return false;
577                     }
578                 }
579                 else
580                 {
581                     bp->ClearCallback();
582                 }
583             }
584         }
585     }
586     return result.Succeeded();
587 }
588 
589 
590 //-------------------------------------------------------------------------
591 // CommandObjectBreakpointCommandList
592 //-------------------------------------------------------------------------
593 
594 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
595     CommandObject (interpreter,
596                    "list",
597                    "List the script or set of commands to be executed when the breakpoint is hit.",
598                     NULL)
599 {
600     CommandArgumentEntry arg;
601     CommandArgumentData bp_id_arg;
602 
603     // Define the first (and only) variant of this arg.
604     bp_id_arg.arg_type = eArgTypeBreakpointID;
605     bp_id_arg.arg_repetition = eArgRepeatPlain;
606 
607     // There is only one variant this argument could be; put it into the argument entry.
608     arg.push_back (bp_id_arg);
609 
610     // Push the data for the first argument into the m_arguments vector.
611     m_arguments.push_back (arg);
612 }
613 
614 CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
615 {
616 }
617 
618 bool
619 CommandObjectBreakpointCommandList::Execute
620 (
621     Args& command,
622     CommandReturnObject &result
623 )
624 {
625     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
626 
627     if (target == NULL)
628     {
629         result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
630         result.SetStatus (eReturnStatusFailed);
631         return false;
632     }
633 
634     const BreakpointList &breakpoints = target->GetBreakpointList();
635     size_t num_breakpoints = breakpoints.GetSize();
636 
637     if (num_breakpoints == 0)
638     {
639         result.AppendError ("No breakpoints exist for which to list commands");
640         result.SetStatus (eReturnStatusFailed);
641         return false;
642     }
643 
644     if (command.GetArgumentCount() == 0)
645     {
646         result.AppendError ("No breakpoint specified for which to list the commands");
647         result.SetStatus (eReturnStatusFailed);
648         return false;
649     }
650 
651     BreakpointIDList valid_bp_ids;
652     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
653 
654     if (result.Succeeded())
655     {
656         const size_t count = valid_bp_ids.GetSize();
657         for (size_t i = 0; i < count; ++i)
658         {
659             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
660             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
661             {
662                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
663 
664                 if (bp)
665                 {
666                     const BreakpointOptions *bp_options = NULL;
667                     if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
668                     {
669                         BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
670                         if (bp_loc_sp)
671                             bp_options = bp_loc_sp->GetOptionsNoCreate();
672                         else
673                         {
674                             result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
675                                                          cur_bp_id.GetBreakpointID(),
676                                                          cur_bp_id.GetLocationID());
677                             result.SetStatus (eReturnStatusFailed);
678                             return false;
679                         }
680                     }
681                     else
682                     {
683                         bp_options = bp->GetOptions();
684                     }
685 
686                     if (bp_options)
687                     {
688                         StreamString id_str;
689                         BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
690                         const Baton *baton = bp_options->GetBaton();
691                         if (baton)
692                         {
693                             result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
694                             result.GetOutputStream().IndentMore ();
695                             baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
696                             result.GetOutputStream().IndentLess ();
697                         }
698                         else
699                         {
700                             result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
701                         }
702                     }
703                     result.SetStatus (eReturnStatusSuccessFinishResult);
704                 }
705                 else
706                 {
707                     result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
708                     result.SetStatus (eReturnStatusFailed);
709                 }
710 
711             }
712         }
713     }
714 
715     return result.Succeeded();
716 }
717 
718 //-------------------------------------------------------------------------
719 // CommandObjectBreakpointCommand
720 //-------------------------------------------------------------------------
721 
722 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
723     CommandObjectMultiword (interpreter,
724                             "command",
725                             "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
726                             "command <sub-command> [<sub-command-options>] <breakpoint-id>")
727 {
728     bool status;
729     CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
730     CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter));
731     CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
732 
733     add_command_object->SetCommandName ("breakpoint command add");
734     remove_command_object->SetCommandName ("breakpoint command remove");
735     list_command_object->SetCommandName ("breakpoint command list");
736 
737     status = LoadSubCommand ("add",    add_command_object);
738     status = LoadSubCommand ("remove", remove_command_object);
739     status = LoadSubCommand ("list",   list_command_object);
740 }
741 
742 
743 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
744 {
745 }
746 
747 bool
748 CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
749 (
750     void *baton,
751     StoppointCallbackContext *context,
752     lldb::user_id_t break_id,
753     lldb::user_id_t break_loc_id
754 )
755 {
756     bool ret_value = true;
757     if (baton == NULL)
758         return true;
759 
760 
761     BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
762     StringList &commands = data->user_source;
763 
764     if (commands.GetSize() > 0)
765     {
766         uint32_t num_commands = commands.GetSize();
767         CommandReturnObject result;
768         if (context->exe_ctx.target)
769         {
770 
771             Debugger &debugger = context->exe_ctx.target->GetDebugger();
772             CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
773 
774             File &out_file = debugger.GetOutputFile();
775             File &err_file = debugger.GetErrorFile();
776 
777             uint32_t i;
778             for (i = 0; i < num_commands; ++i)
779             {
780 
781                 // First time through we use the context from the stoppoint, after that we use whatever
782                 // has been set by the previous command.
783 
784                 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
785                     break;
786 
787                 // FIXME: This isn't really the right way to do this.  We should be able to peek at the public
788                 // to see if there is any new events, but that is racey, since the internal process thread has to run and
789                 // deliver the event to the public queue before a run will show up.  So for now we check
790                 // the internal thread state.
791 
792                 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
793                 if (internal_state != eStateStopped)
794                 {
795                     if (i < num_commands - 1)
796                     {
797                         out_file.Printf ("Short-circuiting command execution because target state changed to %s."
798                                          " last command: \"%s\"\n", StateAsCString(internal_state),
799                                          commands.GetStringAtIndex(i));
800                     }
801                     break;
802                 }
803 
804                 out_file.Printf ("%s", result.GetErrorStream().GetData());
805                 err_file.Printf ("%s", result.GetOutputStream().GetData());
806                 result.Clear();
807                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
808             }
809 
810             if (!result.Succeeded() && i < num_commands)
811                 err_file.Printf ("Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
812 
813             out_file.Printf ("%s", result.GetErrorStream().GetData());
814             err_file.Printf ("%s", result.GetOutputStream().GetData());
815         }
816     }
817     return ret_value;
818 }
819 
820