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