From e20145f12ca3ecd913f28619d5f1b04ee91a18e8 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Mon, 26 Nov 2018 17:27:34 +0000 Subject: [PATCH] libphobos: Fix backtraces in Fibers on AArch64. When throwing an Exception in the Fiber the backtrace generation crashes. This happens because backtrace does not func the stack bottom. Using '.cfi_undefined x30' tells the debug info that the value in the lr is unknown, which seems to be the nicest way to stop the unwinder. Setting x30 to 0 is another option, however it still creates one invalid frame in gdb, so the .cfi variant is used here instead. Backport from upstream druntime 2.083. Reviewed-on: https://github.com/dlang/druntime/pull/2308 From-SVN: r266470 --- libphobos/libdruntime/core/thread.d | 38 +++++++++++++++++++++++++++++++++- libphobos/libdruntime/core/threadasm.S | 24 +++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/libphobos/libdruntime/core/thread.d b/libphobos/libdruntime/core/thread.d index b5244711646..ff15d066a49 100644 --- a/libphobos/libdruntime/core/thread.d +++ b/libphobos/libdruntime/core/thread.d @@ -3582,6 +3582,15 @@ private version = AsmExternal; } } + else version (AArch64) + { + version (Posix) + { + version = AsmAArch64_Posix; + version = AsmExternal; + version = AlignFiberStackTo16Byte; + } + } else version (ARM) { version (Posix) @@ -3673,7 +3682,11 @@ private // Look above the definition of 'class Fiber' for some information about the implementation of this routine version (AsmExternal) - extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc; + { + extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc; + version (AArch64) + extern (C) void fiber_trampoline() nothrow; + } else extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc { @@ -4909,6 +4922,29 @@ private: pstack -= ABOVE; *cast(size_t*)(pstack - SZ_RA) = cast(size_t)&fiber_entryPoint; } + else version (AsmAArch64_Posix) + { + // Like others, FP registers and return address (lr) are kept + // below the saved stack top (tstack) to hide from GC scanning. + // fiber_switchContext expects newp sp to look like this: + // 19: x19 + // ... + // 9: x29 (fp) <-- newp tstack + // 8: x30 (lr) [&fiber_entryPoint] + // 7: d8 + // ... + // 0: d15 + + version (StackGrowsDown) {} + else + static assert(false, "Only full descending stacks supported on AArch64"); + + // Only need to set return address (lr). Everything else is fine + // zero initialized. + pstack -= size_t.sizeof * 11; // skip past x19-x29 + push(cast(size_t) &fiber_trampoline); // see threadasm.S for docs + pstack += size_t.sizeof; // adjust sp (newp) above lr + } else version (AsmARM_Posix) { /* We keep the FP registers and the return address below diff --git a/libphobos/libdruntime/core/threadasm.S b/libphobos/libdruntime/core/threadasm.S index 02bd756de3c..140e5f9a9e4 100644 --- a/libphobos/libdruntime/core/threadasm.S +++ b/libphobos/libdruntime/core/threadasm.S @@ -487,6 +487,7 @@ fiber_switchContext: */ .text .global CSYM(fiber_switchContext) + .type fiber_switchContext, %function .p2align 2 CSYM(fiber_switchContext): stp d15, d14, [sp, #-20*8]! @@ -518,6 +519,29 @@ CSYM(fiber_switchContext): ldp d15, d14, [sp], #20*8 ret + +/** + * When generating any kind of backtrace (gdb, exception handling) for + * a function called in a Fiber, we need to tell the unwinder to stop + * at our Fiber main entry point, i.e. we need to mark the bottom of + * the call stack. This can be done by clearing the link register lr + * prior to calling fiber_entryPoint (i.e. in fiber_switchContext) or + * using a .cfi_undefined directive for the link register in the + * Fiber entry point. cfi_undefined seems to yield better results in gdb. + * Unfortunately we can't place it into fiber_entryPoint using inline + * asm, so we use this trampoline instead. + */ + .text + .global CSYM(fiber_trampoline) + .p2align 2 + .type fiber_trampoline, %function +CSYM(fiber_trampoline): + .cfi_startproc + .cfi_undefined x30 + // fiber_entryPoint never returns + bl fiber_entryPoint + .cfi_endproc + #elif defined(__MINGW32__) /************************************************************************************ * GDC MinGW ASM BITS -- 2.11.4.GIT