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 virtual 173 ~CommandObjectWatchpointCommandAdd () {} 174 175 virtual Options * 176 GetOptions () 177 { 178 return &m_options; 179 } 180 181 virtual void 182 IOHandlerActivated (IOHandler &io_handler) 183 { 184 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 185 if (output_sp) 186 { 187 output_sp->PutCString("Enter your debugger command(s). Type 'DONE' to end.\n"); 188 output_sp->Flush(); 189 } 190 } 191 192 193 virtual void 194 IOHandlerInputComplete (IOHandler &io_handler, std::string &line) 195 { 196 io_handler.SetIsDone(true); 197 198 // The WatchpointOptions object is owned by the watchpoint or watchpoint location 199 WatchpointOptions *wp_options = (WatchpointOptions *) io_handler.GetUserData(); 200 if (wp_options) 201 { 202 std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); 203 if (data_ap.get()) 204 { 205 data_ap->user_source.SplitIntoLines(line); 206 BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); 207 wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp); 208 } 209 } 210 } 211 212 void 213 CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, 214 CommandReturnObject &result) 215 { 216 m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt 217 *this, // IOHandlerDelegate 218 true, // Run IOHandler in async mode 219 wp_options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions 220 } 221 222 /// Set a one-liner as the callback for the watchpoint. 223 void 224 SetWatchpointCommandCallback (WatchpointOptions *wp_options, 225 const char *oneliner) 226 { 227 std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); 228 229 // It's necessary to set both user_source and script_source to the oneliner. 230 // The former is used to generate callback description (as in watchpoint command list) 231 // while the latter is used for Python to interpret during the actual callback. 232 data_ap->user_source.AppendString (oneliner); 233 data_ap->script_source.assign (oneliner); 234 data_ap->stop_on_error = m_options.m_stop_on_error; 235 236 BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); 237 wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp); 238 239 return; 240 } 241 242 static bool 243 WatchpointOptionsCallbackFunction (void *baton, 244 StoppointCallbackContext *context, 245 lldb::user_id_t watch_id) 246 { 247 bool ret_value = true; 248 if (baton == NULL) 249 return true; 250 251 252 WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton; 253 StringList &commands = data->user_source; 254 255 if (commands.GetSize() > 0) 256 { 257 ExecutionContext exe_ctx (context->exe_ctx_ref); 258 Target *target = exe_ctx.GetTargetPtr(); 259 if (target) 260 { 261 CommandReturnObject result; 262 Debugger &debugger = target->GetDebugger(); 263 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 264 // if the debugger is set up that way. 265 266 StreamSP output_stream (debugger.GetAsyncOutputStream()); 267 StreamSP error_stream (debugger.GetAsyncErrorStream()); 268 result.SetImmediateOutputStream (output_stream); 269 result.SetImmediateErrorStream (error_stream); 270 271 CommandInterpreterRunOptions options; 272 options.SetStopOnContinue (true); 273 options.SetStopOnError (data->stop_on_error); 274 options.SetEchoCommands (false); 275 options.SetPrintResults (true); 276 options.SetAddToHistory (false); 277 278 debugger.GetCommandInterpreter().HandleCommands (commands, 279 &exe_ctx, 280 options, 281 result); 282 result.GetImmediateOutputStream()->Flush(); 283 result.GetImmediateErrorStream()->Flush(); 284 } 285 } 286 return ret_value; 287 } 288 289 class CommandOptions : public Options 290 { 291 public: 292 293 CommandOptions (CommandInterpreter &interpreter) : 294 Options (interpreter), 295 m_use_commands (false), 296 m_use_script_language (false), 297 m_script_language (eScriptLanguageNone), 298 m_use_one_liner (false), 299 m_one_liner(), 300 m_function_name() 301 { 302 } 303 304 virtual 305 ~CommandOptions () {} 306 307 virtual Error 308 SetOptionValue (uint32_t option_idx, const char *option_arg) 309 { 310 Error error; 311 const int short_option = m_getopt_table[option_idx].val; 312 313 switch (short_option) 314 { 315 case 'o': 316 m_use_one_liner = true; 317 m_one_liner = option_arg; 318 break; 319 320 case 's': 321 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 322 g_option_table[option_idx].enum_values, 323 eScriptLanguageNone, 324 error); 325 326 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault) 327 { 328 m_use_script_language = true; 329 } 330 else 331 { 332 m_use_script_language = false; 333 } 334 break; 335 336 case 'e': 337 { 338 bool success = false; 339 m_stop_on_error = Args::StringToBoolean(option_arg, false, &success); 340 if (!success) 341 error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg); 342 } 343 break; 344 345 case 'F': 346 { 347 m_use_one_liner = false; 348 m_use_script_language = true; 349 m_function_name.assign(option_arg); 350 } 351 break; 352 353 default: 354 break; 355 } 356 return error; 357 } 358 void 359 OptionParsingStarting () 360 { 361 m_use_commands = true; 362 m_use_script_language = false; 363 m_script_language = eScriptLanguageNone; 364 365 m_use_one_liner = false; 366 m_stop_on_error = true; 367 m_one_liner.clear(); 368 m_function_name.clear(); 369 } 370 371 const OptionDefinition* 372 GetDefinitions () 373 { 374 return g_option_table; 375 } 376 377 // Options table: Required for subclasses of Options. 378 379 static OptionDefinition g_option_table[]; 380 381 // Instance variables to hold the values for command options. 382 383 bool m_use_commands; 384 bool m_use_script_language; 385 lldb::ScriptLanguage m_script_language; 386 387 // Instance variables to hold the values for one_liner options. 388 bool m_use_one_liner; 389 std::string m_one_liner; 390 bool m_stop_on_error; 391 std::string m_function_name; 392 }; 393 394 protected: 395 virtual bool 396 DoExecute (Args& command, CommandReturnObject &result) 397 { 398 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 399 400 if (target == NULL) 401 { 402 result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands"); 403 result.SetStatus (eReturnStatusFailed); 404 return false; 405 } 406 407 const WatchpointList &watchpoints = target->GetWatchpointList(); 408 size_t num_watchpoints = watchpoints.GetSize(); 409 410 if (num_watchpoints == 0) 411 { 412 result.AppendError ("No watchpoints exist to have commands added"); 413 result.SetStatus (eReturnStatusFailed); 414 return false; 415 } 416 417 if (m_options.m_use_script_language == false && m_options.m_function_name.size()) 418 { 419 result.AppendError ("need to enable scripting to have a function run as a watchpoint command"); 420 result.SetStatus (eReturnStatusFailed); 421 return false; 422 } 423 424 std::vector<uint32_t> valid_wp_ids; 425 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 426 { 427 result.AppendError("Invalid watchpoints specification."); 428 result.SetStatus(eReturnStatusFailed); 429 return false; 430 } 431 432 result.SetStatus(eReturnStatusSuccessFinishNoResult); 433 const size_t count = valid_wp_ids.size(); 434 for (size_t i = 0; i < count; ++i) 435 { 436 uint32_t cur_wp_id = valid_wp_ids.at (i); 437 if (cur_wp_id != LLDB_INVALID_WATCH_ID) 438 { 439 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 440 // Sanity check wp first. 441 if (wp == NULL) continue; 442 443 WatchpointOptions *wp_options = wp->GetOptions(); 444 // Skip this watchpoint if wp_options is not good. 445 if (wp_options == NULL) continue; 446 447 // If we are using script language, get the script interpreter 448 // in order to set or collect command callback. Otherwise, call 449 // the methods associated with this object. 450 if (m_options.m_use_script_language) 451 { 452 // Special handling for one-liner specified inline. 453 if (m_options.m_use_one_liner) 454 { 455 m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options, 456 m_options.m_one_liner.c_str()); 457 } 458 // Special handling for using a Python function by name 459 // instead of extending the watchpoint callback data structures, we just automatize 460 // what the user would do manually: make their watchpoint command be a function call 461 else if (m_options.m_function_name.size()) 462 { 463 std::string oneliner(m_options.m_function_name); 464 oneliner += "(frame, wp, internal_dict)"; 465 m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options, 466 oneliner.c_str()); 467 } 468 else 469 { 470 m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options, 471 result); 472 } 473 } 474 else 475 { 476 // Special handling for one-liner specified inline. 477 if (m_options.m_use_one_liner) 478 SetWatchpointCommandCallback (wp_options, 479 m_options.m_one_liner.c_str()); 480 else 481 CollectDataForWatchpointCommandCallback (wp_options, 482 result); 483 } 484 } 485 } 486 487 return result.Succeeded(); 488 } 489 490 private: 491 CommandOptions m_options; 492 }; 493 494 495 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting 496 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. 497 498 static OptionEnumValueElement 499 g_script_option_enumeration[4] = 500 { 501 { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"}, 502 { eScriptLanguagePython, "python", "Commands are in the Python language."}, 503 { eSortOrderByName, "default-script", "Commands are in the default scripting language."}, 504 { 0, NULL, NULL } 505 }; 506 507 OptionDefinition 508 CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] = 509 { 510 { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOneLiner, 511 "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." }, 512 513 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, 514 "Specify whether watchpoint command execution should terminate on error." }, 515 516 { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, NULL, g_script_option_enumeration, 0, eArgTypeNone, 517 "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."}, 518 519 { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, 520 "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."}, 521 522 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 523 }; 524 525 //------------------------------------------------------------------------- 526 // CommandObjectWatchpointCommandDelete 527 //------------------------------------------------------------------------- 528 529 class CommandObjectWatchpointCommandDelete : public CommandObjectParsed 530 { 531 public: 532 CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) : 533 CommandObjectParsed (interpreter, 534 "delete", 535 "Delete the set of commands from a watchpoint.", 536 NULL) 537 { 538 CommandArgumentEntry arg; 539 CommandArgumentData wp_id_arg; 540 541 // Define the first (and only) variant of this arg. 542 wp_id_arg.arg_type = eArgTypeWatchpointID; 543 wp_id_arg.arg_repetition = eArgRepeatPlain; 544 545 // There is only one variant this argument could be; put it into the argument entry. 546 arg.push_back (wp_id_arg); 547 548 // Push the data for the first argument into the m_arguments vector. 549 m_arguments.push_back (arg); 550 } 551 552 553 virtual 554 ~CommandObjectWatchpointCommandDelete () {} 555 556 protected: 557 virtual bool 558 DoExecute (Args& command, CommandReturnObject &result) 559 { 560 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 561 562 if (target == NULL) 563 { 564 result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands"); 565 result.SetStatus (eReturnStatusFailed); 566 return false; 567 } 568 569 const WatchpointList &watchpoints = target->GetWatchpointList(); 570 size_t num_watchpoints = watchpoints.GetSize(); 571 572 if (num_watchpoints == 0) 573 { 574 result.AppendError ("No watchpoints exist to have commands deleted"); 575 result.SetStatus (eReturnStatusFailed); 576 return false; 577 } 578 579 if (command.GetArgumentCount() == 0) 580 { 581 result.AppendError ("No watchpoint specified from which to delete the commands"); 582 result.SetStatus (eReturnStatusFailed); 583 return false; 584 } 585 586 std::vector<uint32_t> valid_wp_ids; 587 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 588 { 589 result.AppendError("Invalid watchpoints specification."); 590 result.SetStatus(eReturnStatusFailed); 591 return false; 592 } 593 594 result.SetStatus(eReturnStatusSuccessFinishNoResult); 595 const size_t count = valid_wp_ids.size(); 596 for (size_t i = 0; i < count; ++i) 597 { 598 uint32_t cur_wp_id = valid_wp_ids.at (i); 599 if (cur_wp_id != LLDB_INVALID_WATCH_ID) 600 { 601 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 602 if (wp) 603 wp->ClearCallback(); 604 } 605 else 606 { 607 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", 608 cur_wp_id); 609 result.SetStatus (eReturnStatusFailed); 610 return false; 611 } 612 } 613 return result.Succeeded(); 614 } 615 }; 616 617 //------------------------------------------------------------------------- 618 // CommandObjectWatchpointCommandList 619 //------------------------------------------------------------------------- 620 621 class CommandObjectWatchpointCommandList : public CommandObjectParsed 622 { 623 public: 624 CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) : 625 CommandObjectParsed (interpreter, 626 "list", 627 "List the script or set of commands to be executed when the watchpoint is hit.", 628 NULL) 629 { 630 CommandArgumentEntry arg; 631 CommandArgumentData wp_id_arg; 632 633 // Define the first (and only) variant of this arg. 634 wp_id_arg.arg_type = eArgTypeWatchpointID; 635 wp_id_arg.arg_repetition = eArgRepeatPlain; 636 637 // There is only one variant this argument could be; put it into the argument entry. 638 arg.push_back (wp_id_arg); 639 640 // Push the data for the first argument into the m_arguments vector. 641 m_arguments.push_back (arg); 642 } 643 644 virtual 645 ~CommandObjectWatchpointCommandList () {} 646 647 protected: 648 virtual bool 649 DoExecute (Args& command, 650 CommandReturnObject &result) 651 { 652 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 653 654 if (target == NULL) 655 { 656 result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands"); 657 result.SetStatus (eReturnStatusFailed); 658 return false; 659 } 660 661 const WatchpointList &watchpoints = target->GetWatchpointList(); 662 size_t num_watchpoints = watchpoints.GetSize(); 663 664 if (num_watchpoints == 0) 665 { 666 result.AppendError ("No watchpoints exist for which to list commands"); 667 result.SetStatus (eReturnStatusFailed); 668 return false; 669 } 670 671 if (command.GetArgumentCount() == 0) 672 { 673 result.AppendError ("No watchpoint specified for which to list the commands"); 674 result.SetStatus (eReturnStatusFailed); 675 return false; 676 } 677 678 std::vector<uint32_t> valid_wp_ids; 679 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 680 { 681 result.AppendError("Invalid watchpoints specification."); 682 result.SetStatus(eReturnStatusFailed); 683 return false; 684 } 685 686 result.SetStatus(eReturnStatusSuccessFinishNoResult); 687 const size_t count = valid_wp_ids.size(); 688 for (size_t i = 0; i < count; ++i) 689 { 690 uint32_t cur_wp_id = valid_wp_ids.at (i); 691 if (cur_wp_id != LLDB_INVALID_WATCH_ID) 692 { 693 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 694 695 if (wp) 696 { 697 const WatchpointOptions *wp_options = wp->GetOptions(); 698 if (wp_options) 699 { 700 // Get the callback baton associated with the current watchpoint. 701 const Baton *baton = wp_options->GetBaton(); 702 if (baton) 703 { 704 result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id); 705 result.GetOutputStream().IndentMore (); 706 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 707 result.GetOutputStream().IndentLess (); 708 } 709 else 710 { 711 result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n", 712 cur_wp_id); 713 } 714 } 715 result.SetStatus (eReturnStatusSuccessFinishResult); 716 } 717 else 718 { 719 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id); 720 result.SetStatus (eReturnStatusFailed); 721 } 722 } 723 } 724 725 return result.Succeeded(); 726 } 727 }; 728 729 //------------------------------------------------------------------------- 730 // CommandObjectWatchpointCommand 731 //------------------------------------------------------------------------- 732 733 CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) : 734 CommandObjectMultiword (interpreter, 735 "command", 736 "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').", 737 "command <sub-command> [<sub-command-options>] <watchpoint-id>") 738 { 739 CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter)); 740 CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter)); 741 CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter)); 742 743 add_command_object->SetCommandName ("watchpoint command add"); 744 delete_command_object->SetCommandName ("watchpoint command delete"); 745 list_command_object->SetCommandName ("watchpoint command list"); 746 747 LoadSubCommand ("add", add_command_object); 748 LoadSubCommand ("delete", delete_command_object); 749 LoadSubCommand ("list", list_command_object); 750 } 751 752 CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand () 753 { 754 } 755 756 757