Index: libgcc/config/i386/freebsd-unwind.h =================================================================== --- libgcc/config/i386/freebsd-unwind.h (revision 254205) +++ libgcc/config/i386/freebsd-unwind.h (working copy) @@ -28,7 +28,10 @@ #include #include +#include +#include #include +#include #include #define REG_NAME(reg) sf_uc.uc_mcontext.mc_## reg @@ -36,38 +39,46 @@ #ifdef __x86_64__ #define MD_FALLBACK_FRAME_STATE_FOR x86_64_freebsd_fallback_frame_state +static int +x86_64_outside_sigtramp_range (unsigned char *pc) +{ + static int sigtramp_range_determined = 0; + static unsigned char *sigtramp_start, *sigtramp_end; + + if (sigtramp_range_determined == 0) + { + struct kinfo_sigtramp kst = {0}; + size_t len = sizeof (kst); + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_SIGTRAMP, getpid() }; + + sigtramp_range_determined = 1; + if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0) + { + sigtramp_range_determined = 2; + sigtramp_start = kst.ksigtramp_start; + sigtramp_end = kst.ksigtramp_end; + } + } + if (sigtramp_range_determined < 2) /* sysctl failed if < 2 */ + return 1; + + return (pc < sigtramp_start || pc >= sigtramp_end); +} + static _Unwind_Reason_Code x86_64_freebsd_fallback_frame_state (struct _Unwind_Context *context, _Unwind_FrameState *fs) { struct sigframe *sf; - long new_cfa; + _Unwind_Ptr new_cfa; - /* Prior to FreeBSD 9, the signal trampoline was located immediately - before the ps_strings. To support non-executable stacks on AMD64, - the sigtramp was moved to a shared page for FreeBSD 9. Unfortunately - this means looking frame patterns again (sys/amd64/amd64/sigtramp.S) - rather than using the robust and convenient KERN_PS_STRINGS trick. - - : lea 0x10(%rsp),%rdi - : pushq $0x0 - : mov $0x1a1,%rax - : syscall - - If we can't find this pattern, we're at the end of the stack. - */ - - if (!( *(unsigned int *)(context->ra) == 0x247c8d48 - && *(unsigned int *)(context->ra + 4) == 0x48006a10 - && *(unsigned int *)(context->ra + 8) == 0x01a1c0c7 - && *(unsigned int *)(context->ra + 12) == 0x050f0000 )) + if (x86_64_outside_sigtramp_range(context->ra)) return _URC_END_OF_STACK; sf = (struct sigframe *) context->cfa; new_cfa = sf->REG_NAME(rsp); fs->regs.cfa_how = CFA_REG_OFFSET; - /* Register 7 is rsp */ - fs->regs.cfa_reg = 7; + fs->regs.cfa_reg = __LIBGCC_STACK_POINTER_REGNUM__; fs->regs.cfa_offset = new_cfa - (long) context->cfa; /* The SVR4 register numbering macros aren't usable in libgcc. */