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