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
This commit is contained in:
Iain Buclaw 2018-11-26 17:27:34 +00:00
parent ef6e6914c8
commit e20145f12c
2 changed files with 61 additions and 1 deletions

View File

@ -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

View File

@ -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