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