Index: libunwind/include/__libunwind_config.h =================================================================== --- libunwind/include/__libunwind_config.h +++ 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(__i386__) # define _LIBUNWIND_TARGET_I386 # define _LIBUNWIND_CONTEXT_SIZE 8 @@ -70,6 +73,8 @@ # define _LIBUNWIND_CONTEXT_SIZE 66 # if defined(__SEH__) # define _LIBUNWIND_CURSOR_SIZE 164 +#elif defined(_LIBUNWIND_TARGET_FREEBSD) +#define _LIBUNWIND_CURSOR_SIZE 80 # else # define _LIBUNWIND_CURSOR_SIZE 78 # endif Index: libunwind/src/UnwindCursor.hpp =================================================================== --- libunwind/src/UnwindCursor.hpp +++ libunwind/src/UnwindCursor.hpp @@ -37,6 +37,17 @@ #include #include #define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1 +#define _LIBUNWIND_CHECK_SIGRETURN 1 +#endif + +#if defined(_LIBUNWIND_TARGET_FREEBSD) && defined(_LIBUNWIND_TARGET_AARCH64) +#include +#include +#include +#include +#include +#define _LIBUNWIND_CHECK_FREEBSD_SIGRETURN 1 +#define _LIBUNWIND_CHECK_SIGRETURN 1 #endif #include "AddressSpace.hpp" @@ -981,7 +992,7 @@ } #endif -#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) +#if defined(_LIBUNWIND_CHECK_SIGRETURN) bool setInfoForSigReturn() { R dummy; return setInfoForSigReturn(dummy); @@ -1008,7 +1019,7 @@ template int stepThroughSigReturn(Registers &) { return UNW_STEP_END; } -#endif +#endif // defined(_LIBUNWIND_CHECK_SIGRETURN) #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) bool getInfoFromFdeCie(const typename CFI_Parser::FDE_Info &fdeInfo, @@ -1311,9 +1322,14 @@ unw_proc_info_t _info; bool _unwindInfoMissing; bool _isSignalFrame; -#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) +#if defined(_LIBUNWIND_CHECK_SIGRETURN) bool _isSigReturn = false; +#if defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN) + bool _isSigTrampDetermined = false; + pint_t _sigTrampStart; + pint_t _sigTrampEnd; #endif +#endif // defined(_LIBUNWIND_CHECK_SIGRETURN) }; @@ -2523,7 +2539,7 @@ template void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { -#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) +#if defined(_LIBUNWIND_CHECK_SIGRETURN) _isSigReturn = false; #endif @@ -2638,7 +2654,7 @@ } #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) -#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) +#if defined(_LIBUNWIND_CHECK_SIGRETURN) if (setInfoForSigReturn()) return; #endif @@ -2885,6 +2901,63 @@ #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) && // defined(_LIBUNWIND_TARGET_S390X) +#if defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN) && \ + defined(_LIBUNWIND_TARGET_AARCH64) +template +bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) { + // Look for the sigreturn trampoline. + // + // https://cgit.freebsd.org/src/tree/sys/arm64/arm64/sigtramp.S + const pint_t pc = static_cast(this->getReg(UNW_REG_IP)); + + if (_isSigTrampDetermined == false) { + struct kinfo_sigtramp kst = {0}; + size_t len = sizeof(kst); + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_SIGTRAMP, getpid()}; + if (sysctl(mib, 4, &kst, &len, NULL, 0) == 0) { + _isSigTrampDetermined = true; + _sigTrampStart = reinterpret_cast(kst.ksigtramp_start); + _sigTrampEnd = reinterpret_cast(kst.ksigtramp_end); + } + } + + if (_isSigTrampDetermined == false || + (pc < _sigTrampStart || pc >= _sigTrampEnd)) + return false; + + _info = {}; + _info.start_ip = _sigTrampStart; + _info.end_ip = _sigTrampEnd; + _isSigReturn = true; + return true; +} + +template +int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) { + // In the signal trampoline frame, sp points to a sigframe + const pint_t kOffsetSpToSigcontext = + offsetof(struct sigframe, sf_uc) + offsetof(ucontext_t, uc_mcontext); + + // Offsets from mcontext_t to each register. + const pint_t kOffsetGprs = offsetof(struct gpregs, gp_x[0]); + const pint_t kOffsetSp = offsetof(struct gpregs, gp_sp); + const pint_t kOffsetPc = offsetof(struct gpregs, gp_lr); + + pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext; + + for (int i = 0; i <= 29; ++i) { + uint64_t value = + _addressSpace.get64(sigctx + kOffsetGprs + static_cast(i * 8)); + _registers.setRegister(UNW_AARCH64_X0 + i, value); + } + _registers.setSP(_addressSpace.get64(sigctx + kOffsetSp)); + _registers.setIP(_addressSpace.get64(sigctx + kOffsetPc)); + _isSignalFrame = true; + return UNW_STEP_SUCCESS; +} +#endif // defined(_LIBUNWIND_CHECK_FREEBSD_SIGRETURN) && + // defined(_LIBUNWIND_TARGET_AARCH64) + template int UnwindCursor::step(bool stage2) { (void)stage2; // Bottom of stack is defined is when unwind info cannot be found. @@ -2893,7 +2966,7 @@ // Use unwinding info to modify register set as if function returned. int result; -#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) +#if defined(_LIBUNWIND_CHECK_SIGRETURN) if (_isSigReturn) { result = this->stepThroughSigReturn(); } else