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