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

David Spickett via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 13 03:42:08 PDT 2024


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

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.

>From a251b494614a0700f424c2bedebcabd2e053a653 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Wed, 6 Mar 2024 09:08:25 +0000
Subject: [PATCH 1/3] [lldb][FreeBSD] Add FreeBSD specific AT_HWCAP2 value

While adding register fields I realised that the AUXV values
for Linux and FreeBSD disagree here.

So I've added a FreeBSD specific HWCAP2 value that I can
use from FreeBSD specific code.

The alternative is translating GetAuxValue calls depending
on platform, which requires that we know what we are at all
times.

Another way would be to convert the entries' values when
we construct the AuxVector but the platform specific call
that reads the data just returns a raw array. So adding
another layer here is more disruption.
---
 lldb/source/Plugins/Process/Utility/AuxVector.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h
index 3b0f55d35e5d11..237c120a426941 100644
--- a/lldb/source/Plugins/Process/Utility/AuxVector.h
+++ b/lldb/source/Plugins/Process/Utility/AuxVector.h
@@ -20,9 +20,13 @@ class AuxVector {
   AuxVector(const lldb_private::DataExtractor &data);
 
   /// Constants describing the type of entry.
-  /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX
+  /// On Linux and FreeBSD, running "LD_SHOW_AUXV=1 ./executable" will spew AUX
   /// information. Added AUXV prefix to avoid potential conflicts with system-
-  /// defined macros
+  /// defined macros. For FreeBSD, the numbers can be found in sys/elf_common.h.
+  ///
+  /// Linux and FreeBSD values diverge, so the FreeBSD classes will convert
+  /// some entries to the Linux AT_ value so that LLDB only has to use
+  /// the constants listed here when asking the AuxVector for a value.
   enum EntryType {
     AUXV_AT_NULL = 0,      ///< End of auxv.
     AUXV_AT_IGNORE = 1,    ///< Ignore entry.
@@ -39,6 +43,11 @@ class AuxVector {
     AUXV_AT_EUID = 12,     ///< Effective UID.
     AUXV_AT_GID = 13,      ///< GID.
     AUXV_AT_EGID = 14,     ///< Effective GID.
+
+    // At this point Linux and FreeBSD diverge and many of the following values
+    // are Linux specific. If you use them make sure you are in Linux specific
+    // code or they have the same value on other platforms.
+
     AUXV_AT_CLKTCK = 17,   ///< Clock frequency (e.g. times(2)).
     AUXV_AT_PLATFORM = 15, ///< String identifying platform.
     AUXV_AT_HWCAP =
@@ -60,6 +69,10 @@ class AuxVector {
     AUXV_AT_L1D_CACHESHAPE = 35,
     AUXV_AT_L2_CACHESHAPE = 36,
     AUXV_AT_L3_CACHESHAPE = 37,
+
+    // Platform specific values which may overlap the Linux values.
+
+    AUXV_FREEBSD_AT_HWCAP = 25, ///< FreeBSD specific AT_HWCAP value.
   };
 
   std::optional<uint64_t> GetAuxValue(enum EntryType entry_type) const;

>From 546c7a728041db2e6f55bc6bce7231640da85bee Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Wed, 6 Mar 2024 09:13:37 +0000
Subject: [PATCH 2/3] [lldb] clang-format AuxVector.h

Doing this in its own commit so the intent of the previous
change is clearer.
---
 .../Plugins/Process/Utility/AuxVector.h       | 30 +++++++++----------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h
index 237c120a426941..9e489b05ab5ee6 100644
--- a/lldb/source/Plugins/Process/Utility/AuxVector.h
+++ b/lldb/source/Plugins/Process/Utility/AuxVector.h
@@ -28,21 +28,21 @@ class AuxVector {
   /// some entries to the Linux AT_ value so that LLDB only has to use
   /// the constants listed here when asking the AuxVector for a value.
   enum EntryType {
-    AUXV_AT_NULL = 0,      ///< End of auxv.
-    AUXV_AT_IGNORE = 1,    ///< Ignore entry.
-    AUXV_AT_EXECFD = 2,    ///< File descriptor of program.
-    AUXV_AT_PHDR = 3,      ///< Program headers.
-    AUXV_AT_PHENT = 4,     ///< Size of program header.
-    AUXV_AT_PHNUM = 5,     ///< Number of program headers.
-    AUXV_AT_PAGESZ = 6,    ///< Page size.
-    AUXV_AT_BASE = 7,      ///< Interpreter base address.
-    AUXV_AT_FLAGS = 8,     ///< Flags.
-    AUXV_AT_ENTRY = 9,     ///< Program entry point.
-    AUXV_AT_NOTELF = 10,   ///< Set if program is not an ELF.
-    AUXV_AT_UID = 11,      ///< UID.
-    AUXV_AT_EUID = 12,     ///< Effective UID.
-    AUXV_AT_GID = 13,      ///< GID.
-    AUXV_AT_EGID = 14,     ///< Effective GID.
+    AUXV_AT_NULL = 0,    ///< End of auxv.
+    AUXV_AT_IGNORE = 1,  ///< Ignore entry.
+    AUXV_AT_EXECFD = 2,  ///< File descriptor of program.
+    AUXV_AT_PHDR = 3,    ///< Program headers.
+    AUXV_AT_PHENT = 4,   ///< Size of program header.
+    AUXV_AT_PHNUM = 5,   ///< Number of program headers.
+    AUXV_AT_PAGESZ = 6,  ///< Page size.
+    AUXV_AT_BASE = 7,    ///< Interpreter base address.
+    AUXV_AT_FLAGS = 8,   ///< Flags.
+    AUXV_AT_ENTRY = 9,   ///< Program entry point.
+    AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF.
+    AUXV_AT_UID = 11,    ///< UID.
+    AUXV_AT_EUID = 12,   ///< Effective UID.
+    AUXV_AT_GID = 13,    ///< GID.
+    AUXV_AT_EGID = 14,   ///< Effective GID.
 
     // At this point Linux and FreeBSD diverge and many of the following values
     // are Linux specific. If you use them make sure you are in Linux specific

>From 146be6d33e8e145d94160ef7ac7295f4a31b8c1c 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 3/3] [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 8ce6ee5cebb266..bea301ef36a28e 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -155,6 +155,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