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