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 Example multiple line Python breakpoint command, using function definition: \n\
166  \n\
167 (lldb) breakpoint command add -p 1 \n\
168 Enter your Python command(s). Type 'DONE' to end. \n\
169 > def breakpoint_output (bp_no): \n\
170 >     out_string = \"Hit breakpoint number \" + repr (bp_no) \n\
171 >     print out_string \n\
172 >     return True \n\
173 > breakpoint_output (1) \n\
174 > DONE \n\
175  \n\
176  \n\
177 Example multiple line Python breakpoint command, using 'loose' Python: \n\
178  \n\
179 (lldb) breakpoint command add -p 1 \n\
180 Enter your Python command(s). Type 'DONE' to end. \n\
181 > global bp_count \n\
182 > bp_count = bp_count + 1 \n\
183 > print \"Hit this breakpoint \" + repr(bp_count) + \" times!\" \n\
184 > DONE \n\
185  \n\
186 In this case, since there is a reference to a global variable, \n\
187 'bp_count', you will also need to make sure 'bp_count' exists and is \n\
188 initialized: \n\
189  \n\
190 (lldb) script \n\
191 >>> bp_count = 0 \n\
192 >>> quit() \n\
193  \n\
194 (lldb)  \n\
195  \n\
196 Special information about debugger command breakpoint commands \n\
197 -------------------------------------------------------------- \n\
198  \n\
199 You may enter any debugger command, exactly as you would at the \n\
200 debugger prompt.  You may enter as many debugger commands as you like, \n\
201 but do NOT enter more than one command per line. \n" );
202 }
203 
204 CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd ()
205 {
206 }
207 
208 bool
209 CommandObjectBreakpointCommandAdd::Execute
210 (
211     CommandInterpreter &interpreter,
212     Args& command,
213     CommandReturnObject &result
214 )
215 {
216     Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
217 
218     if (target == NULL)
219     {
220         result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
221         result.SetStatus (eReturnStatusFailed);
222         return false;
223     }
224 
225     const BreakpointList &breakpoints = target->GetBreakpointList();
226     size_t num_breakpoints = breakpoints.GetSize();
227 
228     if (num_breakpoints == 0)
229     {
230         result.AppendError ("No breakpoints exist to have commands added");
231         result.SetStatus (eReturnStatusFailed);
232         return false;
233     }
234 
235     if (command.GetArgumentCount() == 0)
236     {
237         result.AppendError ("No breakpoint specified to which to add the commands");
238         result.SetStatus (eReturnStatusFailed);
239         return false;
240     }
241 
242     BreakpointIDList valid_bp_ids;
243     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
244 
245     if (result.Succeeded())
246     {
247         const size_t count = valid_bp_ids.GetSize();
248         for (size_t i = 0; i < count; ++i)
249         {
250             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
251             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
252             {
253                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
254                 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
255                 {
256                     BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
257                     if (bp_loc_sp)
258                     {
259                         if (m_options.m_use_script_language)
260                         {
261                             // Special handling for one-liner.
262                             if (command.GetArgumentCount() == 2)
263                                 interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (interpreter,
264                                                                                                   bp_loc_sp->GetLocationOptions(),
265                                                                                                   command.GetArgumentAtIndex(1));
266                             else
267                                 interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (interpreter,
268                                                                                                              bp_loc_sp->GetLocationOptions(),
269                                                                                                              result);
270                         }
271                         else
272                         {
273                             CollectDataForBreakpointCommandCallback (interpreter,
274                                                                      bp_loc_sp->GetLocationOptions(),
275                                                                      result);
276                         }
277                     }
278                 }
279                 else
280                 {
281                     if (m_options.m_use_script_language)
282                     {
283                         // Special handling for one-liner.
284                         if (command.GetArgumentCount() == 2)
285                             interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (interpreter,
286                                                                                               bp->GetOptions(),
287                                                                                               command.GetArgumentAtIndex(1));
288                         else
289                             interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (interpreter,
290                                                                                                          bp->GetOptions(),
291                                                                                                          result);
292                     }
293                     else
294                     {
295                         CollectDataForBreakpointCommandCallback (interpreter,
296                                                                  bp->GetOptions(),
297                                                                  result);
298                     }
299                 }
300             }
301         }
302     }
303 
304     return result.Succeeded();
305 }
306 
307 Options *
308 CommandObjectBreakpointCommandAdd::GetOptions ()
309 {
310     return &m_options;
311 }
312 
313 const char *g_reader_instructions = "Enter your debugger command(s).  Type 'DONE' to end.";
314 
315 void
316 CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
317 (
318     CommandInterpreter &interpreter,
319     BreakpointOptions *bp_options,
320     CommandReturnObject &result
321 )
322 {
323     InputReaderSP reader_sp (new InputReader(interpreter.GetDebugger()));
324     std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
325     if (reader_sp && data_ap.get())
326     {
327         BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
328         bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
329 
330         Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
331                                           bp_options,                   // baton
332                                           eInputReaderGranularityLine,  // token size, to pass to callback function
333                                           "DONE",                       // end token
334                                           "> ",                         // prompt
335                                           true));                       // echo input
336         if (err.Success())
337         {
338             interpreter.GetDebugger().PushInputReader (reader_sp);
339             result.SetStatus (eReturnStatusSuccessFinishNoResult);
340         }
341         else
342         {
343             result.AppendError (err.AsCString());
344             result.SetStatus (eReturnStatusFailed);
345         }
346     }
347     else
348     {
349         result.AppendError("out of memory");
350         result.SetStatus (eReturnStatusFailed);
351     }
352 
353 }
354 
355 size_t
356 CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
357 (
358     void *baton,
359     InputReader &reader,
360     lldb::InputReaderAction notification,
361     const char *bytes,
362     size_t bytes_len
363 )
364 {
365     FILE *out_fh = reader.GetDebugger().GetOutputFileHandle();
366 
367     switch (notification)
368     {
369     case eInputReaderActivate:
370         if (out_fh)
371         {
372             ::fprintf (out_fh, "%s\n", g_reader_instructions);
373             if (reader.GetPrompt())
374                 ::fprintf (out_fh, "%s", reader.GetPrompt());
375         }
376         break;
377 
378     case eInputReaderDeactivate:
379         break;
380 
381     case eInputReaderReactivate:
382         if (out_fh && reader.GetPrompt())
383             ::fprintf (out_fh, "%s", reader.GetPrompt());
384         break;
385 
386     case eInputReaderGotToken:
387         if (bytes && bytes_len && baton)
388         {
389             BreakpointOptions *bp_options = (BreakpointOptions *) baton;
390             if (bp_options)
391             {
392                 Baton *bp_options_baton = bp_options->GetBaton();
393                 if (bp_options_baton)
394                     ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
395             }
396         }
397         if (out_fh && !reader.IsDone() && reader.GetPrompt())
398             ::fprintf (out_fh, "%s", reader.GetPrompt());
399         break;
400 
401     case eInputReaderDone:
402         break;
403     }
404 
405     return bytes_len;
406 }
407 
408 
409 //-------------------------------------------------------------------------
410 // CommandObjectBreakpointCommandRemove
411 //-------------------------------------------------------------------------
412 
413 CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove () :
414     CommandObject ("remove",
415                    "Remove the set of commands from a breakpoint.",
416                    "breakpoint command remove <breakpoint-id>")
417 {
418 }
419 
420 CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
421 {
422 }
423 
424 bool
425 CommandObjectBreakpointCommandRemove::Execute
426 (
427     CommandInterpreter &interpreter,
428     Args& command,
429     CommandReturnObject &result
430 )
431 {
432     Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
433 
434     if (target == NULL)
435     {
436         result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
437         result.SetStatus (eReturnStatusFailed);
438         return false;
439     }
440 
441     const BreakpointList &breakpoints = target->GetBreakpointList();
442     size_t num_breakpoints = breakpoints.GetSize();
443 
444     if (num_breakpoints == 0)
445     {
446         result.AppendError ("No breakpoints exist to have commands removed");
447         result.SetStatus (eReturnStatusFailed);
448         return false;
449     }
450 
451     if (command.GetArgumentCount() == 0)
452     {
453         result.AppendError ("No breakpoint specified from which to remove the commands");
454         result.SetStatus (eReturnStatusFailed);
455         return false;
456     }
457 
458     BreakpointIDList valid_bp_ids;
459     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
460 
461     if (result.Succeeded())
462     {
463         const size_t count = valid_bp_ids.GetSize();
464         for (size_t i = 0; i < count; ++i)
465         {
466             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
467             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
468             {
469                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
470                 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
471                 {
472                     BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
473                     if (bp_loc_sp)
474                         bp_loc_sp->ClearCallback();
475                     else
476                     {
477                         result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
478                                                      cur_bp_id.GetBreakpointID(),
479                                                      cur_bp_id.GetLocationID());
480                         result.SetStatus (eReturnStatusFailed);
481                         return false;
482                     }
483                 }
484                 else
485                 {
486                     bp->ClearCallback();
487                 }
488             }
489         }
490     }
491     return result.Succeeded();
492 }
493 
494 
495 //-------------------------------------------------------------------------
496 // CommandObjectBreakpointCommandList
497 //-------------------------------------------------------------------------
498 
499 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList () :
500     CommandObject ("List",
501                    "List the script or set of commands to be executed when the breakpoint is hit.",
502                    "breakpoint command list <breakpoint-id>")
503 {
504 }
505 
506 CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
507 {
508 }
509 
510 bool
511 CommandObjectBreakpointCommandList::Execute
512 (
513     CommandInterpreter &interpreter,
514     Args& command,
515     CommandReturnObject &result
516 )
517 {
518     Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
519 
520     if (target == NULL)
521     {
522         result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
523         result.SetStatus (eReturnStatusFailed);
524         return false;
525     }
526 
527     const BreakpointList &breakpoints = target->GetBreakpointList();
528     size_t num_breakpoints = breakpoints.GetSize();
529 
530     if (num_breakpoints == 0)
531     {
532         result.AppendError ("No breakpoints exist for which to list commands");
533         result.SetStatus (eReturnStatusFailed);
534         return false;
535     }
536 
537     if (command.GetArgumentCount() == 0)
538     {
539         result.AppendError ("No breakpoint specified for which to list the commands");
540         result.SetStatus (eReturnStatusFailed);
541         return false;
542     }
543 
544     BreakpointIDList valid_bp_ids;
545     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
546 
547     if (result.Succeeded())
548     {
549         const size_t count = valid_bp_ids.GetSize();
550         for (size_t i = 0; i < count; ++i)
551         {
552             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
553             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
554             {
555                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
556 
557                 if (bp)
558                 {
559                     const BreakpointOptions *bp_options = NULL;
560                     if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
561                     {
562                         BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
563                         if (bp_loc_sp)
564                             bp_options = bp_loc_sp->GetOptionsNoCreate();
565                         else
566                         {
567                             result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
568                                                          cur_bp_id.GetBreakpointID(),
569                                                          cur_bp_id.GetLocationID());
570                             result.SetStatus (eReturnStatusFailed);
571                             return false;
572                         }
573                     }
574                     else
575                     {
576                         bp_options = bp->GetOptions();
577                     }
578 
579                     if (bp_options)
580                     {
581                         StreamString id_str;
582                         BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
583                         const Baton *baton = bp_options->GetBaton();
584                         if (baton)
585                         {
586                             result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
587                             result.GetOutputStream().IndentMore ();
588                             baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
589                             result.GetOutputStream().IndentLess ();
590                         }
591                         else
592                         {
593                             result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
594                         }
595                     }
596                     result.SetStatus (eReturnStatusSuccessFinishResult);
597                 }
598                 else
599                 {
600                     result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
601                     result.SetStatus (eReturnStatusFailed);
602                 }
603 
604             }
605         }
606     }
607 
608     return result.Succeeded();
609 }
610 
611 //-------------------------------------------------------------------------
612 // CommandObjectBreakpointCommand
613 //-------------------------------------------------------------------------
614 
615 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
616     CommandObjectMultiword ("command",
617                             "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
618                             "command <sub-command> [<sub-command-options>] <breakpoint-id>")
619 {
620     bool status;
621     CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd ());
622     CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove ());
623     CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList ());
624 
625     add_command_object->SetCommandName ("breakpoint command add");
626     remove_command_object->SetCommandName ("breakpoint command remove");
627     list_command_object->SetCommandName ("breakpoint command list");
628 
629     status = LoadSubCommand (interpreter, "add",    add_command_object);
630     status = LoadSubCommand (interpreter, "remove", remove_command_object);
631     status = LoadSubCommand (interpreter, "list",   list_command_object);
632 }
633 
634 
635 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
636 {
637 }
638 
639 bool
640 CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
641 (
642     void *baton,
643     StoppointCallbackContext *context,
644     lldb::user_id_t break_id,
645     lldb::user_id_t break_loc_id
646 )
647 {
648     bool ret_value = true;
649     if (baton == NULL)
650         return true;
651 
652 
653     BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
654     StringList &commands = data->user_source;
655 
656     if (commands.GetSize() > 0)
657     {
658         uint32_t num_commands = commands.GetSize();
659         CommandReturnObject result;
660         if (context->exe_ctx.target)
661         {
662 
663             Debugger &debugger = context->exe_ctx.target->GetDebugger();
664             CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
665 
666             FILE *out_fh = debugger.GetOutputFileHandle();
667             FILE *err_fh = debugger.GetErrorFileHandle();
668 
669             uint32_t i;
670             for (i = 0; i < num_commands; ++i)
671             {
672 
673                 // First time through we use the context from the stoppoint, after that we use whatever
674                 // has been set by the previous command.
675 
676                 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
677                     break;
678 
679                 // FIXME: This isn't really the right way to do this.  We should be able to peek at the public
680                 // to see if there is any new events, but that is racey, since the internal process thread has to run and
681                 // deliver the event to the public queue before a run will show up.  So for now we check
682                 // the internal thread state.
683 
684                 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
685                 if (internal_state != eStateStopped)
686                 {
687                     if (i < num_commands - 1)
688                     {
689                         if (out_fh)
690                             ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
691                                                " last command: \"%s\"\n", StateAsCString(internal_state),
692                                                commands.GetStringAtIndex(i));
693                     }
694                     break;
695                 }
696 
697                 if (out_fh)
698                     ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
699                 if (err_fh)
700                     ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
701                 result.Clear();
702                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
703             }
704 
705             if (err_fh && !result.Succeeded() && i < num_commands)
706                 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
707 
708             if (out_fh)
709                 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
710 
711             if (err_fh)
712                 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
713         }
714     }
715     return ret_value;
716 }
717 
718