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