andrew created this revision.
andrew added a reviewer: mgorny.
Herald added subscribers: kristof.beyls, krytarowski, arichardson.
andrew requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Read the mask using ptrace with PT_GETREGSET with NT_ARM_ADDR_MASK
for live processes, or from the NT_ARM_ADDR_MASK note in a core
file.

As NT_ARM_ADDR_MASK is on FreeBSD is the same value as NT_ARM_PAC_MASK
and it contains a structure with the same layout and a superset of the
same data use this when reading a core file.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D120485

Files:
  lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
  lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
  lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
  lldb/source/Plugins/Process/elf-core/RegisterUtilities.h

Index: lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
===================================================================
--- lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
+++ lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
@@ -120,6 +120,7 @@
 };
 
 constexpr RegsetDesc AARCH64_PAC_Desc[] = {
+    {llvm::Triple::FreeBSD, llvm::Triple::aarch64, llvm::ELF::NT_ARM_PAC_MASK},
     {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_PAC_MASK},
 };
 
Index: lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
===================================================================
--- lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
+++ lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
@@ -36,8 +36,10 @@
     : public NativeRegisterContextFreeBSD,
       public NativeRegisterContextDBReg_arm64 {
 public:
-  NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch,
-                                     NativeThreadProtocol &native_thread);
+  NativeRegisterContextFreeBSD_arm64(
+      const ArchSpec &target_arch,
+      NativeThreadProtocol &native_thread,
+      std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up);
 
   uint32_t GetRegisterSetCount() const override;
 
@@ -65,6 +67,15 @@
   // a unittest to assert that).
   std::array<uint8_t, sizeof(reg)> m_reg_data;
   std::array<uint8_t, sizeof(fpreg)> m_fpreg_data;
+
+  struct arm64_addr_mask {
+    uint64_t data_mask;
+    uint64_t insn_mask;
+  };
+
+  bool m_addr_mask_is_valid;
+  struct arm64_addr_mask m_addr_mask;
+
 #ifdef LLDB_HAS_FREEBSD_WATCHPOINT
   dbreg m_dbreg;
   bool m_read_dbreg;
@@ -76,16 +87,22 @@
   void *GetFPRBuffer() { return &m_fpreg_data; }
   size_t GetFPRSize() { return sizeof(m_fpreg_data); }
 
+  void *GetAddrMaskBuffer() { return &m_addr_mask; }
+  size_t GetAddrMaskBufferSize() { return sizeof(m_addr_mask); }
+
   bool IsGPR(unsigned reg) const;
   bool IsFPR(unsigned reg) const;
+  bool IsAddrMask(unsigned reg) const;
 
   Status ReadGPR();
   Status WriteGPR();
+  Status ReadAddrMask();
 
   Status ReadFPR();
   Status WriteFPR();
 
   uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
+  uint32_t CalculateAddrMaskOffset(const RegisterInfo *reg_info) const;
 
   llvm::Error ReadHardwareDebugInfo() override;
   llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
Index: lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
+++ lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
@@ -19,9 +19,11 @@
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 
 // clang-format off
+#include <sys/elf.h>
 #include <sys/param.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
+#include <sys/uio.h>
 // clang-format on
 
 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
@@ -33,13 +35,19 @@
 NativeRegisterContextFreeBSD *
 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
-  return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread);
+  Flags opt_regsets;
+  opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth);
+  auto register_info_up =
+      std::make_unique<RegisterInfoPOSIX_arm64>(target_arch, opt_regsets);
+  return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread,
+      std::move(register_info_up));
 }
 
 NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
-    : NativeRegisterContextRegisterInfo(
-          native_thread, new RegisterInfoPOSIX_arm64(target_arch, 0))
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+    std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up)
+    : NativeRegisterContextRegisterInfo(native_thread,
+                                        register_info_up.release())
 #ifdef LLDB_HAS_FREEBSD_WATCHPOINT
       ,
       m_read_dbreg(false)
@@ -47,6 +55,9 @@
 {
   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
   ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
+  ::memset(&m_addr_mask, 0, sizeof(m_addr_mask));
+
+  m_addr_mask_is_valid = false;
 }
 
 RegisterInfoPOSIX_arm64 &
@@ -84,6 +95,13 @@
   return false;
 }
 
+bool NativeRegisterContextFreeBSD_arm64::IsAddrMask(unsigned reg) const {
+  // Reuse the Linux PAuth mask register for now. On FreeBSD it can be
+  // used when PAC isn't available, e.g. with TBI.
+  return GetRegisterInfo().IsPAuthReg(reg);
+}
+
+
 Status NativeRegisterContextFreeBSD_arm64::ReadGPR() {
   return NativeProcessFreeBSD::PtraceWrapper(
       PT_GETREGS, m_thread.GetID(), m_reg_data.data());
@@ -104,11 +122,37 @@
       PT_SETFPREGS, m_thread.GetID(), m_fpreg_data.data());
 }
 
+Status NativeRegisterContextFreeBSD_arm64::ReadAddrMask() {
+  Status error;
+
+#ifdef NT_ARM_ADDR_MASK
+  if (m_addr_mask_is_valid)
+    return error;
+
+  struct iovec ioVec;
+  ioVec.iov_base = GetAddrMaskBuffer();
+  ioVec.iov_len = GetAddrMaskBufferSize();
+
+  error = NativeProcessFreeBSD::PtraceWrapper(
+      PT_GETREGSET, m_thread.GetID(), &ioVec, NT_ARM_ADDR_MASK);
+
+  if (error.Success())
+    m_addr_mask_is_valid = true;
+#endif
+
+  return error;
+}
+
 uint32_t NativeRegisterContextFreeBSD_arm64::CalculateFprOffset(
     const RegisterInfo *reg_info) const {
   return reg_info->byte_offset - GetGPRSize();
 }
 
+uint32_t NativeRegisterContextFreeBSD_arm64::CalculateAddrMaskOffset(
+    const RegisterInfo *reg_info) const {
+  return reg_info->byte_offset - GetRegisterInfo().GetPAuthOffset();
+}
+
 Status
 NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo *reg_info,
                                                  RegisterValue &reg_value) {
@@ -145,6 +189,14 @@
     offset = CalculateFprOffset(reg_info);
     assert(offset < GetFPRSize());
     src = (uint8_t *)GetFPRBuffer() + offset;
+  } else if (IsAddrMask(reg)) {
+    error = ReadAddrMask();
+    if (error.Fail())
+      return error;
+
+    offset = CalculateAddrMaskOffset(reg_info);
+    assert(offset < GetAddrMaskBufferSize());
+    src = (uint8_t *)GetAddrMaskBuffer() + offset;
   } else
     return Status("Failed to read register value");
 
Index: lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
===================================================================
--- lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
+++ lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
@@ -788,6 +788,31 @@
   return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
 }
 
+// Reads code or data address mask for the current Linux process.
+static lldb::addr_t ReadFreeBSDProcessAddressMask(lldb::ProcessSP process_sp,
+                                                  llvm::StringRef reg_name) {
+  uint64_t address_mask = 0;
+
+  // If Pointer Authentication feature is enabled then FreeBSD exposes
+  // PAC data and code mask register. Try reading relevant register
+  // below and merge it with default address mask calculated above.
+  lldb::ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread();
+  if (thread_sp) {
+    lldb::RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
+    if (reg_ctx_sp) {
+      const RegisterInfo *reg_info =
+          reg_ctx_sp->GetRegisterInfoByName(reg_name, 0);
+      if (reg_info) {
+        lldb::addr_t mask_reg_val = reg_ctx_sp->ReadRegisterAsUnsigned(
+            reg_info->kinds[eRegisterKindLLDB], LLDB_INVALID_ADDRESS);
+        if (mask_reg_val != LLDB_INVALID_ADDRESS)
+          address_mask |= mask_reg_val;
+      }
+    }
+  }
+  return address_mask;
+}
+
 // Reads code or data address mask for the current Linux process.
 static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp,
                                                 llvm::StringRef reg_name) {
@@ -820,6 +845,10 @@
         !process_sp->GetCodeAddressMask())
       process_sp->SetCodeAddressMask(
           ReadLinuxProcessAddressMask(process_sp, "code_mask"));
+    else if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSFreeBSD() &&
+        !process_sp->GetCodeAddressMask())
+      process_sp->SetCodeAddressMask(
+          ReadFreeBSDProcessAddressMask(process_sp, "code_mask"));
 
     return FixAddress(pc, process_sp->GetCodeAddressMask());
   }
@@ -832,6 +861,10 @@
         !process_sp->GetDataAddressMask())
       process_sp->SetDataAddressMask(
           ReadLinuxProcessAddressMask(process_sp, "data_mask"));
+    else if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSFreeBSD() &&
+        !process_sp->GetDataAddressMask())
+      process_sp->SetDataAddressMask(
+          ReadFreeBSDProcessAddressMask(process_sp, "data_mask"));
 
     return FixAddress(pc, process_sp->GetDataAddressMask());
   }
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to