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