1 //===-- CommandObjectWatchpoint.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 "CommandObjectWatchpoint.h" 11 #include "CommandObjectWatchpointCommand.h" 12 13 // C Includes 14 // C++ Includes 15 #include <vector> 16 17 // Other libraries and framework includes 18 #include "llvm/ADT/StringRef.h" 19 20 // Project includes 21 #include "lldb/Breakpoint/Watchpoint.h" 22 #include "lldb/Breakpoint/WatchpointList.h" 23 #include "lldb/Core/StreamString.h" 24 #include "lldb/Core/ValueObject.h" 25 #include "lldb/Core/ValueObjectVariable.h" 26 #include "lldb/Host/StringConvert.h" 27 #include "lldb/Interpreter/CommandInterpreter.h" 28 #include "lldb/Interpreter/CommandReturnObject.h" 29 #include "lldb/Interpreter/CommandCompletions.h" 30 #include "lldb/Symbol/Variable.h" 31 #include "lldb/Symbol/VariableList.h" 32 #include "lldb/Target/StackFrame.h" 33 #include "lldb/Target/Target.h" 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 static void 39 AddWatchpointDescription(Stream *s, Watchpoint *wp, lldb::DescriptionLevel level) 40 { 41 s->IndentMore(); 42 wp->GetDescription(s, level); 43 s->IndentLess(); 44 s->EOL(); 45 } 46 47 static bool 48 CheckTargetForWatchpointOperations(Target *target, CommandReturnObject &result) 49 { 50 if (target == nullptr) 51 { 52 result.AppendError ("Invalid target. No existing target or watchpoints."); 53 result.SetStatus (eReturnStatusFailed); 54 return false; 55 } 56 bool process_is_valid = target->GetProcessSP() && target->GetProcessSP()->IsAlive(); 57 if (!process_is_valid) 58 { 59 result.AppendError ("Thre's no process or it is not alive."); 60 result.SetStatus (eReturnStatusFailed); 61 return false; 62 } 63 // Target passes our checks, return true. 64 return true; 65 } 66 67 // Equivalent class: {"-", "to", "To", "TO"} of range specifier array. 68 static const char* RSA[4] = { "-", "to", "To", "TO" }; 69 70 // Return the index to RSA if found; otherwise -1 is returned. 71 static int32_t 72 WithRSAIndex(llvm::StringRef &Arg) 73 { 74 75 uint32_t i; 76 for (i = 0; i < 4; ++i) 77 if (Arg.find(RSA[i]) != llvm::StringRef::npos) 78 return i; 79 return -1; 80 } 81 82 // Return true if wp_ids is successfully populated with the watch ids. 83 // False otherwise. 84 bool 85 CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(Target *target, Args &args, std::vector<uint32_t> &wp_ids) 86 { 87 // Pre-condition: args.GetArgumentCount() > 0. 88 if (args.GetArgumentCount() == 0) 89 { 90 if (target == nullptr) 91 return false; 92 WatchpointSP watch_sp = target->GetLastCreatedWatchpoint(); 93 if (watch_sp) 94 { 95 wp_ids.push_back(watch_sp->GetID()); 96 return true; 97 } 98 else 99 return false; 100 } 101 102 llvm::StringRef Minus("-"); 103 std::vector<llvm::StringRef> StrRefArgs; 104 std::pair<llvm::StringRef, llvm::StringRef> Pair; 105 size_t i; 106 int32_t idx; 107 // Go through the arguments and make a canonical form of arg list containing 108 // only numbers with possible "-" in between. 109 for (i = 0; i < args.GetArgumentCount(); ++i) { 110 llvm::StringRef Arg(args.GetArgumentAtIndex(i)); 111 if ((idx = WithRSAIndex(Arg)) == -1) { 112 StrRefArgs.push_back(Arg); 113 continue; 114 } 115 // The Arg contains the range specifier, split it, then. 116 Pair = Arg.split(RSA[idx]); 117 if (!Pair.first.empty()) 118 StrRefArgs.push_back(Pair.first); 119 StrRefArgs.push_back(Minus); 120 if (!Pair.second.empty()) 121 StrRefArgs.push_back(Pair.second); 122 } 123 // Now process the canonical list and fill in the vector of uint32_t's. 124 // If there is any error, return false and the client should ignore wp_ids. 125 uint32_t beg, end, id; 126 size_t size = StrRefArgs.size(); 127 bool in_range = false; 128 for (i = 0; i < size; ++i) { 129 llvm::StringRef Arg = StrRefArgs[i]; 130 if (in_range) { 131 // Look for the 'end' of the range. Note StringRef::getAsInteger() 132 // returns true to signify error while parsing. 133 if (Arg.getAsInteger(0, end)) 134 return false; 135 // Found a range! Now append the elements. 136 for (id = beg; id <= end; ++id) 137 wp_ids.push_back(id); 138 in_range = false; 139 continue; 140 } 141 if (i < (size - 1) && StrRefArgs[i+1] == Minus) { 142 if (Arg.getAsInteger(0, beg)) 143 return false; 144 // Turn on the in_range flag, we are looking for end of range next. 145 ++i; in_range = true; 146 continue; 147 } 148 // Otherwise, we have a simple ID. Just append it. 149 if (Arg.getAsInteger(0, beg)) 150 return false; 151 wp_ids.push_back(beg); 152 } 153 // It is an error if after the loop, we're still in_range. 154 if (in_range) 155 return false; 156 157 return true; // Success! 158 } 159 160 //------------------------------------------------------------------------- 161 // CommandObjectWatchpointList 162 //------------------------------------------------------------------------- 163 #pragma mark List 164 165 class CommandObjectWatchpointList : public CommandObjectParsed 166 { 167 public: 168 CommandObjectWatchpointList (CommandInterpreter &interpreter) : 169 CommandObjectParsed(interpreter, 170 "watchpoint list", 171 "List all watchpoints at configurable levels of detail.", 172 nullptr), 173 m_options(interpreter) 174 { 175 CommandArgumentEntry arg; 176 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 177 // Add the entry for the first argument for this command to the object's arguments vector. 178 m_arguments.push_back(arg); 179 } 180 181 ~CommandObjectWatchpointList() override = default; 182 183 Options * 184 GetOptions () override 185 { 186 return &m_options; 187 } 188 189 class CommandOptions : public Options 190 { 191 public: 192 CommandOptions (CommandInterpreter &interpreter) : 193 Options(interpreter), 194 m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to brief descriptions 195 { 196 } 197 198 ~CommandOptions() override = default; 199 200 Error 201 SetOptionValue (uint32_t option_idx, const char *option_arg) override 202 { 203 Error error; 204 const int short_option = m_getopt_table[option_idx].val; 205 206 switch (short_option) 207 { 208 case 'b': 209 m_level = lldb::eDescriptionLevelBrief; 210 break; 211 case 'f': 212 m_level = lldb::eDescriptionLevelFull; 213 break; 214 case 'v': 215 m_level = lldb::eDescriptionLevelVerbose; 216 break; 217 default: 218 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 219 break; 220 } 221 222 return error; 223 } 224 225 void 226 OptionParsingStarting () override 227 { 228 m_level = lldb::eDescriptionLevelFull; 229 } 230 231 const OptionDefinition * 232 GetDefinitions () override 233 { 234 return g_option_table; 235 } 236 237 // Options table: Required for subclasses of Options. 238 239 static OptionDefinition g_option_table[]; 240 241 // Instance variables to hold the values for command options. 242 243 lldb::DescriptionLevel m_level; 244 }; 245 246 protected: 247 bool 248 DoExecute (Args& command, CommandReturnObject &result) override 249 { 250 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 251 if (target == nullptr) 252 { 253 result.AppendError ("Invalid target. No current target or watchpoints."); 254 result.SetStatus (eReturnStatusSuccessFinishNoResult); 255 return true; 256 } 257 258 if (target->GetProcessSP() && target->GetProcessSP()->IsAlive()) 259 { 260 uint32_t num_supported_hardware_watchpoints; 261 Error error = target->GetProcessSP()->GetWatchpointSupportInfo(num_supported_hardware_watchpoints); 262 if (error.Success()) 263 result.AppendMessageWithFormat("Number of supported hardware watchpoints: %u\n", 264 num_supported_hardware_watchpoints); 265 } 266 267 const WatchpointList &watchpoints = target->GetWatchpointList(); 268 Mutex::Locker locker; 269 target->GetWatchpointList().GetListMutex(locker); 270 271 size_t num_watchpoints = watchpoints.GetSize(); 272 273 if (num_watchpoints == 0) 274 { 275 result.AppendMessage("No watchpoints currently set."); 276 result.SetStatus(eReturnStatusSuccessFinishNoResult); 277 return true; 278 } 279 280 Stream &output_stream = result.GetOutputStream(); 281 282 if (command.GetArgumentCount() == 0) 283 { 284 // No watchpoint selected; show info about all currently set watchpoints. 285 result.AppendMessage ("Current watchpoints:"); 286 for (size_t i = 0; i < num_watchpoints; ++i) 287 { 288 Watchpoint *wp = watchpoints.GetByIndex(i).get(); 289 AddWatchpointDescription(&output_stream, wp, m_options.m_level); 290 } 291 result.SetStatus(eReturnStatusSuccessFinishNoResult); 292 } 293 else 294 { 295 // Particular watchpoints selected; enable them. 296 std::vector<uint32_t> wp_ids; 297 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids)) 298 { 299 result.AppendError("Invalid watchpoints specification."); 300 result.SetStatus(eReturnStatusFailed); 301 return false; 302 } 303 304 const size_t size = wp_ids.size(); 305 for (size_t i = 0; i < size; ++i) 306 { 307 Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get(); 308 if (wp) 309 AddWatchpointDescription(&output_stream, wp, m_options.m_level); 310 result.SetStatus(eReturnStatusSuccessFinishNoResult); 311 } 312 } 313 314 return result.Succeeded(); 315 } 316 317 private: 318 CommandOptions m_options; 319 }; 320 321 //------------------------------------------------------------------------- 322 // CommandObjectWatchpointList::Options 323 //------------------------------------------------------------------------- 324 #pragma mark List::CommandOptions 325 326 OptionDefinition 327 CommandObjectWatchpointList::CommandOptions::g_option_table[] = 328 { 329 { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, 330 "Give a brief description of the watchpoint (no location info)."}, 331 332 { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, 333 "Give a full description of the watchpoint and its locations."}, 334 335 { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, 336 "Explain everything we know about the watchpoint (for debugging debugger bugs)." }, 337 338 { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } 339 }; 340 341 //------------------------------------------------------------------------- 342 // CommandObjectWatchpointEnable 343 //------------------------------------------------------------------------- 344 #pragma mark Enable 345 346 class CommandObjectWatchpointEnable : public CommandObjectParsed 347 { 348 public: 349 CommandObjectWatchpointEnable (CommandInterpreter &interpreter) : 350 CommandObjectParsed(interpreter, 351 "enable", 352 "Enable the specified disabled watchpoint(s). If no watchpoints are specified, enable all of them.", 353 nullptr) 354 { 355 CommandArgumentEntry arg; 356 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 357 // Add the entry for the first argument for this command to the object's arguments vector. 358 m_arguments.push_back(arg); 359 } 360 361 ~CommandObjectWatchpointEnable() override = default; 362 363 protected: 364 bool 365 DoExecute (Args& command, 366 CommandReturnObject &result) override 367 { 368 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 369 if (!CheckTargetForWatchpointOperations(target, result)) 370 return false; 371 372 Mutex::Locker locker; 373 target->GetWatchpointList().GetListMutex(locker); 374 375 const WatchpointList &watchpoints = target->GetWatchpointList(); 376 377 size_t num_watchpoints = watchpoints.GetSize(); 378 379 if (num_watchpoints == 0) 380 { 381 result.AppendError("No watchpoints exist to be enabled."); 382 result.SetStatus(eReturnStatusFailed); 383 return false; 384 } 385 386 if (command.GetArgumentCount() == 0) 387 { 388 // No watchpoint selected; enable all currently set watchpoints. 389 target->EnableAllWatchpoints(); 390 result.AppendMessageWithFormat("All watchpoints enabled. (%" PRIu64 " watchpoints)\n", (uint64_t)num_watchpoints); 391 result.SetStatus(eReturnStatusSuccessFinishNoResult); 392 } 393 else 394 { 395 // Particular watchpoints selected; enable them. 396 std::vector<uint32_t> wp_ids; 397 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids)) 398 { 399 result.AppendError("Invalid watchpoints specification."); 400 result.SetStatus(eReturnStatusFailed); 401 return false; 402 } 403 404 int count = 0; 405 const size_t size = wp_ids.size(); 406 for (size_t i = 0; i < size; ++i) 407 if (target->EnableWatchpointByID(wp_ids[i])) 408 ++count; 409 result.AppendMessageWithFormat("%d watchpoints enabled.\n", count); 410 result.SetStatus(eReturnStatusSuccessFinishNoResult); 411 } 412 413 return result.Succeeded(); 414 } 415 }; 416 417 //------------------------------------------------------------------------- 418 // CommandObjectWatchpointDisable 419 //------------------------------------------------------------------------- 420 #pragma mark Disable 421 422 class CommandObjectWatchpointDisable : public CommandObjectParsed 423 { 424 public: 425 CommandObjectWatchpointDisable (CommandInterpreter &interpreter) : 426 CommandObjectParsed(interpreter, 427 "watchpoint disable", 428 "Disable the specified watchpoint(s) without removing it/them. If no watchpoints are specified, disable them all.", 429 nullptr) 430 { 431 CommandArgumentEntry arg; 432 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 433 // Add the entry for the first argument for this command to the object's arguments vector. 434 m_arguments.push_back(arg); 435 } 436 437 ~CommandObjectWatchpointDisable() override = default; 438 439 protected: 440 bool 441 DoExecute (Args& command, CommandReturnObject &result) override 442 { 443 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 444 if (!CheckTargetForWatchpointOperations(target, result)) 445 return false; 446 447 Mutex::Locker locker; 448 target->GetWatchpointList().GetListMutex(locker); 449 450 const WatchpointList &watchpoints = target->GetWatchpointList(); 451 size_t num_watchpoints = watchpoints.GetSize(); 452 453 if (num_watchpoints == 0) 454 { 455 result.AppendError("No watchpoints exist to be disabled."); 456 result.SetStatus(eReturnStatusFailed); 457 return false; 458 } 459 460 if (command.GetArgumentCount() == 0) 461 { 462 // No watchpoint selected; disable all currently set watchpoints. 463 if (target->DisableAllWatchpoints()) 464 { 465 result.AppendMessageWithFormat("All watchpoints disabled. (%" PRIu64 " watchpoints)\n", (uint64_t)num_watchpoints); 466 result.SetStatus(eReturnStatusSuccessFinishNoResult); 467 } 468 else 469 { 470 result.AppendError("Disable all watchpoints failed\n"); 471 result.SetStatus(eReturnStatusFailed); 472 } 473 } 474 else 475 { 476 // Particular watchpoints selected; disable them. 477 std::vector<uint32_t> wp_ids; 478 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids)) 479 { 480 result.AppendError("Invalid watchpoints specification."); 481 result.SetStatus(eReturnStatusFailed); 482 return false; 483 } 484 485 int count = 0; 486 const size_t size = wp_ids.size(); 487 for (size_t i = 0; i < size; ++i) 488 if (target->DisableWatchpointByID(wp_ids[i])) 489 ++count; 490 result.AppendMessageWithFormat("%d watchpoints disabled.\n", count); 491 result.SetStatus(eReturnStatusSuccessFinishNoResult); 492 } 493 494 return result.Succeeded(); 495 } 496 }; 497 498 //------------------------------------------------------------------------- 499 // CommandObjectWatchpointDelete 500 //------------------------------------------------------------------------- 501 #pragma mark Delete 502 503 class CommandObjectWatchpointDelete : public CommandObjectParsed 504 { 505 public: 506 CommandObjectWatchpointDelete (CommandInterpreter &interpreter) : 507 CommandObjectParsed(interpreter, 508 "watchpoint delete", 509 "Delete the specified watchpoint(s). If no watchpoints are specified, delete them all.", 510 nullptr) 511 { 512 CommandArgumentEntry arg; 513 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 514 // Add the entry for the first argument for this command to the object's arguments vector. 515 m_arguments.push_back(arg); 516 } 517 518 ~CommandObjectWatchpointDelete() override = default; 519 520 protected: 521 bool 522 DoExecute (Args& command, CommandReturnObject &result) override 523 { 524 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 525 if (!CheckTargetForWatchpointOperations(target, result)) 526 return false; 527 528 Mutex::Locker locker; 529 target->GetWatchpointList().GetListMutex(locker); 530 531 const WatchpointList &watchpoints = target->GetWatchpointList(); 532 533 size_t num_watchpoints = watchpoints.GetSize(); 534 535 if (num_watchpoints == 0) 536 { 537 result.AppendError("No watchpoints exist to be deleted."); 538 result.SetStatus(eReturnStatusFailed); 539 return false; 540 } 541 542 if (command.GetArgumentCount() == 0) 543 { 544 if (!m_interpreter.Confirm("About to delete all watchpoints, do you want to do that?", true)) 545 { 546 result.AppendMessage("Operation cancelled..."); 547 } 548 else 549 { 550 target->RemoveAllWatchpoints(); 551 result.AppendMessageWithFormat("All watchpoints removed. (%" PRIu64 " watchpoints)\n", (uint64_t)num_watchpoints); 552 } 553 result.SetStatus (eReturnStatusSuccessFinishNoResult); 554 } 555 else 556 { 557 // Particular watchpoints selected; delete them. 558 std::vector<uint32_t> wp_ids; 559 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids)) 560 { 561 result.AppendError("Invalid watchpoints specification."); 562 result.SetStatus(eReturnStatusFailed); 563 return false; 564 } 565 566 int count = 0; 567 const size_t size = wp_ids.size(); 568 for (size_t i = 0; i < size; ++i) 569 if (target->RemoveWatchpointByID(wp_ids[i])) 570 ++count; 571 result.AppendMessageWithFormat("%d watchpoints deleted.\n",count); 572 result.SetStatus (eReturnStatusSuccessFinishNoResult); 573 } 574 575 return result.Succeeded(); 576 } 577 }; 578 579 //------------------------------------------------------------------------- 580 // CommandObjectWatchpointIgnore 581 //------------------------------------------------------------------------- 582 583 class CommandObjectWatchpointIgnore : public CommandObjectParsed 584 { 585 public: 586 CommandObjectWatchpointIgnore (CommandInterpreter &interpreter) : 587 CommandObjectParsed(interpreter, 588 "watchpoint ignore", 589 "Set ignore count on the specified watchpoint(s). If no watchpoints are specified, set them all.", 590 nullptr), 591 m_options (interpreter) 592 { 593 CommandArgumentEntry arg; 594 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 595 // Add the entry for the first argument for this command to the object's arguments vector. 596 m_arguments.push_back(arg); 597 } 598 599 ~CommandObjectWatchpointIgnore() override = default; 600 601 Options * 602 GetOptions () override 603 { 604 return &m_options; 605 } 606 607 class CommandOptions : public Options 608 { 609 public: 610 CommandOptions (CommandInterpreter &interpreter) : 611 Options (interpreter), 612 m_ignore_count (0) 613 { 614 } 615 616 ~CommandOptions() override = default; 617 618 Error 619 SetOptionValue (uint32_t option_idx, const char *option_arg) override 620 { 621 Error error; 622 const int short_option = m_getopt_table[option_idx].val; 623 624 switch (short_option) 625 { 626 case 'i': 627 m_ignore_count = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); 628 if (m_ignore_count == UINT32_MAX) 629 error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); 630 break; 631 default: 632 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 633 break; 634 } 635 636 return error; 637 } 638 639 void 640 OptionParsingStarting () override 641 { 642 m_ignore_count = 0; 643 } 644 645 const OptionDefinition * 646 GetDefinitions () override 647 { 648 return g_option_table; 649 } 650 651 // Options table: Required for subclasses of Options. 652 653 static OptionDefinition g_option_table[]; 654 655 // Instance variables to hold the values for command options. 656 657 uint32_t m_ignore_count; 658 }; 659 660 protected: 661 bool 662 DoExecute (Args& command, 663 CommandReturnObject &result) override 664 { 665 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 666 if (!CheckTargetForWatchpointOperations(target, result)) 667 return false; 668 669 Mutex::Locker locker; 670 target->GetWatchpointList().GetListMutex(locker); 671 672 const WatchpointList &watchpoints = target->GetWatchpointList(); 673 674 size_t num_watchpoints = watchpoints.GetSize(); 675 676 if (num_watchpoints == 0) 677 { 678 result.AppendError("No watchpoints exist to be ignored."); 679 result.SetStatus(eReturnStatusFailed); 680 return false; 681 } 682 683 if (command.GetArgumentCount() == 0) 684 { 685 target->IgnoreAllWatchpoints(m_options.m_ignore_count); 686 result.AppendMessageWithFormat("All watchpoints ignored. (%" PRIu64 " watchpoints)\n", (uint64_t)num_watchpoints); 687 result.SetStatus (eReturnStatusSuccessFinishNoResult); 688 } 689 else 690 { 691 // Particular watchpoints selected; ignore them. 692 std::vector<uint32_t> wp_ids; 693 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids)) 694 { 695 result.AppendError("Invalid watchpoints specification."); 696 result.SetStatus(eReturnStatusFailed); 697 return false; 698 } 699 700 int count = 0; 701 const size_t size = wp_ids.size(); 702 for (size_t i = 0; i < size; ++i) 703 if (target->IgnoreWatchpointByID(wp_ids[i], m_options.m_ignore_count)) 704 ++count; 705 result.AppendMessageWithFormat("%d watchpoints ignored.\n",count); 706 result.SetStatus (eReturnStatusSuccessFinishNoResult); 707 } 708 709 return result.Succeeded(); 710 } 711 712 private: 713 CommandOptions m_options; 714 }; 715 716 #pragma mark Ignore::CommandOptions 717 718 OptionDefinition 719 CommandObjectWatchpointIgnore::CommandOptions::g_option_table[] = 720 { 721 { LLDB_OPT_SET_ALL, true, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the number of times this watchpoint is skipped before stopping." }, 722 { 0, false, nullptr, 0 , 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } 723 }; 724 725 //------------------------------------------------------------------------- 726 // CommandObjectWatchpointModify 727 //------------------------------------------------------------------------- 728 #pragma mark Modify 729 730 class CommandObjectWatchpointModify : public CommandObjectParsed 731 { 732 public: 733 CommandObjectWatchpointModify (CommandInterpreter &interpreter) : 734 CommandObjectParsed(interpreter, 735 "watchpoint modify", 736 "Modify the options on a watchpoint or set of watchpoints in the executable. " 737 "If no watchpoint is specified, act on the last created watchpoint. " 738 "Passing an empty argument clears the modification.", 739 nullptr), 740 m_options (interpreter) 741 { 742 CommandArgumentEntry arg; 743 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 744 // Add the entry for the first argument for this command to the object's arguments vector. 745 m_arguments.push_back (arg); 746 } 747 748 ~CommandObjectWatchpointModify() override = default; 749 750 Options * 751 GetOptions () override 752 { 753 return &m_options; 754 } 755 756 class CommandOptions : public Options 757 { 758 public: 759 CommandOptions (CommandInterpreter &interpreter) : 760 Options (interpreter), 761 m_condition (), 762 m_condition_passed (false) 763 { 764 } 765 766 ~CommandOptions() override = default; 767 768 Error 769 SetOptionValue (uint32_t option_idx, const char *option_arg) override 770 { 771 Error error; 772 const int short_option = m_getopt_table[option_idx].val; 773 774 switch (short_option) 775 { 776 case 'c': 777 if (option_arg != nullptr) 778 m_condition.assign (option_arg); 779 else 780 m_condition.clear(); 781 m_condition_passed = true; 782 break; 783 default: 784 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 785 break; 786 } 787 788 return error; 789 } 790 791 void 792 OptionParsingStarting () override 793 { 794 m_condition.clear(); 795 m_condition_passed = false; 796 } 797 798 const OptionDefinition* 799 GetDefinitions () override 800 { 801 return g_option_table; 802 } 803 804 // Options table: Required for subclasses of Options. 805 806 static OptionDefinition g_option_table[]; 807 808 // Instance variables to hold the values for command options. 809 810 std::string m_condition; 811 bool m_condition_passed; 812 }; 813 814 protected: 815 bool 816 DoExecute (Args& command, CommandReturnObject &result) override 817 { 818 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 819 if (!CheckTargetForWatchpointOperations(target, result)) 820 return false; 821 822 Mutex::Locker locker; 823 target->GetWatchpointList().GetListMutex(locker); 824 825 const WatchpointList &watchpoints = target->GetWatchpointList(); 826 827 size_t num_watchpoints = watchpoints.GetSize(); 828 829 if (num_watchpoints == 0) 830 { 831 result.AppendError("No watchpoints exist to be modified."); 832 result.SetStatus(eReturnStatusFailed); 833 return false; 834 } 835 836 if (command.GetArgumentCount() == 0) 837 { 838 WatchpointSP wp_sp = target->GetLastCreatedWatchpoint(); 839 wp_sp->SetCondition(m_options.m_condition.c_str()); 840 result.SetStatus (eReturnStatusSuccessFinishNoResult); 841 } 842 else 843 { 844 // Particular watchpoints selected; set condition on them. 845 std::vector<uint32_t> wp_ids; 846 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids)) 847 { 848 result.AppendError("Invalid watchpoints specification."); 849 result.SetStatus(eReturnStatusFailed); 850 return false; 851 } 852 853 int count = 0; 854 const size_t size = wp_ids.size(); 855 for (size_t i = 0; i < size; ++i) 856 { 857 WatchpointSP wp_sp = watchpoints.FindByID(wp_ids[i]); 858 if (wp_sp) 859 { 860 wp_sp->SetCondition(m_options.m_condition.c_str()); 861 ++count; 862 } 863 } 864 result.AppendMessageWithFormat("%d watchpoints modified.\n",count); 865 result.SetStatus (eReturnStatusSuccessFinishNoResult); 866 } 867 868 return result.Succeeded(); 869 } 870 871 private: 872 CommandOptions m_options; 873 }; 874 875 #pragma mark Modify::CommandOptions 876 877 OptionDefinition 878 CommandObjectWatchpointModify::CommandOptions::g_option_table[] = 879 { 880 { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The watchpoint stops only if this condition expression evaluates to true."}, 881 { 0, false, nullptr, 0 , 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } 882 }; 883 884 //------------------------------------------------------------------------- 885 // CommandObjectWatchpointSetVariable 886 //------------------------------------------------------------------------- 887 #pragma mark SetVariable 888 889 class CommandObjectWatchpointSetVariable : public CommandObjectParsed 890 { 891 public: 892 CommandObjectWatchpointSetVariable (CommandInterpreter &interpreter) : 893 CommandObjectParsed(interpreter, 894 "watchpoint set variable", 895 "Set a watchpoint on a variable. " 896 "Use the '-w' option to specify the type of watchpoint and " 897 "the '-s' option to specify the byte size to watch for. " 898 "If no '-w' option is specified, it defaults to write. " 899 "If no '-s' option is specified, it defaults to the variable's " 900 "byte size. " 901 "Note that there are limited hardware resources for watchpoints. " 902 "If watchpoint setting fails, consider disable/delete existing ones " 903 "to free up resources.", 904 nullptr, 905 eCommandRequiresFrame | 906 eCommandTryTargetAPILock | 907 eCommandProcessMustBeLaunched | 908 eCommandProcessMustBePaused ), 909 m_option_group (interpreter), 910 m_option_watchpoint () 911 { 912 SetHelpLong( 913 R"( 914 Examples: 915 916 (lldb) watchpoint set variable -w read_write my_global_var 917 918 )" " Watches my_global_var for read/write access, with the region to watch \ 919 corresponding to the byte size of the data type." 920 ); 921 922 CommandArgumentEntry arg; 923 CommandArgumentData var_name_arg; 924 925 // Define the only variant of this arg. 926 var_name_arg.arg_type = eArgTypeVarName; 927 var_name_arg.arg_repetition = eArgRepeatPlain; 928 929 // Push the variant into the argument entry. 930 arg.push_back (var_name_arg); 931 932 // Push the data for the only argument into the m_arguments vector. 933 m_arguments.push_back (arg); 934 935 // Absorb the '-w' and '-s' options into our option group. 936 m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 937 m_option_group.Finalize(); 938 } 939 940 ~CommandObjectWatchpointSetVariable() override = default; 941 942 Options * 943 GetOptions () override 944 { 945 return &m_option_group; 946 } 947 948 protected: 949 static size_t GetVariableCallback (void *baton, 950 const char *name, 951 VariableList &variable_list) 952 { 953 Target *target = static_cast<Target *>(baton); 954 if (target) 955 { 956 return target->GetImages().FindGlobalVariables (ConstString(name), 957 true, 958 UINT32_MAX, 959 variable_list); 960 } 961 return 0; 962 } 963 964 bool 965 DoExecute (Args& command, CommandReturnObject &result) override 966 { 967 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 968 StackFrame *frame = m_exe_ctx.GetFramePtr(); 969 970 // If no argument is present, issue an error message. There's no way to set a watchpoint. 971 if (command.GetArgumentCount() <= 0) 972 { 973 result.GetErrorStream().Printf("error: required argument missing; specify your program variable to watch for\n"); 974 result.SetStatus(eReturnStatusFailed); 975 return false; 976 } 977 978 // If no '-w' is specified, default to '-w write'. 979 if (!m_option_watchpoint.watch_type_specified) 980 { 981 m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite; 982 } 983 984 // We passed the sanity check for the command. 985 // Proceed to set the watchpoint now. 986 lldb::addr_t addr = 0; 987 size_t size = 0; 988 989 VariableSP var_sp; 990 ValueObjectSP valobj_sp; 991 Stream &output_stream = result.GetOutputStream(); 992 993 // A simple watch variable gesture allows only one argument. 994 if (command.GetArgumentCount() != 1) 995 { 996 result.GetErrorStream().Printf("error: specify exactly one variable to watch for\n"); 997 result.SetStatus(eReturnStatusFailed); 998 return false; 999 } 1000 1001 // Things have checked out ok... 1002 Error error; 1003 uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember | 1004 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; 1005 valobj_sp = frame->GetValueForVariableExpressionPath (command.GetArgumentAtIndex(0), 1006 eNoDynamicValues, 1007 expr_path_options, 1008 var_sp, 1009 error); 1010 1011 if (!valobj_sp) 1012 { 1013 // Not in the frame; let's check the globals. 1014 1015 VariableList variable_list; 1016 ValueObjectList valobj_list; 1017 1018 Error error (Variable::GetValuesForVariableExpressionPath (command.GetArgumentAtIndex(0), 1019 m_exe_ctx.GetBestExecutionContextScope(), 1020 GetVariableCallback, 1021 target, 1022 variable_list, 1023 valobj_list)); 1024 1025 if (valobj_list.GetSize()) 1026 valobj_sp = valobj_list.GetValueObjectAtIndex(0); 1027 } 1028 1029 CompilerType compiler_type; 1030 1031 if (valobj_sp) 1032 { 1033 AddressType addr_type; 1034 addr = valobj_sp->GetAddressOf(false, &addr_type); 1035 if (addr_type == eAddressTypeLoad) 1036 { 1037 // We're in business. 1038 // Find out the size of this variable. 1039 size = m_option_watchpoint.watch_size == 0 ? valobj_sp->GetByteSize() 1040 : m_option_watchpoint.watch_size; 1041 } 1042 compiler_type = valobj_sp->GetCompilerType(); 1043 } 1044 else 1045 { 1046 const char *error_cstr = error.AsCString(nullptr); 1047 if (error_cstr) 1048 result.GetErrorStream().Printf("error: %s\n", error_cstr); 1049 else 1050 result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", 1051 command.GetArgumentAtIndex(0)); 1052 return false; 1053 } 1054 1055 // Now it's time to create the watchpoint. 1056 uint32_t watch_type = m_option_watchpoint.watch_type; 1057 1058 error.Clear(); 1059 Watchpoint *wp = target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error).get(); 1060 if (wp) 1061 { 1062 wp->SetWatchSpec(command.GetArgumentAtIndex(0)); 1063 wp->SetWatchVariable(true); 1064 if (var_sp && var_sp->GetDeclaration().GetFile()) 1065 { 1066 StreamString ss; 1067 // True to show fullpath for declaration file. 1068 var_sp->GetDeclaration().DumpStopContext(&ss, true); 1069 wp->SetDeclInfo(ss.GetString()); 1070 } 1071 output_stream.Printf("Watchpoint created: "); 1072 wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull); 1073 output_stream.EOL(); 1074 result.SetStatus(eReturnStatusSuccessFinishResult); 1075 } 1076 else 1077 { 1078 result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64 ", variable expression='%s').\n", 1079 addr, (uint64_t)size, command.GetArgumentAtIndex(0)); 1080 if (error.AsCString(nullptr)) 1081 result.AppendError(error.AsCString()); 1082 result.SetStatus(eReturnStatusFailed); 1083 } 1084 1085 return result.Succeeded(); 1086 } 1087 1088 private: 1089 OptionGroupOptions m_option_group; 1090 OptionGroupWatchpoint m_option_watchpoint; 1091 }; 1092 1093 //------------------------------------------------------------------------- 1094 // CommandObjectWatchpointSetExpression 1095 //------------------------------------------------------------------------- 1096 #pragma mark Set 1097 1098 class CommandObjectWatchpointSetExpression : public CommandObjectRaw 1099 { 1100 public: 1101 CommandObjectWatchpointSetExpression (CommandInterpreter &interpreter) : 1102 CommandObjectRaw(interpreter, 1103 "watchpoint set expression", 1104 "Set a watchpoint on an address by supplying an expression. " 1105 "Use the '-w' option to specify the type of watchpoint and " 1106 "the '-s' option to specify the byte size to watch for. " 1107 "If no '-w' option is specified, it defaults to write. " 1108 "If no '-s' option is specified, it defaults to the target's " 1109 "pointer byte size. " 1110 "Note that there are limited hardware resources for watchpoints. " 1111 "If watchpoint setting fails, consider disable/delete existing ones " 1112 "to free up resources.", 1113 nullptr, 1114 eCommandRequiresFrame | 1115 eCommandTryTargetAPILock | 1116 eCommandProcessMustBeLaunched | 1117 eCommandProcessMustBePaused ), 1118 m_option_group (interpreter), 1119 m_option_watchpoint () 1120 { 1121 SetHelpLong( 1122 R"( 1123 Examples: 1124 1125 (lldb) watchpoint set expression -w write -s 1 -- foo + 32 1126 1127 Watches write access for the 1-byte region pointed to by the address 'foo + 32')" 1128 ); 1129 1130 CommandArgumentEntry arg; 1131 CommandArgumentData expression_arg; 1132 1133 // Define the only variant of this arg. 1134 expression_arg.arg_type = eArgTypeExpression; 1135 expression_arg.arg_repetition = eArgRepeatPlain; 1136 1137 // Push the only variant into the argument entry. 1138 arg.push_back (expression_arg); 1139 1140 // Push the data for the only argument into the m_arguments vector. 1141 m_arguments.push_back (arg); 1142 1143 // Absorb the '-w' and '-s' options into our option group. 1144 m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 1145 m_option_group.Finalize(); 1146 } 1147 1148 ~CommandObjectWatchpointSetExpression() override = default; 1149 1150 // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString. 1151 bool 1152 WantsCompletion() override { return true; } 1153 1154 Options * 1155 GetOptions () override 1156 { 1157 return &m_option_group; 1158 } 1159 1160 protected: 1161 bool 1162 DoExecute (const char *raw_command, CommandReturnObject &result) override 1163 { 1164 m_option_group.NotifyOptionParsingStarting(); // This is a raw command, so notify the option group 1165 1166 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 1167 StackFrame *frame = m_exe_ctx.GetFramePtr(); 1168 1169 Args command(raw_command); 1170 const char *expr = nullptr; 1171 if (raw_command[0] == '-') 1172 { 1173 // We have some options and these options MUST end with --. 1174 const char *end_options = nullptr; 1175 const char *s = raw_command; 1176 while (s && s[0]) 1177 { 1178 end_options = ::strstr (s, "--"); 1179 if (end_options) 1180 { 1181 end_options += 2; // Get past the "--" 1182 if (::isspace (end_options[0])) 1183 { 1184 expr = end_options; 1185 while (::isspace (*expr)) 1186 ++expr; 1187 break; 1188 } 1189 } 1190 s = end_options; 1191 } 1192 1193 if (end_options) 1194 { 1195 Args args (llvm::StringRef(raw_command, end_options - raw_command)); 1196 if (!ParseOptions (args, result)) 1197 return false; 1198 1199 Error error (m_option_group.NotifyOptionParsingFinished()); 1200 if (error.Fail()) 1201 { 1202 result.AppendError (error.AsCString()); 1203 result.SetStatus (eReturnStatusFailed); 1204 return false; 1205 } 1206 } 1207 } 1208 1209 if (expr == nullptr) 1210 expr = raw_command; 1211 1212 // If no argument is present, issue an error message. There's no way to set a watchpoint. 1213 if (command.GetArgumentCount() == 0) 1214 { 1215 result.GetErrorStream().Printf("error: required argument missing; specify an expression to evaulate into the address to watch for\n"); 1216 result.SetStatus(eReturnStatusFailed); 1217 return false; 1218 } 1219 1220 // If no '-w' is specified, default to '-w write'. 1221 if (!m_option_watchpoint.watch_type_specified) 1222 { 1223 m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite; 1224 } 1225 1226 // We passed the sanity check for the command. 1227 // Proceed to set the watchpoint now. 1228 lldb::addr_t addr = 0; 1229 size_t size = 0; 1230 1231 ValueObjectSP valobj_sp; 1232 1233 // Use expression evaluation to arrive at the address to watch. 1234 EvaluateExpressionOptions options; 1235 options.SetCoerceToId(false); 1236 options.SetUnwindOnError(true); 1237 options.SetKeepInMemory(false); 1238 options.SetTryAllThreads(true); 1239 options.SetTimeoutUsec(0); 1240 1241 ExpressionResults expr_result = target->EvaluateExpression (expr, 1242 frame, 1243 valobj_sp, 1244 options); 1245 if (expr_result != eExpressionCompleted) 1246 { 1247 result.GetErrorStream().Printf("error: expression evaluation of address to watch failed\n"); 1248 result.GetErrorStream().Printf("expression evaluated: %s\n", expr); 1249 result.SetStatus(eReturnStatusFailed); 1250 return false; 1251 } 1252 1253 // Get the address to watch. 1254 bool success = false; 1255 addr = valobj_sp->GetValueAsUnsigned(0, &success); 1256 if (!success) 1257 { 1258 result.GetErrorStream().Printf("error: expression did not evaluate to an address\n"); 1259 result.SetStatus(eReturnStatusFailed); 1260 return false; 1261 } 1262 1263 if (m_option_watchpoint.watch_size != 0) 1264 size = m_option_watchpoint.watch_size; 1265 else 1266 size = target->GetArchitecture().GetAddressByteSize(); 1267 1268 // Now it's time to create the watchpoint. 1269 uint32_t watch_type = m_option_watchpoint.watch_type; 1270 1271 // Fetch the type from the value object, the type of the watched object is the pointee type 1272 /// of the expression, so convert to that if we found a valid type. 1273 CompilerType compiler_type(valobj_sp->GetCompilerType()); 1274 1275 Error error; 1276 Watchpoint *wp = target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error).get(); 1277 if (wp) 1278 { 1279 Stream &output_stream = result.GetOutputStream(); 1280 output_stream.Printf("Watchpoint created: "); 1281 wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull); 1282 output_stream.EOL(); 1283 result.SetStatus(eReturnStatusSuccessFinishResult); 1284 } 1285 else 1286 { 1287 result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64 ").\n", 1288 addr, (uint64_t)size); 1289 if (error.AsCString(nullptr)) 1290 result.AppendError(error.AsCString()); 1291 result.SetStatus(eReturnStatusFailed); 1292 } 1293 1294 return result.Succeeded(); 1295 } 1296 1297 private: 1298 OptionGroupOptions m_option_group; 1299 OptionGroupWatchpoint m_option_watchpoint; 1300 }; 1301 1302 //------------------------------------------------------------------------- 1303 // CommandObjectWatchpointSet 1304 //------------------------------------------------------------------------- 1305 #pragma mark Set 1306 1307 class CommandObjectWatchpointSet : public CommandObjectMultiword 1308 { 1309 public: 1310 CommandObjectWatchpointSet (CommandInterpreter &interpreter) : 1311 CommandObjectMultiword (interpreter, 1312 "watchpoint set", 1313 "A set of commands for setting a watchpoint.", 1314 "watchpoint set <subcommand> [<subcommand-options>]") 1315 { 1316 1317 LoadSubCommand ("variable", CommandObjectSP (new CommandObjectWatchpointSetVariable (interpreter))); 1318 LoadSubCommand ("expression", CommandObjectSP (new CommandObjectWatchpointSetExpression (interpreter))); 1319 } 1320 1321 ~CommandObjectWatchpointSet() override = default; 1322 }; 1323 1324 //------------------------------------------------------------------------- 1325 // CommandObjectMultiwordWatchpoint 1326 //------------------------------------------------------------------------- 1327 #pragma mark MultiwordWatchpoint 1328 1329 CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(CommandInterpreter &interpreter) : 1330 CommandObjectMultiword (interpreter, 1331 "watchpoint", 1332 "A set of commands for operating on watchpoints.", 1333 "watchpoint <command> [<command-options>]") 1334 { 1335 CommandObjectSP list_command_object (new CommandObjectWatchpointList (interpreter)); 1336 CommandObjectSP enable_command_object (new CommandObjectWatchpointEnable (interpreter)); 1337 CommandObjectSP disable_command_object (new CommandObjectWatchpointDisable (interpreter)); 1338 CommandObjectSP delete_command_object (new CommandObjectWatchpointDelete (interpreter)); 1339 CommandObjectSP ignore_command_object (new CommandObjectWatchpointIgnore (interpreter)); 1340 CommandObjectSP command_command_object (new CommandObjectWatchpointCommand (interpreter)); 1341 CommandObjectSP modify_command_object (new CommandObjectWatchpointModify (interpreter)); 1342 CommandObjectSP set_command_object (new CommandObjectWatchpointSet (interpreter)); 1343 1344 list_command_object->SetCommandName ("watchpoint list"); 1345 enable_command_object->SetCommandName("watchpoint enable"); 1346 disable_command_object->SetCommandName("watchpoint disable"); 1347 delete_command_object->SetCommandName("watchpoint delete"); 1348 ignore_command_object->SetCommandName("watchpoint ignore"); 1349 command_command_object->SetCommandName ("watchpoint command"); 1350 modify_command_object->SetCommandName("watchpoint modify"); 1351 set_command_object->SetCommandName("watchpoint set"); 1352 1353 LoadSubCommand ("list", list_command_object); 1354 LoadSubCommand ("enable", enable_command_object); 1355 LoadSubCommand ("disable", disable_command_object); 1356 LoadSubCommand ("delete", delete_command_object); 1357 LoadSubCommand ("ignore", ignore_command_object); 1358 LoadSubCommand ("command", command_command_object); 1359 LoadSubCommand ("modify", modify_command_object); 1360 LoadSubCommand ("set", set_command_object); 1361 } 1362 1363 CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() = default; 1364