1 //===-- CommandObjectWatchpointCommand.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 "CommandObjectWatchpointCommand.h" 15 #include "CommandObjectWatchpoint.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/Watchpoint.h" 23 #include "lldb/Breakpoint/StoppointCallbackContext.h" 24 #include "lldb/Core/State.h" 25 26 #include <vector> 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 //------------------------------------------------------------------------- 32 // CommandObjectWatchpointCommandAdd 33 //------------------------------------------------------------------------- 34 35 36 class CommandObjectWatchpointCommandAdd : 37 public CommandObjectParsed, 38 public IOHandlerDelegateMultiline 39 { 40 public: 41 42 CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) : 43 CommandObjectParsed (interpreter, 44 "add", 45 "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.", 46 NULL), 47 IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand), 48 m_options (interpreter) 49 { 50 SetHelpLong ( 51 R"( 52 General information about entering watchpoint commands 53 ------------------------------------------------------ 54 55 )" "This command will prompt for commands to be executed when the specified \ 56 watchpoint is hit. Each command is typed on its own line following the '> ' \ 57 prompt until 'DONE' is entered." R"( 58 59 )" "Syntactic errors may not be detected when initially entered, and many \ 60 malformed commands can silently fail when executed. If your watchpoint commands \ 61 do not appear to be executing, double-check the command syntax." R"( 62 63 )" "Note: You may enter any debugger command exactly as you would at the debugger \ 64 prompt. There is no limit to the number of commands supplied, but do NOT enter \ 65 more than one command per line." R"( 66 67 Special information about PYTHON watchpoint commands 68 ---------------------------------------------------- 69 70 )" "You may enter either one or more lines of Python, including function \ 71 definitions or calls to functions that will have been imported by the time \ 72 the code executes. Single line watchpoint commands will be interpreted 'as is' \ 73 when the watchpoint is hit. Multiple lines of Python will be wrapped in a \ 74 generated function, and a call to the function will be attached to the watchpoint." R"( 75 76 This auto-generated function is passed in three arguments: 77 78 frame: an lldb.SBFrame object for the frame which hit the watchpoint. 79 80 wp: the watchpoint that was hit. 81 82 )" "When specifying a python function with the --python-function option, you need \ 83 to supply the function name prepended by the module name:" R"( 84 85 --python-function myutils.watchpoint_callback 86 87 The function itself must have the following prototype: 88 89 def watchpoint_callback(frame, wp): 90 # Your code goes here 91 92 )" "The arguments are the same as the arguments passed to generated functions as \ 93 described above. Note that the global variable 'lldb.frame' will NOT be updated when \ 94 this function is called, so be sure to use the 'frame' argument. The 'frame' argument \ 95 can get you to the thread via frame.GetThread(), the thread can get you to the \ 96 process via thread.GetProcess(), and the process can get you back to the target \ 97 via process.GetTarget()." R"( 98 99 )" "Important Note: As Python code gets collected into functions, access to global \ 100 variables requires explicit scoping using the 'global' keyword. Be sure to use correct \ 101 Python syntax, including indentation, when entering Python watchpoint commands." R"( 102 103 Example Python one-line watchpoint command: 104 105 (lldb) watchpoint command add -s python 1 106 Enter your Python command(s). Type 'DONE' to end. 107 > print "Hit this watchpoint!" 108 > DONE 109 110 As a convenience, this also works for a short Python one-liner: 111 112 (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()' 113 (lldb) run 114 Launching '.../a.out' (x86_64) 115 (lldb) Fri Sep 10 12:17:45 2010 116 Process 21778 Stopped 117 * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread 118 36 119 37 int c(int val) 120 38 { 121 39 -> return val + 3; 122 40 } 123 41 124 42 int main (int argc, char const *argv[]) 125 126 Example multiple line Python watchpoint command, using function definition: 127 128 (lldb) watchpoint command add -s python 1 129 Enter your Python command(s). Type 'DONE' to end. 130 > def watchpoint_output (wp_no): 131 > out_string = "Hit watchpoint number " + repr (wp_no) 132 > print out_string 133 > return True 134 > watchpoint_output (1) 135 > DONE 136 137 Example multiple line Python watchpoint command, using 'loose' Python: 138 139 (lldb) watchpoint command add -s p 1 140 Enter your Python command(s). Type 'DONE' to end. 141 > global wp_count 142 > wp_count = wp_count + 1 143 > print "Hit this watchpoint " + repr(wp_count) + " times!" 144 > DONE 145 146 )" "In this case, since there is a reference to a global variable, \ 147 'wp_count', you will also need to make sure 'wp_count' exists and is \ 148 initialized:" R"( 149 150 (lldb) script 151 >>> wp_count = 0 152 >>> quit() 153 154 )" "Final Note: A warning that no watchpoint command was generated when there \ 155 are no syntax errors may indicate that a function was declared but never called." 156 ); 157 158 CommandArgumentEntry arg; 159 CommandArgumentData wp_id_arg; 160 161 // Define the first (and only) variant of this arg. 162 wp_id_arg.arg_type = eArgTypeWatchpointID; 163 wp_id_arg.arg_repetition = eArgRepeatPlain; 164 165 // There is only one variant this argument could be; put it into the argument entry. 166 arg.push_back (wp_id_arg); 167 168 // Push the data for the first argument into the m_arguments vector. 169 m_arguments.push_back (arg); 170 } 171 172 ~CommandObjectWatchpointCommandAdd () override {} 173 174 Options * 175 GetOptions () override 176 { 177 return &m_options; 178 } 179 180 void 181 IOHandlerActivated (IOHandler &io_handler) override 182 { 183 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 184 if (output_sp) 185 { 186 output_sp->PutCString("Enter your debugger command(s). Type 'DONE' to end.\n"); 187 output_sp->Flush(); 188 } 189 } 190 191 192 void 193 IOHandlerInputComplete (IOHandler &io_handler, std::string &line) override 194 { 195 io_handler.SetIsDone(true); 196 197 // The WatchpointOptions object is owned by the watchpoint or watchpoint location 198 WatchpointOptions *wp_options = (WatchpointOptions *) io_handler.GetUserData(); 199 if (wp_options) 200 { 201 std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); 202 if (data_ap.get()) 203 { 204 data_ap->user_source.SplitIntoLines(line); 205 BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); 206 wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp); 207 } 208 } 209 } 210 211 void 212 CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, 213 CommandReturnObject &result) 214 { 215 m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt 216 *this, // IOHandlerDelegate 217 true, // Run IOHandler in async mode 218 wp_options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions 219 } 220 221 /// Set a one-liner as the callback for the watchpoint. 222 void 223 SetWatchpointCommandCallback (WatchpointOptions *wp_options, 224 const char *oneliner) 225 { 226 std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); 227 228 // It's necessary to set both user_source and script_source to the oneliner. 229 // The former is used to generate callback description (as in watchpoint command list) 230 // while the latter is used for Python to interpret during the actual callback. 231 data_ap->user_source.AppendString (oneliner); 232 data_ap->script_source.assign (oneliner); 233 data_ap->stop_on_error = m_options.m_stop_on_error; 234 235 BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); 236 wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp); 237 238 return; 239 } 240 241 static bool 242 WatchpointOptionsCallbackFunction (void *baton, 243 StoppointCallbackContext *context, 244 lldb::user_id_t watch_id) 245 { 246 bool ret_value = true; 247 if (baton == NULL) 248 return true; 249 250 251 WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton; 252 StringList &commands = data->user_source; 253 254 if (commands.GetSize() > 0) 255 { 256 ExecutionContext exe_ctx (context->exe_ctx_ref); 257 Target *target = exe_ctx.GetTargetPtr(); 258 if (target) 259 { 260 CommandReturnObject result; 261 Debugger &debugger = target->GetDebugger(); 262 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 263 // if the debugger is set up that way. 264 265 StreamSP output_stream (debugger.GetAsyncOutputStream()); 266 StreamSP error_stream (debugger.GetAsyncErrorStream()); 267 result.SetImmediateOutputStream (output_stream); 268 result.SetImmediateErrorStream (error_stream); 269 270 CommandInterpreterRunOptions options; 271 options.SetStopOnContinue (true); 272 options.SetStopOnError (data->stop_on_error); 273 options.SetEchoCommands (false); 274 options.SetPrintResults (true); 275 options.SetAddToHistory (false); 276 277 debugger.GetCommandInterpreter().HandleCommands (commands, 278 &exe_ctx, 279 options, 280 result); 281 result.GetImmediateOutputStream()->Flush(); 282 result.GetImmediateErrorStream()->Flush(); 283 } 284 } 285 return ret_value; 286 } 287 288 class CommandOptions : public Options 289 { 290 public: 291 292 CommandOptions (CommandInterpreter &interpreter) : 293 Options (interpreter), 294 m_use_commands (false), 295 m_use_script_language (false), 296 m_script_language (eScriptLanguageNone), 297 m_use_one_liner (false), 298 m_one_liner(), 299 m_function_name() 300 { 301 } 302 303 ~CommandOptions () override {} 304 305 Error 306 SetOptionValue (uint32_t option_idx, const char *option_arg) override 307 { 308 Error error; 309 const int short_option = m_getopt_table[option_idx].val; 310 311 switch (short_option) 312 { 313 case 'o': 314 m_use_one_liner = true; 315 m_one_liner = option_arg; 316 break; 317 318 case 's': 319 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 320 g_option_table[option_idx].enum_values, 321 eScriptLanguageNone, 322 error); 323 324 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault) 325 { 326 m_use_script_language = true; 327 } 328 else 329 { 330 m_use_script_language = false; 331 } 332 break; 333 334 case 'e': 335 { 336 bool success = false; 337 m_stop_on_error = Args::StringToBoolean(option_arg, false, &success); 338 if (!success) 339 error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg); 340 } 341 break; 342 343 case 'F': 344 { 345 m_use_one_liner = false; 346 m_use_script_language = true; 347 m_function_name.assign(option_arg); 348 } 349 break; 350 351 default: 352 break; 353 } 354 return error; 355 } 356 void 357 OptionParsingStarting () override 358 { 359 m_use_commands = true; 360 m_use_script_language = false; 361 m_script_language = eScriptLanguageNone; 362 363 m_use_one_liner = false; 364 m_stop_on_error = true; 365 m_one_liner.clear(); 366 m_function_name.clear(); 367 } 368 369 const OptionDefinition* 370 GetDefinitions () override 371 { 372 return g_option_table; 373 } 374 375 // Options table: Required for subclasses of Options. 376 377 static OptionDefinition g_option_table[]; 378 379 // Instance variables to hold the values for command options. 380 381 bool m_use_commands; 382 bool m_use_script_language; 383 lldb::ScriptLanguage m_script_language; 384 385 // Instance variables to hold the values for one_liner options. 386 bool m_use_one_liner; 387 std::string m_one_liner; 388 bool m_stop_on_error; 389 std::string m_function_name; 390 }; 391 392 protected: 393 bool 394 DoExecute (Args& command, CommandReturnObject &result) override 395 { 396 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 397 398 if (target == NULL) 399 { 400 result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands"); 401 result.SetStatus (eReturnStatusFailed); 402 return false; 403 } 404 405 const WatchpointList &watchpoints = target->GetWatchpointList(); 406 size_t num_watchpoints = watchpoints.GetSize(); 407 408 if (num_watchpoints == 0) 409 { 410 result.AppendError ("No watchpoints exist to have commands added"); 411 result.SetStatus (eReturnStatusFailed); 412 return false; 413 } 414 415 if (m_options.m_use_script_language == false && m_options.m_function_name.size()) 416 { 417 result.AppendError ("need to enable scripting to have a function run as a watchpoint command"); 418 result.SetStatus (eReturnStatusFailed); 419 return false; 420 } 421 422 std::vector<uint32_t> valid_wp_ids; 423 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 424 { 425 result.AppendError("Invalid watchpoints specification."); 426 result.SetStatus(eReturnStatusFailed); 427 return false; 428 } 429 430 result.SetStatus(eReturnStatusSuccessFinishNoResult); 431 const size_t count = valid_wp_ids.size(); 432 for (size_t i = 0; i < count; ++i) 433 { 434 uint32_t cur_wp_id = valid_wp_ids.at (i); 435 if (cur_wp_id != LLDB_INVALID_WATCH_ID) 436 { 437 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 438 // Sanity check wp first. 439 if (wp == NULL) continue; 440 441 WatchpointOptions *wp_options = wp->GetOptions(); 442 // Skip this watchpoint if wp_options is not good. 443 if (wp_options == NULL) continue; 444 445 // If we are using script language, get the script interpreter 446 // in order to set or collect command callback. Otherwise, call 447 // the methods associated with this object. 448 if (m_options.m_use_script_language) 449 { 450 // Special handling for one-liner specified inline. 451 if (m_options.m_use_one_liner) 452 { 453 m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options, 454 m_options.m_one_liner.c_str()); 455 } 456 // Special handling for using a Python function by name 457 // instead of extending the watchpoint callback data structures, we just automatize 458 // what the user would do manually: make their watchpoint command be a function call 459 else if (m_options.m_function_name.size()) 460 { 461 std::string oneliner(m_options.m_function_name); 462 oneliner += "(frame, wp, internal_dict)"; 463 m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options, 464 oneliner.c_str()); 465 } 466 else 467 { 468 m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options, 469 result); 470 } 471 } 472 else 473 { 474 // Special handling for one-liner specified inline. 475 if (m_options.m_use_one_liner) 476 SetWatchpointCommandCallback (wp_options, 477 m_options.m_one_liner.c_str()); 478 else 479 CollectDataForWatchpointCommandCallback (wp_options, 480 result); 481 } 482 } 483 } 484 485 return result.Succeeded(); 486 } 487 488 private: 489 CommandOptions m_options; 490 }; 491 492 493 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting 494 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. 495 496 static OptionEnumValueElement 497 g_script_option_enumeration[4] = 498 { 499 { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"}, 500 { eScriptLanguagePython, "python", "Commands are in the Python language."}, 501 { eSortOrderByName, "default-script", "Commands are in the default scripting language."}, 502 { 0, NULL, NULL } 503 }; 504 505 OptionDefinition 506 CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] = 507 { 508 { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner, 509 "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." }, 510 511 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, 512 "Specify whether watchpoint command execution should terminate on error." }, 513 514 { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, NULL, g_script_option_enumeration, 0, eArgTypeNone, 515 "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."}, 516 517 { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, 518 "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."}, 519 520 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 521 }; 522 523 //------------------------------------------------------------------------- 524 // CommandObjectWatchpointCommandDelete 525 //------------------------------------------------------------------------- 526 527 class CommandObjectWatchpointCommandDelete : public CommandObjectParsed 528 { 529 public: 530 CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) : 531 CommandObjectParsed (interpreter, 532 "delete", 533 "Delete the set of commands from a watchpoint.", 534 NULL) 535 { 536 CommandArgumentEntry arg; 537 CommandArgumentData wp_id_arg; 538 539 // Define the first (and only) variant of this arg. 540 wp_id_arg.arg_type = eArgTypeWatchpointID; 541 wp_id_arg.arg_repetition = eArgRepeatPlain; 542 543 // There is only one variant this argument could be; put it into the argument entry. 544 arg.push_back (wp_id_arg); 545 546 // Push the data for the first argument into the m_arguments vector. 547 m_arguments.push_back (arg); 548 } 549 550 551 ~CommandObjectWatchpointCommandDelete () override {} 552 553 protected: 554 bool 555 DoExecute (Args& command, CommandReturnObject &result) override 556 { 557 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 558 559 if (target == NULL) 560 { 561 result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands"); 562 result.SetStatus (eReturnStatusFailed); 563 return false; 564 } 565 566 const WatchpointList &watchpoints = target->GetWatchpointList(); 567 size_t num_watchpoints = watchpoints.GetSize(); 568 569 if (num_watchpoints == 0) 570 { 571 result.AppendError ("No watchpoints exist to have commands deleted"); 572 result.SetStatus (eReturnStatusFailed); 573 return false; 574 } 575 576 if (command.GetArgumentCount() == 0) 577 { 578 result.AppendError ("No watchpoint specified from which to delete the commands"); 579 result.SetStatus (eReturnStatusFailed); 580 return false; 581 } 582 583 std::vector<uint32_t> valid_wp_ids; 584 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 585 { 586 result.AppendError("Invalid watchpoints specification."); 587 result.SetStatus(eReturnStatusFailed); 588 return false; 589 } 590 591 result.SetStatus(eReturnStatusSuccessFinishNoResult); 592 const size_t count = valid_wp_ids.size(); 593 for (size_t i = 0; i < count; ++i) 594 { 595 uint32_t cur_wp_id = valid_wp_ids.at (i); 596 if (cur_wp_id != LLDB_INVALID_WATCH_ID) 597 { 598 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 599 if (wp) 600 wp->ClearCallback(); 601 } 602 else 603 { 604 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", 605 cur_wp_id); 606 result.SetStatus (eReturnStatusFailed); 607 return false; 608 } 609 } 610 return result.Succeeded(); 611 } 612 }; 613 614 //------------------------------------------------------------------------- 615 // CommandObjectWatchpointCommandList 616 //------------------------------------------------------------------------- 617 618 class CommandObjectWatchpointCommandList : public CommandObjectParsed 619 { 620 public: 621 CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) : 622 CommandObjectParsed (interpreter, 623 "list", 624 "List the script or set of commands to be executed when the watchpoint is hit.", 625 NULL) 626 { 627 CommandArgumentEntry arg; 628 CommandArgumentData wp_id_arg; 629 630 // Define the first (and only) variant of this arg. 631 wp_id_arg.arg_type = eArgTypeWatchpointID; 632 wp_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 (wp_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 ~CommandObjectWatchpointCommandList () override {} 642 643 protected: 644 bool 645 DoExecute (Args& command, CommandReturnObject &result) override 646 { 647 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 648 649 if (target == NULL) 650 { 651 result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands"); 652 result.SetStatus (eReturnStatusFailed); 653 return false; 654 } 655 656 const WatchpointList &watchpoints = target->GetWatchpointList(); 657 size_t num_watchpoints = watchpoints.GetSize(); 658 659 if (num_watchpoints == 0) 660 { 661 result.AppendError ("No watchpoints exist for which to list commands"); 662 result.SetStatus (eReturnStatusFailed); 663 return false; 664 } 665 666 if (command.GetArgumentCount() == 0) 667 { 668 result.AppendError ("No watchpoint specified for which to list the commands"); 669 result.SetStatus (eReturnStatusFailed); 670 return false; 671 } 672 673 std::vector<uint32_t> valid_wp_ids; 674 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 675 { 676 result.AppendError("Invalid watchpoints specification."); 677 result.SetStatus(eReturnStatusFailed); 678 return false; 679 } 680 681 result.SetStatus(eReturnStatusSuccessFinishNoResult); 682 const size_t count = valid_wp_ids.size(); 683 for (size_t i = 0; i < count; ++i) 684 { 685 uint32_t cur_wp_id = valid_wp_ids.at (i); 686 if (cur_wp_id != LLDB_INVALID_WATCH_ID) 687 { 688 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 689 690 if (wp) 691 { 692 const WatchpointOptions *wp_options = wp->GetOptions(); 693 if (wp_options) 694 { 695 // Get the callback baton associated with the current watchpoint. 696 const Baton *baton = wp_options->GetBaton(); 697 if (baton) 698 { 699 result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id); 700 result.GetOutputStream().IndentMore (); 701 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 702 result.GetOutputStream().IndentLess (); 703 } 704 else 705 { 706 result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n", 707 cur_wp_id); 708 } 709 } 710 result.SetStatus (eReturnStatusSuccessFinishResult); 711 } 712 else 713 { 714 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id); 715 result.SetStatus (eReturnStatusFailed); 716 } 717 } 718 } 719 720 return result.Succeeded(); 721 } 722 }; 723 724 //------------------------------------------------------------------------- 725 // CommandObjectWatchpointCommand 726 //------------------------------------------------------------------------- 727 728 CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) : 729 CommandObjectMultiword (interpreter, 730 "command", 731 "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').", 732 "command <sub-command> [<sub-command-options>] <watchpoint-id>") 733 { 734 CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter)); 735 CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter)); 736 CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter)); 737 738 add_command_object->SetCommandName ("watchpoint command add"); 739 delete_command_object->SetCommandName ("watchpoint command delete"); 740 list_command_object->SetCommandName ("watchpoint command list"); 741 742 LoadSubCommand ("add", add_command_object); 743 LoadSubCommand ("delete", delete_command_object); 744 LoadSubCommand ("list", list_command_object); 745 } 746 747 CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand () 748 { 749 } 750 751 752