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