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 eInputReaderAsynchronousOutputWritten: 470 break; 471 472 case eInputReaderGotToken: 473 if (bytes && bytes_len && baton) 474 { 475 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 476 if (bp_options) 477 { 478 Baton *bp_options_baton = bp_options->GetBaton(); 479 if (bp_options_baton) 480 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 481 } 482 } 483 if (!reader.IsDone() && reader.GetPrompt()) 484 { 485 out_file.Printf ("%s", reader.GetPrompt()); 486 out_file.Flush(); 487 } 488 break; 489 490 case eInputReaderInterrupt: 491 { 492 // Finish, and cancel the breakpoint command. 493 reader.SetIsDone (true); 494 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 495 if (bp_options) 496 { 497 Baton *bp_options_baton = bp_options->GetBaton (); 498 if (bp_options_baton) 499 { 500 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear(); 501 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.Clear(); 502 } 503 } 504 out_file.Printf ("Warning: No command attached to breakpoint.\n"); 505 out_file.Flush(); 506 } 507 break; 508 509 case eInputReaderEndOfFile: 510 reader.SetIsDone (true); 511 break; 512 513 case eInputReaderDone: 514 break; 515 } 516 517 return bytes_len; 518 } 519 520 521 //------------------------------------------------------------------------- 522 // CommandObjectBreakpointCommandRemove 523 //------------------------------------------------------------------------- 524 525 CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) : 526 CommandObject (interpreter, 527 "remove", 528 "Remove the set of commands from a breakpoint.", 529 NULL) 530 { 531 CommandArgumentEntry arg; 532 CommandArgumentData bp_id_arg; 533 534 // Define the first (and only) variant of this arg. 535 bp_id_arg.arg_type = eArgTypeBreakpointID; 536 bp_id_arg.arg_repetition = eArgRepeatPlain; 537 538 // There is only one variant this argument could be; put it into the argument entry. 539 arg.push_back (bp_id_arg); 540 541 // Push the data for the first argument into the m_arguments vector. 542 m_arguments.push_back (arg); 543 } 544 545 CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove () 546 { 547 } 548 549 bool 550 CommandObjectBreakpointCommandRemove::Execute 551 ( 552 Args& command, 553 CommandReturnObject &result 554 ) 555 { 556 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 557 558 if (target == NULL) 559 { 560 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands"); 561 result.SetStatus (eReturnStatusFailed); 562 return false; 563 } 564 565 const BreakpointList &breakpoints = target->GetBreakpointList(); 566 size_t num_breakpoints = breakpoints.GetSize(); 567 568 if (num_breakpoints == 0) 569 { 570 result.AppendError ("No breakpoints exist to have commands removed"); 571 result.SetStatus (eReturnStatusFailed); 572 return false; 573 } 574 575 if (command.GetArgumentCount() == 0) 576 { 577 result.AppendError ("No breakpoint specified from which to remove the commands"); 578 result.SetStatus (eReturnStatusFailed); 579 return false; 580 } 581 582 BreakpointIDList valid_bp_ids; 583 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 584 585 if (result.Succeeded()) 586 { 587 const size_t count = valid_bp_ids.GetSize(); 588 for (size_t i = 0; i < count; ++i) 589 { 590 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 591 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 592 { 593 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 594 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 595 { 596 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 597 if (bp_loc_sp) 598 bp_loc_sp->ClearCallback(); 599 else 600 { 601 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 602 cur_bp_id.GetBreakpointID(), 603 cur_bp_id.GetLocationID()); 604 result.SetStatus (eReturnStatusFailed); 605 return false; 606 } 607 } 608 else 609 { 610 bp->ClearCallback(); 611 } 612 } 613 } 614 } 615 return result.Succeeded(); 616 } 617 618 619 //------------------------------------------------------------------------- 620 // CommandObjectBreakpointCommandList 621 //------------------------------------------------------------------------- 622 623 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 624 CommandObject (interpreter, 625 "list", 626 "List the script or set of commands to be executed when the breakpoint is hit.", 627 NULL) 628 { 629 CommandArgumentEntry arg; 630 CommandArgumentData bp_id_arg; 631 632 // Define the first (and only) variant of this arg. 633 bp_id_arg.arg_type = eArgTypeBreakpointID; 634 bp_id_arg.arg_repetition = eArgRepeatPlain; 635 636 // There is only one variant this argument could be; put it into the argument entry. 637 arg.push_back (bp_id_arg); 638 639 // Push the data for the first argument into the m_arguments vector. 640 m_arguments.push_back (arg); 641 } 642 643 CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList () 644 { 645 } 646 647 bool 648 CommandObjectBreakpointCommandList::Execute 649 ( 650 Args& command, 651 CommandReturnObject &result 652 ) 653 { 654 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 655 656 if (target == NULL) 657 { 658 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 659 result.SetStatus (eReturnStatusFailed); 660 return false; 661 } 662 663 const BreakpointList &breakpoints = target->GetBreakpointList(); 664 size_t num_breakpoints = breakpoints.GetSize(); 665 666 if (num_breakpoints == 0) 667 { 668 result.AppendError ("No breakpoints exist for which to list commands"); 669 result.SetStatus (eReturnStatusFailed); 670 return false; 671 } 672 673 if (command.GetArgumentCount() == 0) 674 { 675 result.AppendError ("No breakpoint specified for which to list the commands"); 676 result.SetStatus (eReturnStatusFailed); 677 return false; 678 } 679 680 BreakpointIDList valid_bp_ids; 681 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 682 683 if (result.Succeeded()) 684 { 685 const size_t count = valid_bp_ids.GetSize(); 686 for (size_t i = 0; i < count; ++i) 687 { 688 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 689 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 690 { 691 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 692 693 if (bp) 694 { 695 const BreakpointOptions *bp_options = NULL; 696 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 697 { 698 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 699 if (bp_loc_sp) 700 bp_options = bp_loc_sp->GetOptionsNoCreate(); 701 else 702 { 703 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 704 cur_bp_id.GetBreakpointID(), 705 cur_bp_id.GetLocationID()); 706 result.SetStatus (eReturnStatusFailed); 707 return false; 708 } 709 } 710 else 711 { 712 bp_options = bp->GetOptions(); 713 } 714 715 if (bp_options) 716 { 717 StreamString id_str; 718 BreakpointID::GetCanonicalReference (&id_str, 719 cur_bp_id.GetBreakpointID(), 720 cur_bp_id.GetLocationID()); 721 const Baton *baton = bp_options->GetBaton(); 722 if (baton) 723 { 724 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 725 result.GetOutputStream().IndentMore (); 726 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 727 result.GetOutputStream().IndentLess (); 728 } 729 else 730 { 731 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", 732 id_str.GetData()); 733 } 734 } 735 result.SetStatus (eReturnStatusSuccessFinishResult); 736 } 737 else 738 { 739 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 740 result.SetStatus (eReturnStatusFailed); 741 } 742 743 } 744 } 745 } 746 747 return result.Succeeded(); 748 } 749 750 //------------------------------------------------------------------------- 751 // CommandObjectBreakpointCommand 752 //------------------------------------------------------------------------- 753 754 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 755 CommandObjectMultiword (interpreter, 756 "command", 757 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').", 758 "command <sub-command> [<sub-command-options>] <breakpoint-id>") 759 { 760 bool status; 761 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); 762 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter)); 763 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 764 765 add_command_object->SetCommandName ("breakpoint command add"); 766 remove_command_object->SetCommandName ("breakpoint command remove"); 767 list_command_object->SetCommandName ("breakpoint command list"); 768 769 status = LoadSubCommand ("add", add_command_object); 770 status = LoadSubCommand ("remove", remove_command_object); 771 status = LoadSubCommand ("list", list_command_object); 772 } 773 774 775 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () 776 { 777 } 778 779 bool 780 CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction 781 ( 782 void *baton, 783 StoppointCallbackContext *context, 784 lldb::user_id_t break_id, 785 lldb::user_id_t break_loc_id 786 ) 787 { 788 bool ret_value = true; 789 if (baton == NULL) 790 return true; 791 792 793 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; 794 StringList &commands = data->user_source; 795 796 if (commands.GetSize() > 0) 797 { 798 if (context->exe_ctx.target) 799 { 800 CommandReturnObject result; 801 Debugger &debugger = context->exe_ctx.target->GetDebugger(); 802 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 803 // if the debugger is set up that way. 804 805 result.SetImmediateOutputFile (debugger.GetOutputFile().GetStream()); 806 result.SetImmediateErrorFile (debugger.GetErrorFile().GetStream()); 807 808 bool stop_on_continue = true; 809 bool echo_commands = false; 810 bool print_results = true; 811 812 debugger.GetCommandInterpreter().HandleCommands (commands, 813 &(context->exe_ctx), 814 stop_on_continue, 815 data->stop_on_error, 816 echo_commands, 817 print_results, 818 result); 819 } 820 } 821 return ret_value; 822 } 823 824