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