git: 6a936d939b88 - main - Merge commit 4d7292e58078 from llvm-project (by Minsoo Choo):

From: Dimitry Andric <dim_at_FreeBSD.org>
Date: Sun, 25 Oct 2026 12:12:26 UTC
The branch main has been updated by dim:

URL: https://cgit.FreeBSD.org/src/commit/?id=6a936d939b886fe3d777d33b0327987c3aa08f51

commit 6a936d939b886fe3d777d33b0327987c3aa08f51
Author:     Dimitry Andric <dim@FreeBSD.org>
AuthorDate: 2026-10-25 11:34:38 +0000
Commit:     Dimitry Andric <dim@FreeBSD.org>
CommitDate: 2026-10-25 12:11:27 +0000

    Merge commit 4d7292e58078 from llvm-project (by Minsoo Choo):
    
      [libunwind] Unwind through AArch64 FreeBSD signal trampolines (#235065)
    
      Retried from https://reviews.llvm.org/D155066.
    
      Recognize signal trampolines using KERN_PROC_SIGTRAMP when unwind
      metadata is unavailable. Restore the interrupted PC, LR, SP, general
      registers, and valid floating-point registers.
    
      Add coverage for unwinding out of an interrupted leaf function on both
      regular and alternate signal stacks.
    
      Assisted-by: GPT
    
    MFC after:      1 week
---
 .../libunwind/include/__libunwind_config.h         |  3 +
 .../llvm-project/libunwind/src/UnwindCursor.hpp    | 77 +++++++++++++++++++++-
 2 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/contrib/llvm-project/libunwind/include/__libunwind_config.h b/contrib/llvm-project/libunwind/include/__libunwind_config.h
index bb7fe4c83a3c..493910c3df51 100644
--- a/contrib/llvm-project/libunwind/include/__libunwind_config.h
+++ b/contrib/llvm-project/libunwind/include/__libunwind_config.h
@@ -36,6 +36,9 @@
 # if defined(__linux__)
 #  define _LIBUNWIND_TARGET_LINUX 1
 # endif
+# if defined(__FreeBSD__)
+#  define _LIBUNWIND_TARGET_FREEBSD 1
+# endif
 # if defined(__HAIKU__)
 #  define _LIBUNWIND_TARGET_HAIKU 1
 # endif
diff --git a/contrib/llvm-project/libunwind/src/UnwindCursor.hpp b/contrib/llvm-project/libunwind/src/UnwindCursor.hpp
index 9a1afd3721f5..067a3c238245 100644
--- a/contrib/llvm-project/libunwind/src/UnwindCursor.hpp
+++ b/contrib/llvm-project/libunwind/src/UnwindCursor.hpp
@@ -41,6 +41,17 @@
 #define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
 #endif
 
+#if defined(_LIBUNWIND_TARGET_FREEBSD) && defined(_LIBUNWIND_TARGET_AARCH64)
+#include <errno.h>
+#include <machine/frame.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ucontext.h>
+#include <sys/user.h>
+#include <unistd.h>
+#define _LIBUNWIND_CHECK_FREEBSD_SIGRETURN 1
+#endif
+
 #if defined(_LIBUNWIND_TARGET_HAIKU) && defined(_LIBUNWIND_TARGET_X86_64)
 #include <OS.h>
 #include <signal.h>
@@ -1038,7 +1049,8 @@ private:
   template <typename Registers> int stepThroughSigReturn(Registers &) {
     return UNW_STEP_END;
   }
-#elif defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
+#elif defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN) ||                           \
+    defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
   bool setInfoForSigReturn();
   int stepThroughSigReturn();
 #endif
@@ -1345,6 +1357,7 @@ private:
   bool             _unwindInfoMissing;
   bool             _isSignalFrame;
 #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) ||                               \
+    defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN) ||                             \
     defined(_LIBUNWIND_TARGET_HAIKU)
   bool             _isSigReturn = false;
 #endif
@@ -2637,6 +2650,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
 template <typename A, typename R>
 void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
 #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) ||                               \
+    defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN) ||                             \
     defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
   _isSigReturn = false;
 #endif
@@ -2762,6 +2776,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
 #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
 
 #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) ||                               \
+    defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN) ||                             \
     defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
   if (setInfoForSigReturn())
     return;
@@ -3053,6 +3068,65 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
 #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
        // defined(_LIBUNWIND_TARGET_S390X)
 
+#if defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::setInfoForSigReturn() {
+  // Ask the kernel rather than reading instructions at a possibly invalid PC.
+  // This is only used when no unwind information was found. Keep the result
+  // local to avoid shared mutable state when unwinding from a signal handler.
+  struct kinfo_sigtramp kst = {};
+  size_t len = sizeof(kst);
+  int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_SIGTRAMP, getpid()};
+  const int savedErrno = errno;
+  const int result = sysctl(mib, 4, &kst, &len, nullptr, 0);
+  errno = savedErrno;
+  if (result != 0)
+    return false;
+
+  const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+  const pint_t start = reinterpret_cast<pint_t>(kst.ksigtramp_start);
+  const pint_t end = reinterpret_cast<pint_t>(kst.ksigtramp_end);
+  if (pc < start || pc >= end)
+    return false;
+
+  _info = {};
+  _info.start_ip = start;
+  _info.end_ip = end;
+  _isSigReturn = true;
+  return true;
+}
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+template <typename A, typename R>
+int UnwindCursor<A, R>::stepThroughSigReturn() {
+  // The trampoline leaves SP pointing at the sigframe installed by sendsig().
+  const pint_t sigctx = _registers.getSP() + offsetof(struct sigframe, sf_uc) +
+                        offsetof(ucontext_t, uc_mcontext);
+  const pint_t gprs = sigctx + offsetof(mcontext_t, mc_gpregs);
+  for (int i = 0; i < 30; ++i)
+    _registers.setRegister(
+        UNW_AARCH64_X0 + i,
+        _addressSpace.get64(gprs + offsetof(struct gpregs, gp_x) + i * 8));
+  _registers.setRegister(
+      UNW_AARCH64_LR,
+      _addressSpace.get64(gprs + offsetof(struct gpregs, gp_lr)));
+  _registers.setSP(_addressSpace.get64(gprs + offsetof(struct gpregs, gp_sp)));
+  _registers.setIP(_addressSpace.get64(gprs + offsetof(struct gpregs, gp_elr)));
+
+  if (_addressSpace.get32(sigctx + offsetof(mcontext_t, mc_flags)) &
+      _MC_FP_VALID) {
+    const pint_t fprs = sigctx + offsetof(mcontext_t, mc_fpregs) +
+                        offsetof(struct fpregs, fp_q);
+    for (int i = 0; i < 32; ++i)
+      _registers.setFloatRegister(UNW_AARCH64_V0 + i,
+                                  _addressSpace.getDouble(fprs + i * 16));
+  }
+  _isSignalFrame = true;
+  return UNW_STEP_SUCCESS;
+}
+#endif // defined(_LIBUNWIND_TARGET_AARCH64)
+#endif // defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN)
+
 #if defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
 template <typename A, typename R>
 bool UnwindCursor<A, R>::setInfoForSigReturn() {
@@ -3152,6 +3226,7 @@ template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
   // Use unwinding info to modify register set as if function returned.
   int result;
 #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) ||                               \
+    defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN) ||                             \
     defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
   if (_isSigReturn) {
     result = this->stepThroughSigReturn();