[lldb] [llvm] [lldb][FreeBSD][AArch64] Enable register field detection (PR #85058)

David Spickett via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 2 04:25:15 PDT 2024


https://github.com/DavidSpickett updated https://github.com/llvm/llvm-project/pull/85058

>From a18b685eda074527abdd127456681b03ec2aed0f Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Mon, 4 Mar 2024 14:31:40 +0000
Subject: [PATCH] [lldb][FreeBSD][AArch64] Enable register field detection

This extends the existing register fields support from AArch64 Linux
to AArch64 FreeBSD. So you will now see output like this:
```
(lldb) register read cpsr
    cpsr = 0x60000200
         = (N = 0, Z = 1, C = 1, V = 0, DIT = 0, SS = 0, IL = 0, SSBS = 0, D = 1, A = 0, I = 0, F = 0, nRW = 0, EL = 0, SP = 0)
```

Linux and FreeBSD both have HWCAP/HWCAP2 so the detection mechanism
is the same and I've renamed the detector class to reflect that.

I have confirmed that FreeBSD's treatment of CPSR (spsr as the kernel
calls it) is similair enough that we can use the same field information.

(see `sys/arm64/include/armreg.h` and `PSR_SETTABLE_64`)

For testing I've enabled the same live process test as Linux
and added a shell test using an existing FreeBSD core file.

Note that the latter does not need XML support because when reading
a core file we are not sending the information via target.xml,
it's just internal to LLDB.

The `svcr` and `mte_ctrl` registers will not appear on FreeBSD
at all so I've not made their information conditional, it'll just
never be used.
---
 .../FreeBSD/NativeRegisterContextFreeBSD.h    |  5 +-
 .../NativeRegisterContextFreeBSD_arm.cpp      |  4 +-
 .../NativeRegisterContextFreeBSD_arm64.cpp    | 24 +++++++++-
 .../NativeRegisterContextFreeBSD_arm64.h      |  2 +-
 .../NativeRegisterContextFreeBSD_mips64.cpp   |  4 +-
 .../NativeRegisterContextFreeBSD_powerpc.cpp  |  4 +-
 .../NativeRegisterContextFreeBSD_x86_64.cpp   |  4 +-
 .../Process/FreeBSD/NativeThreadFreeBSD.cpp   |  4 ++
 .../Process/FreeBSD/NativeThreadFreeBSD.h     |  2 +
 .../NativeRegisterContextLinux_arm64.cpp      | 16 +++----
 .../Plugins/Process/Utility/CMakeLists.txt    |  2 +-
 ...64.cpp => RegisterFlagsDetector_arm64.cpp} | 46 ++++++++++---------
 ..._arm64.h => RegisterFlagsDetector_arm64.h} | 18 ++++----
 .../RegisterContextPOSIXCore_arm64.cpp        | 18 ++++----
 .../elf-core/RegisterContextPOSIXCore_arm64.h |  4 +-
 .../register_command/TestRegisters.py         |  2 +-
 .../Core/aarch64-freebsd-register-fields.test | 15 ++++++
 llvm/docs/ReleaseNotes.rst                    |  3 ++
 .../source/Plugins/Process/Utility/BUILD.gn   |  2 +-
 19 files changed, 114 insertions(+), 65 deletions(-)
 rename lldb/source/Plugins/Process/Utility/{RegisterFlagsLinux_arm64.cpp => RegisterFlagsDetector_arm64.cpp} (80%)
 rename lldb/source/Plugins/Process/Utility/{RegisterFlagsLinux_arm64.h => RegisterFlagsDetector_arm64.h} (83%)
 create mode 100644 lldb/test/Shell/Register/Core/aarch64-freebsd-register-fields.test

diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h
index 0000484beac999..b7f659ef24de2c 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h
@@ -9,14 +9,13 @@
 #ifndef lldb_NativeRegisterContextFreeBSD_h
 #define lldb_NativeRegisterContextFreeBSD_h
 
-#include "lldb/Host/common/NativeThreadProtocol.h"
-
 #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
 
 namespace lldb_private {
 namespace process_freebsd {
 
 class NativeProcessFreeBSD;
+class NativeThreadFreeBSD;
 
 class NativeRegisterContextFreeBSD
     : public virtual NativeRegisterContextRegisterInfo {
@@ -28,7 +27,7 @@ class NativeRegisterContextFreeBSD
   // executable.
   static NativeRegisterContextFreeBSD *
   CreateHostNativeRegisterContextFreeBSD(const ArchSpec &target_arch,
-                                         NativeThreadProtocol &native_thread);
+                                         NativeThreadFreeBSD &native_thread);
   virtual llvm::Error
   CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) = 0;
 
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp
index 2c50176643878d..f19085600d6c93 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp
@@ -29,12 +29,12 @@ using namespace lldb_private::process_freebsd;
 
 NativeRegisterContextFreeBSD *
 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
   return new NativeRegisterContextFreeBSD_arm(target_arch, native_thread);
 }
 
 NativeRegisterContextFreeBSD_arm::NativeRegisterContextFreeBSD_arm(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
     : NativeRegisterContextRegisterInfo(
           native_thread, new RegisterInfoPOSIX_arm(target_arch)) {}
 
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
index 9db5970af653e3..28ea8b7ac11826 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
@@ -16,6 +16,7 @@
 
 #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 
 // clang-format off
@@ -28,14 +29,29 @@ using namespace lldb;
 using namespace lldb_private;
 using namespace lldb_private::process_freebsd;
 
+// A NativeRegisterContext is constructed per thread, but all threads' registers
+// will contain the same fields. Therefore this mutex prevents each instance
+// competing with the other, and subsequent instances from having to detect the
+// fields all over again.
+static std::mutex g_register_flags_detector_mutex;
+static Arm64RegisterFlagsDetector g_register_flags_detector;
+
 NativeRegisterContextFreeBSD *
 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
+  std::lock_guard<std::mutex> lock(g_register_flags_detector_mutex);
+  if (!g_register_flags_detector.HasDetected()) {
+    NativeProcessFreeBSD &process = native_thread.GetProcess();
+    g_register_flags_detector.DetectFields(
+        process.GetAuxValue(AuxVector::AUXV_FREEBSD_AT_HWCAP).value_or(0),
+        process.GetAuxValue(AuxVector::AUXV_AT_HWCAP2).value_or(0));
+  }
+
   return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread);
 }
 
 NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
     : NativeRegisterContextRegisterInfo(
           native_thread, new RegisterInfoPOSIX_arm64(target_arch, 0))
 #ifdef LLDB_HAS_FREEBSD_WATCHPOINT
@@ -43,6 +59,10 @@ NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64(
       m_read_dbreg(false)
 #endif
 {
+  g_register_flags_detector.UpdateRegisterInfo(
+      GetRegisterInfoInterface().GetRegisterInfo(),
+      GetRegisterInfoInterface().GetRegisterCount());
+
   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
   ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
 }
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
index 799209e26e868d..ba876006c6c530 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h
@@ -37,7 +37,7 @@ class NativeRegisterContextFreeBSD_arm64
       public NativeRegisterContextDBReg_arm64 {
 public:
   NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch,
-                                     NativeThreadProtocol &native_thread);
+                                     NativeThreadFreeBSD &native_thread);
 
   uint32_t GetRegisterSetCount() const override;
 
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp
index 0349f13945e31c..090d0f3802c3bb 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp
@@ -30,12 +30,12 @@ using namespace lldb_private::process_freebsd;
 
 NativeRegisterContextFreeBSD *
 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
   return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread);
 }
 
 NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
     : NativeRegisterContextRegisterInfo(
           native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {}
 
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp
index bdb57251f706a4..fd5eb1ee2a1c84 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp
@@ -67,7 +67,7 @@ static const RegisterSet g_reg_sets_powerpc[k_num_register_sets] = {
 
 NativeRegisterContextFreeBSD *
 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
   return new NativeRegisterContextFreeBSD_powerpc(target_arch, native_thread);
 }
 
@@ -83,7 +83,7 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) {
 }
 
 NativeRegisterContextFreeBSD_powerpc::NativeRegisterContextFreeBSD_powerpc(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
     : NativeRegisterContextRegisterInfo(
           native_thread, CreateRegisterInfoInterface(target_arch)) {}
 
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp
index f4171a134aeb79..5eed2d02b0a8ce 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp
@@ -237,7 +237,7 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
 
 NativeRegisterContextFreeBSD *
 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
   return new NativeRegisterContextFreeBSD_x86_64(target_arch, native_thread);
 }
 
@@ -258,7 +258,7 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) {
 }
 
 NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64(
-    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+    const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
     : NativeRegisterContextRegisterInfo(
           native_thread, CreateRegisterInfoInterface(target_arch)),
       NativeRegisterContextDBReg_x86(native_thread), m_regset_offsets({0}) {
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
index 449ec27e0da8fc..a0de7751c7e55c 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp
@@ -316,6 +316,10 @@ NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) {
   return s;
 }
 
+NativeProcessFreeBSD &NativeThreadFreeBSD::GetProcess() {
+  return static_cast<NativeProcessFreeBSD &>(m_process);
+}
+
 llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
 NativeThreadFreeBSD::GetSiginfo() const {
   Log *log = GetLog(POSIXLog::Process);
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
index 6294a7a7096356..edfb07658e19c7 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h
@@ -47,6 +47,8 @@ class NativeThreadFreeBSD : public NativeThreadProtocol {
 
   Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
 
+  NativeProcessFreeBSD &GetProcess();
+
   llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
   GetSiginfo() const override;
 
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 9b5f7aef1efe53..d72b6ce9b0c8e3 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -23,7 +23,7 @@
 #include "Plugins/Process/Linux/Procfs.h"
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
 #include "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h"
-#include "Plugins/Process/Utility/RegisterFlagsLinux_arm64.h"
+#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 
 // System includes - They have to be included after framework includes because
@@ -72,8 +72,8 @@ using namespace lldb_private::process_linux;
 // will contain the same fields. Therefore this mutex prevents each instance
 // competing with the other, and subsequent instances from having to detect the
 // fields all over again.
-static std::mutex g_register_flags_mutex;
-static LinuxArm64RegisterFlags g_register_flags;
+static std::mutex g_register_flags_detector_mutex;
+static Arm64RegisterFlagsDetector g_register_flags_detector;
 
 std::unique_ptr<NativeRegisterContextLinux>
 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
@@ -144,10 +144,10 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
 
     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS);
 
-    std::lock_guard<std::mutex> lock(g_register_flags_mutex);
-    if (!g_register_flags.HasDetected())
-      g_register_flags.DetectFields(auxv_at_hwcap.value_or(0),
-                                    auxv_at_hwcap2.value_or(0));
+    std::lock_guard<std::mutex> lock(g_register_flags_detector_mutex);
+    if (!g_register_flags_detector.HasDetected())
+      g_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
+                                             auxv_at_hwcap2.value_or(0));
 
     auto register_info_up =
         std::make_unique<RegisterInfoPOSIX_arm64>(target_arch, opt_regsets);
@@ -171,7 +171,7 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
     : NativeRegisterContextRegisterInfo(native_thread,
                                         register_info_up.release()),
       NativeRegisterContextLinux(native_thread) {
-  g_register_flags.UpdateRegisterInfo(
+  g_register_flags_detector.UpdateRegisterInfo(
       GetRegisterInfoInterface().GetRegisterInfo(),
       GetRegisterInfoInterface().GetRegisterCount());
 
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 37b53b7e3e7edd..5df4a9e5ac5c86 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -47,7 +47,7 @@ add_lldb_library(lldbPluginProcessUtility
   RegisterContextThreadMemory.cpp
   RegisterContextWindows_i386.cpp
   RegisterContextWindows_x86_64.cpp
-  RegisterFlagsLinux_arm64.cpp
+  RegisterFlagsDetector_arm64.cpp
   RegisterInfos_x86_64_with_base_shared.cpp
   RegisterInfoPOSIX_arm.cpp
   RegisterInfoPOSIX_arm64.cpp
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
similarity index 80%
rename from lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp
rename to lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
index 51553817921f35..54c1aae36f231c 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
@@ -1,4 +1,4 @@
-//===-- RegisterFlagsLinux_arm64.cpp --------------------------------------===//
+//===-- RegisterFlagsDetector_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.
@@ -6,11 +6,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "RegisterFlagsLinux_arm64.h"
+#include "RegisterFlagsDetector_arm64.h"
 #include "lldb/lldb-private-types.h"
 
 // This file is built on all systems because it is used by native processes and
 // core files, so we manually define the needed HWCAP values here.
+// These values are the same for Linux and FreeBSD.
 
 #define HWCAP_FPHP (1ULL << 9)
 #define HWCAP_ASIMDHP (1ULL << 10)
@@ -24,34 +25,35 @@
 
 using namespace lldb_private;
 
-LinuxArm64RegisterFlags::Fields
-LinuxArm64RegisterFlags::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
   (void)hwcap;
   (void)hwcap2;
-  // Represents the pseudo register that lldb-server builds, which itself
-  // matches the architectural register SCVR. The fields match SVCR in the Arm
-  // manual.
+  // Represents the pseudo register that lldb-server on Linux builds, which
+  // itself matches the architectural register SCVR. The fields match SVCR in
+  // the Arm manual.
   return {
       {"ZA", 1},
       {"SM", 0},
   };
 }
 
-LinuxArm64RegisterFlags::Fields
-LinuxArm64RegisterFlags::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2) {
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap,
+                                                uint64_t hwcap2) {
   (void)hwcap;
   (void)hwcap2;
-  // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
-  // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
-  // used to build the value.
+  // Represents the contents of Linux's NT_ARM_TAGGED_ADDR_CTRL and the value
+  // passed to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the
+  // defines used to build the value.
   return {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT.
           {"TCF_ASYNC", 2},
           {"TCF_SYNC", 1},
           {"TAGGED_ADDR_ENABLE", 0}};
 }
 
-LinuxArm64RegisterFlags::Fields
-LinuxArm64RegisterFlags::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) {
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) {
   std::vector<RegisterFlags::Field> fpcr_fields{
       {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23},
       // Bits 21-20 are "Stride" which is unused in AArch64 state.
@@ -86,8 +88,8 @@ LinuxArm64RegisterFlags::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) {
   return fpcr_fields;
 }
 
-LinuxArm64RegisterFlags::Fields
-LinuxArm64RegisterFlags::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) {
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) {
   // fpsr's contents are constant.
   (void)hwcap;
   (void)hwcap2;
@@ -106,8 +108,8 @@ LinuxArm64RegisterFlags::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) {
   };
 }
 
-LinuxArm64RegisterFlags::Fields
-LinuxArm64RegisterFlags::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) {
+Arm64RegisterFlagsDetector::Fields
+Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) {
   // The fields here are a combination of the Arm manual's SPSR_EL1,
   // plus a few changes where Linux has decided not to make use of them at all,
   // or at least not from userspace.
@@ -124,7 +126,7 @@ LinuxArm64RegisterFlags::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) {
     cpsr_fields.push_back({"DIT", 24});
 
   // UAO and PAN are bits 23 and 22 and have no meaning for userspace so
-  // are treated as reserved by the kernel.
+  // are treated as reserved by the kernels.
 
   cpsr_fields.push_back({"SS", 21});
   cpsr_fields.push_back({"IL", 20});
@@ -152,14 +154,14 @@ LinuxArm64RegisterFlags::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) {
   return cpsr_fields;
 }
 
-void LinuxArm64RegisterFlags::DetectFields(uint64_t hwcap, uint64_t hwcap2) {
+void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2) {
   for (auto &reg : m_registers)
     reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2));
   m_has_detected = true;
 }
 
-void LinuxArm64RegisterFlags::UpdateRegisterInfo(const RegisterInfo *reg_info,
-                                                 uint32_t num_regs) {
+void Arm64RegisterFlagsDetector::UpdateRegisterInfo(
+    const RegisterInfo *reg_info, uint32_t num_regs) {
   assert(m_has_detected &&
          "Must call DetectFields before updating register info.");
 
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
similarity index 83%
rename from lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h
rename to lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
index 660bef08700f4c..62c9341beffa5c 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
@@ -1,4 +1,4 @@
-//===-- RegisterFlagsLinux_arm64.h ------------------------------*- C++ -*-===//
+//===-- RegisterFlagsDetector_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.
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H
-#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
 
 #include "lldb/Target/RegisterFlags.h"
 #include "llvm/ADT/StringRef.h"
@@ -18,9 +18,9 @@ namespace lldb_private {
 struct RegisterInfo;
 
 /// This class manages the storage and detection of register field information
-/// for Arm64 Linux registers. The same register may have different fields on
-/// different CPUs. This class abstracts out the field detection process so we
-/// can use it on live processes and core files.
+/// for Arm64 Linux and FreeBSD registers. The same register may have different
+/// fields on different CPUs. This class abstracts out the field detection
+/// process so we can use it on live processes and core files.
 ///
 /// The general way to use this class is:
 /// * Make an instance somewhere that will last as long as the debug session
@@ -33,7 +33,7 @@ struct RegisterInfo;
 /// This must be done in that order, and you should ensure that if multiple
 /// threads will reference the information, a mutex is used to make sure only
 /// one calls DetectFields.
-class LinuxArm64RegisterFlags {
+class Arm64RegisterFlagsDetector {
 public:
   /// For the registers listed in this class, detect which fields are
   /// present. Must be called before UpdateRegisterInfos.
@@ -73,7 +73,9 @@ class LinuxArm64RegisterFlags {
       RegisterEntry("cpsr", 4, DetectCPSRFields),
       RegisterEntry("fpsr", 4, DetectFPSRFields),
       RegisterEntry("fpcr", 4, DetectFPCRFields),
+      // Linux only, won't be found on FreeBSD.
       RegisterEntry("mte_ctrl", 8, DetectMTECtrlFields),
+      // Linux only, won't be found on FreeBSD.
       RegisterEntry("svcr", 8, DetectSVCRFields),
   };
 
@@ -83,4 +85,4 @@ class LinuxArm64RegisterFlags {
 
 } // namespace lldb_private
 
-#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H
\ No newline at end of file
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
\ No newline at end of file
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
index 07501c10ec3c92..413bf1bbdb2a58 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
@@ -10,7 +10,7 @@
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 
 #include "Plugins/Process/Utility/AuxVector.h"
-#include "Plugins/Process/Utility/RegisterFlagsLinux_arm64.h"
+#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
 #include "Plugins/Process/elf-core/ProcessElfCore.h"
 #include "Plugins/Process/elf-core/RegisterUtilities.h"
 #include "lldb/Target/Thread.h"
@@ -79,17 +79,19 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
 
   ProcessElfCore *process =
       static_cast<ProcessElfCore *>(thread.GetProcess().get());
-  if (process->GetArchitecture().GetTriple().getOS() == llvm::Triple::Linux) {
+  llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS();
+  if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) {
     AuxVector aux_vec(process->GetAuxvData());
-    std::optional<uint64_t> auxv_at_hwcap =
-        aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP);
+    std::optional<uint64_t> auxv_at_hwcap = aux_vec.GetAuxValue(
+        os == llvm::Triple::FreeBSD ? AuxVector::AUXV_FREEBSD_AT_HWCAP
+                                    : AuxVector::AUXV_AT_HWCAP);
     std::optional<uint64_t> auxv_at_hwcap2 =
         aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2);
 
-    m_linux_register_flags.DetectFields(auxv_at_hwcap.value_or(0),
-                                        auxv_at_hwcap2.value_or(0));
-    m_linux_register_flags.UpdateRegisterInfo(GetRegisterInfo(),
-                                              GetRegisterCount());
+    m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
+                                           auxv_at_hwcap2.value_or(0));
+    m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(),
+                                                 GetRegisterCount());
   }
 
   m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
index 38e958851dfe23..ff94845e58d602 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
@@ -11,7 +11,7 @@
 
 #include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h"
 #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
-#include "Plugins/Process/Utility/RegisterFlagsLinux_arm64.h"
+#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
 
 #include "Plugins/Process/elf-core/RegisterUtilities.h"
 #include "lldb/Utility/DataBufferHeap.h"
@@ -75,7 +75,7 @@ class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 {
 
   struct sme_pseudo_regs m_sme_pseudo_regs;
 
-  lldb_private::LinuxArm64RegisterFlags m_linux_register_flags;
+  lldb_private::Arm64RegisterFlagsDetector m_register_flags_detector;
 
   const uint8_t *GetSVEBuffer(uint64_t offset = 0);
 
diff --git a/lldb/test/API/commands/register/register/register_command/TestRegisters.py b/lldb/test/API/commands/register/register/register_command/TestRegisters.py
index 5c4f3a4bb374c2..dd887740c3c12e 100644
--- a/lldb/test/API/commands/register/register/register_command/TestRegisters.py
+++ b/lldb/test/API/commands/register/register/register_command/TestRegisters.py
@@ -619,7 +619,7 @@ def test_info_register(self):
         self.expect("register info x30", substrs=["Name: lr (x30)"])
 
     @skipIfXmlSupportMissing
-    @skipUnlessPlatform(["linux"])
+    @skipUnlessPlatform(["linux", "freebsd"])
     @skipIf(archs=no_match(["aarch64"]))
     def test_register_read_fields(self):
         """Test that when debugging a live process, we see the fields of certain
diff --git a/lldb/test/Shell/Register/Core/aarch64-freebsd-register-fields.test b/lldb/test/Shell/Register/Core/aarch64-freebsd-register-fields.test
new file mode 100644
index 00000000000000..0c8b52c14b964b
--- /dev/null
+++ b/lldb/test/Shell/Register/Core/aarch64-freebsd-register-fields.test
@@ -0,0 +1,15 @@
+# RUN: %lldb -b -s %s -c %p/Inputs/aarch64-freebsd-multithread.core | FileCheck %s
+
+# Check that we see register fields for control registers when using a core file.
+# As this is a corefile we check all fields as they will always be the same
+# (on real cores they may vary).
+
+register read cpsr
+# CHECK:      cpsr = 0x60000200
+# CHECK-NEXT:      = (N = 0, Z = 1, C = 1, V = 0, SS = 0, IL = 0, D = 1, A = 0, I = 0, F = 0, nRW = 0, EL = 0, SP = 0)
+register read fpsr
+# CHECK:      fpsr = 0x00000000
+# CHECK-NEXT:      = (QC = 0, IDC = 0, IXC = 0, UFC = 0, OFC = 0, DZC = 0, IOC = 0)
+register read fpcr
+# CHECK:      fpcr = 0x02000000
+# CHECK-NEXT:      = (AHP = 0, DN = 1, FZ = 0, RMode = 0, IDE = 0, IXE = 0, UFE = 0, OFE = 0, DZE = 0, IOE = 0)
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 7588048334d792..ebd8c9a464d0fb 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -190,6 +190,9 @@ Changes to the LLVM tools
 Changes to LLDB
 ---------------------------------
 
+* Register field information is now provided on AArch64 FreeBSD for live
+  processes and core files (previously only provided on AArch64 Linux).
+
 Changes to Sanitizers
 ---------------------
 
diff --git a/llvm/utils/gn/secondary/lldb/source/Plugins/Process/Utility/BUILD.gn b/llvm/utils/gn/secondary/lldb/source/Plugins/Process/Utility/BUILD.gn
index 4d98de81f3c26e..acf279bf16373c 100644
--- a/llvm/utils/gn/secondary/lldb/source/Plugins/Process/Utility/BUILD.gn
+++ b/llvm/utils/gn/secondary/lldb/source/Plugins/Process/Utility/BUILD.gn
@@ -66,7 +66,7 @@ static_library("Utility") {
     "RegisterContextWindows_i386.cpp",
     "RegisterContextWindows_x86_64.cpp",
     "RegisterContext_x86.cpp",
-    "RegisterFlagsLinux_arm64.cpp",
+    "RegisterFlagsDetector_arm64.cpp",
     "RegisterInfoPOSIX_arm.cpp",
     "RegisterInfoPOSIX_arm64.cpp",
     "RegisterInfoPOSIX_loongarch64.cpp",



More information about the llvm-commits mailing list