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