Hi, This patch is backported from druntime 2.083, in continuation of finishing off AArch64 library support.
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. Bootstrapped and tested on aarch64-linux-gnu. Committed to trunk as r266470. -- Iain
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