mgorny created this revision.
mgorny added reviewers: labath, krytarowski, emaste, omjavaid.
Herald added subscribers: kristof.beyls, arichardson.
mgorny requested review of this revision.

Introduce arm64 support in the FreeBSDRemote plugin.  The code
is roughly based on Linux and reuses the same POSIX RegisterInfos
(but the buffers need to be a few bytes larger due to stricter struct
member alignment in FreeBSD structures -- luckily, they do not affect
the actual member offsets).  It supports reading and writing
general-purpose and FPU registers.  SVE and hardware watchpoint support
is missing due to the limitations of FreeBSD ptrace(2) API.


https://reviews.llvm.org/D95297

Files:
  lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
  lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
  
lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm64.cpp
  lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm64.h
  lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp

Index: lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp
===================================================================
--- lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp
+++ lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp
@@ -17,6 +17,8 @@
 #include "Plugins/Process/Utility/lldb-x86-register-enums.h"
 #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
 #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -231,3 +233,92 @@
 }
 
 #endif // defined(__i386__) || defined(__x86_64__)
+
+#if defined(__aarch64__)
+
+#define EXPECT_GPR_ARM64(lldb_reg, fbsd_reg)                                   \
+  EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_arm64),                   \
+              ::testing::Pair(offsetof(reg, fbsd_reg), sizeof(reg::fbsd_reg)))
+#define EXPECT_FPU_ARM64(lldb_reg, fbsd_reg)                                   \
+  EXPECT_THAT(GetRegParams(reg_ctx, fpu_##lldb_reg##_arm64),                   \
+              ::testing::Pair(offsetof(fpreg, fbsd_reg) + base_offset,         \
+                              sizeof(fpreg::fbsd_reg)))
+
+TEST(RegisterContextFreeBSDTest, arm64) {
+  ArchSpec arch{"aarch64-unknown-freebsd"};
+  RegisterInfoPOSIX_arm64 reg_ctx{arch};
+
+  EXPECT_GPR_ARM64(x0, x[0]);
+  EXPECT_GPR_ARM64(x1, x[1]);
+  EXPECT_GPR_ARM64(x2, x[2]);
+  EXPECT_GPR_ARM64(x3, x[3]);
+  EXPECT_GPR_ARM64(x4, x[4]);
+  EXPECT_GPR_ARM64(x5, x[5]);
+  EXPECT_GPR_ARM64(x6, x[6]);
+  EXPECT_GPR_ARM64(x7, x[7]);
+  EXPECT_GPR_ARM64(x8, x[8]);
+  EXPECT_GPR_ARM64(x9, x[9]);
+  EXPECT_GPR_ARM64(x10, x[10]);
+  EXPECT_GPR_ARM64(x11, x[11]);
+  EXPECT_GPR_ARM64(x12, x[12]);
+  EXPECT_GPR_ARM64(x13, x[13]);
+  EXPECT_GPR_ARM64(x14, x[14]);
+  EXPECT_GPR_ARM64(x15, x[15]);
+  EXPECT_GPR_ARM64(x16, x[16]);
+  EXPECT_GPR_ARM64(x17, x[17]);
+  EXPECT_GPR_ARM64(x18, x[18]);
+  EXPECT_GPR_ARM64(x19, x[19]);
+  EXPECT_GPR_ARM64(x20, x[20]);
+  EXPECT_GPR_ARM64(x21, x[21]);
+  EXPECT_GPR_ARM64(x22, x[22]);
+  EXPECT_GPR_ARM64(x23, x[23]);
+  EXPECT_GPR_ARM64(x24, x[24]);
+  EXPECT_GPR_ARM64(x25, x[25]);
+  EXPECT_GPR_ARM64(x26, x[26]);
+  EXPECT_GPR_ARM64(x27, x[27]);
+  EXPECT_GPR_ARM64(x28, x[28]);
+  EXPECT_GPR_ARM64(fp, x[29]);
+  EXPECT_GPR_ARM64(lr, lr);
+  EXPECT_GPR_ARM64(sp, sp);
+  EXPECT_GPR_ARM64(pc, elr);
+  EXPECT_GPR_ARM64(cpsr, spsr);
+
+  size_t base_offset = reg_ctx.GetRegisterInfo()[fpu_v0_arm64].byte_offset;
+
+  EXPECT_FPU_ARM64(v0, fp_q[0]);
+  EXPECT_FPU_ARM64(v1, fp_q[1]);
+  EXPECT_FPU_ARM64(v2, fp_q[2]);
+  EXPECT_FPU_ARM64(v3, fp_q[3]);
+  EXPECT_FPU_ARM64(v4, fp_q[4]);
+  EXPECT_FPU_ARM64(v5, fp_q[5]);
+  EXPECT_FPU_ARM64(v6, fp_q[6]);
+  EXPECT_FPU_ARM64(v7, fp_q[7]);
+  EXPECT_FPU_ARM64(v8, fp_q[8]);
+  EXPECT_FPU_ARM64(v9, fp_q[9]);
+  EXPECT_FPU_ARM64(v10, fp_q[10]);
+  EXPECT_FPU_ARM64(v11, fp_q[11]);
+  EXPECT_FPU_ARM64(v12, fp_q[12]);
+  EXPECT_FPU_ARM64(v13, fp_q[13]);
+  EXPECT_FPU_ARM64(v14, fp_q[14]);
+  EXPECT_FPU_ARM64(v15, fp_q[15]);
+  EXPECT_FPU_ARM64(v16, fp_q[16]);
+  EXPECT_FPU_ARM64(v17, fp_q[17]);
+  EXPECT_FPU_ARM64(v18, fp_q[18]);
+  EXPECT_FPU_ARM64(v19, fp_q[19]);
+  EXPECT_FPU_ARM64(v20, fp_q[20]);
+  EXPECT_FPU_ARM64(v21, fp_q[21]);
+  EXPECT_FPU_ARM64(v22, fp_q[22]);
+  EXPECT_FPU_ARM64(v23, fp_q[23]);
+  EXPECT_FPU_ARM64(v24, fp_q[24]);
+  EXPECT_FPU_ARM64(v25, fp_q[25]);
+  EXPECT_FPU_ARM64(v26, fp_q[26]);
+  EXPECT_FPU_ARM64(v27, fp_q[27]);
+  EXPECT_FPU_ARM64(v28, fp_q[28]);
+  EXPECT_FPU_ARM64(v29, fp_q[29]);
+  EXPECT_FPU_ARM64(v30, fp_q[30]);
+  EXPECT_FPU_ARM64(v31, fp_q[31]);
+  EXPECT_FPU_ARM64(fpsr, fp_sr);
+  EXPECT_FPU_ARM64(fpcr, fp_cr);
+}
+
+#endif // defined(__aarch64__)
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm64.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm64.h
@@ -0,0 +1,75 @@
+//===-- NativeRegisterContextFreeBSD_arm64.h --------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__aarch64__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_arm64_h
+#define lldb_NativeRegisterContextFreeBSD_arm64_h
+
+// clang-format off
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+
+#include <array>
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_arm64 : public NativeRegisterContextFreeBSD {
+public:
+  NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch,
+                                     NativeThreadProtocol &native_thread);
+
+  uint32_t GetRegisterSetCount() const override;
+
+  uint32_t GetUserRegisterCount() const override;
+
+  const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+  Status ReadRegister(const RegisterInfo *reg_info,
+                      RegisterValue &reg_value) override;
+
+  Status WriteRegister(const RegisterInfo *reg_info,
+                       const RegisterValue &reg_value) override;
+
+  Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+  Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+  bool RegisterOffsetIsDynamic() const override { return true; }
+
+  llvm::Error
+  CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+  // Due to alignment, FreeBSD reg/fpreg are a few bytes larger than
+  // LLDB's GPR/FPU structs.  However, all fields have matching offsets
+  // and sizes, so we do not have to worry about these (and we have
+  // a unittest to assert that).
+  std::array<uint8_t, sizeof(reg) + sizeof(fpreg)> m_reg_data;
+
+  Status ReadRegisterSet(uint32_t set);
+  Status WriteRegisterSet(uint32_t set);
+
+  uint8_t *GetOffsetRegSetData(uint32_t set, size_t reg_offset);
+
+  RegisterInfoPOSIX_arm64 &GetRegisterInfo() const;
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm64_h
+
+#endif // defined (__aarch64__)
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm64.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm64.cpp
@@ -0,0 +1,211 @@
+//===-- NativeRegisterContextFreeBSD_arm64.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
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__aarch64__)
+
+#include "NativeRegisterContextFreeBSD_arm64.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+// clang-format on
+
+#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+  return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread);
+}
+
+NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64(
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+    : NativeRegisterContextRegisterInfo(
+          native_thread, new RegisterInfoPOSIX_arm64(target_arch)) {
+  GetRegisterInfo().ConfigureVectorRegisterInfos(
+      RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64);
+}
+
+RegisterInfoPOSIX_arm64 &
+NativeRegisterContextFreeBSD_arm64::GetRegisterInfo() const {
+  return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up);
+}
+
+uint32_t NativeRegisterContextFreeBSD_arm64::GetRegisterSetCount() const {
+  return GetRegisterInfo().GetRegisterSetCount();
+}
+
+const RegisterSet *
+NativeRegisterContextFreeBSD_arm64::GetRegisterSet(uint32_t set_index) const {
+  return GetRegisterInfo().GetRegisterSet(set_index);
+}
+
+uint32_t NativeRegisterContextFreeBSD_arm64::GetUserRegisterCount() const {
+  uint32_t count = 0;
+  for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
+    count += GetRegisterSet(set_index)->num_registers;
+  return count;
+}
+
+Status NativeRegisterContextFreeBSD_arm64::ReadRegisterSet(uint32_t set) {
+  switch (set) {
+  case RegisterInfoPOSIX_arm64::GPRegSet:
+    return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+                                               m_reg_data.data());
+  case RegisterInfoPOSIX_arm64::FPRegSet:
+    return NativeProcessFreeBSD::PtraceWrapper(
+        PT_GETFPREGS, m_thread.GetID(),
+        m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR));
+  case RegisterInfoPOSIX_arm64::SVERegSet:
+    return Status("not supported");
+  }
+  llvm_unreachable("NativeRegisterContextFreeBSD_arm64::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_arm64::WriteRegisterSet(uint32_t set) {
+  switch (set) {
+  case RegisterInfoPOSIX_arm64::GPRegSet:
+    return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+                                               m_reg_data.data());
+  case RegisterInfoPOSIX_arm64::FPRegSet:
+    return NativeProcessFreeBSD::PtraceWrapper(
+        PT_SETFPREGS, m_thread.GetID(),
+        m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR));
+  case RegisterInfoPOSIX_arm64::SVERegSet:
+    return Status("not supported");
+  }
+  llvm_unreachable("NativeRegisterContextFreeBSD_arm64::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo *reg_info,
+                                                 RegisterValue &reg_value) {
+  Status error;
+
+  if (!reg_info) {
+    error.SetErrorString("reg_info NULL");
+    return error;
+  }
+
+  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+  if (reg == LLDB_INVALID_REGNUM)
+    return Status("no lldb regnum for %s", reg_info && reg_info->name
+                                               ? reg_info->name
+                                               : "<unknown register>");
+
+  uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
+  error = ReadRegisterSet(set);
+  if (error.Fail())
+    return error;
+
+  assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+  reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
+                     reg_info->byte_size, endian::InlHostByteOrder());
+  return error;
+}
+
+Status NativeRegisterContextFreeBSD_arm64::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+  Status error;
+
+  if (!reg_info)
+    return Status("reg_info NULL");
+
+  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+  if (reg == LLDB_INVALID_REGNUM)
+    return Status("no lldb regnum for %s", reg_info && reg_info->name
+                                               ? reg_info->name
+                                               : "<unknown register>");
+
+  uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
+  error = ReadRegisterSet(set);
+  if (error.Fail())
+    return error;
+
+  assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
+  ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
+           reg_info->byte_size);
+
+  return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_arm64::ReadAllRegisterValues(
+    lldb::DataBufferSP &data_sp) {
+  Status error;
+
+  error = ReadRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet);
+  if (error.Fail())
+    return error;
+
+  error = ReadRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet);
+  if (error.Fail())
+    return error;
+
+  data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
+  uint8_t *dst = data_sp->GetBytes();
+  ::memcpy(dst, m_reg_data.data(), m_reg_data.size());
+
+  return error;
+}
+
+Status NativeRegisterContextFreeBSD_arm64::WriteAllRegisterValues(
+    const lldb::DataBufferSP &data_sp) {
+  Status error;
+
+  if (!data_sp) {
+    error.SetErrorStringWithFormat(
+        "NativeRegisterContextFreeBSD_arm64::%s invalid data_sp provided",
+        __FUNCTION__);
+    return error;
+  }
+
+  if (data_sp->GetByteSize() != m_reg_data.size()) {
+    error.SetErrorStringWithFormat(
+        "NativeRegisterContextFreeBSD_arm64::%s data_sp contained mismatched "
+        "data size, expected %" PRIu64 ", actual %" PRIu64,
+        __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
+    return error;
+  }
+
+  uint8_t *src = data_sp->GetBytes();
+  if (src == nullptr) {
+    error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm64::%s "
+                                   "DataBuffer::GetBytes() returned a null "
+                                   "pointer",
+                                   __FUNCTION__);
+    return error;
+  }
+  ::memcpy(m_reg_data.data(), src, m_reg_data.size());
+
+  error = WriteRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet);
+  if (error.Fail())
+    return error;
+
+  return WriteRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet);
+}
+
+llvm::Error NativeRegisterContextFreeBSD_arm64::CopyHardwareWatchpointsFrom(
+    NativeRegisterContextFreeBSD &source) {
+  return llvm::Error::success();
+}
+
+#endif // defined (__aarch64__)
Index: lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
+++ lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_lldb_library(lldbPluginProcessFreeBSDRemote
   NativeProcessFreeBSD.cpp
   NativeRegisterContextFreeBSD.cpp
+  NativeRegisterContextFreeBSD_arm64.cpp
   NativeRegisterContextFreeBSD_x86_64.cpp
   NativeThreadFreeBSD.cpp
 
Index: lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
===================================================================
--- lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -253,9 +253,9 @@
     bool use_legacy_plugin;
 
     switch (host_triple.getArch()) {
+      case llvm::Triple::aarch64:
       case llvm::Triple::x86:
       case llvm::Triple::x86_64:
-        // FreeBSDRemote plugin supports x86 only at the moment
         use_legacy_plugin = !!getenv("FREEBSD_LEGACY_PLUGIN");
         break;
       default:
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to