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