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