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