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