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 (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 Special information about debugger command breakpoint commands \n\ 229 -------------------------------------------------------------- \n\ 230 \n\ 231 You may enter any debugger command, exactly as you would at the \n\ 232 debugger prompt. You may enter as many debugger commands as you like, \n\ 233 but do NOT enter more than one command per line. \n" ); 234 } 235 236 CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd () 237 { 238 } 239 240 bool 241 CommandObjectBreakpointCommandAdd::Execute 242 ( 243 Args& command, 244 CommandReturnObject &result 245 ) 246 { 247 Target *target = m_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 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, 311 m_options.m_one_liner.c_str()); 312 else 313 m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options, 314 result); 315 } 316 else 317 { 318 // Special handling for one-liner specified inline. 319 if (m_options.m_use_one_liner) 320 SetBreakpointCommandCallback (bp_options, 321 m_options.m_one_liner.c_str()); 322 else 323 CollectDataForBreakpointCommandCallback (bp_options, 324 result); 325 } 326 } 327 } 328 } 329 330 return result.Succeeded(); 331 } 332 333 Options * 334 CommandObjectBreakpointCommandAdd::GetOptions () 335 { 336 return &m_options; 337 } 338 339 const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; 340 341 void 342 CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback 343 ( 344 BreakpointOptions *bp_options, 345 CommandReturnObject &result 346 ) 347 { 348 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 349 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 350 if (reader_sp && data_ap.get()) 351 { 352 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 353 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp); 354 355 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback, 356 bp_options, // baton 357 eInputReaderGranularityLine, // token size, to pass to callback function 358 "DONE", // end token 359 "> ", // prompt 360 true)); // echo input 361 if (err.Success()) 362 { 363 m_interpreter.GetDebugger().PushInputReader (reader_sp); 364 result.SetStatus (eReturnStatusSuccessFinishNoResult); 365 } 366 else 367 { 368 result.AppendError (err.AsCString()); 369 result.SetStatus (eReturnStatusFailed); 370 } 371 } 372 else 373 { 374 result.AppendError("out of memory"); 375 result.SetStatus (eReturnStatusFailed); 376 } 377 378 } 379 380 // Set a one-liner as the callback for the breakpoint. 381 void 382 CommandObjectBreakpointCommandAdd::SetBreakpointCommandCallback (BreakpointOptions *bp_options, 383 const char *oneliner) 384 { 385 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 386 387 // It's necessary to set both user_source and script_source to the oneliner. 388 // The former is used to generate callback description (as in breakpoint command list) 389 // while the latter is used for Python to interpret during the actual callback. 390 data_ap->user_source.AppendString (oneliner); 391 data_ap->script_source.AppendString (oneliner); 392 393 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 394 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp); 395 396 return; 397 } 398 399 size_t 400 CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback 401 ( 402 void *baton, 403 InputReader &reader, 404 lldb::InputReaderAction notification, 405 const char *bytes, 406 size_t bytes_len 407 ) 408 { 409 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle(); 410 411 switch (notification) 412 { 413 case eInputReaderActivate: 414 if (out_fh) 415 { 416 ::fprintf (out_fh, "%s\n", g_reader_instructions); 417 if (reader.GetPrompt()) 418 ::fprintf (out_fh, "%s", reader.GetPrompt()); 419 } 420 break; 421 422 case eInputReaderDeactivate: 423 break; 424 425 case eInputReaderReactivate: 426 if (out_fh && reader.GetPrompt()) 427 ::fprintf (out_fh, "%s", reader.GetPrompt()); 428 break; 429 430 case eInputReaderGotToken: 431 if (bytes && bytes_len && baton) 432 { 433 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 434 if (bp_options) 435 { 436 Baton *bp_options_baton = bp_options->GetBaton(); 437 if (bp_options_baton) 438 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 439 } 440 } 441 if (out_fh && !reader.IsDone() && reader.GetPrompt()) 442 ::fprintf (out_fh, "%s", reader.GetPrompt()); 443 break; 444 445 case eInputReaderDone: 446 break; 447 } 448 449 return bytes_len; 450 } 451 452 453 //------------------------------------------------------------------------- 454 // CommandObjectBreakpointCommandRemove 455 //------------------------------------------------------------------------- 456 457 CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) : 458 CommandObject (interpreter, 459 "remove", 460 "Remove the set of commands from a breakpoint.", 461 "breakpoint command remove <breakpoint-id>") 462 { 463 } 464 465 CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove () 466 { 467 } 468 469 bool 470 CommandObjectBreakpointCommandRemove::Execute 471 ( 472 Args& command, 473 CommandReturnObject &result 474 ) 475 { 476 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 477 478 if (target == NULL) 479 { 480 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands"); 481 result.SetStatus (eReturnStatusFailed); 482 return false; 483 } 484 485 const BreakpointList &breakpoints = target->GetBreakpointList(); 486 size_t num_breakpoints = breakpoints.GetSize(); 487 488 if (num_breakpoints == 0) 489 { 490 result.AppendError ("No breakpoints exist to have commands removed"); 491 result.SetStatus (eReturnStatusFailed); 492 return false; 493 } 494 495 if (command.GetArgumentCount() == 0) 496 { 497 result.AppendError ("No breakpoint specified from which to remove the commands"); 498 result.SetStatus (eReturnStatusFailed); 499 return false; 500 } 501 502 BreakpointIDList valid_bp_ids; 503 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 504 505 if (result.Succeeded()) 506 { 507 const size_t count = valid_bp_ids.GetSize(); 508 for (size_t i = 0; i < count; ++i) 509 { 510 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 511 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 512 { 513 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 514 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 515 { 516 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 517 if (bp_loc_sp) 518 bp_loc_sp->ClearCallback(); 519 else 520 { 521 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 522 cur_bp_id.GetBreakpointID(), 523 cur_bp_id.GetLocationID()); 524 result.SetStatus (eReturnStatusFailed); 525 return false; 526 } 527 } 528 else 529 { 530 bp->ClearCallback(); 531 } 532 } 533 } 534 } 535 return result.Succeeded(); 536 } 537 538 539 //------------------------------------------------------------------------- 540 // CommandObjectBreakpointCommandList 541 //------------------------------------------------------------------------- 542 543 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 544 CommandObject (interpreter, 545 "list", 546 "List the script or set of commands to be executed when the breakpoint is hit.", 547 "breakpoint command list <breakpoint-id>") 548 { 549 } 550 551 CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList () 552 { 553 } 554 555 bool 556 CommandObjectBreakpointCommandList::Execute 557 ( 558 Args& command, 559 CommandReturnObject &result 560 ) 561 { 562 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 563 564 if (target == NULL) 565 { 566 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 567 result.SetStatus (eReturnStatusFailed); 568 return false; 569 } 570 571 const BreakpointList &breakpoints = target->GetBreakpointList(); 572 size_t num_breakpoints = breakpoints.GetSize(); 573 574 if (num_breakpoints == 0) 575 { 576 result.AppendError ("No breakpoints exist for which to list commands"); 577 result.SetStatus (eReturnStatusFailed); 578 return false; 579 } 580 581 if (command.GetArgumentCount() == 0) 582 { 583 result.AppendError ("No breakpoint specified for which to list the commands"); 584 result.SetStatus (eReturnStatusFailed); 585 return false; 586 } 587 588 BreakpointIDList valid_bp_ids; 589 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 590 591 if (result.Succeeded()) 592 { 593 const size_t count = valid_bp_ids.GetSize(); 594 for (size_t i = 0; i < count; ++i) 595 { 596 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 597 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 598 { 599 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 600 601 if (bp) 602 { 603 const BreakpointOptions *bp_options = NULL; 604 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 605 { 606 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 607 if (bp_loc_sp) 608 bp_options = bp_loc_sp->GetOptionsNoCreate(); 609 else 610 { 611 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 612 cur_bp_id.GetBreakpointID(), 613 cur_bp_id.GetLocationID()); 614 result.SetStatus (eReturnStatusFailed); 615 return false; 616 } 617 } 618 else 619 { 620 bp_options = bp->GetOptions(); 621 } 622 623 if (bp_options) 624 { 625 StreamString id_str; 626 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); 627 const Baton *baton = bp_options->GetBaton(); 628 if (baton) 629 { 630 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 631 result.GetOutputStream().IndentMore (); 632 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 633 result.GetOutputStream().IndentLess (); 634 } 635 else 636 { 637 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData()); 638 } 639 } 640 result.SetStatus (eReturnStatusSuccessFinishResult); 641 } 642 else 643 { 644 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 645 result.SetStatus (eReturnStatusFailed); 646 } 647 648 } 649 } 650 } 651 652 return result.Succeeded(); 653 } 654 655 //------------------------------------------------------------------------- 656 // CommandObjectBreakpointCommand 657 //------------------------------------------------------------------------- 658 659 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 660 CommandObjectMultiword (interpreter, 661 "command", 662 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').", 663 "command <sub-command> [<sub-command-options>] <breakpoint-id>") 664 { 665 bool status; 666 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); 667 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter)); 668 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 669 670 add_command_object->SetCommandName ("breakpoint command add"); 671 remove_command_object->SetCommandName ("breakpoint command remove"); 672 list_command_object->SetCommandName ("breakpoint command list"); 673 674 status = LoadSubCommand ("add", add_command_object); 675 status = LoadSubCommand ("remove", remove_command_object); 676 status = LoadSubCommand ("list", list_command_object); 677 } 678 679 680 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () 681 { 682 } 683 684 bool 685 CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction 686 ( 687 void *baton, 688 StoppointCallbackContext *context, 689 lldb::user_id_t break_id, 690 lldb::user_id_t break_loc_id 691 ) 692 { 693 bool ret_value = true; 694 if (baton == NULL) 695 return true; 696 697 698 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; 699 StringList &commands = data->user_source; 700 701 if (commands.GetSize() > 0) 702 { 703 uint32_t num_commands = commands.GetSize(); 704 CommandReturnObject result; 705 if (context->exe_ctx.target) 706 { 707 708 Debugger &debugger = context->exe_ctx.target->GetDebugger(); 709 CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); 710 711 FILE *out_fh = debugger.GetOutputFileHandle(); 712 FILE *err_fh = debugger.GetErrorFileHandle(); 713 714 uint32_t i; 715 for (i = 0; i < num_commands; ++i) 716 { 717 718 // First time through we use the context from the stoppoint, after that we use whatever 719 // has been set by the previous command. 720 721 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx)) 722 break; 723 724 // FIXME: This isn't really the right way to do this. We should be able to peek at the public 725 // to see if there is any new events, but that is racey, since the internal process thread has to run and 726 // deliver the event to the public queue before a run will show up. So for now we check 727 // the internal thread state. 728 729 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState(); 730 if (internal_state != eStateStopped) 731 { 732 if (i < num_commands - 1) 733 { 734 if (out_fh) 735 ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s." 736 " last command: \"%s\"\n", StateAsCString(internal_state), 737 commands.GetStringAtIndex(i)); 738 } 739 break; 740 } 741 742 if (out_fh) 743 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData()); 744 if (err_fh) 745 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData()); 746 result.Clear(); 747 result.SetStatus (eReturnStatusSuccessFinishNoResult); 748 } 749 750 if (err_fh && !result.Succeeded() && i < num_commands) 751 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i)); 752 753 if (out_fh) 754 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData()); 755 756 if (err_fh) 757 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData()); 758 } 759 } 760 return ret_value; 761 } 762 763