krytarowski created this revision.
krytarowski added a project: LLDB.

This code offers Debug Registers (80386) model in LLDB/amd64.

This is initial support and has one issue that will be addressed later,
Debug Register trap (TRAP_DBREG) is registered as (TRAP_TRACE)
for unknown reason. On the other hand this state is good enough to
move on to add FPR/amd64 support.

Improve the NativeProcessNetBSD::ReinitializeThreads() function,
stop setting inside it SetStoppedByExec(). This fixes incorrect
stop reason on attaching (SetStoppedBySignal(SIGSTOP)).

This commits also has no functional style improvements from
clang-format.

Demo:

  $ lldb ./watch                                                                
                                                                      
  (lldb) target create "./watch"
  Current executable set to './watch' (x86_64).
  (lldb) c
  error: invalid process
  (lldb) r
  Process 1573 launched: './watch' (x86_64)
  Process 1573 stopped
  * thread #1, stop reason = breakpoint 1.1
      frame #0: 0x000000000040087f watch`main(argc=1, argv=0x00007f7fffa12b88) 
at watch.c:8
     5    {
     6            int i, j, k;
     7    
  -> 8            for (i = 0; i < 3; i++)
     9                    for (j = 0; j < 3; j++)
     10                           for (k = 0; k < 3; k++)
     11                                   printf("Hello world! i=%d j=%d 
k=%d\n", i, j, k);
  (lldb) watch set var i
  Watchpoint created: Watchpoint 1: addr = 0x7f7fffa12b4c size = 4 state = 
enabled type = w
      declare @ '/public/lldb_devel/watch.c:6'
      watchpoint spec = 'i'
      new value: 0
  (lldb) c
  Process 1573 resuming
  Hello world! i=0 j=0 k=0
  Hello world! i=0 j=0 k=1
  Hello world! i=0 j=0 k=2
  Hello world! i=0 j=1 k=0
  Hello world! i=0 j=1 k=1
  Hello world! i=0 j=1 k=2
  Hello world! i=0 j=2 k=0
  Hello world! i=0 j=2 k=1
  Hello world! i=0 j=2 k=2
  Process 1573 stopped
  * thread #1, stop reason = trace
      frame #0: 0x00000000004008cc watch`main(argc=1, argv=0x00007f7fffa12b88) 
at watch.c:8
     5    {
     6            int i, j, k;
     7    
  -> 8            for (i = 0; i < 3; i++)
     9                    for (j = 0; j < 3; j++)
     10                           for (k = 0; k < 3; k++)
     11                                   printf("Hello world! i=%d j=%d 
k=%d\n", i, j, k)

Sponsored by <The NetBSD Foundation>


Repository:
  rL LLVM

https://reviews.llvm.org/D32080

Files:
  source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
  source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
  source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
  source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
  source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
  source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
  source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
  source/Plugins/Process/Utility/RegisterInfos_x86_64.h

Index: source/Plugins/Process/Utility/RegisterInfos_x86_64.h
===================================================================
--- source/Plugins/Process/Utility/RegisterInfos_x86_64.h
+++ source/Plugins/Process/Utility/RegisterInfos_x86_64.h
@@ -148,7 +148,7 @@
         DR_OFFSET(i), eEncodingUint, eFormatHex,                               \
                   {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,                   \
                    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,                   \
-                   LLDB_INVALID_REGNUM },                                      \
+                   lldb_##reg##i##_x86_64 },                                   \
                    nullptr, nullptr, nullptr, 0                                \
   }
 
Index: source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
===================================================================
--- source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
+++ source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
@@ -12,6 +12,9 @@
 
 #include "lldb/Host/common/NativeThreadProtocol.h"
 
+#include <map>
+#include <string>
+
 namespace lldb_private {
 namespace process_netbsd {
 
@@ -53,6 +56,7 @@
   void SetStoppedByBreakpoint();
   void SetStoppedByTrace();
   void SetStoppedByExec();
+  void SetStoppedByWatchpoint(uint32_t wp_index);
   void SetStopped();
   void SetRunning();
   void SetStepping();
@@ -64,6 +68,9 @@
   ThreadStopInfo m_stop_info;
   NativeRegisterContextSP m_reg_context_sp;
   std::string m_stop_description;
+  using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+  WatchpointIndexMap m_watchpoint_index_map;
+  WatchpointIndexMap m_hw_break_index_map;
 };
 
 typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
Index: source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
===================================================================
--- source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
+++ source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
@@ -16,6 +16,9 @@
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
 #include "lldb/Core/RegisterValue.h"
 #include "lldb/Core/State.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+#include <sstream>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -68,6 +71,23 @@
   m_stop_info.details.signal.signo = SIGTRAP;
 }
 
+void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
+  SetStopped();
+
+  lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
+
+  std::ostringstream ostr;
+  ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " ";
+  ostr << wp_index;
+
+  ostr << " " << GetRegisterContext()->GetWatchpointHitAddress(wp_index);
+
+  m_stop_description = ostr.str();
+
+  m_stop_info.reason = StopReason::eStopReasonWatchpoint;
+  m_stop_info.details.signal.signo = SIGTRAP;
+}
+
 void NativeThreadNetBSD::SetStopped() {
   const StateType new_state = StateType::eStateStopped;
   m_state = new_state;
@@ -142,18 +162,61 @@
 
 Error NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
                                         uint32_t watch_flags, bool hardware) {
-  return Error("Unimplemented");
+  if (!hardware)
+    return Error("not implemented");
+  if (m_state == eStateLaunching)
+    return Error();
+  Error error = RemoveWatchpoint(addr);
+  if (error.Fail())
+    return error;
+  NativeRegisterContextSP reg_ctx = GetRegisterContext();
+  uint32_t wp_index = reg_ctx->SetHardwareWatchpoint(addr, size, watch_flags);
+  if (wp_index == LLDB_INVALID_INDEX32)
+    return Error("Setting hardware watchpoint failed.");
+  m_watchpoint_index_map.insert({addr, wp_index});
+  return Error();
 }
 
 Error NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
-  return Error("Unimplemented");
+  auto wp = m_watchpoint_index_map.find(addr);
+  if (wp == m_watchpoint_index_map.end())
+    return Error();
+  uint32_t wp_index = wp->second;
+  m_watchpoint_index_map.erase(wp);
+  if (GetRegisterContext()->ClearHardwareWatchpoint(wp_index))
+    return Error();
+  return Error("Clearing hardware watchpoint failed.");
 }
 
 Error NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
                                                 size_t size) {
-  return Error("Unimplemented");
+  if (m_state == eStateLaunching)
+    return Error();
+
+  Error error = RemoveHardwareBreakpoint(addr);
+  if (error.Fail())
+    return error;
+
+  NativeRegisterContextSP reg_ctx = GetRegisterContext();
+  uint32_t bp_index = reg_ctx->SetHardwareBreakpoint(addr, size);
+
+  if (bp_index == LLDB_INVALID_INDEX32)
+    return Error("Setting hardware breakpoint failed.");
+
+  m_hw_break_index_map.insert({addr, bp_index});
+  return Error();
 }
 
 Error NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
-  return Error("Unimplemented");
+  auto bp = m_hw_break_index_map.find(addr);
+  if (bp == m_hw_break_index_map.end())
+    return Error();
+
+  uint32_t bp_index = bp->second;
+  if (GetRegisterContext()->ClearHardwareBreakpoint(bp_index)) {
+    m_hw_break_index_map.erase(bp);
+    return Error();
+  }
+
+  return Error("Clearing hardware breakpoint failed.");
 }
Index: source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
===================================================================
--- source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
+++ source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
@@ -46,17 +46,40 @@
 
   Error WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
 
+  Error IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
+
+  Error GetWatchpointHitIndex(uint32_t &wp_index,
+                              lldb::addr_t trap_addr) override;
+
+  Error IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
+
+  bool ClearHardwareWatchpoint(uint32_t wp_index) override;
+
+  Error ClearAllHardwareWatchpoints() override;
+
+  Error SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
+                                       uint32_t watch_flags, uint32_t wp_index);
+
+  uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+                                 uint32_t watch_flags) override;
+
+  lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
+
+  uint32_t NumSupportedHardwareWatchpoints() override;
+
 protected:
   void *GetGPRBuffer() override { return &m_gpr_x86_64; }
   void *GetFPRBuffer() override { return &m_fpr_x86_64; }
+  void *GetDBRBuffer() override { return &m_dbr_x86_64; }
 
 private:
   // Private member types.
-  enum { GPRegSet, FPRegSet };
+  enum { GPRegSet, FPRegSet, DBRegSet };
 
   // Private member variables.
   struct reg m_gpr_x86_64;
   struct fpreg m_fpr_x86_64;
+  struct dbreg m_dbr_x86_64;
 
   int GetSetForNativeRegNum(int reg_num) const;
 
Index: source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
===================================================================
--- source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
+++ source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
@@ -114,7 +114,7 @@
     uint32_t concrete_frame_idx)
     : NativeRegisterContextNetBSD(native_thread, concrete_frame_idx,
                                   CreateRegisterInfoInterface(target_arch)),
-      m_gpr_x86_64() {}
+      m_gpr_x86_64(), m_fpr_x86_64(), m_dbr_x86_64() {}
 
 // CONSIDER after local and llgs debugging are merged, register set support can
 // be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
@@ -143,8 +143,20 @@
 
 int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
     int reg_num) const {
-  if (reg_num < lldb_fctrl_x86_64)
+  if (reg_num <= k_last_gpr_x86_64)
     return GPRegSet;
+  else if (reg_num <= k_last_fpr_x86_64)
+    return FPRegSet;
+  else if (reg_num <= k_last_avx_x86_64)
+    return -1; // AVX
+  else if (reg_num <= k_last_mpxr_x86_64)
+    return -1; // MPXR
+  else if (reg_num <= k_last_mpxc_x86_64)
+    return -1; // MPXC
+  else if (reg_num <= k_last_avx_x86_64)
+    return -1; // AVX
+  else if (reg_num <= lldb_dr7_x86_64)
+    return DBRegSet; // DBR
   else
     return -1;
 }
@@ -157,6 +169,9 @@
   case FPRegSet:
     ReadFPR();
     return 0;
+  case DBRegSet:
+    ReadDBR();
+    return 0;
   default:
     break;
   }
@@ -170,6 +185,9 @@
   case FPRegSet:
     WriteFPR();
     return 0;
+  case DBRegSet:
+    WriteDBR();
+    return 0;
   default:
     break;
   }
@@ -285,6 +303,16 @@
   case lldb_es_x86_64:
     reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
     break;
+  case lldb_dr0_x86_64:
+  case lldb_dr1_x86_64:
+  case lldb_dr2_x86_64:
+  case lldb_dr3_x86_64:
+  case lldb_dr4_x86_64:
+  case lldb_dr5_x86_64:
+  case lldb_dr6_x86_64:
+  case lldb_dr7_x86_64:
+    reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64];
+    break;
   }
 
   return error;
@@ -400,6 +428,16 @@
   case lldb_es_x86_64:
     m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
     break;
+  case lldb_dr0_x86_64:
+  case lldb_dr1_x86_64:
+  case lldb_dr2_x86_64:
+  case lldb_dr3_x86_64:
+  case lldb_dr4_x86_64:
+  case lldb_dr5_x86_64:
+  case lldb_dr6_x86_64:
+  case lldb_dr7_x86_64:
+    m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64();
+    break;
   }
 
   if (WriteRegisterSet(set) != 0)
@@ -480,4 +518,223 @@
   return error;
 }
 
+Error NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
+                                                          bool &is_hit) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return Error("Watchpoint index out of range");
+
+  RegisterValue reg_value;
+  const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64);
+  Error error = ReadRegister(reg_info, reg_value);
+  if (error.Fail()) {
+    is_hit = false;
+    return error;
+  }
+
+  uint64_t status_bits = reg_value.GetAsUInt64();
+
+  is_hit = status_bits & (1 << wp_index);
+
+  return error;
+}
+
+Error NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex(
+    uint32_t &wp_index, lldb::addr_t trap_addr) {
+  uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+  for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
+    bool is_hit;
+    Error error = IsWatchpointHit(wp_index, is_hit);
+    if (error.Fail()) {
+      wp_index = LLDB_INVALID_INDEX32;
+      return error;
+    } else if (is_hit) {
+      return error;
+    }
+  }
+  wp_index = LLDB_INVALID_INDEX32;
+  return Error();
+}
+
+Error NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
+                                                             bool &is_vacant) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return Error("Watchpoint index out of range");
+
+  RegisterValue reg_value;
+  const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64);
+  Error error = ReadRegister(reg_info, reg_value);
+  if (error.Fail()) {
+    is_vacant = false;
+    return error;
+  }
+
+  uint64_t control_bits = reg_value.GetAsUInt64();
+
+  is_vacant = !(control_bits & (1 << (2 * wp_index)));
+
+  return error;
+}
+
+Error NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex(
+    lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
+
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return Error("Watchpoint index out of range");
+
+  // Read only watchpoints aren't supported on x86_64. Fall back to read/write
+  // waitchpoints instead.
+  // TODO: Add logic to detect when a write happens and ignore that watchpoint
+  // hit.
+  if (watch_flags == 0x2)
+    watch_flags = 0x3;
+
+  if (watch_flags != 0x1 && watch_flags != 0x3)
+    return Error("Invalid read/write bits for watchpoint");
+
+  if (size != 1 && size != 2 && size != 4 && size != 8)
+    return Error("Invalid size for watchpoint");
+
+  bool is_vacant;
+  Error error = IsWatchpointVacant(wp_index, is_vacant);
+  if (error.Fail())
+    return error;
+  if (!is_vacant)
+    return Error("Watchpoint index not vacant");
+
+  RegisterValue reg_value;
+  const RegisterInfo *const reg_info_dr7 =
+      GetRegisterInfoAtIndex(lldb_dr7_x86_64);
+  error = ReadRegister(reg_info_dr7, reg_value);
+  if (error.Fail())
+    return error;
+
+  // for watchpoints 0, 1, 2, or 3, respectively,
+  // set bits 1, 3, 5, or 7
+  uint64_t enable_bit = 1 << (2 * wp_index);
+
+  // set bits 16-17, 20-21, 24-25, or 28-29
+  // with 0b01 for write, and 0b11 for read/write
+  uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
+
+  // set bits 18-19, 22-23, 26-27, or 30-31
+  // with 0b00, 0b01, 0b10, or 0b11
+  // for 1, 2, 8 (if supported), or 4 bytes, respectively
+  uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
+
+  uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
+
+  uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+
+  control_bits |= enable_bit | rw_bits | size_bits;
+
+  const RegisterInfo *const reg_info_drN =
+      GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
+  error = WriteRegister(reg_info_drN, RegisterValue(addr));
+  if (error.Fail())
+    return error;
+
+  error = WriteRegister(reg_info_dr7, RegisterValue(control_bits));
+  if (error.Fail())
+    return error;
+
+  error.Clear();
+  return error;
+}
+
+bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint(
+    uint32_t wp_index) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return false;
+
+  RegisterValue reg_value;
+
+  // for watchpoints 0, 1, 2, or 3, respectively,
+  // clear bits 0, 1, 2, or 3 of the debug status register (DR6)
+  const RegisterInfo *const reg_info_dr6 =
+      GetRegisterInfoAtIndex(lldb_dr6_x86_64);
+  Error error = ReadRegister(reg_info_dr6, reg_value);
+  if (error.Fail())
+    return false;
+  uint64_t bit_mask = 1 << wp_index;
+  uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+  error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
+  if (error.Fail())
+    return false;
+
+  // for watchpoints 0, 1, 2, or 3, respectively,
+  // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
+  // of the debug control register (DR7)
+  const RegisterInfo *const reg_info_dr7 =
+      GetRegisterInfoAtIndex(lldb_dr7_x86_64);
+  error = ReadRegister(reg_info_dr7, reg_value);
+  if (error.Fail())
+    return false;
+  bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
+  uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+  return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success();
+}
+
+Error NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() {
+  RegisterValue reg_value;
+
+  // clear bits {0-4} of the debug status register (DR6)
+  const RegisterInfo *const reg_info_dr6 =
+      GetRegisterInfoAtIndex(lldb_dr6_x86_64);
+  Error error = ReadRegister(reg_info_dr6, reg_value);
+  if (error.Fail())
+    return error;
+  uint64_t bit_mask = 0xF;
+  uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+  error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
+  if (error.Fail())
+    return error;
+
+  // clear bits {0-7,16-31} of the debug control register (DR7)
+  const RegisterInfo *const reg_info_dr7 =
+      GetRegisterInfoAtIndex(lldb_dr7_x86_64);
+  error = ReadRegister(reg_info_dr7, reg_value);
+  if (error.Fail())
+    return error;
+  bit_mask = 0xFF | (0xFFFF << 16);
+  uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+  return WriteRegister(reg_info_dr7, RegisterValue(control_bits));
+}
+
+uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint(
+    lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+  const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+  for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
+    bool is_vacant;
+    Error error = IsWatchpointVacant(wp_index, is_vacant);
+    if (is_vacant) {
+      error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
+      if (error.Success())
+        return wp_index;
+    }
+    if (error.Fail() && log) {
+      log->Printf("NativeRegisterContextNetBSD_x86_64::%s Error: %s",
+                  __FUNCTION__, error.AsCString());
+    }
+  }
+  return LLDB_INVALID_INDEX32;
+}
+
+lldb::addr_t
+NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return LLDB_INVALID_ADDRESS;
+  RegisterValue reg_value;
+  const RegisterInfo *const reg_info_drN =
+      GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
+  if (ReadRegister(reg_info_drN, reg_value).Fail())
+    return LLDB_INVALID_ADDRESS;
+  return reg_value.GetAsUInt64();
+}
+
+uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() {
+  // Available debug address registers: dr0, dr1, dr2, dr3
+  return 4;
+}
+
 #endif // defined(__x86_64__)
Index: source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
===================================================================
--- source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
+++ source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
@@ -41,20 +41,29 @@
   virtual Error ReadFPR();
   virtual Error WriteFPR();
 
+  virtual Error ReadDBR();
+  virtual Error WriteDBR();
+
   virtual void *GetGPRBuffer() { return nullptr; }
   virtual size_t GetGPRSize() {
     return GetRegisterInfoInterface().GetGPRSize();
   }
 
   virtual void *GetFPRBuffer() { return nullptr; }
   virtual size_t GetFPRSize() { return 0; }
 
+  virtual void *GetDBRBuffer() { return nullptr; }
+  virtual size_t GetDBRSize() { return 0; }
+
   virtual Error DoReadGPR(void *buf);
   virtual Error DoWriteGPR(void *buf);
 
   virtual Error DoReadFPR(void *buf);
   virtual Error DoWriteFPR(void *buf);
 
+  virtual Error DoReadDBR(void *buf);
+  virtual Error DoWriteDBR(void *buf);
+
   virtual NativeProcessNetBSD &GetProcess();
   virtual ::pid_t GetProcessPid();
 };
Index: source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
===================================================================
--- source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
+++ source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
@@ -57,6 +57,22 @@
   return DoWriteFPR(buf);
 }
 
+Error NativeRegisterContextNetBSD::ReadDBR() {
+  void *buf = GetDBRBuffer();
+  if (!buf)
+    return Error("DBR buffer is NULL");
+
+  return DoReadDBR(buf);
+}
+
+Error NativeRegisterContextNetBSD::WriteDBR() {
+  void *buf = GetDBRBuffer();
+  if (!buf)
+    return Error("DBR buffer is NULL");
+
+  return DoWriteDBR(buf);
+}
+
 Error NativeRegisterContextNetBSD::DoReadGPR(void *buf) {
   return NativeProcessNetBSD::PtraceWrapper(PT_GETREGS, GetProcessPid(), buf,
                                             m_thread.GetID());
@@ -77,6 +93,16 @@
                                             m_thread.GetID());
 }
 
+Error NativeRegisterContextNetBSD::DoReadDBR(void *buf) {
+  return NativeProcessNetBSD::PtraceWrapper(PT_GETDBREGS, GetProcessPid(), buf,
+                                            m_thread.GetID());
+}
+
+Error NativeRegisterContextNetBSD::DoWriteDBR(void *buf) {
+  return NativeProcessNetBSD::PtraceWrapper(PT_SETDBREGS, GetProcessPid(), buf,
+                                            m_thread.GetID());
+}
+
 NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
   auto process_sp =
       std::static_pointer_cast<NativeProcessNetBSD>(m_thread.GetProcess());
Index: source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
===================================================================
--- source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -224,36 +224,83 @@
       PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
 
   // Get details on the signal raised.
-  if (siginfo_err.Success()) {
-    switch (info.psi_siginfo.si_code) {
-    case TRAP_BRKPT:
+  if (siginfo_err.Fail()) {
+    return;
+  }
+
+  switch (info.psi_siginfo.si_code) {
+  case TRAP_BRKPT:
+    for (const auto &thread_sp : m_threads) {
+      static_pointer_cast<NativeThreadNetBSD>(thread_sp)
+          ->SetStoppedByBreakpoint();
+      FixupBreakpointPCAsNeeded(
+          *static_pointer_cast<NativeThreadNetBSD>(thread_sp));
+    }
+    SetState(StateType::eStateStopped, true);
+    break;
+  case TRAP_TRACE:
+    for (const auto &thread_sp : m_threads) {
+      static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByTrace();
+    }
+    SetState(StateType::eStateStopped, true);
+    break;
+  case TRAP_EXEC: {
+    Error error = ReinitializeThreads();
+    if (error.Fail()) {
+      SetState(StateType::eStateInvalid);
+      return;
+    }
+
+    // Let our delegate know we have just exec'd.
+    NotifyDidExec();
+
+    for (const auto &thread_sp : m_threads) {
+      static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByExec();
+    }
+    SetState(StateType::eStateStopped, true);
+  } break;
+  case TRAP_DBREG: {
+    // If a watchpoint was hit, report it
+    uint32_t wp_index;
+    Error error =
+        static_pointer_cast<NativeThreadNetBSD>(m_threads[info.psi_lwpid])
+            ->GetRegisterContext()
+            ->GetWatchpointHitIndex(wp_index,
+                                    (uintptr_t)info.psi_siginfo.si_addr);
+    if (error.Fail())
+      LLDB_LOG(log,
+               "received error while checking for watchpoint hits, pid = "
+               "{0}, LWP = {1}, error = {2}",
+               GetID(), info.psi_lwpid, error);
+    if (wp_index != LLDB_INVALID_INDEX32) {
       for (const auto &thread_sp : m_threads) {
         static_pointer_cast<NativeThreadNetBSD>(thread_sp)
-            ->SetStoppedByBreakpoint();
-        FixupBreakpointPCAsNeeded(
-            *static_pointer_cast<NativeThreadNetBSD>(thread_sp));
+            ->SetStoppedByWatchpoint(wp_index);
       }
       SetState(StateType::eStateStopped, true);
       break;
-    case TRAP_TRACE:
+    }
+
+    // If a breakpoint was hit, report it
+    uint32_t bp_index;
+    error = static_pointer_cast<NativeThreadNetBSD>(m_threads[info.psi_lwpid])
+                ->GetRegisterContext()
+                ->GetHardwareBreakHitIndex(bp_index,
+                                           (uintptr_t)info.psi_siginfo.si_addr);
+    if (error.Fail())
+      LLDB_LOG(log,
+               "received error while checking for hardware "
+               "breakpoint hits, pid = {0}, LWP = {1}, error = {2}",
+               GetID(), info.psi_lwpid, error);
+    if (bp_index != LLDB_INVALID_INDEX32) {
       for (const auto &thread_sp : m_threads) {
-        static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByTrace();
+        static_pointer_cast<NativeThreadNetBSD>(thread_sp)
+            ->SetStoppedByBreakpoint();
       }
       SetState(StateType::eStateStopped, true);
       break;
-    case TRAP_EXEC: {
-      Error error = ReinitializeThreads();
-      if (error.Fail()) {
-        SetState(StateType::eStateInvalid);
-        return;
-      }
-
-      // Let our delegate know we have just exec'd.
-      NotifyDidExec();
-
-      SetState(StateType::eStateStopped, true);
-    } break;
     }
+  } break;
   }
 }
 
@@ -328,8 +375,8 @@
     return error;
   } else
     LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size);
-  // First try probing for a breakpoint at a software breakpoint location: PC -
-  // breakpoint size.
+  // First try probing for a breakpoint at a software breakpoint location: PC
+  // - breakpoint size.
   const lldb::addr_t initial_pc_addr =
       context_sp->GetPCfromBreakpointLocation();
   lldb::addr_t breakpoint_addr = initial_pc_addr;
@@ -439,7 +486,7 @@
     llvm_unreachable("Unexpected state");
 
   default:
-    return Error("NativeProcessLinux::%s (): unexpected state %s specified "
+    return Error("NativeProcessNetBSD::%s (): unexpected state %s specified "
                  "for pid %" PRIu64 ", tid %" PRIu64,
                  __FUNCTION__, StateAsCString(action->state), GetID(),
                  thread_sp->GetID());
@@ -540,8 +587,8 @@
            "descending memory map entries detected, unexpected");
     prev_base_address = proc_entry_info.GetRange().GetRangeBase();
     UNUSED_IF_ASSERT_DISABLED(prev_base_address);
-    // If the target address comes before this entry, indicate distance to next
-    // region.
+    // If the target address comes before this entry, indicate distance to
+    // next region.
     if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
       range_info.GetRange().SetRangeBase(load_addr);
       range_info.GetRange().SetByteSize(
@@ -561,9 +608,8 @@
   }
   // If we made it here, we didn't find an entry that contained the given
   // address. Return the
-  // load_addr as start and the amount of bytes betwwen load address and the end
-  // of the memory as
-  // size.
+  // load_addr as start and the amount of bytes betwwen load address and the
+  // end of the memory as size.
   range_info.GetRange().SetRangeBase(load_addr);
   range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
   range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
@@ -722,8 +768,8 @@
     LLDB_LOG(log, "waitpid for inferior failed with %s", error);
 
     // Mark the inferior as invalid.
-    // FIXME this could really use a new state - eStateLaunchFailure.  For now,
-    // using eStateInvalid.
+    // FIXME this could really use a new state - eStateLaunchFailure.  For
+    // now, using eStateInvalid.
     SetState(StateType::eStateInvalid);
 
     return error;
@@ -766,6 +812,11 @@
     return error;
   }
 
+  for (const auto &thread_sp : m_threads) {
+    static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
+        SIGSTOP);
+  }
+
   /* Set process stopped */
   SetState(StateType::eStateStopped);
 
@@ -894,6 +945,11 @@
     return -1;
   }
 
+  for (const auto &thread_sp : m_threads) {
+    static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
+        SIGSTOP);
+  }
+
   // Let our process instance know the thread has stopped.
   SetState(StateType::eStateStopped);
 
@@ -1007,7 +1063,6 @@
   // Reinitialize from scratch threads and register them in process
   while (info.pl_lwpid != 0) {
     NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
-    thread_sp->SetStoppedByExec();
     error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info));
     if (error.Fail()) {
       return error;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to