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