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-line breakpoint command inline. Be sure to surround it with quotes." }, 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 (CommandInterpreter &interpreter) : 129 CommandObject (interpreter, 130 "add", 131 "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.", 132 "breakpoint command add <cmd-options> <breakpoint-id>") 133 { 134 SetHelpLong ( 135 "\nGeneral information about entering breakpoint commands \n\ 136 ------------------------------------------------------ \n\ 137 \n\ 138 This command will cause you to be prompted to enter the command or set \n\ 139 of commands you wish to be executed when the specified breakpoint is \n\ 140 hit. You will be told to enter your command(s), and will see a '> ' \n\ 141 prompt. Because you can enter one or many commands to be executed when \n\ 142 a breakpoint is hit, you will continue to be prompted after each \n\ 143 new-line that you enter, until you enter the word 'DONE', which will \n\ 144 cause the commands you have entered to be stored with the breakpoint \n\ 145 and executed when the breakpoint is hit. \n\ 146 \n\ 147 Syntax checking is not necessarily done when breakpoint commands are \n\ 148 entered. An improperly written breakpoint command will attempt to get \n\ 149 executed when the breakpoint gets hit, and usually silently fail. If \n\ 150 your breakpoint command does not appear to be getting executed, go \n\ 151 back and check your syntax. \n\ 152 \n\ 153 \n\ 154 Special information about PYTHON breakpoint commands \n\ 155 ---------------------------------------------------- \n\ 156 \n\ 157 You may enter either one line of Python or multiple lines of Python \n\ 158 (including defining whole functions, if desired). If you enter a \n\ 159 single line of Python, that will be passed to the Python interpreter \n\ 160 'as is' when the breakpoint gets hit. If you enter function \n\ 161 definitions, they will be passed to the Python interpreter as soon as \n\ 162 you finish entering the breakpoint command, and they can be called \n\ 163 later (don't forget to add calls to them, if you want them called when \n\ 164 the breakpoint is hit). If you enter multiple lines of Python that \n\ 165 are not function definitions, they will be collected into a new, \n\ 166 automatically generated Python function, and a call to the newly \n\ 167 generated function will be attached to the breakpoint. Important \n\ 168 Note: Because loose Python code gets collected into functions, if you \n\ 169 want to access global variables in the 'loose' code, you need to \n\ 170 specify that they are global, using the 'global' keyword. Be sure to \n\ 171 use correct Python syntax, including indentation, when entering Python \n\ 172 breakpoint commands. \n\ 173 \n\ 174 Example Python one-line breakpoint command: \n\ 175 \n\ 176 (lldb) breakpoint command add -p 1 \n\ 177 Enter your Python command(s). Type 'DONE' to end. \n\ 178 > print \"Hit this breakpoint!\" \n\ 179 > DONE \n\ 180 \n\ 181 As a convenience, this also works for a short Python one-liner: \n\ 182 (lldb) breakpoint command add -p 1 -o \"import time; print time.asctime()\" \n\ 183 (lldb) run \n\ 184 Launching '.../a.out' (x86_64) \n\ 185 (lldb) Fri Sep 10 12:17:45 2010 \n\ 186 Process 21778 Stopped \n\ 187 * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread \n\ 188 36 \n\ 189 37 int c(int val)\n\ 190 38 {\n\ 191 39 -> return val + 3;\n\ 192 40 }\n\ 193 41 \n\ 194 42 int main (int argc, char const *argv[])\n\ 195 (lldb) \n\ 196 \n\ 197 Example multiple line Python breakpoint command, using function definition: \n\ 198 \n\ 199 (lldb) breakpoint command add -p 1 \n\ 200 Enter your Python command(s). Type 'DONE' to end. \n\ 201 > def breakpoint_output (bp_no): \n\ 202 > out_string = \"Hit breakpoint number \" + repr (bp_no) \n\ 203 > print out_string \n\ 204 > return True \n\ 205 > breakpoint_output (1) \n\ 206 > DONE \n\ 207 \n\ 208 \n\ 209 Example multiple line Python breakpoint command, using 'loose' Python: \n\ 210 \n\ 211 (lldb) breakpoint command add -p 1 \n\ 212 Enter your Python command(s). Type 'DONE' to end. \n\ 213 > global bp_count \n\ 214 > bp_count = bp_count + 1 \n\ 215 > print \"Hit this breakpoint \" + repr(bp_count) + \" times!\" \n\ 216 > DONE \n\ 217 \n\ 218 In this case, since there is a reference to a global variable, \n\ 219 'bp_count', you will also need to make sure 'bp_count' exists and is \n\ 220 initialized: \n\ 221 \n\ 222 (lldb) script \n\ 223 >>> bp_count = 0 \n\ 224 >>> quit() \n\ 225 \n\ 226 (lldb) \n\ 227 \n\ 228 \n\ 229 Final Note: If you get a warning that no breakpoint command was generated, \n\ 230 but you did not get any syntax errors, you probably forgot to add a call \n\ 231 to your functions. \n\ 232 \n\ 233 Special information about debugger command breakpoint commands \n\ 234 -------------------------------------------------------------- \n\ 235 \n\ 236 You may enter any debugger command, exactly as you would at the \n\ 237 debugger prompt. You may enter as many debugger commands as you like, \n\ 238 but do NOT enter more than one command per line. \n" ); 239 } 240 241 CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd () 242 { 243 } 244 245 bool 246 CommandObjectBreakpointCommandAdd::Execute 247 ( 248 Args& command, 249 CommandReturnObject &result 250 ) 251 { 252 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 253 254 if (target == NULL) 255 { 256 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands"); 257 result.SetStatus (eReturnStatusFailed); 258 return false; 259 } 260 261 const BreakpointList &breakpoints = target->GetBreakpointList(); 262 size_t num_breakpoints = breakpoints.GetSize(); 263 264 if (num_breakpoints == 0) 265 { 266 result.AppendError ("No breakpoints exist to have commands added"); 267 result.SetStatus (eReturnStatusFailed); 268 return false; 269 } 270 271 if (command.GetArgumentCount() == 0) 272 { 273 result.AppendError ("No breakpoint specified to which to add the commands"); 274 result.SetStatus (eReturnStatusFailed); 275 return false; 276 } 277 278 BreakpointIDList valid_bp_ids; 279 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 280 281 if (result.Succeeded()) 282 { 283 const size_t count = valid_bp_ids.GetSize(); 284 for (size_t i = 0; i < count; ++i) 285 { 286 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 287 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 288 { 289 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 290 BreakpointOptions *bp_options = NULL; 291 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) 292 { 293 // This breakpoint does not have an associated location. 294 bp_options = bp->GetOptions(); 295 } 296 else 297 { 298 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 299 // This breakpoint does have an associated location. 300 // Get its breakpoint options. 301 if (bp_loc_sp) 302 bp_options = bp_loc_sp->GetLocationOptions(); 303 } 304 305 // Skip this breakpoiont if bp_options is not good. 306 if (bp_options == NULL) continue; 307 308 // If we are using script language, get the script interpreter 309 // in order to set or collect command callback. Otherwise, call 310 // the methods associated with this object. 311 if (m_options.m_use_script_language) 312 { 313 // Special handling for one-liner specified inline. 314 if (m_options.m_use_one_liner) 315 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, 316 m_options.m_one_liner.c_str()); 317 else 318 m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options, 319 result); 320 } 321 else 322 { 323 // Special handling for one-liner specified inline. 324 if (m_options.m_use_one_liner) 325 SetBreakpointCommandCallback (bp_options, 326 m_options.m_one_liner.c_str()); 327 else 328 CollectDataForBreakpointCommandCallback (bp_options, 329 result); 330 } 331 } 332 } 333 } 334 335 return result.Succeeded(); 336 } 337 338 Options * 339 CommandObjectBreakpointCommandAdd::GetOptions () 340 { 341 return &m_options; 342 } 343 344 const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; 345 346 void 347 CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback 348 ( 349 BreakpointOptions *bp_options, 350 CommandReturnObject &result 351 ) 352 { 353 InputReaderSP reader_sp (new InputReader(m_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 m_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 (BreakpointOptions *bp_options, 388 const char *oneliner) 389 { 390 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 391 392 // It's necessary to set both user_source and script_source to the oneliner. 393 // The former is used to generate callback description (as in breakpoint command list) 394 // while the latter is used for Python to interpret during the actual callback. 395 data_ap->user_source.AppendString (oneliner); 396 data_ap->script_source.AppendString (oneliner); 397 398 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 399 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp); 400 401 return; 402 } 403 404 size_t 405 CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback 406 ( 407 void *baton, 408 InputReader &reader, 409 lldb::InputReaderAction notification, 410 const char *bytes, 411 size_t bytes_len 412 ) 413 { 414 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle(); 415 416 switch (notification) 417 { 418 case eInputReaderActivate: 419 if (out_fh) 420 { 421 ::fprintf (out_fh, "%s\n", g_reader_instructions); 422 if (reader.GetPrompt()) 423 ::fprintf (out_fh, "%s", reader.GetPrompt()); 424 } 425 break; 426 427 case eInputReaderDeactivate: 428 break; 429 430 case eInputReaderReactivate: 431 if (out_fh && reader.GetPrompt()) 432 ::fprintf (out_fh, "%s", reader.GetPrompt()); 433 break; 434 435 case eInputReaderGotToken: 436 if (bytes && bytes_len && baton) 437 { 438 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 439 if (bp_options) 440 { 441 Baton *bp_options_baton = bp_options->GetBaton(); 442 if (bp_options_baton) 443 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 444 } 445 } 446 if (out_fh && !reader.IsDone() && reader.GetPrompt()) 447 ::fprintf (out_fh, "%s", reader.GetPrompt()); 448 break; 449 450 case eInputReaderDone: 451 break; 452 } 453 454 return bytes_len; 455 } 456 457 458 //------------------------------------------------------------------------- 459 // CommandObjectBreakpointCommandRemove 460 //------------------------------------------------------------------------- 461 462 CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) : 463 CommandObject (interpreter, 464 "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 Args& command, 478 CommandReturnObject &result 479 ) 480 { 481 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 482 483 if (target == NULL) 484 { 485 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands"); 486 result.SetStatus (eReturnStatusFailed); 487 return false; 488 } 489 490 const BreakpointList &breakpoints = target->GetBreakpointList(); 491 size_t num_breakpoints = breakpoints.GetSize(); 492 493 if (num_breakpoints == 0) 494 { 495 result.AppendError ("No breakpoints exist to have commands removed"); 496 result.SetStatus (eReturnStatusFailed); 497 return false; 498 } 499 500 if (command.GetArgumentCount() == 0) 501 { 502 result.AppendError ("No breakpoint specified from which to remove the commands"); 503 result.SetStatus (eReturnStatusFailed); 504 return false; 505 } 506 507 BreakpointIDList valid_bp_ids; 508 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 509 510 if (result.Succeeded()) 511 { 512 const size_t count = valid_bp_ids.GetSize(); 513 for (size_t i = 0; i < count; ++i) 514 { 515 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 516 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 517 { 518 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 519 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 520 { 521 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 522 if (bp_loc_sp) 523 bp_loc_sp->ClearCallback(); 524 else 525 { 526 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 527 cur_bp_id.GetBreakpointID(), 528 cur_bp_id.GetLocationID()); 529 result.SetStatus (eReturnStatusFailed); 530 return false; 531 } 532 } 533 else 534 { 535 bp->ClearCallback(); 536 } 537 } 538 } 539 } 540 return result.Succeeded(); 541 } 542 543 544 //------------------------------------------------------------------------- 545 // CommandObjectBreakpointCommandList 546 //------------------------------------------------------------------------- 547 548 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 549 CommandObject (interpreter, 550 "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 Args& command, 564 CommandReturnObject &result 565 ) 566 { 567 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 568 569 if (target == NULL) 570 { 571 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 572 result.SetStatus (eReturnStatusFailed); 573 return false; 574 } 575 576 const BreakpointList &breakpoints = target->GetBreakpointList(); 577 size_t num_breakpoints = breakpoints.GetSize(); 578 579 if (num_breakpoints == 0) 580 { 581 result.AppendError ("No breakpoints exist for which to list commands"); 582 result.SetStatus (eReturnStatusFailed); 583 return false; 584 } 585 586 if (command.GetArgumentCount() == 0) 587 { 588 result.AppendError ("No breakpoint specified for which to list the commands"); 589 result.SetStatus (eReturnStatusFailed); 590 return false; 591 } 592 593 BreakpointIDList valid_bp_ids; 594 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 595 596 if (result.Succeeded()) 597 { 598 const size_t count = valid_bp_ids.GetSize(); 599 for (size_t i = 0; i < count; ++i) 600 { 601 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 602 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 603 { 604 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 605 606 if (bp) 607 { 608 const BreakpointOptions *bp_options = NULL; 609 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 610 { 611 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 612 if (bp_loc_sp) 613 bp_options = bp_loc_sp->GetOptionsNoCreate(); 614 else 615 { 616 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 617 cur_bp_id.GetBreakpointID(), 618 cur_bp_id.GetLocationID()); 619 result.SetStatus (eReturnStatusFailed); 620 return false; 621 } 622 } 623 else 624 { 625 bp_options = bp->GetOptions(); 626 } 627 628 if (bp_options) 629 { 630 StreamString id_str; 631 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); 632 const Baton *baton = bp_options->GetBaton(); 633 if (baton) 634 { 635 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 636 result.GetOutputStream().IndentMore (); 637 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 638 result.GetOutputStream().IndentLess (); 639 } 640 else 641 { 642 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData()); 643 } 644 } 645 result.SetStatus (eReturnStatusSuccessFinishResult); 646 } 647 else 648 { 649 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 650 result.SetStatus (eReturnStatusFailed); 651 } 652 653 } 654 } 655 } 656 657 return result.Succeeded(); 658 } 659 660 //------------------------------------------------------------------------- 661 // CommandObjectBreakpointCommand 662 //------------------------------------------------------------------------- 663 664 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 665 CommandObjectMultiword (interpreter, 666 "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 (interpreter)); 672 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter)); 673 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 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 ("add", add_command_object); 680 status = LoadSubCommand ("remove", remove_command_object); 681 status = LoadSubCommand ("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