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