diff mbox series

[libphobos] Committed fix backtraces in Fibers on AArch64

Message ID CABOHX+czzEzBG+uxzJc1h9fcm17zj=47qMZ5Dcaw-7BbiAC33w@mail.gmail.com
State New
Headers show
Series [libphobos] Committed fix backtraces in Fibers on AArch64 | expand

Commit Message

Iain Buclaw Nov. 26, 2018, 5:28 p.m. UTC
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.
diff mbox series

Patch

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