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 uint32_t num_supported_hardware_watchpoints; 213 Status error = target->GetProcessSP()->GetWatchpointSupportInfo( 214 num_supported_hardware_watchpoints); 215 if (error.Success()) 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 Watchpoint *wp = watchpoints.GetByIndex(i).get(); 241 AddWatchpointDescription(&output_stream, wp, 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 Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get(); 256 if (wp) 257 AddWatchpointDescription(&output_stream, wp, 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 wp_sp = target->GetLastCreatedWatchpoint(); 762 wp_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 wp_sp = watchpoints.FindByID(wp_ids[i]); 777 if (wp_sp) { 778 wp_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_ALL, 839 LLDB_OPT_SET_1); 840 m_option_group.Finalize(); 841 } 842 843 ~CommandObjectWatchpointSetVariable() override = default; 844 845 void 846 HandleArgumentCompletion(CompletionRequest &request, 847 OptionElementVector &opt_element_vector) override { 848 if (request.GetCursorIndex() != 0) 849 return; 850 CommandCompletions::InvokeCommonCompletionCallbacks( 851 GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 852 request, nullptr); 853 } 854 855 Options *GetOptions() override { return &m_option_group; } 856 857 protected: 858 static size_t GetVariableCallback(void *baton, const char *name, 859 VariableList &variable_list) { 860 size_t old_size = variable_list.GetSize(); 861 Target *target = static_cast<Target *>(baton); 862 if (target) 863 target->GetImages().FindGlobalVariables(ConstString(name), UINT32_MAX, 864 variable_list); 865 return variable_list.GetSize() - old_size; 866 } 867 868 bool DoExecute(Args &command, CommandReturnObject &result) override { 869 Target *target = GetDebugger().GetSelectedTarget().get(); 870 StackFrame *frame = m_exe_ctx.GetFramePtr(); 871 872 // If no argument is present, issue an error message. There's no way to 873 // set a watchpoint. 874 if (command.GetArgumentCount() <= 0) { 875 result.AppendError("required argument missing; " 876 "specify your program variable to watch for"); 877 return false; 878 } 879 880 // If no '-w' is specified, default to '-w write'. 881 if (!m_option_watchpoint.watch_type_specified) { 882 m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite; 883 } 884 885 // We passed the sanity check for the command. Proceed to set the 886 // watchpoint now. 887 lldb::addr_t addr = 0; 888 size_t size = 0; 889 890 VariableSP var_sp; 891 ValueObjectSP valobj_sp; 892 Stream &output_stream = result.GetOutputStream(); 893 894 // A simple watch variable gesture allows only one argument. 895 if (command.GetArgumentCount() != 1) { 896 result.AppendError("specify exactly one variable to watch for"); 897 return false; 898 } 899 900 // Things have checked out ok... 901 Status error; 902 uint32_t expr_path_options = 903 StackFrame::eExpressionPathOptionCheckPtrVsMember | 904 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; 905 valobj_sp = frame->GetValueForVariableExpressionPath( 906 command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options, 907 var_sp, error); 908 909 if (!valobj_sp) { 910 // Not in the frame; let's check the globals. 911 912 VariableList variable_list; 913 ValueObjectList valobj_list; 914 915 Status error(Variable::GetValuesForVariableExpressionPath( 916 command.GetArgumentAtIndex(0), 917 m_exe_ctx.GetBestExecutionContextScope(), GetVariableCallback, target, 918 variable_list, valobj_list)); 919 920 if (valobj_list.GetSize()) 921 valobj_sp = valobj_list.GetValueObjectAtIndex(0); 922 } 923 924 CompilerType compiler_type; 925 926 if (valobj_sp) { 927 AddressType addr_type; 928 addr = valobj_sp->GetAddressOf(false, &addr_type); 929 if (addr_type == eAddressTypeLoad) { 930 // We're in business. 931 // Find out the size of this variable. 932 size = m_option_watchpoint.watch_size == 0 933 ? valobj_sp->GetByteSize().value_or(0) 934 : m_option_watchpoint.watch_size; 935 } 936 compiler_type = valobj_sp->GetCompilerType(); 937 } else { 938 const char *error_cstr = error.AsCString(nullptr); 939 if (error_cstr) 940 result.AppendError(error_cstr); 941 else 942 result.AppendErrorWithFormat("unable to find any variable " 943 "expression path that matches '%s'", 944 command.GetArgumentAtIndex(0)); 945 return false; 946 } 947 948 // Now it's time to create the watchpoint. 949 uint32_t watch_type = m_option_watchpoint.watch_type; 950 951 error.Clear(); 952 Watchpoint *wp = 953 target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error) 954 .get(); 955 if (wp) { 956 wp->SetWatchSpec(command.GetArgumentAtIndex(0)); 957 wp->SetWatchVariable(true); 958 if (var_sp && var_sp->GetDeclaration().GetFile()) { 959 StreamString ss; 960 // True to show fullpath for declaration file. 961 var_sp->GetDeclaration().DumpStopContext(&ss, true); 962 wp->SetDeclInfo(std::string(ss.GetString())); 963 } 964 output_stream.Printf("Watchpoint created: "); 965 wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull); 966 output_stream.EOL(); 967 result.SetStatus(eReturnStatusSuccessFinishResult); 968 } else { 969 result.AppendErrorWithFormat( 970 "Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64 971 ", variable expression='%s').\n", 972 addr, (uint64_t)size, command.GetArgumentAtIndex(0)); 973 if (error.AsCString(nullptr)) 974 result.AppendError(error.AsCString()); 975 } 976 977 return result.Succeeded(); 978 } 979 980 private: 981 OptionGroupOptions m_option_group; 982 OptionGroupWatchpoint m_option_watchpoint; 983 }; 984 985 // CommandObjectWatchpointSetExpression 986 #pragma mark Set 987 988 class CommandObjectWatchpointSetExpression : public CommandObjectRaw { 989 public: 990 CommandObjectWatchpointSetExpression(CommandInterpreter &interpreter) 991 : CommandObjectRaw( 992 interpreter, "watchpoint set expression", 993 "Set a watchpoint on an address by supplying an expression. " 994 "Use the '-w' option to specify the type of watchpoint and " 995 "the '-s' option to specify the byte size to watch for. " 996 "If no '-w' option is specified, it defaults to write. " 997 "If no '-s' option is specified, it defaults to the target's " 998 "pointer byte size. " 999 "Note that there are limited hardware resources for watchpoints. " 1000 "If watchpoint setting fails, consider disable/delete existing " 1001 "ones " 1002 "to free up resources.", 1003 "", 1004 eCommandRequiresFrame | eCommandTryTargetAPILock | 1005 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { 1006 SetHelpLong( 1007 R"( 1008 Examples: 1009 1010 (lldb) watchpoint set expression -w write -s 1 -- foo + 32 1011 1012 Watches write access for the 1-byte region pointed to by the address 'foo + 32')"); 1013 1014 CommandArgumentEntry arg; 1015 CommandArgumentData expression_arg; 1016 1017 // Define the only variant of this arg. 1018 expression_arg.arg_type = eArgTypeExpression; 1019 expression_arg.arg_repetition = eArgRepeatPlain; 1020 1021 // Push the only variant into the argument entry. 1022 arg.push_back(expression_arg); 1023 1024 // Push the data for the only argument into the m_arguments vector. 1025 m_arguments.push_back(arg); 1026 1027 // Absorb the '-w' and '-s' options into our option group. 1028 m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL, 1029 LLDB_OPT_SET_1); 1030 m_option_group.Finalize(); 1031 } 1032 1033 ~CommandObjectWatchpointSetExpression() override = default; 1034 1035 // Overrides base class's behavior where WantsCompletion = 1036 // !WantsRawCommandString. 1037 bool WantsCompletion() override { return true; } 1038 1039 Options *GetOptions() override { return &m_option_group; } 1040 1041 protected: 1042 bool DoExecute(llvm::StringRef raw_command, 1043 CommandReturnObject &result) override { 1044 auto exe_ctx = GetCommandInterpreter().GetExecutionContext(); 1045 m_option_group.NotifyOptionParsingStarting( 1046 &exe_ctx); // This is a raw command, so notify the option group 1047 1048 Target *target = GetDebugger().GetSelectedTarget().get(); 1049 StackFrame *frame = m_exe_ctx.GetFramePtr(); 1050 1051 OptionsWithRaw args(raw_command); 1052 1053 llvm::StringRef expr = args.GetRawPart(); 1054 1055 if (args.HasArgs()) 1056 if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, 1057 exe_ctx)) 1058 return false; 1059 1060 // If no argument is present, issue an error message. There's no way to 1061 // set a watchpoint. 1062 if (raw_command.trim().empty()) { 1063 result.AppendError("required argument missing; specify an expression " 1064 "to evaluate into the address to watch for"); 1065 return false; 1066 } 1067 1068 // If no '-w' is specified, default to '-w write'. 1069 if (!m_option_watchpoint.watch_type_specified) { 1070 m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite; 1071 } 1072 1073 // We passed the sanity check for the command. Proceed to set the 1074 // watchpoint now. 1075 lldb::addr_t addr = 0; 1076 size_t size = 0; 1077 1078 ValueObjectSP valobj_sp; 1079 1080 // Use expression evaluation to arrive at the address to watch. 1081 EvaluateExpressionOptions options; 1082 options.SetCoerceToId(false); 1083 options.SetUnwindOnError(true); 1084 options.SetKeepInMemory(false); 1085 options.SetTryAllThreads(true); 1086 options.SetTimeout(std::nullopt); 1087 1088 ExpressionResults expr_result = 1089 target->EvaluateExpression(expr, frame, valobj_sp, options); 1090 if (expr_result != eExpressionCompleted) { 1091 result.AppendError("expression evaluation of address to watch failed"); 1092 result.AppendErrorWithFormat("expression evaluated: \n%s", expr.data()); 1093 if (valobj_sp && !valobj_sp->GetError().Success()) 1094 result.AppendError(valobj_sp->GetError().AsCString()); 1095 return false; 1096 } 1097 1098 // Get the address to watch. 1099 bool success = false; 1100 addr = valobj_sp->GetValueAsUnsigned(0, &success); 1101 if (!success) { 1102 result.AppendError("expression did not evaluate to an address"); 1103 return false; 1104 } 1105 1106 if (m_option_watchpoint.watch_size != 0) 1107 size = m_option_watchpoint.watch_size; 1108 else 1109 size = target->GetArchitecture().GetAddressByteSize(); 1110 1111 // Now it's time to create the watchpoint. 1112 uint32_t watch_type = m_option_watchpoint.watch_type; 1113 1114 // Fetch the type from the value object, the type of the watched object is 1115 // the pointee type 1116 /// of the expression, so convert to that if we found a valid type. 1117 CompilerType compiler_type(valobj_sp->GetCompilerType()); 1118 1119 Status error; 1120 Watchpoint *wp = 1121 target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error) 1122 .get(); 1123 if (wp) { 1124 Stream &output_stream = result.GetOutputStream(); 1125 output_stream.Printf("Watchpoint created: "); 1126 wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull); 1127 output_stream.EOL(); 1128 result.SetStatus(eReturnStatusSuccessFinishResult); 1129 } else { 1130 result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 1131 ", size=%" PRIu64 ").\n", 1132 addr, (uint64_t)size); 1133 if (error.AsCString(nullptr)) 1134 result.AppendError(error.AsCString()); 1135 } 1136 1137 return result.Succeeded(); 1138 } 1139 1140 private: 1141 OptionGroupOptions m_option_group; 1142 OptionGroupWatchpoint m_option_watchpoint; 1143 }; 1144 1145 // CommandObjectWatchpointSet 1146 #pragma mark Set 1147 1148 class CommandObjectWatchpointSet : public CommandObjectMultiword { 1149 public: 1150 CommandObjectWatchpointSet(CommandInterpreter &interpreter) 1151 : CommandObjectMultiword( 1152 interpreter, "watchpoint set", "Commands for setting a watchpoint.", 1153 "watchpoint set <subcommand> [<subcommand-options>]") { 1154 1155 LoadSubCommand( 1156 "variable", 1157 CommandObjectSP(new CommandObjectWatchpointSetVariable(interpreter))); 1158 LoadSubCommand( 1159 "expression", 1160 CommandObjectSP(new CommandObjectWatchpointSetExpression(interpreter))); 1161 } 1162 1163 ~CommandObjectWatchpointSet() override = default; 1164 }; 1165 1166 // CommandObjectMultiwordWatchpoint 1167 #pragma mark MultiwordWatchpoint 1168 1169 CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint( 1170 CommandInterpreter &interpreter) 1171 : CommandObjectMultiword(interpreter, "watchpoint", 1172 "Commands for operating on watchpoints.", 1173 "watchpoint <subcommand> [<command-options>]") { 1174 CommandObjectSP list_command_object( 1175 new CommandObjectWatchpointList(interpreter)); 1176 CommandObjectSP enable_command_object( 1177 new CommandObjectWatchpointEnable(interpreter)); 1178 CommandObjectSP disable_command_object( 1179 new CommandObjectWatchpointDisable(interpreter)); 1180 CommandObjectSP delete_command_object( 1181 new CommandObjectWatchpointDelete(interpreter)); 1182 CommandObjectSP ignore_command_object( 1183 new CommandObjectWatchpointIgnore(interpreter)); 1184 CommandObjectSP command_command_object( 1185 new CommandObjectWatchpointCommand(interpreter)); 1186 CommandObjectSP modify_command_object( 1187 new CommandObjectWatchpointModify(interpreter)); 1188 CommandObjectSP set_command_object( 1189 new CommandObjectWatchpointSet(interpreter)); 1190 1191 list_command_object->SetCommandName("watchpoint list"); 1192 enable_command_object->SetCommandName("watchpoint enable"); 1193 disable_command_object->SetCommandName("watchpoint disable"); 1194 delete_command_object->SetCommandName("watchpoint delete"); 1195 ignore_command_object->SetCommandName("watchpoint ignore"); 1196 command_command_object->SetCommandName("watchpoint command"); 1197 modify_command_object->SetCommandName("watchpoint modify"); 1198 set_command_object->SetCommandName("watchpoint set"); 1199 1200 LoadSubCommand("list", list_command_object); 1201 LoadSubCommand("enable", enable_command_object); 1202 LoadSubCommand("disable", disable_command_object); 1203 LoadSubCommand("delete", delete_command_object); 1204 LoadSubCommand("ignore", ignore_command_object); 1205 LoadSubCommand("command", command_command_object); 1206 LoadSubCommand("modify", modify_command_object); 1207 LoadSubCommand("set", set_command_object); 1208 } 1209 1210 CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() = default; 1211