Hi all,

There is a patch proposed on glibc that removes the powerpc backtrace
implementation [1]. As discussed in that thread, it would be helpful to have a
backchain fallback on libgcc before removing it.
This patch is moving part of that code to libgcc in order to do that. Is it
acceptable to have the trace_arg struct here or should this be handled by the
trace function passed to _Unwind_Backtrace()?
Any comments are appreciated.

Best Regards,
Raphael Moreira Zinsly

[1] https://sourceware.org/pipermail/libc-alpha/2021-February/122600.html

---
 libgcc/config/rs6000/linux-unwind.h | 58 ++++++++++++++++++++++++++++-
 libgcc/unwind.inc                   | 12 +++++-
 2 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/libgcc/config/rs6000/linux-unwind.h 
b/libgcc/config/rs6000/linux-unwind.h
index acdc948f85d..1f4b5e72d47 100644
--- a/libgcc/config/rs6000/linux-unwind.h
+++ b/libgcc/config/rs6000/linux-unwind.h
@@ -203,7 +203,7 @@ ppc_fallback_frame_state (struct _Unwind_Context *context,
   int i;
 
   if (regs == NULL)
-    return _URC_END_OF_STACK;
+    return _URC_NORMAL_STOP;
 
   new_cfa = regs->gpr[__LIBGCC_STACK_POINTER_REGNUM__];
   fs->regs.cfa_how = CFA_REG_OFFSET;
@@ -352,3 +352,59 @@ frob_update_context (struct _Unwind_Context *context, 
_Unwind_FrameState *fs ATT
     }
 #endif
 }
+
+#define MD_BACKCHAIN_FALLBACK ppc_backchain_fallback
+
+struct trace_arg
+{
+  void **array;
+  struct unwind_link *unwind_link;
+  _Unwind_Word cfa;
+  int cnt;
+  int size;
+};
+
+/* This is the stack layout we see with every stack frame.
+   Note that every routine is required by the ABI to lay out the stack
+   like this.
+
+           +----------------+        +-----------------+
+    %r1  -> | %r1 last frame--------> | %r1 last frame--->...  --> NULL
+           |                |        |                 |
+           | cr save        |        | cr save         |
+           |                |        |                 |
+           | (unused)       |        | return address  |
+           +----------------+        +-----------------+
+*/
+struct layout
+{
+  struct layout *next;
+  long int condition_register;
+  void *return_address;
+};
+
+void ppc_backchain_fallback (void *a)
+{
+  struct layout *current;
+  struct trace_arg *arg = a;
+
+  /* Force gcc to spill LR.  */
+  asm volatile ("" : "=l"(current));
+
+  /* Get the address on top-of-stack.  */
+  asm volatile ("ld %0,0(1)" : "=r"(current));
+
+  for (int count = 0; current != NULL; current = current->next, count++)
+    {
+      arg->array[count] = current->return_address;
+
+      /* Check if the symbol is the signal trampoline and get the interrupted
+       * symbol address from the trampoline saved area. (WIP)  */
+      if (IS_SIGTRAMP_ADDRESS(current->return_address))
+       {
+         if (count + 1 == arg->size)
+           break;
+         // Get sigframe, update arg->array[++count] and current.
+       }
+    }
+}
diff --git a/libgcc/unwind.inc b/libgcc/unwind.inc
index aa48d104fd0..955722b1743 100644
--- a/libgcc/unwind.inc
+++ b/libgcc/unwind.inc
@@ -300,14 +300,22 @@ _Unwind_Backtrace(_Unwind_Trace_Fn trace, void * 
trace_argument)
 
       /* Set up fs to describe the FDE for the caller of context.  */
       code = uw_frame_state_for (&context, &fs);
-      if (code != _URC_NO_REASON && code != _URC_END_OF_STACK)
+      if (code != _URC_NO_REASON && code != _URC_END_OF_STACK
+          && code != _URC_NORMAL_STOP)
        return _URC_FATAL_PHASE1_ERROR;
 
       /* Call trace function.  */
       if ((*trace) (&context, trace_argument) != _URC_NO_REASON)
        return _URC_FATAL_PHASE1_ERROR;
 
-      /* We're done at end of stack.  */       
+      /* Do a backchain if there is no CFI data.  */
+      if (code == _URC_NORMAL_STOP)
+       {
+         MD_BACKCHAIN_FALLBACK(trace_argument);
+         break;
+       }
+
+      /* We're done at end of stack.  */
       if (code == _URC_END_OF_STACK)
        break;
 
-- 
2.29.2

Reply via email to