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