diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp')
| -rw-r--r-- | contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp | 1215 | 
1 files changed, 1215 insertions, 0 deletions
| diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp new file mode 100644 index 000000000000..9fbf036a19d1 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -0,0 +1,1215 @@ +//===-- CommandObjectWatchpoint.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectWatchpoint.h" +#include "CommandObjectWatchpointCommand.h" + +#include <vector> + +#include "llvm/ADT/StringRef.h" + +#include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Breakpoint/WatchpointList.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +static void AddWatchpointDescription(Stream *s, Watchpoint *wp, +                                     lldb::DescriptionLevel level) { +  s->IndentMore(); +  wp->GetDescription(s, level); +  s->IndentLess(); +  s->EOL(); +} + +static bool CheckTargetForWatchpointOperations(Target *target, +                                               CommandReturnObject &result) { +  bool process_is_valid = +      target->GetProcessSP() && target->GetProcessSP()->IsAlive(); +  if (!process_is_valid) { +    result.AppendError("There's no process or it is not alive."); +    return false; +  } +  // Target passes our checks, return true. +  return true; +} + +// Equivalent class: {"-", "to", "To", "TO"} of range specifier array. +static const char *RSA[4] = {"-", "to", "To", "TO"}; + +// Return the index to RSA if found; otherwise -1 is returned. +static int32_t WithRSAIndex(llvm::StringRef Arg) { + +  uint32_t i; +  for (i = 0; i < 4; ++i) +    if (Arg.contains(RSA[i])) +      return i; +  return -1; +} + +// Return true if wp_ids is successfully populated with the watch ids. False +// otherwise. +bool CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( +    Target *target, Args &args, std::vector<uint32_t> &wp_ids) { +  // Pre-condition: args.GetArgumentCount() > 0. +  if (args.GetArgumentCount() == 0) { +    if (target == nullptr) +      return false; +    WatchpointSP watch_sp = target->GetLastCreatedWatchpoint(); +    if (watch_sp) { +      wp_ids.push_back(watch_sp->GetID()); +      return true; +    } else +      return false; +  } + +  llvm::StringRef Minus("-"); +  std::vector<llvm::StringRef> StrRefArgs; +  llvm::StringRef first; +  llvm::StringRef second; +  size_t i; +  int32_t idx; +  // Go through the arguments and make a canonical form of arg list containing +  // only numbers with possible "-" in between. +  for (auto &entry : args.entries()) { +    if ((idx = WithRSAIndex(entry.ref())) == -1) { +      StrRefArgs.push_back(entry.ref()); +      continue; +    } +    // The Arg contains the range specifier, split it, then. +    std::tie(first, second) = entry.ref().split(RSA[idx]); +    if (!first.empty()) +      StrRefArgs.push_back(first); +    StrRefArgs.push_back(Minus); +    if (!second.empty()) +      StrRefArgs.push_back(second); +  } +  // Now process the canonical list and fill in the vector of uint32_t's. If +  // there is any error, return false and the client should ignore wp_ids. +  uint32_t beg, end, id; +  size_t size = StrRefArgs.size(); +  bool in_range = false; +  for (i = 0; i < size; ++i) { +    llvm::StringRef Arg = StrRefArgs[i]; +    if (in_range) { +      // Look for the 'end' of the range.  Note StringRef::getAsInteger() +      // returns true to signify error while parsing. +      if (Arg.getAsInteger(0, end)) +        return false; +      // Found a range!  Now append the elements. +      for (id = beg; id <= end; ++id) +        wp_ids.push_back(id); +      in_range = false; +      continue; +    } +    if (i < (size - 1) && StrRefArgs[i + 1] == Minus) { +      if (Arg.getAsInteger(0, beg)) +        return false; +      // Turn on the in_range flag, we are looking for end of range next. +      ++i; +      in_range = true; +      continue; +    } +    // Otherwise, we have a simple ID.  Just append it. +    if (Arg.getAsInteger(0, beg)) +      return false; +    wp_ids.push_back(beg); +  } + +  // It is an error if after the loop, we're still in_range. +  return !in_range; +} + +// CommandObjectWatchpointList + +// CommandObjectWatchpointList::Options +#pragma mark List::CommandOptions +#define LLDB_OPTIONS_watchpoint_list +#include "CommandOptions.inc" + +#pragma mark List + +class CommandObjectWatchpointList : public CommandObjectParsed { +public: +  CommandObjectWatchpointList(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "watchpoint list", +            "List all watchpoints at configurable levels of detail.", nullptr, +            eCommandRequiresTarget), +        m_options() { +    CommandArgumentEntry arg; +    CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, +                                      eArgTypeWatchpointIDRange); +    // Add the entry for the first argument for this command to the object's +    // arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectWatchpointList() override = default; + +  Options *GetOptions() override { return &m_options; } + +  class CommandOptions : public Options { +  public: +    CommandOptions() : Options() {} + +    ~CommandOptions() override = default; + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      Status error; +      const int short_option = m_getopt_table[option_idx].val; + +      switch (short_option) { +      case 'b': +        m_level = lldb::eDescriptionLevelBrief; +        break; +      case 'f': +        m_level = lldb::eDescriptionLevelFull; +        break; +      case 'v': +        m_level = lldb::eDescriptionLevelVerbose; +        break; +      default: +        llvm_unreachable("Unimplemented option"); +      } + +      return error; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_level = lldb::eDescriptionLevelFull; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_watchpoint_list_options); +    } + +    // Instance variables to hold the values for command options. + +    lldb::DescriptionLevel m_level = lldb::eDescriptionLevelBrief; +  }; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); + +    if (target->GetProcessSP() && target->GetProcessSP()->IsAlive()) { +      uint32_t num_supported_hardware_watchpoints; +      Status error = target->GetProcessSP()->GetWatchpointSupportInfo( +          num_supported_hardware_watchpoints); +      if (error.Success()) +        result.AppendMessageWithFormat( +            "Number of supported hardware watchpoints: %u\n", +            num_supported_hardware_watchpoints); +    } + +    const WatchpointList &watchpoints = target->GetWatchpointList(); + +    std::unique_lock<std::recursive_mutex> lock; +    target->GetWatchpointList().GetListMutex(lock); + +    size_t num_watchpoints = watchpoints.GetSize(); + +    if (num_watchpoints == 0) { +      result.AppendMessage("No watchpoints currently set."); +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +      return true; +    } + +    Stream &output_stream = result.GetOutputStream(); + +    if (command.GetArgumentCount() == 0) { +      // No watchpoint selected; show info about all currently set watchpoints. +      result.AppendMessage("Current watchpoints:"); +      for (size_t i = 0; i < num_watchpoints; ++i) { +        Watchpoint *wp = watchpoints.GetByIndex(i).get(); +        AddWatchpointDescription(&output_stream, wp, m_options.m_level); +      } +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    } else { +      // Particular watchpoints selected; enable them. +      std::vector<uint32_t> wp_ids; +      if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( +              target, command, wp_ids)) { +        result.AppendError("Invalid watchpoints specification."); +        return false; +      } + +      const size_t size = wp_ids.size(); +      for (size_t i = 0; i < size; ++i) { +        Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get(); +        if (wp) +          AddWatchpointDescription(&output_stream, wp, m_options.m_level); +        result.SetStatus(eReturnStatusSuccessFinishNoResult); +      } +    } + +    return result.Succeeded(); +  } + +private: +  CommandOptions m_options; +}; + +// CommandObjectWatchpointEnable +#pragma mark Enable + +class CommandObjectWatchpointEnable : public CommandObjectParsed { +public: +  CommandObjectWatchpointEnable(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "enable", +                            "Enable the specified disabled watchpoint(s). If " +                            "no watchpoints are specified, enable all of them.", +                            nullptr, eCommandRequiresTarget) { +    CommandArgumentEntry arg; +    CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, +                                      eArgTypeWatchpointIDRange); +    // Add the entry for the first argument for this command to the object's +    // arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectWatchpointEnable() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, +        request, nullptr); +  } + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    if (!CheckTargetForWatchpointOperations(target, result)) +      return false; + +    std::unique_lock<std::recursive_mutex> lock; +    target->GetWatchpointList().GetListMutex(lock); + +    const WatchpointList &watchpoints = target->GetWatchpointList(); + +    size_t num_watchpoints = watchpoints.GetSize(); + +    if (num_watchpoints == 0) { +      result.AppendError("No watchpoints exist to be enabled."); +      return false; +    } + +    if (command.GetArgumentCount() == 0) { +      // No watchpoint selected; enable all currently set watchpoints. +      target->EnableAllWatchpoints(); +      result.AppendMessageWithFormat("All watchpoints enabled. (%" PRIu64 +                                     " watchpoints)\n", +                                     (uint64_t)num_watchpoints); +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    } else { +      // Particular watchpoints selected; enable them. +      std::vector<uint32_t> wp_ids; +      if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( +              target, command, wp_ids)) { +        result.AppendError("Invalid watchpoints specification."); +        return false; +      } + +      int count = 0; +      const size_t size = wp_ids.size(); +      for (size_t i = 0; i < size; ++i) +        if (target->EnableWatchpointByID(wp_ids[i])) +          ++count; +      result.AppendMessageWithFormat("%d watchpoints enabled.\n", count); +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    } + +    return result.Succeeded(); +  } +}; + +// CommandObjectWatchpointDisable +#pragma mark Disable + +class CommandObjectWatchpointDisable : public CommandObjectParsed { +public: +  CommandObjectWatchpointDisable(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "watchpoint disable", +                            "Disable the specified watchpoint(s) without " +                            "removing it/them.  If no watchpoints are " +                            "specified, disable them all.", +                            nullptr, eCommandRequiresTarget) { +    CommandArgumentEntry arg; +    CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, +                                      eArgTypeWatchpointIDRange); +    // Add the entry for the first argument for this command to the object's +    // arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectWatchpointDisable() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, +        request, nullptr); +  } + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    if (!CheckTargetForWatchpointOperations(target, result)) +      return false; + +    std::unique_lock<std::recursive_mutex> lock; +    target->GetWatchpointList().GetListMutex(lock); + +    const WatchpointList &watchpoints = target->GetWatchpointList(); +    size_t num_watchpoints = watchpoints.GetSize(); + +    if (num_watchpoints == 0) { +      result.AppendError("No watchpoints exist to be disabled."); +      return false; +    } + +    if (command.GetArgumentCount() == 0) { +      // No watchpoint selected; disable all currently set watchpoints. +      if (target->DisableAllWatchpoints()) { +        result.AppendMessageWithFormat("All watchpoints disabled. (%" PRIu64 +                                       " watchpoints)\n", +                                       (uint64_t)num_watchpoints); +        result.SetStatus(eReturnStatusSuccessFinishNoResult); +      } else { +        result.AppendError("Disable all watchpoints failed\n"); +      } +    } else { +      // Particular watchpoints selected; disable them. +      std::vector<uint32_t> wp_ids; +      if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( +              target, command, wp_ids)) { +        result.AppendError("Invalid watchpoints specification."); +        return false; +      } + +      int count = 0; +      const size_t size = wp_ids.size(); +      for (size_t i = 0; i < size; ++i) +        if (target->DisableWatchpointByID(wp_ids[i])) +          ++count; +      result.AppendMessageWithFormat("%d watchpoints disabled.\n", count); +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    } + +    return result.Succeeded(); +  } +}; + +// CommandObjectWatchpointDelete +#define LLDB_OPTIONS_watchpoint_delete +#include "CommandOptions.inc" + +// CommandObjectWatchpointDelete +#pragma mark Delete + +class CommandObjectWatchpointDelete : public CommandObjectParsed { +public: +  CommandObjectWatchpointDelete(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "watchpoint delete", +                            "Delete the specified watchpoint(s).  If no " +                            "watchpoints are specified, delete them all.", +                            nullptr, eCommandRequiresTarget), +        m_options() { +    CommandArgumentEntry arg; +    CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, +                                      eArgTypeWatchpointIDRange); +    // Add the entry for the first argument for this command to the object's +    // arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectWatchpointDelete() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, +        request, nullptr); +  } + +  Options *GetOptions() override { return &m_options; } + +  class CommandOptions : public Options { +  public: +    CommandOptions() : Options() {} + +    ~CommandOptions() override = default; + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      const int short_option = m_getopt_table[option_idx].val; + +      switch (short_option) { +      case 'f': +        m_force = true; +        break; +      default: +        llvm_unreachable("Unimplemented option"); +      } + +      return {}; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_force = false; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_watchpoint_delete_options); +    } + +    // Instance variables to hold the values for command options. +    bool m_force = false; +  }; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    if (!CheckTargetForWatchpointOperations(target, result)) +      return false; + +    std::unique_lock<std::recursive_mutex> lock; +    target->GetWatchpointList().GetListMutex(lock); + +    const WatchpointList &watchpoints = target->GetWatchpointList(); + +    size_t num_watchpoints = watchpoints.GetSize(); + +    if (num_watchpoints == 0) { +      result.AppendError("No watchpoints exist to be deleted."); +      return false; +    } + +    if (command.empty()) { +      if (!m_options.m_force && +          !m_interpreter.Confirm( +              "About to delete all watchpoints, do you want to do that?", +              true)) { +        result.AppendMessage("Operation cancelled..."); +      } else { +        target->RemoveAllWatchpoints(); +        result.AppendMessageWithFormat("All watchpoints removed. (%" PRIu64 +                                       " watchpoints)\n", +                                       (uint64_t)num_watchpoints); +      } +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +      return result.Succeeded(); +    } + +    // Particular watchpoints selected; delete them. +    std::vector<uint32_t> wp_ids; +    if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, +                                                               wp_ids)) { +      result.AppendError("Invalid watchpoints specification."); +      return false; +    } + +    int count = 0; +    const size_t size = wp_ids.size(); +    for (size_t i = 0; i < size; ++i) +      if (target->RemoveWatchpointByID(wp_ids[i])) +        ++count; +    result.AppendMessageWithFormat("%d watchpoints deleted.\n", count); +    result.SetStatus(eReturnStatusSuccessFinishNoResult); + +    return result.Succeeded(); +  } + +private: +  CommandOptions m_options; +}; + +// CommandObjectWatchpointIgnore + +#pragma mark Ignore::CommandOptions +#define LLDB_OPTIONS_watchpoint_ignore +#include "CommandOptions.inc" + +class CommandObjectWatchpointIgnore : public CommandObjectParsed { +public: +  CommandObjectWatchpointIgnore(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "watchpoint ignore", +                            "Set ignore count on the specified watchpoint(s).  " +                            "If no watchpoints are specified, set them all.", +                            nullptr, eCommandRequiresTarget), +        m_options() { +    CommandArgumentEntry arg; +    CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, +                                      eArgTypeWatchpointIDRange); +    // Add the entry for the first argument for this command to the object's +    // arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectWatchpointIgnore() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, +        request, nullptr); +  } + +  Options *GetOptions() override { return &m_options; } + +  class CommandOptions : public Options { +  public: +    CommandOptions() : Options() {} + +    ~CommandOptions() override = default; + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      Status error; +      const int short_option = m_getopt_table[option_idx].val; + +      switch (short_option) { +      case 'i': +        if (option_arg.getAsInteger(0, m_ignore_count)) +          error.SetErrorStringWithFormat("invalid ignore count '%s'", +                                         option_arg.str().c_str()); +        break; +      default: +        llvm_unreachable("Unimplemented option"); +      } + +      return error; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_ignore_count = 0; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_watchpoint_ignore_options); +    } + +    // Instance variables to hold the values for command options. + +    uint32_t m_ignore_count = 0; +  }; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    if (!CheckTargetForWatchpointOperations(target, result)) +      return false; + +    std::unique_lock<std::recursive_mutex> lock; +    target->GetWatchpointList().GetListMutex(lock); + +    const WatchpointList &watchpoints = target->GetWatchpointList(); + +    size_t num_watchpoints = watchpoints.GetSize(); + +    if (num_watchpoints == 0) { +      result.AppendError("No watchpoints exist to be ignored."); +      return false; +    } + +    if (command.GetArgumentCount() == 0) { +      target->IgnoreAllWatchpoints(m_options.m_ignore_count); +      result.AppendMessageWithFormat("All watchpoints ignored. (%" PRIu64 +                                     " watchpoints)\n", +                                     (uint64_t)num_watchpoints); +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    } else { +      // Particular watchpoints selected; ignore them. +      std::vector<uint32_t> wp_ids; +      if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( +              target, command, wp_ids)) { +        result.AppendError("Invalid watchpoints specification."); +        return false; +      } + +      int count = 0; +      const size_t size = wp_ids.size(); +      for (size_t i = 0; i < size; ++i) +        if (target->IgnoreWatchpointByID(wp_ids[i], m_options.m_ignore_count)) +          ++count; +      result.AppendMessageWithFormat("%d watchpoints ignored.\n", count); +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    } + +    return result.Succeeded(); +  } + +private: +  CommandOptions m_options; +}; + +// CommandObjectWatchpointModify + +#pragma mark Modify::CommandOptions +#define LLDB_OPTIONS_watchpoint_modify +#include "CommandOptions.inc" + +#pragma mark Modify + +class CommandObjectWatchpointModify : public CommandObjectParsed { +public: +  CommandObjectWatchpointModify(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "watchpoint modify", +            "Modify the options on a watchpoint or set of watchpoints in the " +            "executable.  " +            "If no watchpoint is specified, act on the last created " +            "watchpoint.  " +            "Passing an empty argument clears the modification.", +            nullptr, eCommandRequiresTarget), +        m_options() { +    CommandArgumentEntry arg; +    CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, +                                      eArgTypeWatchpointIDRange); +    // Add the entry for the first argument for this command to the object's +    // arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectWatchpointModify() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, +        request, nullptr); +  } + +  Options *GetOptions() override { return &m_options; } + +  class CommandOptions : public Options { +  public: +    CommandOptions() : Options(), m_condition() {} + +    ~CommandOptions() override = default; + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      Status error; +      const int short_option = m_getopt_table[option_idx].val; + +      switch (short_option) { +      case 'c': +        m_condition = std::string(option_arg); +        m_condition_passed = true; +        break; +      default: +        llvm_unreachable("Unimplemented option"); +      } + +      return error; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_condition.clear(); +      m_condition_passed = false; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_watchpoint_modify_options); +    } + +    // Instance variables to hold the values for command options. + +    std::string m_condition; +    bool m_condition_passed = false; +  }; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    if (!CheckTargetForWatchpointOperations(target, result)) +      return false; + +    std::unique_lock<std::recursive_mutex> lock; +    target->GetWatchpointList().GetListMutex(lock); + +    const WatchpointList &watchpoints = target->GetWatchpointList(); + +    size_t num_watchpoints = watchpoints.GetSize(); + +    if (num_watchpoints == 0) { +      result.AppendError("No watchpoints exist to be modified."); +      return false; +    } + +    if (command.GetArgumentCount() == 0) { +      WatchpointSP wp_sp = target->GetLastCreatedWatchpoint(); +      wp_sp->SetCondition(m_options.m_condition.c_str()); +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    } else { +      // Particular watchpoints selected; set condition on them. +      std::vector<uint32_t> wp_ids; +      if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( +              target, command, wp_ids)) { +        result.AppendError("Invalid watchpoints specification."); +        return false; +      } + +      int count = 0; +      const size_t size = wp_ids.size(); +      for (size_t i = 0; i < size; ++i) { +        WatchpointSP wp_sp = watchpoints.FindByID(wp_ids[i]); +        if (wp_sp) { +          wp_sp->SetCondition(m_options.m_condition.c_str()); +          ++count; +        } +      } +      result.AppendMessageWithFormat("%d watchpoints modified.\n", count); +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    } + +    return result.Succeeded(); +  } + +private: +  CommandOptions m_options; +}; + +// CommandObjectWatchpointSetVariable +#pragma mark SetVariable + +class CommandObjectWatchpointSetVariable : public CommandObjectParsed { +public: +  CommandObjectWatchpointSetVariable(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "watchpoint set variable", +            "Set a watchpoint on a variable. " +            "Use the '-w' option to specify the type of watchpoint and " +            "the '-s' option to specify the byte size to watch for. " +            "If no '-w' option is specified, it defaults to write. " +            "If no '-s' option is specified, it defaults to the variable's " +            "byte size. " +            "Note that there are limited hardware resources for watchpoints. " +            "If watchpoint setting fails, consider disable/delete existing " +            "ones " +            "to free up resources.", +            nullptr, +            eCommandRequiresFrame | eCommandTryTargetAPILock | +                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), +        m_option_group(), m_option_watchpoint() { +    SetHelpLong( +        R"( +Examples: + +(lldb) watchpoint set variable -w read_write my_global_var + +)" +        "    Watches my_global_var for read/write access, with the region to watch \ +corresponding to the byte size of the data type."); + +    CommandArgumentEntry arg; +    CommandArgumentData var_name_arg; + +    // Define the only variant of this arg. +    var_name_arg.arg_type = eArgTypeVarName; +    var_name_arg.arg_repetition = eArgRepeatPlain; + +    // Push the variant into the argument entry. +    arg.push_back(var_name_arg); + +    // Push the data for the only argument into the m_arguments vector. +    m_arguments.push_back(arg); + +    // Absorb the '-w' and '-s' options into our option group. +    m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL, +                          LLDB_OPT_SET_1); +    m_option_group.Finalize(); +  } + +  ~CommandObjectWatchpointSetVariable() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    if (request.GetCursorIndex() != 0) +      return; +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, +        request, nullptr); +  } + +  Options *GetOptions() override { return &m_option_group; } + +protected: +  static size_t GetVariableCallback(void *baton, const char *name, +                                    VariableList &variable_list) { +    size_t old_size = variable_list.GetSize(); +    Target *target = static_cast<Target *>(baton); +    if (target) +      target->GetImages().FindGlobalVariables(ConstString(name), UINT32_MAX, +                                              variable_list); +    return variable_list.GetSize() - old_size; +  } + +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = GetDebugger().GetSelectedTarget().get(); +    StackFrame *frame = m_exe_ctx.GetFramePtr(); + +    // If no argument is present, issue an error message.  There's no way to +    // set a watchpoint. +    if (command.GetArgumentCount() <= 0) { +      result.AppendError("required argument missing; " +                         "specify your program variable to watch for"); +      return false; +    } + +    // If no '-w' is specified, default to '-w write'. +    if (!m_option_watchpoint.watch_type_specified) { +      m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite; +    } + +    // We passed the sanity check for the command. Proceed to set the +    // watchpoint now. +    lldb::addr_t addr = 0; +    size_t size = 0; + +    VariableSP var_sp; +    ValueObjectSP valobj_sp; +    Stream &output_stream = result.GetOutputStream(); + +    // A simple watch variable gesture allows only one argument. +    if (command.GetArgumentCount() != 1) { +      result.AppendError("specify exactly one variable to watch for"); +      return false; +    } + +    // Things have checked out ok... +    Status error; +    uint32_t expr_path_options = +        StackFrame::eExpressionPathOptionCheckPtrVsMember | +        StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; +    valobj_sp = frame->GetValueForVariableExpressionPath( +        command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options, +        var_sp, error); + +    if (!valobj_sp) { +      // Not in the frame; let's check the globals. + +      VariableList variable_list; +      ValueObjectList valobj_list; + +      Status error(Variable::GetValuesForVariableExpressionPath( +          command.GetArgumentAtIndex(0), +          m_exe_ctx.GetBestExecutionContextScope(), GetVariableCallback, target, +          variable_list, valobj_list)); + +      if (valobj_list.GetSize()) +        valobj_sp = valobj_list.GetValueObjectAtIndex(0); +    } + +    CompilerType compiler_type; + +    if (valobj_sp) { +      AddressType addr_type; +      addr = valobj_sp->GetAddressOf(false, &addr_type); +      if (addr_type == eAddressTypeLoad) { +        // We're in business. +        // Find out the size of this variable. +        size = m_option_watchpoint.watch_size == 0 +                   ? valobj_sp->GetByteSize().getValueOr(0) +                   : m_option_watchpoint.watch_size; +      } +      compiler_type = valobj_sp->GetCompilerType(); +    } else { +      const char *error_cstr = error.AsCString(nullptr); +      if (error_cstr) +        result.AppendError(error_cstr); +      else +        result.AppendErrorWithFormat("unable to find any variable " +                                     "expression path that matches '%s'", +                                     command.GetArgumentAtIndex(0)); +      return false; +    } + +    // Now it's time to create the watchpoint. +    uint32_t watch_type = m_option_watchpoint.watch_type; + +    error.Clear(); +    Watchpoint *wp = +        target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error) +            .get(); +    if (wp) { +      wp->SetWatchSpec(command.GetArgumentAtIndex(0)); +      wp->SetWatchVariable(true); +      if (var_sp && var_sp->GetDeclaration().GetFile()) { +        StreamString ss; +        // True to show fullpath for declaration file. +        var_sp->GetDeclaration().DumpStopContext(&ss, true); +        wp->SetDeclInfo(std::string(ss.GetString())); +      } +      output_stream.Printf("Watchpoint created: "); +      wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull); +      output_stream.EOL(); +      result.SetStatus(eReturnStatusSuccessFinishResult); +    } else { +      result.AppendErrorWithFormat( +          "Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64 +          ", variable expression='%s').\n", +          addr, (uint64_t)size, command.GetArgumentAtIndex(0)); +      if (error.AsCString(nullptr)) +        result.AppendError(error.AsCString()); +    } + +    return result.Succeeded(); +  } + +private: +  OptionGroupOptions m_option_group; +  OptionGroupWatchpoint m_option_watchpoint; +}; + +// CommandObjectWatchpointSetExpression +#pragma mark Set + +class CommandObjectWatchpointSetExpression : public CommandObjectRaw { +public: +  CommandObjectWatchpointSetExpression(CommandInterpreter &interpreter) +      : CommandObjectRaw( +            interpreter, "watchpoint set expression", +            "Set a watchpoint on an address by supplying an expression. " +            "Use the '-w' option to specify the type of watchpoint and " +            "the '-s' option to specify the byte size to watch for. " +            "If no '-w' option is specified, it defaults to write. " +            "If no '-s' option is specified, it defaults to the target's " +            "pointer byte size. " +            "Note that there are limited hardware resources for watchpoints. " +            "If watchpoint setting fails, consider disable/delete existing " +            "ones " +            "to free up resources.", +            "", +            eCommandRequiresFrame | eCommandTryTargetAPILock | +                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), +        m_option_group(), m_option_watchpoint() { +    SetHelpLong( +        R"( +Examples: + +(lldb) watchpoint set expression -w write -s 1 -- foo + 32 + +    Watches write access for the 1-byte region pointed to by the address 'foo + 32')"); + +    CommandArgumentEntry arg; +    CommandArgumentData expression_arg; + +    // Define the only variant of this arg. +    expression_arg.arg_type = eArgTypeExpression; +    expression_arg.arg_repetition = eArgRepeatPlain; + +    // Push the only variant into the argument entry. +    arg.push_back(expression_arg); + +    // Push the data for the only argument into the m_arguments vector. +    m_arguments.push_back(arg); + +    // Absorb the '-w' and '-s' options into our option group. +    m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL, +                          LLDB_OPT_SET_1); +    m_option_group.Finalize(); +  } + +  ~CommandObjectWatchpointSetExpression() override = default; + +  // Overrides base class's behavior where WantsCompletion = +  // !WantsRawCommandString. +  bool WantsCompletion() override { return true; } + +  Options *GetOptions() override { return &m_option_group; } + +protected: +  bool DoExecute(llvm::StringRef raw_command, +                 CommandReturnObject &result) override { +    auto exe_ctx = GetCommandInterpreter().GetExecutionContext(); +    m_option_group.NotifyOptionParsingStarting( +        &exe_ctx); // This is a raw command, so notify the option group + +    Target *target = GetDebugger().GetSelectedTarget().get(); +    StackFrame *frame = m_exe_ctx.GetFramePtr(); + +    OptionsWithRaw args(raw_command); + +    llvm::StringRef expr = args.GetRawPart(); + +    if (args.HasArgs()) +      if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, +                                 exe_ctx)) +        return false; + +    // If no argument is present, issue an error message.  There's no way to +    // set a watchpoint. +    if (raw_command.trim().empty()) { +      result.AppendError("required argument missing; specify an expression " +                         "to evaluate into the address to watch for"); +      return false; +    } + +    // If no '-w' is specified, default to '-w write'. +    if (!m_option_watchpoint.watch_type_specified) { +      m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite; +    } + +    // We passed the sanity check for the command. Proceed to set the +    // watchpoint now. +    lldb::addr_t addr = 0; +    size_t size = 0; + +    ValueObjectSP valobj_sp; + +    // Use expression evaluation to arrive at the address to watch. +    EvaluateExpressionOptions options; +    options.SetCoerceToId(false); +    options.SetUnwindOnError(true); +    options.SetKeepInMemory(false); +    options.SetTryAllThreads(true); +    options.SetTimeout(llvm::None); + +    ExpressionResults expr_result = +        target->EvaluateExpression(expr, frame, valobj_sp, options); +    if (expr_result != eExpressionCompleted) { +      result.AppendError("expression evaluation of address to watch failed"); +      result.AppendErrorWithFormat("expression evaluated: \n%s", expr.data()); +      if (valobj_sp && !valobj_sp->GetError().Success()) +        result.AppendError(valobj_sp->GetError().AsCString()); +      return false; +    } + +    // Get the address to watch. +    bool success = false; +    addr = valobj_sp->GetValueAsUnsigned(0, &success); +    if (!success) { +      result.AppendError("expression did not evaluate to an address"); +      return false; +    } + +    if (m_option_watchpoint.watch_size != 0) +      size = m_option_watchpoint.watch_size; +    else +      size = target->GetArchitecture().GetAddressByteSize(); + +    // Now it's time to create the watchpoint. +    uint32_t watch_type = m_option_watchpoint.watch_type; + +    // Fetch the type from the value object, the type of the watched object is +    // the pointee type +    /// of the expression, so convert to that if we  found a valid type. +    CompilerType compiler_type(valobj_sp->GetCompilerType()); + +    Status error; +    Watchpoint *wp = +        target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error) +            .get(); +    if (wp) { +      Stream &output_stream = result.GetOutputStream(); +      output_stream.Printf("Watchpoint created: "); +      wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull); +      output_stream.EOL(); +      result.SetStatus(eReturnStatusSuccessFinishResult); +    } else { +      result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 +                                   ", size=%" PRIu64 ").\n", +                                   addr, (uint64_t)size); +      if (error.AsCString(nullptr)) +        result.AppendError(error.AsCString()); +    } + +    return result.Succeeded(); +  } + +private: +  OptionGroupOptions m_option_group; +  OptionGroupWatchpoint m_option_watchpoint; +}; + +// CommandObjectWatchpointSet +#pragma mark Set + +class CommandObjectWatchpointSet : public CommandObjectMultiword { +public: +  CommandObjectWatchpointSet(CommandInterpreter &interpreter) +      : CommandObjectMultiword( +            interpreter, "watchpoint set", "Commands for setting a watchpoint.", +            "watchpoint set <subcommand> [<subcommand-options>]") { + +    LoadSubCommand( +        "variable", +        CommandObjectSP(new CommandObjectWatchpointSetVariable(interpreter))); +    LoadSubCommand( +        "expression", +        CommandObjectSP(new CommandObjectWatchpointSetExpression(interpreter))); +  } + +  ~CommandObjectWatchpointSet() override = default; +}; + +// CommandObjectMultiwordWatchpoint +#pragma mark MultiwordWatchpoint + +CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint( +    CommandInterpreter &interpreter) +    : CommandObjectMultiword(interpreter, "watchpoint", +                             "Commands for operating on watchpoints.", +                             "watchpoint <subcommand> [<command-options>]") { +  CommandObjectSP list_command_object( +      new CommandObjectWatchpointList(interpreter)); +  CommandObjectSP enable_command_object( +      new CommandObjectWatchpointEnable(interpreter)); +  CommandObjectSP disable_command_object( +      new CommandObjectWatchpointDisable(interpreter)); +  CommandObjectSP delete_command_object( +      new CommandObjectWatchpointDelete(interpreter)); +  CommandObjectSP ignore_command_object( +      new CommandObjectWatchpointIgnore(interpreter)); +  CommandObjectSP command_command_object( +      new CommandObjectWatchpointCommand(interpreter)); +  CommandObjectSP modify_command_object( +      new CommandObjectWatchpointModify(interpreter)); +  CommandObjectSP set_command_object( +      new CommandObjectWatchpointSet(interpreter)); + +  list_command_object->SetCommandName("watchpoint list"); +  enable_command_object->SetCommandName("watchpoint enable"); +  disable_command_object->SetCommandName("watchpoint disable"); +  delete_command_object->SetCommandName("watchpoint delete"); +  ignore_command_object->SetCommandName("watchpoint ignore"); +  command_command_object->SetCommandName("watchpoint command"); +  modify_command_object->SetCommandName("watchpoint modify"); +  set_command_object->SetCommandName("watchpoint set"); + +  LoadSubCommand("list", list_command_object); +  LoadSubCommand("enable", enable_command_object); +  LoadSubCommand("disable", disable_command_object); +  LoadSubCommand("delete", delete_command_object); +  LoadSubCommand("ignore", ignore_command_object); +  LoadSubCommand("command", command_command_object); +  LoadSubCommand("modify", modify_command_object); +  LoadSubCommand("set", set_command_object); +} + +CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() = default; | 
