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