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