Skip to content

[lldb][Process/FreeBSDKernelCore] Add assertion for pcb#183969

Merged
mchoo7 merged 2 commits intollvm:mainfrom
mchoo7:pcb
Mar 12, 2026
Merged

[lldb][Process/FreeBSDKernelCore] Add assertion for pcb#183969
mchoo7 merged 2 commits intollvm:mainfrom
mchoo7:pcb

Conversation

@mchoo7
Copy link
Copy Markdown
Contributor

@mchoo7 mchoo7 commented Mar 1, 2026

pcb layout is not stable yet so it can be changed anytime on FreeBSD side. Changes to pcb might not be reflected to FreeBSD source tree or upstream LLDB possibly because the developer forgot to do so, which breaks kernel debugging functionality. This patch adds assertion thus LLDB cannot be built if its expected pcb layout doesn't match the real one. This assertion is only enabled when the build machine architecture matches RegisterContextFreeBSDKernelCore_<arch>.

Due to identifier conflict, I had to lower PCB_FP and PCB_LR.

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 1, 2026

@llvm/pr-subscribers-lldb

Author: Minsoo Choo (mchoo7)

Changes

Add offset check for pcb structs. This is only enabled when the host machine architecture matches the architecture of register context its building. Note that &lt;machine/foo.h&gt; is dependent on host machine not the target, so #ifdef __arch__ cannot be used here. List of HOST_ARCH is available here.

Due to identifier conflict, I had to lower PCB_FP and PCB_LR.


Full diff: https://github.com/llvm/llvm-project/pull/183969.diff

7 Files Affected:

  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt (+8)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp (+32)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp (+21-4)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp (+14)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp (+14)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp (+13)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp (+16)
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt
index 1937143171369..b5ea4772a8b92 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt
@@ -1,3 +1,11 @@
+# Used for pcb assertion
+# List of architectures:
+# https://man.freebsd.org/cgi/man.cgi?query=arch&apropos=0&sektion=0&manpath=FreeBSD+16.0-CURRENT&format=html
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "FreeBSD")
+    set(HOST_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR})
+    add_definitions(-DFreeBSD_${HOST_ARCH})
+endif()
+
 lldb_tablegen(ProcessFreeBSDKernelCoreProperties.inc -gen-lldb-property-defs
   SOURCE ProcessFreeBSDKernelCoreProperties.td
   TARGET LLDBPluginProcessFreeBSDKernelCorePropertiesGen)
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp
index 0d01a0ec48d3e..9738fc42b0b5e 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp
@@ -14,6 +14,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_armv7
+#include <cstddef>
+#include <machine/frame.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -61,6 +66,33 @@ bool RegisterContextFreeBSDKernelCore_arm::ReadRegister(
     llvm::support::ulittle32_t pc;
   } pcb;
 
+#ifdef FreeBSD_armv7
+  static_assert(offsetof(struct switchframe, sf_r4) ==
+                offsetof(decltype(pcb), r4));
+  static_assert(offsetof(struct switchframe, sf_r5) ==
+                offsetof(decltype(pcb), r5));
+  static_assert(offsetof(struct switchframe, sf_r6) ==
+                offsetof(decltype(pcb), r6));
+  static_assert(offsetof(struct switchframe, sf_r7) ==
+                offsetof(decltype(pcb), r7));
+  static_assert(offsetof(struct switchframe, sf_r8) ==
+                offsetof(decltype(pcb), r8));
+  static_assert(offsetof(struct switchframe, sf_r9) ==
+                offsetof(decltype(pcb), r9));
+  static_assert(offsetof(struct switchframe, sf_r10) ==
+                offsetof(decltype(pcb), r10));
+  static_assert(offsetof(struct switchframe, sf_r11) ==
+                offsetof(decltype(pcb), r11));
+  static_assert(offsetof(struct switchframe, sf_r12) ==
+                offsetof(decltype(pcb), r12));
+  static_assert(offsetof(struct switchframe, sf_sp) ==
+                offsetof(decltype(pcb), sp));
+  static_assert(offsetof(struct switchframe, sf_lr) ==
+                offsetof(decltype(pcb), lr));
+  static_assert(offsetof(struct switchframe, sf_pc) ==
+                offsetof(decltype(pcb), pc));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp
index afd60a64a6365..1931d7bfdbb93 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp
@@ -18,6 +18,12 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_aarch64
+#include <cstddef>
+#include <machine/pcb.h>
+#include <sys/param.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -52,6 +58,11 @@ bool RegisterContextFreeBSDKernelCore_arm64::ReadRegister(
     llvm::support::ulittle64_t sp;
   } pcb;
 
+#if defined(FreeBSD_aarch64) && __FreeBSD_version >= 1400084
+  static_assert(offsetof(struct pcb, pcb_x) == offsetof(decltype(pcb), x));
+  static_assert(offsetof(struct pcb, pcb_sp) == offsetof(decltype(pcb), sp));
+#endif
+
   // https://cgit.freebsd.org/src/tree/sys/arm64/include/pcb.h?h=stable%2F13
   struct {
     llvm::support::ulittle64_t x[30];
@@ -60,6 +71,12 @@ bool RegisterContextFreeBSDKernelCore_arm64::ReadRegister(
     llvm::support::ulittle64_t sp;
   } pcb13;
 
+#if defined(FreeBSD_aarch64) && __FreeBSD_version < 1400084
+  static_assert(offsetof(struct pcb, pcb_x) == offsetof(decltype(pcb13), x));
+  static_assert(offsetof(struct pcb, pcb_lr) == offsetof(decltype(pcb13), lr));
+  static_assert(offsetof(struct pcb, pcb_sp) == offsetof(decltype(pcb13), sp));
+#endif
+
   Status error;
   constexpr int FBSD14 = 1400084;
   int osreldate = FBSD14;
@@ -72,8 +89,8 @@ bool RegisterContextFreeBSDKernelCore_arm64::ReadRegister(
 
   // TODO: LLVM 24: Remove FreeBSD 13 support
   if (osreldate >= FBSD14) {
-    constexpr uint32_t PCB_FP = 10;
-    constexpr uint32_t PCB_LR = 11;
+    constexpr uint32_t pcb_fp = 10;
+    constexpr uint32_t pcb_lr = 11;
     size_t rd =
         m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
     if (rd != sizeof(pcb))
@@ -92,14 +109,14 @@ bool RegisterContextFreeBSDKernelCore_arm64::ReadRegister(
     case gpr_x27_arm64:
     case gpr_x28_arm64:
     case gpr_fp_arm64:
-      static_assert(gpr_fp_arm64 - gpr_x19_arm64 == PCB_FP,
+      static_assert(gpr_fp_arm64 - gpr_x19_arm64 == pcb_fp,
                     "nonconsecutive arm64 register numbers");
       value = pcb.x[reg - gpr_x19_arm64];
       break;
     case gpr_lr_arm64:
     case gpr_pc_arm64:
       // The pc of crashing thread is stored in lr.
-      static_assert(gpr_lr_arm64 - gpr_x19_arm64 == PCB_LR,
+      static_assert(gpr_lr_arm64 - gpr_x19_arm64 == pcb_lr,
                     "nonconsecutive arm64 register numbers");
       value = pcb.x[reg - gpr_x19_arm64];
       break;
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp
index 83ab12c73b918..b2b65f2380ec2 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp
@@ -13,6 +13,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_i386
+#include <cstddef>
+#include <machine/pcb.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -50,6 +55,15 @@ bool RegisterContextFreeBSDKernelCore_i386::ReadRegister(
     llvm::support::ulittle32_t eip;
   } pcb;
 
+#ifdef FreeBSD_i386
+  static_assert(offsetof(struct pcb, pcb_edi) == offsetof(decltype(pcb), edi));
+  static_assert(offsetof(struct pcb, pcb_esi) == offsetof(decltype(pcb), esi));
+  static_assert(offsetof(struct pcb, pcb_ebp) == offsetof(decltype(pcb), ebp));
+  static_assert(offsetof(struct pcb, pcb_esp) == offsetof(decltype(pcb), esp));
+  static_assert(offsetof(struct pcb, pcb_ebx) == offsetof(decltype(pcb), ebx));
+  static_assert(offsetof(struct pcb, pcb_eip) == offsetof(decltype(pcb), eip));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp
index 69932eaeb4e0b..5cc4d6cf4994e 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp
@@ -13,6 +13,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_powerpc64le
+#include <cstddef>
+#include <machine/pcb.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -37,6 +42,15 @@ bool RegisterContextFreeBSDKernelCore_ppc64le::ReadRegister(
     llvm::support::ulittle64_t lr;
   } pcb;
 
+#ifdef FreeBSD_powerpc64le
+  static_assert(offsetof(struct pcb, pcb_context) ==
+                offsetof(decltype(pcb), context));
+  static_assert(offsetof(struct pcb, pcb_cr) == offsetof(decltype(pcb), cr));
+  static_assert(offsetof(struct pcb, pcb_sp) == offsetof(decltype(pcb), sp));
+  static_assert(offsetof(struct pcb, pcb_toc) == offsetof(decltype(pcb), toc));
+  static_assert(offsetof(struct pcb, pcb_lr) == offsetof(decltype(pcb), lr));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp
index b705c6d6d43bd..00957241b9996 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp
@@ -13,6 +13,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_riscv64
+#include <cstddef>
+#include <machine/pcb.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -52,6 +57,14 @@ bool RegisterContextFreeBSDKernelCore_riscv64::ReadRegister(
     llvm::support::ulittle64_t s[12];
   } pcb;
 
+#ifdef FreeBSD_riscv64
+  static_assert(offsetof(struct pcb, pcb_ra) == offsetof(decltype(pcb), ra));
+  static_assert(offsetof(struct pcb, pcb_sp) == offsetof(decltype(pcb), sp));
+  static_assert(offsetof(struct pcb, pcb_gp) == offsetof(decltype(pcb), gp));
+  static_assert(offsetof(struct pcb, pcb_tp) == offsetof(decltype(pcb), tp));
+  static_assert(offsetof(struct pcb, pcb_s) == offsetof(decltype(pcb), s));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp
index a4fe219a2e72d..b72f5f3b08e40 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp
@@ -13,6 +13,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_amd64
+#include <cstddef>
+#include <machine/pcb.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -54,6 +59,17 @@ bool RegisterContextFreeBSDKernelCore_x86_64::ReadRegister(
     llvm::support::ulittle64_t rip;
   } pcb;
 
+#ifdef FreeBSD_amd64
+  static_assert(offsetof(struct pcb, pcb_r15) == offsetof(decltype(pcb), r15));
+  static_assert(offsetof(struct pcb, pcb_r14) == offsetof(decltype(pcb), r14));
+  static_assert(offsetof(struct pcb, pcb_r13) == offsetof(decltype(pcb), r13));
+  static_assert(offsetof(struct pcb, pcb_r12) == offsetof(decltype(pcb), r12));
+  static_assert(offsetof(struct pcb, pcb_rbp) == offsetof(decltype(pcb), rbp));
+  static_assert(offsetof(struct pcb, pcb_rsp) == offsetof(decltype(pcb), rsp));
+  static_assert(offsetof(struct pcb, pcb_rbx) == offsetof(decltype(pcb), rbx));
+  static_assert(offsetof(struct pcb, pcb_rip) == offsetof(decltype(pcb), rip));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 1, 2026

@llvm/pr-subscribers-backend-risc-v

Author: Minsoo Choo (mchoo7)

Changes

Add offset check for pcb structs. This is only enabled when the host machine architecture matches the architecture of register context its building. Note that &lt;machine/foo.h&gt; is dependent on host machine not the target, so #ifdef __arch__ cannot be used here. List of HOST_ARCH is available here.

Due to identifier conflict, I had to lower PCB_FP and PCB_LR.


Full diff: https://github.com/llvm/llvm-project/pull/183969.diff

7 Files Affected:

  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt (+8)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp (+32)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp (+21-4)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp (+14)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp (+14)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp (+13)
  • (modified) lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp (+16)
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt
index 1937143171369..b5ea4772a8b92 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/CMakeLists.txt
@@ -1,3 +1,11 @@
+# Used for pcb assertion
+# List of architectures:
+# https://man.freebsd.org/cgi/man.cgi?query=arch&apropos=0&sektion=0&manpath=FreeBSD+16.0-CURRENT&format=html
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "FreeBSD")
+    set(HOST_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR})
+    add_definitions(-DFreeBSD_${HOST_ARCH})
+endif()
+
 lldb_tablegen(ProcessFreeBSDKernelCoreProperties.inc -gen-lldb-property-defs
   SOURCE ProcessFreeBSDKernelCoreProperties.td
   TARGET LLDBPluginProcessFreeBSDKernelCorePropertiesGen)
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp
index 0d01a0ec48d3e..9738fc42b0b5e 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm.cpp
@@ -14,6 +14,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_armv7
+#include <cstddef>
+#include <machine/frame.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -61,6 +66,33 @@ bool RegisterContextFreeBSDKernelCore_arm::ReadRegister(
     llvm::support::ulittle32_t pc;
   } pcb;
 
+#ifdef FreeBSD_armv7
+  static_assert(offsetof(struct switchframe, sf_r4) ==
+                offsetof(decltype(pcb), r4));
+  static_assert(offsetof(struct switchframe, sf_r5) ==
+                offsetof(decltype(pcb), r5));
+  static_assert(offsetof(struct switchframe, sf_r6) ==
+                offsetof(decltype(pcb), r6));
+  static_assert(offsetof(struct switchframe, sf_r7) ==
+                offsetof(decltype(pcb), r7));
+  static_assert(offsetof(struct switchframe, sf_r8) ==
+                offsetof(decltype(pcb), r8));
+  static_assert(offsetof(struct switchframe, sf_r9) ==
+                offsetof(decltype(pcb), r9));
+  static_assert(offsetof(struct switchframe, sf_r10) ==
+                offsetof(decltype(pcb), r10));
+  static_assert(offsetof(struct switchframe, sf_r11) ==
+                offsetof(decltype(pcb), r11));
+  static_assert(offsetof(struct switchframe, sf_r12) ==
+                offsetof(decltype(pcb), r12));
+  static_assert(offsetof(struct switchframe, sf_sp) ==
+                offsetof(decltype(pcb), sp));
+  static_assert(offsetof(struct switchframe, sf_lr) ==
+                offsetof(decltype(pcb), lr));
+  static_assert(offsetof(struct switchframe, sf_pc) ==
+                offsetof(decltype(pcb), pc));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp
index afd60a64a6365..1931d7bfdbb93 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_arm64.cpp
@@ -18,6 +18,12 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_aarch64
+#include <cstddef>
+#include <machine/pcb.h>
+#include <sys/param.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -52,6 +58,11 @@ bool RegisterContextFreeBSDKernelCore_arm64::ReadRegister(
     llvm::support::ulittle64_t sp;
   } pcb;
 
+#if defined(FreeBSD_aarch64) && __FreeBSD_version >= 1400084
+  static_assert(offsetof(struct pcb, pcb_x) == offsetof(decltype(pcb), x));
+  static_assert(offsetof(struct pcb, pcb_sp) == offsetof(decltype(pcb), sp));
+#endif
+
   // https://cgit.freebsd.org/src/tree/sys/arm64/include/pcb.h?h=stable%2F13
   struct {
     llvm::support::ulittle64_t x[30];
@@ -60,6 +71,12 @@ bool RegisterContextFreeBSDKernelCore_arm64::ReadRegister(
     llvm::support::ulittle64_t sp;
   } pcb13;
 
+#if defined(FreeBSD_aarch64) && __FreeBSD_version < 1400084
+  static_assert(offsetof(struct pcb, pcb_x) == offsetof(decltype(pcb13), x));
+  static_assert(offsetof(struct pcb, pcb_lr) == offsetof(decltype(pcb13), lr));
+  static_assert(offsetof(struct pcb, pcb_sp) == offsetof(decltype(pcb13), sp));
+#endif
+
   Status error;
   constexpr int FBSD14 = 1400084;
   int osreldate = FBSD14;
@@ -72,8 +89,8 @@ bool RegisterContextFreeBSDKernelCore_arm64::ReadRegister(
 
   // TODO: LLVM 24: Remove FreeBSD 13 support
   if (osreldate >= FBSD14) {
-    constexpr uint32_t PCB_FP = 10;
-    constexpr uint32_t PCB_LR = 11;
+    constexpr uint32_t pcb_fp = 10;
+    constexpr uint32_t pcb_lr = 11;
     size_t rd =
         m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
     if (rd != sizeof(pcb))
@@ -92,14 +109,14 @@ bool RegisterContextFreeBSDKernelCore_arm64::ReadRegister(
     case gpr_x27_arm64:
     case gpr_x28_arm64:
     case gpr_fp_arm64:
-      static_assert(gpr_fp_arm64 - gpr_x19_arm64 == PCB_FP,
+      static_assert(gpr_fp_arm64 - gpr_x19_arm64 == pcb_fp,
                     "nonconsecutive arm64 register numbers");
       value = pcb.x[reg - gpr_x19_arm64];
       break;
     case gpr_lr_arm64:
     case gpr_pc_arm64:
       // The pc of crashing thread is stored in lr.
-      static_assert(gpr_lr_arm64 - gpr_x19_arm64 == PCB_LR,
+      static_assert(gpr_lr_arm64 - gpr_x19_arm64 == pcb_lr,
                     "nonconsecutive arm64 register numbers");
       value = pcb.x[reg - gpr_x19_arm64];
       break;
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp
index 83ab12c73b918..b2b65f2380ec2 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_i386.cpp
@@ -13,6 +13,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_i386
+#include <cstddef>
+#include <machine/pcb.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -50,6 +55,15 @@ bool RegisterContextFreeBSDKernelCore_i386::ReadRegister(
     llvm::support::ulittle32_t eip;
   } pcb;
 
+#ifdef FreeBSD_i386
+  static_assert(offsetof(struct pcb, pcb_edi) == offsetof(decltype(pcb), edi));
+  static_assert(offsetof(struct pcb, pcb_esi) == offsetof(decltype(pcb), esi));
+  static_assert(offsetof(struct pcb, pcb_ebp) == offsetof(decltype(pcb), ebp));
+  static_assert(offsetof(struct pcb, pcb_esp) == offsetof(decltype(pcb), esp));
+  static_assert(offsetof(struct pcb, pcb_ebx) == offsetof(decltype(pcb), ebx));
+  static_assert(offsetof(struct pcb, pcb_eip) == offsetof(decltype(pcb), eip));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp
index 69932eaeb4e0b..5cc4d6cf4994e 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_ppc64le.cpp
@@ -13,6 +13,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_powerpc64le
+#include <cstddef>
+#include <machine/pcb.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -37,6 +42,15 @@ bool RegisterContextFreeBSDKernelCore_ppc64le::ReadRegister(
     llvm::support::ulittle64_t lr;
   } pcb;
 
+#ifdef FreeBSD_powerpc64le
+  static_assert(offsetof(struct pcb, pcb_context) ==
+                offsetof(decltype(pcb), context));
+  static_assert(offsetof(struct pcb, pcb_cr) == offsetof(decltype(pcb), cr));
+  static_assert(offsetof(struct pcb, pcb_sp) == offsetof(decltype(pcb), sp));
+  static_assert(offsetof(struct pcb, pcb_toc) == offsetof(decltype(pcb), toc));
+  static_assert(offsetof(struct pcb, pcb_lr) == offsetof(decltype(pcb), lr));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp
index b705c6d6d43bd..00957241b9996 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_riscv64.cpp
@@ -13,6 +13,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_riscv64
+#include <cstddef>
+#include <machine/pcb.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -52,6 +57,14 @@ bool RegisterContextFreeBSDKernelCore_riscv64::ReadRegister(
     llvm::support::ulittle64_t s[12];
   } pcb;
 
+#ifdef FreeBSD_riscv64
+  static_assert(offsetof(struct pcb, pcb_ra) == offsetof(decltype(pcb), ra));
+  static_assert(offsetof(struct pcb, pcb_sp) == offsetof(decltype(pcb), sp));
+  static_assert(offsetof(struct pcb, pcb_gp) == offsetof(decltype(pcb), gp));
+  static_assert(offsetof(struct pcb, pcb_tp) == offsetof(decltype(pcb), tp));
+  static_assert(offsetof(struct pcb, pcb_s) == offsetof(decltype(pcb), s));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);
diff --git a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp
index a4fe219a2e72d..b72f5f3b08e40 100644
--- a/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD-Kernel-Core/RegisterContextFreeBSDKernelCore_x86_64.cpp
@@ -13,6 +13,11 @@
 #include "lldb/Utility/RegisterValue.h"
 #include "llvm/Support/Endian.h"
 
+#ifdef FreeBSD_amd64
+#include <cstddef>
+#include <machine/pcb.h>
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -54,6 +59,17 @@ bool RegisterContextFreeBSDKernelCore_x86_64::ReadRegister(
     llvm::support::ulittle64_t rip;
   } pcb;
 
+#ifdef FreeBSD_amd64
+  static_assert(offsetof(struct pcb, pcb_r15) == offsetof(decltype(pcb), r15));
+  static_assert(offsetof(struct pcb, pcb_r14) == offsetof(decltype(pcb), r14));
+  static_assert(offsetof(struct pcb, pcb_r13) == offsetof(decltype(pcb), r13));
+  static_assert(offsetof(struct pcb, pcb_r12) == offsetof(decltype(pcb), r12));
+  static_assert(offsetof(struct pcb, pcb_rbp) == offsetof(decltype(pcb), rbp));
+  static_assert(offsetof(struct pcb, pcb_rsp) == offsetof(decltype(pcb), rsp));
+  static_assert(offsetof(struct pcb, pcb_rbx) == offsetof(decltype(pcb), rbx));
+  static_assert(offsetof(struct pcb, pcb_rip) == offsetof(decltype(pcb), rip));
+#endif
+
   Status error;
   size_t rd =
       m_thread.GetProcess()->ReadMemory(m_pcb_addr, &pcb, sizeof(pcb), error);

@jrtc27
Copy link
Copy Markdown
Collaborator

jrtc27 commented Mar 1, 2026

Why does CMake need to be involved? We have preprocessor macros already you can check.

@DavidSpickett
Copy link
Copy Markdown
Collaborator

I did a similar thing for Linux signal codes in lldb/source/Plugins/Process/Utility/LinuxSignals.cpp. I did not need CMake for that either.

@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Mar 2, 2026

I did a similar thing for Linux signal codes in lldb/source/Plugins/Process/Utility/LinuxSignals.cpp. I did not need CMake for that either.

On FreeBSD host, /usr/include/machine only contains amd64 code on amd64 host. When we use "#ifdef arm64" the compiler still resolves #include <machine/foo.h> to host's /usr/include/machine which is amd64 code. This can be solved by passing -sysroot to the compiler where the sysroot points to arm64 sysroot, but obtaining sysroot for different architecture isn't something usual for most users. So here I'm running checks when the host (the machine building LLDB) and register context's architecture match not when the target that LLDB is built for and register context's architecture match.

@jrtc27
Copy link
Copy Markdown
Collaborator

jrtc27 commented Mar 2, 2026

Uh, if you're cross-compiling for arm64, you need an arm64 sysroot. /usr/include being for amd64 will not work for many reasons.

@jrtc27
Copy link
Copy Markdown
Collaborator

jrtc27 commented Mar 2, 2026

(And if /usr/include is amd64, aside from probably giving a slew of errors and all kinds of ABI issues due to all the system headers that do themselves include machine/foo.h getting amd64 ones, if you manage to compile an object file, you won't be able to link it, because /usr/lib will be full of amd64 libraries and, most importantly, crt*.o files that get implicitly linked in)

@aokblast aokblast self-requested a review March 4, 2026 15:18
@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Mar 11, 2026

@DavidSpickett

I might move cmake changes to lldb/cmake so it can be used in UnwindPlan as well, but for now this seems sufficient.

@jrtc27
Copy link
Copy Markdown
Collaborator

jrtc27 commented Mar 11, 2026

Please just gate them on preprocessor defines, no cmake

@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Mar 11, 2026

Please just gate them on preprocessor defines, no cmake

I thought preprocessor defines (e.g. amd64, FreeBSD) are for targets not host that builds the software?

@jrtc27
Copy link
Copy Markdown
Collaborator

jrtc27 commented Mar 11, 2026

Please just gate them on preprocessor defines, no cmake

I thought preprocessor defines (e.g. amd64, FreeBSD) are for targets not host that builds the software?

In GNU autotools build/host/target nomenclature, they are for the host architecture, which is the architecture code is actually being generated for and therefore what the headers and libraries being used are for. Which is exactly what you want here.

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Mar 11, 2026

Build succeeds on amd64 and arm64 machine. Thanks @jrtc27!

@jrtc27
Copy link
Copy Markdown
Collaborator

jrtc27 commented Mar 11, 2026

The PR summary needs to be updated as it (incorrectly) asserts that you can't use preprocessor macros for this and (now inaccurately) states that they're not being used. Also for the first sentence the PCB layout may never be stable, so I'd drop the "yet".

@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Mar 11, 2026

The PR summary needs to be updated as it (incorrectly) asserts that you can't use preprocessor macros for this and (now inaccurately) states that they're not being used. Also for the first sentence the PCB layout may never be stable, so I'd drop the "yet".

Updated PR description. I had discussion with @kostikbel and @bsdjhb on stable pcb, but I'm not sure if Konstantin still wants to work on this.

@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Mar 11, 2026

Cross build for amd64 on arm64 build machine succeeds.

So what happens when I try to build arm64 lldb binary on amd64 build machine? In RegisterContextFreeBSDKernelCore_arm64.cpp , __FreeBSD__ and __aarch64__ will succeed and it will try to #include <machine/pcb.h>, but since machine resolves to amd64 MD code on /usr/include/machine without sysroot, the static assertion on RegisterContextFreeBSDKernelCore_arm64.cpp will fail. Am I missing something here?

@DavidSpickett
Copy link
Copy Markdown
Collaborator

Am I missing something here?

That when cross-compiling, you would have an AArch64 sysroot which would provide the AArch64 pcb.h.

(Some software might compile ok using host headers, but it's basically random chance and not something anyone should rely on)

It's been a while since I tried it but I think I downloaded the base.txz from a release such as https://download.freebsd.org/ftp/releases/arm64/aarch64/15.0-RELEASE/. Then extracted that. This contains a usr/include/machine/pcb.h file that contains the AArch64 pcb:

struct pcb {
	uint64_t	pcb_x[12];
	/* These two need to be in order as we access them together */
	uint64_t	pcb_sp;
	uint64_t	pcb_tpidr_el0;
	uint64_t	pcb_tpidrro_el0;

I don't know if that's the official advice, but you see the idea. You tell the compiler: instead of searching from /, start from /path-to-sysroot. So then include/machine/pcb.h is the one in the sysroot.

We have cross compile instructions for Linux but not FreeBSD - https://lldb.llvm.org/resources/build.html#cross-compiling-lldb. You'll need to find out how to get cmake to pass the sysroot path to clang. But the options to disable libraries should be useful, for testing this PR, you can disable all the optional things to save you time cross compiling those too.

Perhaps in a FreeBSD system, you can install a foreign architecture sysroot. Like you can in Debian with multiarch.

@DavidSpickett
Copy link
Copy Markdown
Collaborator

but since machine resolves to amd64 MD code on /usr/include/machine without sysroot

And to add to this: If someone said the build broke when they did this, my response would be "that is expected behaviour, you should use an AArch64 sysroot".

@mchoo7
Copy link
Copy Markdown
Contributor Author

mchoo7 commented Mar 12, 2026

Thanks for the explanation!

@mchoo7 mchoo7 merged commit 3f65a03 into llvm:main Mar 12, 2026
10 checks passed
@mchoo7 mchoo7 deleted the pcb branch March 12, 2026 16:38
mchoo7 added a commit that referenced this pull request Mar 12, 2026
`<cstddef>` was included for static assertion using `offsetof()`, but it
turns out that the header is already included before. Thus remove
`<cstddef>` includes from `RegisterContextFreeBSDKernelCore_<arch>.cpp`
files.

Fixes 3f65a03 (#183969)

Signed-off-by: Minsoo Choo <minsoochoo0122@proton.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants