brintos

brintos / llvm-project-archived public Read only

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