andrew updated this revision to Diff 426993.
andrew marked 5 inline comments as done and an inline comment as not done.
andrew added a comment.

Cleanup based on feedback


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120485/new/

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
  
lldb/test/API/functionalities/unwind/aarch64_unwind_pac/TestAArch64UnwindPAC.py
  lldb/test/API/functionalities/unwind/aarch64_unwind_pac/main.c
  lldb/test/API/python_api/sbvalue_const_addrof/main.cpp

Index: lldb/test/API/python_api/sbvalue_const_addrof/main.cpp
===================================================================
--- lldb/test/API/python_api/sbvalue_const_addrof/main.cpp
+++ lldb/test/API/python_api/sbvalue_const_addrof/main.cpp
@@ -1,5 +1,5 @@
-#include <stdio.h>
-#include <stdint.h>
+#include <cstdio>
+#include <cstdint>
 
 struct RegisterContext
 {
Index: lldb/test/API/functionalities/unwind/aarch64_unwind_pac/main.c
===================================================================
--- lldb/test/API/functionalities/unwind/aarch64_unwind_pac/main.c
+++ lldb/test/API/functionalities/unwind/aarch64_unwind_pac/main.c
@@ -4,8 +4,32 @@
 // To enable PAC return address signing compile with following clang arguments:
 // -march=armv8.3-a -mbranch-protection=pac-ret+leaf
 
+#include <stdbool.h>
 #include <stdlib.h>
 
+#if defined(__FreeBSD__)
+#include <sys/auxv.h>
+
+// Added in FreeBSD 12.2, can be removed when all supported branches define it.
+#if !defined(HWCAP_PACA)
+#define	HWCAP_PACA	0x40000000
+#endif
+
+static bool pac_supported(void) {
+  unsigned long hwcap;
+
+  if (elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)) != 0)
+    return false;
+
+  return (hwcap & HWCAP_PACA) != 0;
+}
+#else
+static bool pac_supported(void) {
+  // We expect Linux to check for PAC up front using /proc/cpuinfo.
+  return true;
+}
+#endif
+
 static void __attribute__((noinline)) func_c(void) {
   exit(0); // Frame func_c
 }
@@ -19,6 +43,9 @@
 }
 
 int main(int argc, char *argv[]) {
+  if (!pac_supported())
+    return 1;
+
   func_a(); // Frame main
   return 0;
 }
Index: lldb/test/API/functionalities/unwind/aarch64_unwind_pac/TestAArch64UnwindPAC.py
===================================================================
--- lldb/test/API/functionalities/unwind/aarch64_unwind_pac/TestAArch64UnwindPAC.py
+++ lldb/test/API/functionalities/unwind/aarch64_unwind_pac/TestAArch64UnwindPAC.py
@@ -6,28 +6,26 @@
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
 from lldbsuite.test import lldbutil
+import re
 
 
 class AArch64UnwindPAC(TestBase):
     mydir = TestBase.compute_mydir(__file__)
 
-    @skipIf(archs=no_match(["aarch64"]))
-    @skipIf(oslist=no_match(['linux']))
-    def test(self):
-        """Test that we can backtrace correctly when AArch64 PAC is enabled"""
-        if not self.isAArch64PAuth():
-            self.skipTest('Target must support Pointer Authentication.')
-
+    def common(self, backtrace_tail):
         self.build()
 
         self.line = line_number('main.c', '// Frame func_c')
 
         exe = self.getBuildArtifact("a.out")
         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
-
         lldbutil.run_break_set_by_file_and_line(
             self, "main.c", self.line, num_expected_locations=1)
         self.runCmd("run", RUN_SUCCEEDED)
+        if re.match('Process .* exited with status = 1[^0-9]', self.res.GetOutput()):
+            # No PAC support
+            self.skipTest('Target must support Pointer Authentication.')
+
         self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
                     substrs=["stop reason = breakpoint 1."])
 
@@ -35,13 +33,33 @@
         process = target.GetProcess()
         thread = process.GetThreadAtIndex(0)
 
-        backtrace = ["func_c", "func_b", "func_a", "main", "__libc_start_main", "_start"]
-        self.assertEqual(thread.GetNumFrames(), len(backtrace))
+        backtrace = ["func_c", "func_b", "func_a", "main"] + backtrace_tail
         for frame_idx, frame in enumerate(thread.frames):
             frame = thread.GetFrameAtIndex(frame_idx)
+            # On FreeBSD we get ___lldb_unnamed_symbol symbols at the bottom
+            # of the stack. Ignore these and assume we have walked the entire
+            # stack, however check this assumption is correct.
+            if frame.GetFunctionName().startswith("___lldb_unnamed_symbol"):
+                self.assertEqual(len(backtrace), frame_idx)
+                break
             self.assertTrue(frame)
             self.assertEqual(frame.GetFunctionName(), backtrace[frame_idx])
 			# Check line number for functions in main.c
             if (frame_idx < 4):
                 self.assertEqual(frame.GetLineEntry().GetLine(),
                                  line_number("main.c", "Frame " + backtrace[frame_idx]))
+
+    @skipIf(archs=no_match(["aarch64"]))
+    @skipIf(oslist=no_match(['freebsd']))
+    def test_freebsd(self):
+        """Test that we can backtrace correctly when AArch64 PAC is enabled"""
+        self.common(["__start"])
+
+    @skipIf(archs=no_match(["aarch64"]))
+    @skipIf(oslist=no_match(['linux']))
+    def test_linux(self):
+        """Test that we can backtrace correctly when AArch64 PAC is enabled"""
+        if not self.isAArch64PAuth():
+            self.skipTest('Target must support Pointer Authentication.')
+
+        self.common(["__libc_start_main", "_start"])
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,12 @@
   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 +121,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 +188,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
@@ -791,6 +791,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) {
@@ -823,6 +848,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());
   }
@@ -835,6 +864,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