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 ~CommandObjectBreakpointCommandAdd () override {} 182 183 Options * 184 GetOptions () override 185 { 186 return &m_options; 187 } 188 189 void 190 IOHandlerActivated (IOHandler &io_handler) override 191 { 192 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 193 if (output_sp) 194 { 195 output_sp->PutCString(g_reader_instructions); 196 output_sp->Flush(); 197 } 198 } 199 200 201 void 202 IOHandlerInputComplete (IOHandler &io_handler, std::string &line) override 203 { 204 io_handler.SetIsDone(true); 205 206 std::vector<BreakpointOptions *> *bp_options_vec = (std::vector<BreakpointOptions *> *)io_handler.GetUserData(); 207 for (BreakpointOptions *bp_options : *bp_options_vec) 208 { 209 if (!bp_options) 210 continue; 211 212 std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 213 if (data_ap.get()) 214 { 215 data_ap->user_source.SplitIntoLines (line.c_str(), line.size()); 216 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 217 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); 218 } 219 } 220 } 221 222 void 223 CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, 224 CommandReturnObject &result) 225 { 226 m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt 227 *this, // IOHandlerDelegate 228 true, // Run IOHandler in async mode 229 &bp_options_vec); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions 230 } 231 232 /// Set a one-liner as the callback for the breakpoint. 233 void 234 SetBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, 235 const char *oneliner) 236 { 237 for (auto bp_options : bp_options_vec) 238 { 239 std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 240 241 // It's necessary to set both user_source and script_source to the oneliner. 242 // The former is used to generate callback description (as in breakpoint command list) 243 // while the latter is used for Python to interpret during the actual callback. 244 data_ap->user_source.AppendString (oneliner); 245 data_ap->script_source.assign (oneliner); 246 data_ap->stop_on_error = m_options.m_stop_on_error; 247 248 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 249 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); 250 } 251 return; 252 } 253 254 static bool 255 BreakpointOptionsCallbackFunction (void *baton, 256 StoppointCallbackContext *context, 257 lldb::user_id_t break_id, 258 lldb::user_id_t break_loc_id) 259 { 260 bool ret_value = true; 261 if (baton == NULL) 262 return true; 263 264 265 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; 266 StringList &commands = data->user_source; 267 268 if (commands.GetSize() > 0) 269 { 270 ExecutionContext exe_ctx (context->exe_ctx_ref); 271 Target *target = exe_ctx.GetTargetPtr(); 272 if (target) 273 { 274 CommandReturnObject result; 275 Debugger &debugger = target->GetDebugger(); 276 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 277 // if the debugger is set up that way. 278 279 StreamSP output_stream (debugger.GetAsyncOutputStream()); 280 StreamSP error_stream (debugger.GetAsyncErrorStream()); 281 result.SetImmediateOutputStream (output_stream); 282 result.SetImmediateErrorStream (error_stream); 283 284 CommandInterpreterRunOptions options; 285 options.SetStopOnContinue(true); 286 options.SetStopOnError (data->stop_on_error); 287 options.SetEchoCommands (true); 288 options.SetPrintResults (true); 289 options.SetAddToHistory (false); 290 291 debugger.GetCommandInterpreter().HandleCommands (commands, 292 &exe_ctx, 293 options, 294 result); 295 result.GetImmediateOutputStream()->Flush(); 296 result.GetImmediateErrorStream()->Flush(); 297 } 298 } 299 return ret_value; 300 } 301 302 class CommandOptions : public Options 303 { 304 public: 305 306 CommandOptions (CommandInterpreter &interpreter) : 307 Options (interpreter), 308 m_use_commands (false), 309 m_use_script_language (false), 310 m_script_language (eScriptLanguageNone), 311 m_use_one_liner (false), 312 m_one_liner(), 313 m_function_name() 314 { 315 } 316 317 ~CommandOptions () override {} 318 319 Error 320 SetOptionValue (uint32_t option_idx, const char *option_arg) override 321 { 322 Error error; 323 const int short_option = m_getopt_table[option_idx].val; 324 325 switch (short_option) 326 { 327 case 'o': 328 m_use_one_liner = true; 329 m_one_liner = option_arg; 330 break; 331 332 case 's': 333 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 334 g_option_table[option_idx].enum_values, 335 eScriptLanguageNone, 336 error); 337 338 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault) 339 { 340 m_use_script_language = true; 341 } 342 else 343 { 344 m_use_script_language = false; 345 } 346 break; 347 348 case 'e': 349 { 350 bool success = false; 351 m_stop_on_error = Args::StringToBoolean(option_arg, false, &success); 352 if (!success) 353 error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg); 354 } 355 break; 356 357 case 'F': 358 { 359 m_use_one_liner = false; 360 m_use_script_language = true; 361 m_function_name.assign(option_arg); 362 } 363 break; 364 365 case 'D': 366 m_use_dummy = true; 367 break; 368 369 default: 370 break; 371 } 372 return error; 373 } 374 void 375 OptionParsingStarting () override 376 { 377 m_use_commands = true; 378 m_use_script_language = false; 379 m_script_language = eScriptLanguageNone; 380 381 m_use_one_liner = false; 382 m_stop_on_error = true; 383 m_one_liner.clear(); 384 m_function_name.clear(); 385 m_use_dummy = false; 386 } 387 388 const OptionDefinition* 389 GetDefinitions () override 390 { 391 return g_option_table; 392 } 393 394 // Options table: Required for subclasses of Options. 395 396 static OptionDefinition g_option_table[]; 397 398 // Instance variables to hold the values for command options. 399 400 bool m_use_commands; 401 bool m_use_script_language; 402 lldb::ScriptLanguage m_script_language; 403 404 // Instance variables to hold the values for one_liner options. 405 bool m_use_one_liner; 406 std::string m_one_liner; 407 bool m_stop_on_error; 408 std::string m_function_name; 409 bool m_use_dummy; 410 }; 411 412 protected: 413 bool 414 DoExecute (Args& command, CommandReturnObject &result) override 415 { 416 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 417 418 if (target == NULL) 419 { 420 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands"); 421 result.SetStatus (eReturnStatusFailed); 422 return false; 423 } 424 425 const BreakpointList &breakpoints = target->GetBreakpointList(); 426 size_t num_breakpoints = breakpoints.GetSize(); 427 428 if (num_breakpoints == 0) 429 { 430 result.AppendError ("No breakpoints exist to have commands added"); 431 result.SetStatus (eReturnStatusFailed); 432 return false; 433 } 434 435 if (m_options.m_use_script_language == false && m_options.m_function_name.size()) 436 { 437 result.AppendError ("need to enable scripting to have a function run as a breakpoint command"); 438 result.SetStatus (eReturnStatusFailed); 439 return false; 440 } 441 442 BreakpointIDList valid_bp_ids; 443 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); 444 445 m_bp_options_vec.clear(); 446 447 if (result.Succeeded()) 448 { 449 const size_t count = valid_bp_ids.GetSize(); 450 451 for (size_t i = 0; i < count; ++i) 452 { 453 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 454 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 455 { 456 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 457 BreakpointOptions *bp_options = NULL; 458 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) 459 { 460 // This breakpoint does not have an associated location. 461 bp_options = bp->GetOptions(); 462 } 463 else 464 { 465 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 466 // This breakpoint does have an associated location. 467 // Get its breakpoint options. 468 if (bp_loc_sp) 469 bp_options = bp_loc_sp->GetLocationOptions(); 470 } 471 if (bp_options) 472 m_bp_options_vec.push_back (bp_options); 473 } 474 } 475 476 // If we are using script language, get the script interpreter 477 // in order to set or collect command callback. Otherwise, call 478 // the methods associated with this object. 479 if (m_options.m_use_script_language) 480 { 481 ScriptInterpreter *script_interp = m_interpreter.GetScriptInterpreter(); 482 // Special handling for one-liner specified inline. 483 if (m_options.m_use_one_liner) 484 { 485 script_interp->SetBreakpointCommandCallback (m_bp_options_vec, 486 m_options.m_one_liner.c_str()); 487 } 488 else if (m_options.m_function_name.size()) 489 { 490 script_interp->SetBreakpointCommandCallbackFunction (m_bp_options_vec, 491 m_options.m_function_name.c_str()); 492 } 493 else 494 { 495 script_interp->CollectDataForBreakpointCommandCallback (m_bp_options_vec, 496 result); 497 } 498 } 499 else 500 { 501 // Special handling for one-liner specified inline. 502 if (m_options.m_use_one_liner) 503 SetBreakpointCommandCallback (m_bp_options_vec, 504 m_options.m_one_liner.c_str()); 505 else 506 CollectDataForBreakpointCommandCallback (m_bp_options_vec, 507 result); 508 } 509 510 } 511 512 return result.Succeeded(); 513 } 514 515 private: 516 CommandOptions m_options; 517 std::vector<BreakpointOptions *> m_bp_options_vec; // This stores the breakpoint options that we are currently 518 // collecting commands for. In the CollectData... calls we need 519 // to hand this off to the IOHandler, which may run asynchronously. 520 // So we have to have some way to keep it alive, and not leak it. 521 // Making it an ivar of the command object, which never goes away 522 // achieves this. Note that if we were able to run 523 // the same command concurrently in one interpreter we'd have to 524 // make this "per invocation". But there are many more reasons 525 // why it is not in general safe to do that in lldb at present, 526 // so it isn't worthwhile to come up with a more complex mechanism 527 // to address this particular weakness right now. 528 static const char *g_reader_instructions; 529 530 }; 531 532 const char * 533 CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.\n"; 534 535 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting 536 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. 537 538 static OptionEnumValueElement 539 g_script_option_enumeration[4] = 540 { 541 { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"}, 542 { eScriptLanguagePython, "python", "Commands are in the Python language."}, 543 { eSortOrderByName, "default-script", "Commands are in the default scripting language."}, 544 { 0, NULL, NULL } 545 }; 546 547 OptionDefinition 548 CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] = 549 { 550 { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner, 551 "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." }, 552 553 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, 554 "Specify whether breakpoint command execution should terminate on error." }, 555 556 { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, NULL, g_script_option_enumeration, 0, eArgTypeNone, 557 "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."}, 558 559 { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, 560 "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."}, 561 562 { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 563 "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, 564 565 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 566 }; 567 568 //------------------------------------------------------------------------- 569 // CommandObjectBreakpointCommandDelete 570 //------------------------------------------------------------------------- 571 572 class CommandObjectBreakpointCommandDelete : public CommandObjectParsed 573 { 574 public: 575 CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) : 576 CommandObjectParsed (interpreter, 577 "delete", 578 "Delete the set of commands from a breakpoint.", 579 NULL), 580 m_options (interpreter) 581 { 582 CommandArgumentEntry arg; 583 CommandArgumentData bp_id_arg; 584 585 // Define the first (and only) variant of this arg. 586 bp_id_arg.arg_type = eArgTypeBreakpointID; 587 bp_id_arg.arg_repetition = eArgRepeatPlain; 588 589 // There is only one variant this argument could be; put it into the argument entry. 590 arg.push_back (bp_id_arg); 591 592 // Push the data for the first argument into the m_arguments vector. 593 m_arguments.push_back (arg); 594 } 595 596 597 ~CommandObjectBreakpointCommandDelete () override {} 598 599 Options * 600 GetOptions () override 601 { 602 return &m_options; 603 } 604 605 class CommandOptions : public Options 606 { 607 public: 608 609 CommandOptions (CommandInterpreter &interpreter) : 610 Options (interpreter), 611 m_use_dummy (false) 612 { 613 } 614 615 ~CommandOptions () override {} 616 617 Error 618 SetOptionValue (uint32_t option_idx, const char *option_arg) override 619 { 620 Error error; 621 const int short_option = m_getopt_table[option_idx].val; 622 623 switch (short_option) 624 { 625 case 'D': 626 m_use_dummy = true; 627 break; 628 629 default: 630 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 631 break; 632 } 633 634 return error; 635 } 636 637 void 638 OptionParsingStarting () override 639 { 640 m_use_dummy = false; 641 } 642 643 const OptionDefinition* 644 GetDefinitions () override 645 { 646 return g_option_table; 647 } 648 649 // Options table: Required for subclasses of Options. 650 651 static OptionDefinition g_option_table[]; 652 653 // Instance variables to hold the values for command options. 654 bool m_use_dummy; 655 }; 656 657 protected: 658 bool 659 DoExecute (Args& command, CommandReturnObject &result) override 660 { 661 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 662 663 if (target == NULL) 664 { 665 result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands"); 666 result.SetStatus (eReturnStatusFailed); 667 return false; 668 } 669 670 const BreakpointList &breakpoints = target->GetBreakpointList(); 671 size_t num_breakpoints = breakpoints.GetSize(); 672 673 if (num_breakpoints == 0) 674 { 675 result.AppendError ("No breakpoints exist to have commands deleted"); 676 result.SetStatus (eReturnStatusFailed); 677 return false; 678 } 679 680 if (command.GetArgumentCount() == 0) 681 { 682 result.AppendError ("No breakpoint specified from which to delete the commands"); 683 result.SetStatus (eReturnStatusFailed); 684 return false; 685 } 686 687 BreakpointIDList valid_bp_ids; 688 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); 689 690 if (result.Succeeded()) 691 { 692 const size_t count = valid_bp_ids.GetSize(); 693 for (size_t i = 0; i < count; ++i) 694 { 695 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 696 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 697 { 698 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 699 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 700 { 701 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 702 if (bp_loc_sp) 703 bp_loc_sp->ClearCallback(); 704 else 705 { 706 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 707 cur_bp_id.GetBreakpointID(), 708 cur_bp_id.GetLocationID()); 709 result.SetStatus (eReturnStatusFailed); 710 return false; 711 } 712 } 713 else 714 { 715 bp->ClearCallback(); 716 } 717 } 718 } 719 } 720 return result.Succeeded(); 721 } 722 private: 723 CommandOptions m_options; 724 }; 725 726 OptionDefinition 727 CommandObjectBreakpointCommandDelete::CommandOptions::g_option_table[] = 728 { 729 { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 730 "Delete commands from Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, 731 732 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 733 }; 734 735 736 //------------------------------------------------------------------------- 737 // CommandObjectBreakpointCommandList 738 //------------------------------------------------------------------------- 739 740 class CommandObjectBreakpointCommandList : public CommandObjectParsed 741 { 742 public: 743 CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 744 CommandObjectParsed (interpreter, 745 "list", 746 "List the script or set of commands to be executed when the breakpoint is hit.", 747 NULL) 748 { 749 CommandArgumentEntry arg; 750 CommandArgumentData bp_id_arg; 751 752 // Define the first (and only) variant of this arg. 753 bp_id_arg.arg_type = eArgTypeBreakpointID; 754 bp_id_arg.arg_repetition = eArgRepeatPlain; 755 756 // There is only one variant this argument could be; put it into the argument entry. 757 arg.push_back (bp_id_arg); 758 759 // Push the data for the first argument into the m_arguments vector. 760 m_arguments.push_back (arg); 761 } 762 763 ~CommandObjectBreakpointCommandList () override {} 764 765 protected: 766 bool 767 DoExecute (Args& command, 768 CommandReturnObject &result) override 769 { 770 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 771 772 if (target == NULL) 773 { 774 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 775 result.SetStatus (eReturnStatusFailed); 776 return false; 777 } 778 779 const BreakpointList &breakpoints = target->GetBreakpointList(); 780 size_t num_breakpoints = breakpoints.GetSize(); 781 782 if (num_breakpoints == 0) 783 { 784 result.AppendError ("No breakpoints exist for which to list commands"); 785 result.SetStatus (eReturnStatusFailed); 786 return false; 787 } 788 789 if (command.GetArgumentCount() == 0) 790 { 791 result.AppendError ("No breakpoint specified for which to list the commands"); 792 result.SetStatus (eReturnStatusFailed); 793 return false; 794 } 795 796 BreakpointIDList valid_bp_ids; 797 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); 798 799 if (result.Succeeded()) 800 { 801 const size_t count = valid_bp_ids.GetSize(); 802 for (size_t i = 0; i < count; ++i) 803 { 804 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 805 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 806 { 807 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 808 809 if (bp) 810 { 811 const BreakpointOptions *bp_options = NULL; 812 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 813 { 814 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 815 if (bp_loc_sp) 816 bp_options = bp_loc_sp->GetOptionsNoCreate(); 817 else 818 { 819 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 820 cur_bp_id.GetBreakpointID(), 821 cur_bp_id.GetLocationID()); 822 result.SetStatus (eReturnStatusFailed); 823 return false; 824 } 825 } 826 else 827 { 828 bp_options = bp->GetOptions(); 829 } 830 831 if (bp_options) 832 { 833 StreamString id_str; 834 BreakpointID::GetCanonicalReference (&id_str, 835 cur_bp_id.GetBreakpointID(), 836 cur_bp_id.GetLocationID()); 837 const Baton *baton = bp_options->GetBaton(); 838 if (baton) 839 { 840 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 841 result.GetOutputStream().IndentMore (); 842 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 843 result.GetOutputStream().IndentLess (); 844 } 845 else 846 { 847 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", 848 id_str.GetData()); 849 } 850 } 851 result.SetStatus (eReturnStatusSuccessFinishResult); 852 } 853 else 854 { 855 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 856 result.SetStatus (eReturnStatusFailed); 857 } 858 859 } 860 } 861 } 862 863 return result.Succeeded(); 864 } 865 }; 866 867 //------------------------------------------------------------------------- 868 // CommandObjectBreakpointCommand 869 //------------------------------------------------------------------------- 870 871 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 872 CommandObjectMultiword (interpreter, 873 "command", 874 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commands').", 875 "command <sub-command> [<sub-command-options>] <breakpoint-id>") 876 { 877 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); 878 CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter)); 879 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 880 881 add_command_object->SetCommandName ("breakpoint command add"); 882 delete_command_object->SetCommandName ("breakpoint command delete"); 883 list_command_object->SetCommandName ("breakpoint command list"); 884 885 LoadSubCommand ("add", add_command_object); 886 LoadSubCommand ("delete", delete_command_object); 887 LoadSubCommand ("list", list_command_object); 888 } 889 890 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () 891 { 892 } 893 894 895