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