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