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