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