Commit 85438e75e0

Alex Rønne Petersen <alex@alexrp.com>
2025-07-16 10:55:09
libunwind: update to LLVM 21
1 parent c34fc8f
lib/libunwind/src/gcc_personality_v0.c
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+/* zig patch: remove compiler-rt int_lib.h dependency */
 #if __ARM_EABI__
 #ifdef COMPILER_RT_ARMHF_TARGET
 #define COMPILER_RT_ABI
@@ -19,6 +20,7 @@
 #define compilerrt_abort() __builtin_unreachable()
 
 #include <unwind.h>
+/* zig patch: remove unwind-ehabi-helpers.h dependency */
 
 #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
 #include <windows.h>
lib/libunwind/src/Registers.hpp
@@ -15,9 +15,9 @@
 #include <stdint.h>
 #include <string.h>
 
-#include "cet_unwind.h"
 #include "config.h"
 #include "libunwind.h"
+#include "shadow_stack_unwind.h"
 
 namespace libunwind {
 
@@ -48,7 +48,7 @@ class _LIBUNWIND_HIDDEN Registers_x86;
 extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
 
 #if defined(_LIBUNWIND_USE_CET)
-extern "C" void *__libunwind_cet_get_jump_target() {
+extern "C" void *__libunwind_shstk_get_jump_target() {
   return reinterpret_cast<void *>(&__libunwind_Registers_x86_jumpto);
 }
 #endif
@@ -268,7 +268,7 @@ class _LIBUNWIND_HIDDEN Registers_x86_64;
 extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);
 
 #if defined(_LIBUNWIND_USE_CET)
-extern "C" void *__libunwind_cet_get_jump_target() {
+extern "C" void *__libunwind_shstk_get_jump_target() {
   return reinterpret_cast<void *>(&__libunwind_Registers_x86_64_jumpto);
 }
 #endif
@@ -1817,7 +1817,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64;
 extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
 
 #if defined(_LIBUNWIND_USE_GCS)
-extern "C" void *__libunwind_cet_get_jump_target() {
+extern "C" void *__libunwind_shstk_get_jump_target() {
   return reinterpret_cast<void *>(&__libunwind_Registers_arm64_jumpto);
 }
 #endif
@@ -4126,7 +4126,7 @@ inline reg_t Registers_riscv::getRegister(int regNum) const {
     return _registers[regNum];
   if (regNum == UNW_RISCV_VLENB) {
     reg_t vlenb;
-    __asm__("csrr %0, 0xC22" : "=r"(vlenb));
+    __asm__ volatile("csrr %0, 0xC22" : "=r"(vlenb));
     return vlenb;
   }
   _LIBUNWIND_ABORT("unsupported riscv register");
lib/libunwind/src/cet_unwind.h → lib/libunwind/src/shadow_stack_unwind.h
@@ -7,8 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LIBUNWIND_CET_UNWIND_H
-#define LIBUNWIND_CET_UNWIND_H
+#ifndef LIBUNWIND_SHADOW_STACK_UNWIND_H
+#define LIBUNWIND_SHADOW_STACK_UNWIND_H
 
 #include "libunwind.h"
 
@@ -21,7 +21,7 @@
 #include <cet.h>
 #include <immintrin.h>
 
-#define _LIBUNWIND_POP_CET_SSP(x)                                              \
+#define _LIBUNWIND_POP_SHSTK_SSP(x)                                            \
   do {                                                                         \
     unsigned long ssp = _get_ssp();                                            \
     if (ssp != 0) {                                                            \
@@ -46,7 +46,7 @@
 #define _LIBUNWIND_USE_GCS 1
 #endif
 
-#define _LIBUNWIND_POP_CET_SSP(x)                                              \
+#define _LIBUNWIND_POP_SHSTK_SSP(x)                                            \
   do {                                                                         \
     if (__chkfeat(_CHKFEAT_GCS)) {                                             \
       unsigned tmp = (x);                                                      \
@@ -57,7 +57,7 @@
 
 #endif
 
-extern void *__libunwind_cet_get_registers(unw_cursor_t *);
-extern void *__libunwind_cet_get_jump_target(void);
+extern void *__libunwind_shstk_get_registers(unw_cursor_t *);
+extern void *__libunwind_shstk_get_jump_target(void);
 
 #endif
lib/libunwind/src/Unwind-seh.cpp
@@ -51,6 +51,32 @@ static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor);
 static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
                                    DISPATCHER_CONTEXT *disp);
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+// Local redefinition of this type; mingw-w64 headers lack the
+// DISPATCHER_CONTEXT_NONVOLREG_ARM64 type as of May 2025, so locally redefine
+// it and use that definition, to avoid needing to test/guess whether the real
+// type is available of not.
+union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 {
+  BYTE Buffer[11 * sizeof(DWORD64) + 8 * sizeof(double)];
+
+  struct {
+    DWORD64 GpNvRegs[11];
+    double FpNvRegs[8];
+  };
+};
+
+// Custom data type definition; this type is not defined in WinSDK.
+union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM {
+  BYTE Buffer[8 * sizeof(DWORD) + 8 * sizeof(double)];
+
+  struct {
+    DWORD GpNvRegs[8];
+    double FpNvRegs[8];
+  };
+};
+#pragma clang diagnostic pop
+
 /// Common implementation of SEH-style handler functions used by Itanium-
 /// style frames.  Depending on how and why it was called, it may do one of:
 ///  a) Delegate to the given Itanium-style personality function; or
@@ -212,6 +238,21 @@ __libunwind_seh_personality(int version, _Unwind_Action state,
   ms_exc.ExceptionInformation[2] = state;
   DISPATCHER_CONTEXT *disp_ctx =
       __unw_seh_get_disp_ctx((unw_cursor_t *)context);
+#if defined(__aarch64__)
+  LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 nonvol;
+  memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->X19,
+         sizeof(nonvol.GpNvRegs));
+  for (int i = 0; i < 8; i++)
+    nonvol.FpNvRegs[i] = disp_ctx->ContextRecord->V[i + 8].D[0];
+  disp_ctx->NonVolatileRegisters = nonvol.Buffer;
+#elif defined(__arm__)
+  LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM nonvol;
+  memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->R4,
+         sizeof(nonvol.GpNvRegs));
+  memcpy(&nonvol.FpNvRegs, &disp_ctx->ContextRecord->D[8],
+         sizeof(nonvol.FpNvRegs));
+  disp_ctx->NonVolatileRegisters = nonvol.Buffer;
+#endif
   _LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() calling "
                              "LanguageHandler %p(%p, %p, %p, %p)",
                              (void *)disp_ctx->LanguageHandler, (void *)&ms_exc,
lib/libunwind/src/Unwind-wasm.c
@@ -102,8 +102,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
 }
 
 /// Not used in Wasm.
-_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
-                                     uintptr_t value) {}
+_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t) {}
 
 /// Called by personality handler to get LSDA for current frame.
 _LIBUNWIND_EXPORT uintptr_t
@@ -115,8 +114,7 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
 }
 
 /// Not used in Wasm.
-_LIBUNWIND_EXPORT uintptr_t
-_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *) {
   return 0;
 }
 
lib/libunwind/src/UnwindCursor.hpp
@@ -11,7 +11,7 @@
 #ifndef __UNWINDCURSOR_HPP__
 #define __UNWINDCURSOR_HPP__
 
-#include "cet_unwind.h"
+#include "shadow_stack_unwind.h"
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -31,8 +31,9 @@
 #endif
 
 #if defined(_LIBUNWIND_TARGET_LINUX) &&                                        \
-    (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_RISCV) || \
-     defined(_LIBUNWIND_TARGET_S390X))
+    (defined(_LIBUNWIND_TARGET_AARCH64) ||                                     \
+     defined(_LIBUNWIND_TARGET_LOONGARCH) ||                                   \
+     defined(_LIBUNWIND_TARGET_RISCV) || defined(_LIBUNWIND_TARGET_S390X))
 #include <errno.h>
 #include <signal.h>
 #include <sys/syscall.h>
@@ -40,6 +41,12 @@
 #define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
 #endif
 
+#if defined(_LIBUNWIND_TARGET_HAIKU) && defined(_LIBUNWIND_TARGET_X86_64)
+#include <OS.h>
+#include <signal.h>
+#define _LIBUNWIND_CHECK_HAIKU_SIGRETURN 1
+#endif
+
 #include "AddressSpace.hpp"
 #include "CompactUnwinder.hpp"
 #include "config.h"
@@ -82,6 +89,22 @@ struct UNWIND_INFO {
   uint16_t UnwindCodes[2];
 };
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+union UNWIND_INFO_ARM {
+  DWORD HeaderData;
+  struct {
+    DWORD FunctionLength : 18;
+    DWORD Version : 2;
+    DWORD ExceptionDataPresent : 1;
+    DWORD EpilogInHeader : 1;
+    DWORD FunctionFragment : 1;
+    DWORD EpilogCount : 5;
+    DWORD CodeWords : 4;
+  };
+};
+#pragma clang diagnostic pop
+
 extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
     int, _Unwind_Action, uint64_t, _Unwind_Exception *,
     struct _Unwind_Context *);
@@ -150,7 +173,7 @@ bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
 #endif
 
 template <typename A>
-typename DwarfFDECache<A>::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
+typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
   pint_t result = 0;
   _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared());
   for (entry *p = _buffer; p < _bufferUsed; ++p) {
@@ -996,6 +1019,10 @@ private:
   bool setInfoForSigReturn(Registers_arm64 &);
   int stepThroughSigReturn(Registers_arm64 &);
 #endif
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+  bool setInfoForSigReturn(Registers_loongarch &);
+  int stepThroughSigReturn(Registers_loongarch &);
+#endif
 #if defined(_LIBUNWIND_TARGET_RISCV)
   bool setInfoForSigReturn(Registers_riscv &);
   int stepThroughSigReturn(Registers_riscv &);
@@ -1010,7 +1037,7 @@ private:
   template <typename Registers> int stepThroughSigReturn(Registers &) {
     return UNW_STEP_END;
   }
-#elif defined(_LIBUNWIND_TARGET_HAIKU)
+#elif defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
   bool setInfoForSigReturn();
   int stepThroughSigReturn();
 #endif
@@ -2013,6 +2040,61 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) {
       _info.handler = 0;
     }
   }
+#elif defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_ARM)
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+#define FUNC_LENGTH_UNIT 4
+#define XDATA_TYPE IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY_XDATA
+#else
+#define FUNC_LENGTH_UNIT 2
+#define XDATA_TYPE UNWIND_INFO_ARM
+#endif
+  if (unwindEntry->Flag != 0) { // Packed unwind info
+    _info.end_ip =
+        _info.start_ip + unwindEntry->FunctionLength * FUNC_LENGTH_UNIT;
+    // Only fill in the handler and LSDA if they're stale.
+    if (pc != getLastPC()) {
+      // Packed unwind info doesn't have an exception handler.
+      _info.lsda = 0;
+      _info.handler = 0;
+    }
+  } else {
+    XDATA_TYPE *xdata =
+        reinterpret_cast<XDATA_TYPE *>(base + unwindEntry->UnwindData);
+    _info.end_ip = _info.start_ip + xdata->FunctionLength * FUNC_LENGTH_UNIT;
+    // Only fill in the handler and LSDA if they're stale.
+    if (pc != getLastPC()) {
+      if (xdata->ExceptionDataPresent) {
+        uint32_t offset = 1; // The main xdata
+        uint32_t codeWords = xdata->CodeWords;
+        uint32_t epilogScopes = xdata->EpilogCount;
+        if (xdata->EpilogCount == 0 && xdata->CodeWords == 0) {
+          // The extension word has got the same layout for both ARM and ARM64
+          uint32_t extensionWord = reinterpret_cast<uint32_t *>(xdata)[1];
+          codeWords = (extensionWord >> 16) & 0xff;
+          epilogScopes = extensionWord & 0xffff;
+          offset++;
+        }
+        if (!xdata->EpilogInHeader)
+          offset += epilogScopes;
+        offset += codeWords;
+        uint32_t *exceptionHandlerInfo =
+            reinterpret_cast<uint32_t *>(xdata) + offset;
+        _dispContext.HandlerData = &exceptionHandlerInfo[1];
+        _dispContext.LanguageHandler = reinterpret_cast<EXCEPTION_ROUTINE *>(
+            base + exceptionHandlerInfo[0]);
+        _info.lsda = reinterpret_cast<unw_word_t>(_dispContext.HandlerData);
+        if (exceptionHandlerInfo[0])
+          _info.handler =
+              reinterpret_cast<unw_word_t>(__libunwind_seh_personality);
+        else
+          _info.handler = 0;
+      } else {
+        _info.lsda = 0;
+        _info.handler = 0;
+      }
+    }
+  }
 #endif
   setLastPC(pc);
   return true;
@@ -2554,7 +2636,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_TARGET_HAIKU)
+    defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
   _isSigReturn = false;
 #endif
 
@@ -2679,7 +2761,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
 #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
 
 #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) ||                               \
-    defined(_LIBUNWIND_TARGET_HAIKU)
+    defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
   if (setInfoForSigReturn())
     return;
 #endif
@@ -2755,65 +2837,63 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
   _isSignalFrame = true;
   return UNW_STEP_SUCCESS;
 }
+#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
+       // defined(_LIBUNWIND_TARGET_AARCH64)
 
-#elif defined(_LIBUNWIND_TARGET_HAIKU) && defined(_LIBUNWIND_TARGET_X86_64)
-#include <commpage_defs.h>
-#include <signal.h>
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&                               \
+    defined(_LIBUNWIND_TARGET_LOONGARCH)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_loongarch &) {
+  const pint_t pc = static_cast<pint_t>(getReg(UNW_REG_IP));
+  // The PC might contain an invalid address if the unwind info is bad, so
+  // directly accessing it could cause a SIGSEGV.
+  if (!isReadableAddr(pc))
+    return false;
+  const auto *instructions = reinterpret_cast<const uint32_t *>(pc);
+  // Look for the two instructions used in the sigreturn trampoline
+  // __vdso_rt_sigreturn:
+  //
+  // 0x03822c0b li a7,0x8b
+  // 0x002b0000 syscall 0
+  if (instructions[0] != 0x03822c0b || instructions[1] != 0x002b0000)
+    return false;
 
-extern "C" {
-extern void *__gCommPageAddress;
+  _info = {};
+  _info.start_ip = pc;
+  _info.end_ip = pc + 4;
+  _isSigReturn = true;
+  return true;
 }
 
 template <typename A, typename R>
-bool UnwindCursor<A, R>::setInfoForSigReturn() {
-#if defined(_LIBUNWIND_TARGET_X86_64)
-  addr_t signal_handler =
-      (((addr_t *)__gCommPageAddress)[COMMPAGE_ENTRY_X86_SIGNAL_HANDLER] +
-       (addr_t)__gCommPageAddress);
-  addr_t signal_handler_ret = signal_handler + 45;
-#endif
-  pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
-  if (pc == signal_handler_ret) {
-    _info = {};
-    _info.start_ip = signal_handler;
-    _info.end_ip = signal_handler_ret;
-    _isSigReturn = true;
-    return true;
-  }
-  return false;
-}
+int UnwindCursor<A, R>::stepThroughSigReturn(Registers_loongarch &) {
+  // In the signal trampoline frame, sp points to an rt_sigframe[1], which is:
+  //  - 128-byte siginfo struct
+  //  - ucontext_t struct:
+  //     - 8-byte long (__uc_flags)
+  //     - 8-byte pointer (*uc_link)
+  //     - 24-byte uc_stack
+  //     - 8-byte uc_sigmask
+  //     - 120-byte of padding to allow sigset_t to be expanded in the future
+  //     - 8 bytes of padding because sigcontext has 16-byte alignment
+  //     - struct sigcontext uc_mcontext
+  // [1]
+  // https://github.com/torvalds/linux/blob/master/arch/loongarch/kernel/signal.c
+  const pint_t kOffsetSpToSigcontext = 128 + 8 + 8 + 24 + 8 + 128;
 
-template <typename A, typename R>
-int UnwindCursor<A, R>::stepThroughSigReturn() {
+  const pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext;
+  _registers.setIP(_addressSpace.get64(sigctx));
+  for (int i = UNW_LOONGARCH_R1; i <= UNW_LOONGARCH_R31; ++i) {
+    // skip R0
+    uint64_t value =
+        _addressSpace.get64(sigctx + static_cast<pint_t>((i + 1) * 8));
+    _registers.setRegister(i, value);
+  }
   _isSignalFrame = true;
-  pint_t sp = _registers.getSP();
-#if defined(_LIBUNWIND_TARGET_X86_64)
-  vregs *regs = (vregs *)(sp + 0x70);
-
-  _registers.setRegister(UNW_REG_IP, regs->rip);
-  _registers.setRegister(UNW_REG_SP, regs->rsp);
-  _registers.setRegister(UNW_X86_64_RAX, regs->rax);
-  _registers.setRegister(UNW_X86_64_RDX, regs->rdx);
-  _registers.setRegister(UNW_X86_64_RCX, regs->rcx);
-  _registers.setRegister(UNW_X86_64_RBX, regs->rbx);
-  _registers.setRegister(UNW_X86_64_RSI, regs->rsi);
-  _registers.setRegister(UNW_X86_64_RDI, regs->rdi);
-  _registers.setRegister(UNW_X86_64_RBP, regs->rbp);
-  _registers.setRegister(UNW_X86_64_R8, regs->r8);
-  _registers.setRegister(UNW_X86_64_R9, regs->r9);
-  _registers.setRegister(UNW_X86_64_R10, regs->r10);
-  _registers.setRegister(UNW_X86_64_R11, regs->r11);
-  _registers.setRegister(UNW_X86_64_R12, regs->r12);
-  _registers.setRegister(UNW_X86_64_R13, regs->r13);
-  _registers.setRegister(UNW_X86_64_R14, regs->r14);
-  _registers.setRegister(UNW_X86_64_R15, regs->r15);
-  // TODO: XMM
-#endif
-
   return UNW_STEP_SUCCESS;
 }
 #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
-       // defined(_LIBUNWIND_TARGET_AARCH64)
+       // defined(_LIBUNWIND_TARGET_LOONGARCH)
 
 #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&                               \
     defined(_LIBUNWIND_TARGET_RISCV)
@@ -2972,6 +3052,96 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
 #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
        // defined(_LIBUNWIND_TARGET_S390X)
 
+#if defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::setInfoForSigReturn() {
+  Dl_info dlinfo;
+  const auto isSignalHandler = [&](pint_t addr) {
+    if (!dladdr(reinterpret_cast<void *>(addr), &dlinfo))
+      return false;
+    if (strcmp(dlinfo.dli_fname, "commpage"))
+      return false;
+    if (dlinfo.dli_sname == NULL ||
+        strcmp(dlinfo.dli_sname, "commpage_signal_handler"))
+      return false;
+    return true;
+  };
+
+  pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+  if (!isSignalHandler(pc))
+    return false;
+
+  pint_t start = reinterpret_cast<pint_t>(dlinfo.dli_saddr);
+
+  static size_t signalHandlerSize = 0;
+  if (signalHandlerSize == 0) {
+    size_t boundLow = 0;
+    size_t boundHigh = static_cast<size_t>(-1);
+
+    area_info areaInfo;
+    if (get_area_info(area_for(dlinfo.dli_saddr), &areaInfo) == B_OK)
+      boundHigh = areaInfo.size;
+
+    while (boundLow < boundHigh) {
+      size_t boundMid = boundLow + ((boundHigh - boundLow) / 2);
+      pint_t test = start + boundMid;
+      if (test >= start && isSignalHandler(test))
+        boundLow = boundMid + 1;
+      else
+        boundHigh = boundMid;
+    }
+
+    signalHandlerSize = boundHigh;
+  }
+
+  _info = {};
+  _info.start_ip = start;
+  _info.end_ip = start + signalHandlerSize;
+  _isSigReturn = true;
+
+  return true;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A, R>::stepThroughSigReturn() {
+  _isSignalFrame = true;
+
+#if defined(_LIBUNWIND_TARGET_X86_64)
+  // Layout of the stack before function call:
+  // - signal_frame_data
+  //   + siginfo_t    (public struct, fairly stable)
+  //   + ucontext_t   (public struct, fairly stable)
+  //     - mcontext_t -> Offset 0x70, this is what we want.
+  // - frame->ip (8 bytes)
+  // - frame->bp (8 bytes). Not written by the kernel,
+  //   but the signal handler has a "push %rbp" instruction.
+  pint_t bp = this->getReg(UNW_X86_64_RBP);
+  vregs *regs = (vregs *)(bp + 0x70);
+
+  _registers.setRegister(UNW_REG_IP, regs->rip);
+  _registers.setRegister(UNW_REG_SP, regs->rsp);
+  _registers.setRegister(UNW_X86_64_RAX, regs->rax);
+  _registers.setRegister(UNW_X86_64_RDX, regs->rdx);
+  _registers.setRegister(UNW_X86_64_RCX, regs->rcx);
+  _registers.setRegister(UNW_X86_64_RBX, regs->rbx);
+  _registers.setRegister(UNW_X86_64_RSI, regs->rsi);
+  _registers.setRegister(UNW_X86_64_RDI, regs->rdi);
+  _registers.setRegister(UNW_X86_64_RBP, regs->rbp);
+  _registers.setRegister(UNW_X86_64_R8, regs->r8);
+  _registers.setRegister(UNW_X86_64_R9, regs->r9);
+  _registers.setRegister(UNW_X86_64_R10, regs->r10);
+  _registers.setRegister(UNW_X86_64_R11, regs->r11);
+  _registers.setRegister(UNW_X86_64_R12, regs->r12);
+  _registers.setRegister(UNW_X86_64_R13, regs->r13);
+  _registers.setRegister(UNW_X86_64_R14, regs->r14);
+  _registers.setRegister(UNW_X86_64_R15, regs->r15);
+  // TODO: XMM
+#endif // defined(_LIBUNWIND_TARGET_X86_64)
+
+  return UNW_STEP_SUCCESS;
+}
+#endif // defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
+
 template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
   (void)stage2;
   // Bottom of stack is defined is when unwind info cannot be found.
@@ -2981,7 +3151,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_TARGET_HAIKU)
+    defined(_LIBUNWIND_CHECK_HAIKU_SIGRETURN)
   if (_isSigReturn) {
     result = this->stepThroughSigReturn();
   } else
@@ -3062,7 +3232,7 @@ bool UnwindCursor<A, R>::isReadableAddr(const pint_t addr) const {
 #endif
 
 #if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)
-extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) {
+extern "C" void *__libunwind_shstk_get_registers(unw_cursor_t *cursor) {
   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
   return co->get_registers();
 }
lib/libunwind/src/UnwindLevel1.c
@@ -25,10 +25,10 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "cet_unwind.h"
 #include "config.h"
 #include "libunwind.h"
 #include "libunwind_ext.h"
+#include "shadow_stack_unwind.h"
 #include "unwind.h"
 
 #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) &&   \
@@ -36,14 +36,17 @@
 
 #ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND
 
-// When CET is enabled, each "call" instruction will push return address to
-// CET shadow stack, each "ret" instruction will pop current CET shadow stack
-// top and compare it with target address which program will return.
-// In exception handing, some stack frames will be skipped before jumping to
-// landing pad and we must adjust CET shadow stack accordingly.
-// _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we
-// directly jump to __libunwind_Registers_x86/x86_64_jumpto instead of using
-// a regular function call to avoid pushing to CET shadow stack again.
+// When shadow stack is enabled, a separate stack containing only return
+// addresses would be maintained. On function return, the return address would
+// be compared to the popped address from shadow stack to ensure the return
+// target is not tempered with. When unwinding, we're skipping the normal return
+// procedure for multiple frames and thus need to pop the return addresses of
+// the skipped frames from shadow stack to avoid triggering an exception (using
+// `_LIBUNWIND_POP_SHSTK_SSP()`). Also, some architectures, like the x86-family
+// CET, push the return adddresses onto shadow stack with common call
+// instructions, so for these architectures, normal function calls should be
+// avoided when invoking the `jumpto()` function. To do this, we use inline
+// assemblies to "goto" the `jumpto()` for these architectures.
 #if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS)
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
@@ -51,38 +54,38 @@
     __unw_resume((cursor));                                                    \
   } while (0)
 #elif defined(_LIBUNWIND_TARGET_I386)
-#define __cet_ss_step_size 4
+#define __shstk_step_size (4)
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
-    _LIBUNWIND_POP_CET_SSP((fn));                                              \
-    void *cetRegContext = __libunwind_cet_get_registers((cursor));             \
-    void *cetJumpAddress = __libunwind_cet_get_jump_target();                  \
+    _LIBUNWIND_POP_SHSTK_SSP((fn));                                            \
+    void *shstkRegContext = __libunwind_shstk_get_registers((cursor));         \
+    void *shstkJumpAddress = __libunwind_shstk_get_jump_target();              \
     __asm__ volatile("push %%edi\n\t"                                          \
                      "sub $4, %%esp\n\t"                                       \
-                     "jmp *%%edx\n\t" :: "D"(cetRegContext),                   \
-                     "d"(cetJumpAddress));                                     \
+                     "jmp *%%edx\n\t" ::"D"(shstkRegContext),                  \
+                     "d"(shstkJumpAddress));                                   \
   } while (0)
 #elif defined(_LIBUNWIND_TARGET_X86_64)
-#define __cet_ss_step_size 8
+#define __shstk_step_size (8)
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
-    _LIBUNWIND_POP_CET_SSP((fn));                                              \
-    void *cetRegContext = __libunwind_cet_get_registers((cursor));             \
-    void *cetJumpAddress = __libunwind_cet_get_jump_target();                  \
-    __asm__ volatile("jmpq *%%rdx\n\t" :: "D"(cetRegContext),                  \
-                     "d"(cetJumpAddress));                                     \
+    _LIBUNWIND_POP_SHSTK_SSP((fn));                                            \
+    void *shstkRegContext = __libunwind_shstk_get_registers((cursor));         \
+    void *shstkJumpAddress = __libunwind_shstk_get_jump_target();              \
+    __asm__ volatile("jmpq *%%rdx\n\t" ::"D"(shstkRegContext),                 \
+                     "d"(shstkJumpAddress));                                   \
   } while (0)
 #elif defined(_LIBUNWIND_TARGET_AARCH64)
-#define __cet_ss_step_size 8
+#define __shstk_step_size (8)
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
-    _LIBUNWIND_POP_CET_SSP((fn));                                              \
-    void *cetRegContext = __libunwind_cet_get_registers((cursor));             \
-    void *cetJumpAddress = __libunwind_cet_get_jump_target();                  \
+    _LIBUNWIND_POP_SHSTK_SSP((fn));                                            \
+    void *shstkRegContext = __libunwind_shstk_get_registers((cursor));         \
+    void *shstkJumpAddress = __libunwind_shstk_get_jump_target();              \
     __asm__ volatile("mov x0, %0\n\t"                                          \
                      "br %1\n\t"                                               \
                      :                                                         \
-                     : "r"(cetRegContext), "r"(cetJumpAddress)                 \
+                     : "r"(shstkRegContext), "r"(shstkJumpAddress)             \
                      : "x0");                                                  \
   } while (0)
 #endif
@@ -185,10 +188,11 @@ extern int __unw_step_stage2(unw_cursor_t *);
 
 #if defined(_LIBUNWIND_USE_GCS)
 // Enable the GCS target feature to permit gcspop instructions to be used.
-__attribute__((target("gcs")))
+__attribute__((target("+gcs")))
 #endif
 static _Unwind_Reason_Code
-unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
+unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor,
+              _Unwind_Exception *exception_object) {
   __unw_init_local(cursor, uc);
 
   _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p)",
@@ -255,16 +259,16 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
     }
 #endif
 
-// In CET enabled environment, we check return address stored in normal stack
-// against return address stored in CET shadow stack, if the 2 addresses don't
+// In shadow stack enabled environment, we check return address stored in normal
+// stack against return address stored in shadow stack, if the 2 addresses don't
 // match, it means return address in normal stack has been corrupted, we return
 // _URC_FATAL_PHASE2_ERROR.
 #if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)
     if (shadowStackTop != 0) {
       unw_word_t retInNormalStack;
       __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack);
-      unsigned long retInShadowStack = *(
-          unsigned long *)(shadowStackTop + __cet_ss_step_size * framesWalked);
+      unsigned long retInShadowStack =
+          *(unsigned long *)(shadowStackTop + __shstk_step_size * framesWalked);
       if (retInNormalStack != retInShadowStack)
         return _URC_FATAL_PHASE2_ERROR;
     }
@@ -329,12 +333,12 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
 
 #if defined(_LIBUNWIND_USE_GCS)
 // Enable the GCS target feature to permit gcspop instructions to be used.
-__attribute__((target("gcs")))
+__attribute__((target("+gcs")))
 #endif
 static _Unwind_Reason_Code
 unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
-                     _Unwind_Exception *exception_object,
-                     _Unwind_Stop_Fn stop, void *stop_parameter) {
+                     _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop,
+                     void *stop_parameter) {
   __unw_init_local(cursor, uc);
 
   // uc is initialized by __unw_getcontext in the parent frame. The first stack
@@ -440,7 +444,6 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
   return _URC_FATAL_PHASE2_ERROR;
 }
 
-
 /// Called by __cxa_throw.  Only returns if there is a fatal error.
 _LIBUNWIND_EXPORT _Unwind_Reason_Code
 _Unwind_RaiseException(_Unwind_Exception *exception_object) {
lib/libunwind/src/UnwindRegistersRestore.S
@@ -66,7 +66,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
   # skip fs
   # skip gs
 
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) && !defined(__arm64ec__)
 
 DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
 #
lib/libunwind/src/UnwindRegistersSave.S
@@ -65,6 +65,47 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   xorl  %eax, %eax    # return UNW_ESUCCESS
   ret
 
+#elif defined(__arm64ec__)
+
+//
+// extern int __unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+//  thread_state pointer is in x0
+//
+  .section .text,"xr",discard,"#__unw_getcontext"
+  .p2align 2
+DEFINE_LIBUNWIND_FUNCTION("#__unw_getcontext")
+  stp    x8, x27, [x0, #0x000]  // rax, rbx
+  stp    x0, x1,  [x0, #0x010]  // rcx, rdx
+  stp    x26,x25, [x0, #0x020]  // rdi, rsi
+  mov    x1, sp
+  stp    fp, x1,  [x0, #0x030]  // rbp, rsp
+  stp    x2, x3,  [x0, #0x040]  // r8,  r9
+  stp    x4, x5,  [x0, #0x050]  // r10, r11
+  stp    x19,x20, [x0, #0x060]  // r12, r13
+  stp    x21,x22, [x0, #0x070]  // r14, r15
+  str    x30,     [x0, #0x080]  // store return address as pc
+  stp    q0, q1,  [x0, #0x0b0]  // xmm0, xmm1
+  stp    q2, q3,  [x0, #0x0d0]  // xmm2, xmm3
+  stp    q4, q5,  [x0, #0x0f0]  // xmm4, xmm5
+  stp    q6, q7,  [x0, #0x110]  // xmm6, xmm7
+  stp    q8, q9,  [x0, #0x130]  // xmm8, xmm9
+  stp    q10,q11, [x0, #0x150]  // xmm10,xmm11
+  stp    q12,q13, [x0, #0x170]  // xmm12,xmm13
+  stp    q14,q15, [x0, #0x190]  // xmm14,xmm15
+  mov    x0, #0                 // return UNW_ESUCCESS
+  ret
+
+  .weak_anti_dep __unw_getcontext
+  .set __unw_getcontext, "#__unw_getcontext"
+
+  .section .hybmp$x,"yi"
+  .symidx "#__unw_getcontext"
+  .symidx $ientry_thunk$cdecl$i8$i8
+  .word 1
+  .text
+
 #elif defined(__x86_64__)
 
 #
@@ -1181,7 +1222,15 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 
 #endif
 
+#ifdef __arm64ec__
+  .globl "#unw_getcontext"
+  .set "#unw_getcontext", "#__unw_getcontext"
+  .weak_anti_dep unw_getcontext
+  .set unw_getcontext, "#unw_getcontext"
+  EXPORT_SYMBOL(unw_getcontext)
+#else
   WEAK_ALIAS(__unw_getcontext, unw_getcontext)
+#endif
 
 #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) */