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