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