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/Core/IOHandler.h" 18 #include "lldb/Interpreter/CommandInterpreter.h" 19 #include "lldb/Interpreter/CommandReturnObject.h" 20 #include "lldb/Target/Target.h" 21 #include "lldb/Target/Thread.h" 22 #include "lldb/Breakpoint/BreakpointIDList.h" 23 #include "lldb/Breakpoint/Breakpoint.h" 24 #include "lldb/Breakpoint/BreakpointLocation.h" 25 #include "lldb/Breakpoint/StoppointCallbackContext.h" 26 #include "lldb/Core/State.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 //------------------------------------------------------------------------- 32 // CommandObjectBreakpointCommandAdd 33 //------------------------------------------------------------------------- 34 35 36 class CommandObjectBreakpointCommandAdd : 37 public CommandObjectParsed, 38 public IOHandlerDelegateMultiline 39 { 40 public: 41 42 CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) : 43 CommandObjectParsed (interpreter, 44 "add", 45 "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit." 46 " If no breakpoint is specified, adds the commands to the last created breakpoint.", 47 NULL), 48 IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand), 49 m_options (interpreter) 50 { 51 SetHelpLong ( 52 R"( 53 General information about entering breakpoint commands 54 ------------------------------------------------------ 55 56 )" "This command will prompt for commands to be executed when the specified \ 57 breakpoint is hit. Each command is typed on its own line following the '> ' \ 58 prompt until 'DONE' is entered." R"( 59 60 )" "Syntactic errors may not be detected when initially entered, and many \ 61 malformed commands can silently fail when executed. If your breakpoint commands \ 62 do not appear to be executing, double-check the command syntax." R"( 63 64 )" "Note: You may enter any debugger command exactly as you would at the debugger \ 65 prompt. There is no limit to the number of commands supplied, but do NOT enter \ 66 more than one command per line." R"( 67 68 Special information about PYTHON breakpoint commands 69 ---------------------------------------------------- 70 71 )" "You may enter either one or more lines of Python, including function \ 72 definitions or calls to functions that will have been imported by the time \ 73 the code executes. Single line breakpoint commands will be interpreted 'as is' \ 74 when the breakpoint is hit. Multiple lines of Python will be wrapped in a \ 75 generated function, and a call to the function will be attached to the breakpoint." R"( 76 77 This auto-generated function is passed in three arguments: 78 79 frame: an lldb.SBFrame object for the frame which hit breakpoint. 80 81 bp_loc: an lldb.SBBreakpointLocation object that represents the breakpoint location that was hit. 82 83 dict: the python session dictionary hit. 84 85 )" "When specifying a python function with the --python-function option, you need \ 86 to supply the function name prepended by the module name:" R"( 87 88 --python-function myutils.breakpoint_callback 89 90 The function itself must have the following prototype: 91 92 def breakpoint_callback(frame, bp_loc, dict): 93 # Your code goes here 94 95 )" "The arguments are the same as the arguments passed to generated functions as \ 96 described above. Note that the global variable 'lldb.frame' will NOT be updated when \ 97 this function is called, so be sure to use the 'frame' argument. The 'frame' argument \ 98 can get you to the thread via frame.GetThread(), the thread can get you to the \ 99 process via thread.GetProcess(), and the process can get you back to the target \ 100 via process.GetTarget()." R"( 101 102 )" "Important Note: As Python code gets collected into functions, access to global \ 103 variables requires explicit scoping using the 'global' keyword. Be sure to use correct \ 104 Python syntax, including indentation, when entering Python breakpoint commands." R"( 105 106 Example Python one-line breakpoint command: 107 108 (lldb) breakpoint command add -s python 1 109 Enter your Python command(s). Type 'DONE' to end. 110 > print "Hit this breakpoint!" 111 > DONE 112 113 As a convenience, this also works for a short Python one-liner: 114 115 (lldb) breakpoint command add -s python 1 -o 'import time; print time.asctime()' 116 (lldb) run 117 Launching '.../a.out' (x86_64) 118 (lldb) Fri Sep 10 12:17:45 2010 119 Process 21778 Stopped 120 * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread 121 36 122 37 int c(int val) 123 38 { 124 39 -> return val + 3; 125 40 } 126 41 127 42 int main (int argc, char const *argv[]) 128 129 Example multiple line Python breakpoint command: 130 131 (lldb) breakpoint command add -s p 1 132 Enter your Python command(s). Type 'DONE' to end. 133 > global bp_count 134 > bp_count = bp_count + 1 135 > print "Hit this breakpoint " + repr(bp_count) + " times!" 136 > DONE 137 138 Example multiple line Python breakpoint command, using function definition: 139 140 (lldb) breakpoint command add -s python 1 141 Enter your Python command(s). Type 'DONE' to end. 142 > def breakpoint_output (bp_no): 143 > out_string = "Hit breakpoint number " + repr (bp_no) 144 > print out_string 145 > return True 146 > breakpoint_output (1) 147 > DONE 148 149 )" "In this case, since there is a reference to a global variable, \ 150 'bp_count', you will also need to make sure 'bp_count' exists and is \ 151 initialized:" R"( 152 153 (lldb) script 154 >>> bp_count = 0 155 >>> quit() 156 157 )" "Your Python code, however organized, can optionally return a value. \ 158 If the returned value is False, that tells LLDB not to stop at the breakpoint \ 159 to which the code is associated. Returning anything other than False, or even \ 160 returning None, or even omitting a return statement entirely, will cause \ 161 LLDB to stop." R"( 162 163 )" "Final Note: A warning that no breakpoint command was generated when there \ 164 are no syntax errors may indicate that a function was declared but never called." 165 ); 166 167 CommandArgumentEntry arg; 168 CommandArgumentData bp_id_arg; 169 170 // Define the first (and only) variant of this arg. 171 bp_id_arg.arg_type = eArgTypeBreakpointID; 172 bp_id_arg.arg_repetition = eArgRepeatOptional; 173 174 // There is only one variant this argument could be; put it into the argument entry. 175 arg.push_back (bp_id_arg); 176 177 // Push the data for the first argument into the m_arguments vector. 178 m_arguments.push_back (arg); 179 } 180 181 virtual 182 ~CommandObjectBreakpointCommandAdd () {} 183 184 virtual Options * 185 GetOptions () 186 { 187 return &m_options; 188 } 189 190 virtual void 191 IOHandlerActivated (IOHandler &io_handler) 192 { 193 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 194 if (output_sp) 195 { 196 output_sp->PutCString(g_reader_instructions); 197 output_sp->Flush(); 198 } 199 } 200 201 202 virtual void 203 IOHandlerInputComplete (IOHandler &io_handler, std::string &line) 204 { 205 io_handler.SetIsDone(true); 206 207 std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData(); 208 for (BreakpointOptions *bp_options : *bp_options_vec) 209 { 210 if (!bp_options) 211 continue; 212 213 std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 214 if (data_ap.get()) 215 { 216 data_ap->user_source.SplitIntoLines (line.c_str(), line.size()); 217 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 218 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); 219 } 220 } 221 } 222 223 void 224 CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, 225 CommandReturnObject &result) 226 { 227 m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt 228 *this, // IOHandlerDelegate 229 true, // Run IOHandler in async mode 230 &bp_options_vec); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions 231 } 232 233 /// Set a one-liner as the callback for the breakpoint. 234 void 235 SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, 236 const char *oneliner) 237 { 238 for (auto bp_options : bp_options_vec) 239 { 240 std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 241 242 // It's necessary to set both user_source and script_source to the oneliner. 243 // The former is used to generate callback description (as in breakpoint command list) 244 // while the latter is used for Python to interpret during the actual callback. 245 data_ap->user_source.AppendString (oneliner); 246 data_ap->script_source.assign (oneliner); 247 data_ap->stop_on_error = m_options.m_stop_on_error; 248 249 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 250 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); 251 } 252 return; 253 } 254 255 static bool 256 BreakpointOptionsCallbackFunction (void *baton, 257 StoppointCallbackContext *context, 258 lldb::user_id_t break_id, 259 lldb::user_id_t break_loc_id) 260 { 261 bool ret_value = true; 262 if (baton == NULL) 263 return true; 264 265 266 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; 267 StringList &commands = data->user_source; 268 269 if (commands.GetSize() > 0) 270 { 271 ExecutionContext exe_ctx (context->exe_ctx_ref); 272 Target *target = exe_ctx.GetTargetPtr(); 273 if (target) 274 { 275 CommandReturnObject result; 276 Debugger &debugger = target->GetDebugger(); 277 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 278 // if the debugger is set up that way. 279 280 StreamSP output_stream (debugger.GetAsyncOutputStream()); 281 StreamSP error_stream (debugger.GetAsyncErrorStream()); 282 result.SetImmediateOutputStream (output_stream); 283 result.SetImmediateErrorStream (error_stream); 284 285 CommandInterpreterRunOptions options; 286 options.SetStopOnContinue(true); 287 options.SetStopOnError (data->stop_on_error); 288 options.SetEchoCommands (true); 289 options.SetPrintResults (true); 290 options.SetAddToHistory (false); 291 292 debugger.GetCommandInterpreter().HandleCommands (commands, 293 &exe_ctx, 294 options, 295 result); 296 result.GetImmediateOutputStream()->Flush(); 297 result.GetImmediateErrorStream()->Flush(); 298 } 299 } 300 return ret_value; 301 } 302 303 class CommandOptions : public Options 304 { 305 public: 306 307 CommandOptions (CommandInterpreter &interpreter) : 308 Options (interpreter), 309 m_use_commands (false), 310 m_use_script_language (false), 311 m_script_language (eScriptLanguageNone), 312 m_use_one_liner (false), 313 m_one_liner(), 314 m_function_name() 315 { 316 } 317 318 virtual 319 ~CommandOptions () {} 320 321 virtual Error 322 SetOptionValue (uint32_t option_idx, const char *option_arg) 323 { 324 Error error; 325 const int short_option = m_getopt_table[option_idx].val; 326 327 switch (short_option) 328 { 329 case 'o': 330 m_use_one_liner = true; 331 m_one_liner = option_arg; 332 break; 333 334 case 's': 335 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 336 g_option_table[option_idx].enum_values, 337 eScriptLanguageNone, 338 error); 339 340 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault) 341 { 342 m_use_script_language = true; 343 } 344 else 345 { 346 m_use_script_language = false; 347 } 348 break; 349 350 case 'e': 351 { 352 bool success = false; 353 m_stop_on_error = Args::StringToBoolean(option_arg, false, &success); 354 if (!success) 355 error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg); 356 } 357 break; 358 359 case 'F': 360 { 361 m_use_one_liner = false; 362 m_use_script_language = true; 363 m_function_name.assign(option_arg); 364 } 365 break; 366 367 case 'D': 368 m_use_dummy = true; 369 break; 370 371 default: 372 break; 373 } 374 return error; 375 } 376 void 377 OptionParsingStarting () 378 { 379 m_use_commands = true; 380 m_use_script_language = false; 381 m_script_language = eScriptLanguageNone; 382 383 m_use_one_liner = false; 384 m_stop_on_error = true; 385 m_one_liner.clear(); 386 m_function_name.clear(); 387 m_use_dummy = false; 388 } 389 390 const OptionDefinition* 391 GetDefinitions () 392 { 393 return g_option_table; 394 } 395 396 // Options table: Required for subclasses of Options. 397 398 static OptionDefinition g_option_table[]; 399 400 // Instance variables to hold the values for command options. 401 402 bool m_use_commands; 403 bool m_use_script_language; 404 lldb::ScriptLanguage m_script_language; 405 406 // Instance variables to hold the values for one_liner options. 407 bool m_use_one_liner; 408 std::string m_one_liner; 409 bool m_stop_on_error; 410 std::string m_function_name; 411 bool m_use_dummy; 412 }; 413 414 protected: 415 virtual bool 416 DoExecute (Args& command, CommandReturnObject &result) 417 { 418 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 419 420 if (target == NULL) 421 { 422 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands"); 423 result.SetStatus (eReturnStatusFailed); 424 return false; 425 } 426 427 const BreakpointList &breakpoints = target->GetBreakpointList(); 428 size_t num_breakpoints = breakpoints.GetSize(); 429 430 if (num_breakpoints == 0) 431 { 432 result.AppendError ("No breakpoints exist to have commands added"); 433 result.SetStatus (eReturnStatusFailed); 434 return false; 435 } 436 437 if (m_options.m_use_script_language == false && m_options.m_function_name.size()) 438 { 439 result.AppendError ("need to enable scripting to have a function run as a breakpoint command"); 440 result.SetStatus (eReturnStatusFailed); 441 return false; 442 } 443 444 BreakpointIDList valid_bp_ids; 445 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); 446 447 m_bp_options_vec.clear(); 448 449 if (result.Succeeded()) 450 { 451 const size_t count = valid_bp_ids.GetSize(); 452 453 for (size_t i = 0; i < count; ++i) 454 { 455 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 456 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 457 { 458 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 459 BreakpointOptions *bp_options = NULL; 460 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) 461 { 462 // This breakpoint does not have an associated location. 463 bp_options = bp->GetOptions(); 464 } 465 else 466 { 467 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 468 // This breakpoint does have an associated location. 469 // Get its breakpoint options. 470 if (bp_loc_sp) 471 bp_options = bp_loc_sp->GetLocationOptions(); 472 } 473 if (bp_options) 474 m_bp_options_vec.push_back (bp_options); 475 } 476 } 477 478 // If we are using script language, get the script interpreter 479 // in order to set or collect command callback. Otherwise, call 480 // the methods associated with this object. 481 if (m_options.m_use_script_language) 482 { 483 ScriptInterpreter *script_interp = m_interpreter.GetScriptInterpreter(); 484 // Special handling for one-liner specified inline. 485 if (m_options.m_use_one_liner) 486 { 487 script_interp->SetBreakpointCommandCallback (m_bp_options_vec, 488 m_options.m_one_liner.c_str()); 489 } 490 else if (m_options.m_function_name.size()) 491 { 492 script_interp->SetBreakpointCommandCallbackFunction (m_bp_options_vec, 493 m_options.m_function_name.c_str()); 494 } 495 else 496 { 497 script_interp->CollectDataForBreakpointCommandCallback (m_bp_options_vec, 498 result); 499 } 500 } 501 else 502 { 503 // Special handling for one-liner specified inline. 504 if (m_options.m_use_one_liner) 505 SetBreakpointCommandCallback (m_bp_options_vec, 506 m_options.m_one_liner.c_str()); 507 else 508 CollectDataForBreakpointCommandCallback (m_bp_options_vec, 509 result); 510 } 511 512 } 513 514 return result.Succeeded(); 515 } 516 517 private: 518 CommandOptions m_options; 519 std::vector<BreakpointOptions *> m_bp_options_vec; // This stores the breakpoint options that we are currently 520 // collecting commands for. In the CollectData... calls we need 521 // to hand this off to the IOHandler, which may run asynchronously. 522 // So we have to have some way to keep it alive, and not leak it. 523 // Making it an ivar of the command object, which never goes away 524 // achieves this. Note that if we were able to run 525 // the same command concurrently in one interpreter we'd have to 526 // make this "per invocation". But there are many more reasons 527 // why it is not in general safe to do that in lldb at present, 528 // so it isn't worthwhile to come up with a more complex mechanism 529 // to address this particular weakness right now. 530 static const char *g_reader_instructions; 531 532 }; 533 534 const char * 535 CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.\n"; 536 537 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting 538 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. 539 540 static OptionEnumValueElement 541 g_script_option_enumeration[4] = 542 { 543 { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"}, 544 { eScriptLanguagePython, "python", "Commands are in the Python language."}, 545 { eSortOrderByName, "default-script", "Commands are in the default scripting language."}, 546 { 0, NULL, NULL } 547 }; 548 549 OptionDefinition 550 CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] = 551 { 552 { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner, 553 "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." }, 554 555 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, 556 "Specify whether breakpoint command execution should terminate on error." }, 557 558 { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, NULL, g_script_option_enumeration, 0, eArgTypeNone, 559 "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."}, 560 561 { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, 562 "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."}, 563 564 { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 565 "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, 566 567 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 568 }; 569 570 //------------------------------------------------------------------------- 571 // CommandObjectBreakpointCommandDelete 572 //------------------------------------------------------------------------- 573 574 class CommandObjectBreakpointCommandDelete : public CommandObjectParsed 575 { 576 public: 577 CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) : 578 CommandObjectParsed (interpreter, 579 "delete", 580 "Delete the set of commands from a breakpoint.", 581 NULL), 582 m_options (interpreter) 583 { 584 CommandArgumentEntry arg; 585 CommandArgumentData bp_id_arg; 586 587 // Define the first (and only) variant of this arg. 588 bp_id_arg.arg_type = eArgTypeBreakpointID; 589 bp_id_arg.arg_repetition = eArgRepeatPlain; 590 591 // There is only one variant this argument could be; put it into the argument entry. 592 arg.push_back (bp_id_arg); 593 594 // Push the data for the first argument into the m_arguments vector. 595 m_arguments.push_back (arg); 596 } 597 598 599 virtual 600 ~CommandObjectBreakpointCommandDelete () {} 601 602 virtual Options * 603 GetOptions () 604 { 605 return &m_options; 606 } 607 608 class CommandOptions : public Options 609 { 610 public: 611 612 CommandOptions (CommandInterpreter &interpreter) : 613 Options (interpreter), 614 m_use_dummy (false) 615 { 616 } 617 618 virtual 619 ~CommandOptions () {} 620 621 virtual Error 622 SetOptionValue (uint32_t option_idx, const char *option_arg) 623 { 624 Error error; 625 const int short_option = m_getopt_table[option_idx].val; 626 627 switch (short_option) 628 { 629 case 'D': 630 m_use_dummy = true; 631 break; 632 633 default: 634 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 635 break; 636 } 637 638 return error; 639 } 640 641 void 642 OptionParsingStarting () 643 { 644 m_use_dummy = false; 645 } 646 647 const OptionDefinition* 648 GetDefinitions () 649 { 650 return g_option_table; 651 } 652 653 // Options table: Required for subclasses of Options. 654 655 static OptionDefinition g_option_table[]; 656 657 // Instance variables to hold the values for command options. 658 bool m_use_dummy; 659 }; 660 661 protected: 662 virtual bool 663 DoExecute (Args& command, CommandReturnObject &result) 664 { 665 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 666 667 if (target == NULL) 668 { 669 result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands"); 670 result.SetStatus (eReturnStatusFailed); 671 return false; 672 } 673 674 const BreakpointList &breakpoints = target->GetBreakpointList(); 675 size_t num_breakpoints = breakpoints.GetSize(); 676 677 if (num_breakpoints == 0) 678 { 679 result.AppendError ("No breakpoints exist to have commands deleted"); 680 result.SetStatus (eReturnStatusFailed); 681 return false; 682 } 683 684 if (command.GetArgumentCount() == 0) 685 { 686 result.AppendError ("No breakpoint specified from which to delete the commands"); 687 result.SetStatus (eReturnStatusFailed); 688 return false; 689 } 690 691 BreakpointIDList valid_bp_ids; 692 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); 693 694 if (result.Succeeded()) 695 { 696 const size_t count = valid_bp_ids.GetSize(); 697 for (size_t i = 0; i < count; ++i) 698 { 699 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 700 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 701 { 702 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 703 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 704 { 705 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 706 if (bp_loc_sp) 707 bp_loc_sp->ClearCallback(); 708 else 709 { 710 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 711 cur_bp_id.GetBreakpointID(), 712 cur_bp_id.GetLocationID()); 713 result.SetStatus (eReturnStatusFailed); 714 return false; 715 } 716 } 717 else 718 { 719 bp->ClearCallback(); 720 } 721 } 722 } 723 } 724 return result.Succeeded(); 725 } 726 private: 727 CommandOptions m_options; 728 }; 729 730 OptionDefinition 731 CommandObjectBreakpointCommandDelete::CommandOptions::g_option_table[] = 732 { 733 { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 734 "Delete commands from Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, 735 736 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 737 }; 738 739 740 //------------------------------------------------------------------------- 741 // CommandObjectBreakpointCommandList 742 //------------------------------------------------------------------------- 743 744 class CommandObjectBreakpointCommandList : public CommandObjectParsed 745 { 746 public: 747 CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 748 CommandObjectParsed (interpreter, 749 "list", 750 "List the script or set of commands to be executed when the breakpoint is hit.", 751 NULL) 752 { 753 CommandArgumentEntry arg; 754 CommandArgumentData bp_id_arg; 755 756 // Define the first (and only) variant of this arg. 757 bp_id_arg.arg_type = eArgTypeBreakpointID; 758 bp_id_arg.arg_repetition = eArgRepeatPlain; 759 760 // There is only one variant this argument could be; put it into the argument entry. 761 arg.push_back (bp_id_arg); 762 763 // Push the data for the first argument into the m_arguments vector. 764 m_arguments.push_back (arg); 765 } 766 767 virtual 768 ~CommandObjectBreakpointCommandList () {} 769 770 protected: 771 virtual bool 772 DoExecute (Args& command, 773 CommandReturnObject &result) 774 { 775 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 776 777 if (target == NULL) 778 { 779 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 780 result.SetStatus (eReturnStatusFailed); 781 return false; 782 } 783 784 const BreakpointList &breakpoints = target->GetBreakpointList(); 785 size_t num_breakpoints = breakpoints.GetSize(); 786 787 if (num_breakpoints == 0) 788 { 789 result.AppendError ("No breakpoints exist for which to list commands"); 790 result.SetStatus (eReturnStatusFailed); 791 return false; 792 } 793 794 if (command.GetArgumentCount() == 0) 795 { 796 result.AppendError ("No breakpoint specified for which to list the commands"); 797 result.SetStatus (eReturnStatusFailed); 798 return false; 799 } 800 801 BreakpointIDList valid_bp_ids; 802 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); 803 804 if (result.Succeeded()) 805 { 806 const size_t count = valid_bp_ids.GetSize(); 807 for (size_t i = 0; i < count; ++i) 808 { 809 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 810 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 811 { 812 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 813 814 if (bp) 815 { 816 const BreakpointOptions *bp_options = NULL; 817 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 818 { 819 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 820 if (bp_loc_sp) 821 bp_options = bp_loc_sp->GetOptionsNoCreate(); 822 else 823 { 824 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 825 cur_bp_id.GetBreakpointID(), 826 cur_bp_id.GetLocationID()); 827 result.SetStatus (eReturnStatusFailed); 828 return false; 829 } 830 } 831 else 832 { 833 bp_options = bp->GetOptions(); 834 } 835 836 if (bp_options) 837 { 838 StreamString id_str; 839 BreakpointID::GetCanonicalReference (&id_str, 840 cur_bp_id.GetBreakpointID(), 841 cur_bp_id.GetLocationID()); 842 const Baton *baton = bp_options->GetBaton(); 843 if (baton) 844 { 845 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 846 result.GetOutputStream().IndentMore (); 847 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 848 result.GetOutputStream().IndentLess (); 849 } 850 else 851 { 852 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", 853 id_str.GetData()); 854 } 855 } 856 result.SetStatus (eReturnStatusSuccessFinishResult); 857 } 858 else 859 { 860 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 861 result.SetStatus (eReturnStatusFailed); 862 } 863 864 } 865 } 866 } 867 868 return result.Succeeded(); 869 } 870 }; 871 872 //------------------------------------------------------------------------- 873 // CommandObjectBreakpointCommand 874 //------------------------------------------------------------------------- 875 876 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 877 CommandObjectMultiword (interpreter, 878 "command", 879 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commands').", 880 "command <sub-command> [<sub-command-options>] <breakpoint-id>") 881 { 882 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); 883 CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter)); 884 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 885 886 add_command_object->SetCommandName ("breakpoint command add"); 887 delete_command_object->SetCommandName ("breakpoint command delete"); 888 list_command_object->SetCommandName ("breakpoint command list"); 889 890 LoadSubCommand ("add", add_command_object); 891 LoadSubCommand ("delete", delete_command_object); 892 LoadSubCommand ("list", list_command_object); 893 } 894 895 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () 896 { 897 } 898 899 900