public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Raphael Moreira Zinsly <rzinsly@linux.ibm.com>
To: gcc-patches@gcc.gnu.org
Cc: segher@kernel.crashing.org, dje.gcc@gmail.com, amodra@gmail.com,
	wschmidt@linux.ibm.com, tuliom@linux.ibm.com,
	Raphael Moreira Zinsly <rzinsly@linux.ibm.com>
Subject: [PATCH v2] libgcc: Add a backchain fallback to _Unwind_Backtrace() on PowerPC
Date: Thu, 26 Aug 2021 11:53:24 -0300	[thread overview]
Message-ID: <20210826145324.19505-1-rzinsly@linux.ibm.com> (raw)

Without dwarf2 unwind tables available _Unwind_Backtrace() is not
able to return the full backtrace.
This patch adds a fallback function on powerpc to get the backtrace
by doing a backchain, this code was originally at glibc.

libgcc/ChangeLog:

	* config/rs6000/linux-unwind.h (struct rt_sigframe): Move it to
	outside of get_regs() in order to use it in another function,
	this is done twice: for __powerpc64__ and for !__powerpc64__.
	(struct trace_arg): New struct.
	(struct layout): New struct.
	(ppc_backchain_fallback): New function.
	* unwind.inc (_Unwind_Backtrace): Look for _URC_NORMAL_STOP
	code state and call MD_BACKCHAIN_FALLBACK.

gcc/testsuite/ChangeLog:

	* gcc.target/powerpc/unwind-backchain.c: New test.
---
 .../gcc.target/powerpc/unwind-backchain.c     |  22 ++++
 libgcc/config/rs6000/linux-unwind.h           | 102 +++++++++++++++---
 libgcc/unwind.inc                             |  14 ++-
 3 files changed, 122 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/unwind-backchain.c

diff --git a/gcc/testsuite/gcc.target/powerpc/unwind-backchain.c b/gcc/testsuite/gcc.target/powerpc/unwind-backchain.c
new file mode 100644
index 00000000000..fdce78a1f63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/unwind-backchain.c
@@ -0,0 +1,22 @@
+/* { dg-do run { target { powerpc*-*-linux* } } } */
+/* { dg-options "-fno-asynchronous-unwind-tables" } */
+
+#include <execinfo.h>
+
+void
+test_backtrace()
+{
+  int addresses;
+  void *buffer[10];
+
+  addresses = backtrace(buffer, 10);
+  if(addresses != 4)
+    __builtin_abort();
+}
+
+int
+main()
+{
+  test_backtrace();
+  return 0;
+}
diff --git a/libgcc/config/rs6000/linux-unwind.h b/libgcc/config/rs6000/linux-unwind.h
index acdc948f85d..8deccc1d650 100644
--- a/libgcc/config/rs6000/linux-unwind.h
+++ b/libgcc/config/rs6000/linux-unwind.h
@@ -94,6 +94,15 @@ struct gcc_ucontext
 
 enum { SIGNAL_FRAMESIZE = 128 };
 
+struct rt_sigframe {
+  char gap[SIGNAL_FRAMESIZE];
+  struct gcc_ucontext uc;
+  unsigned long pad[2];
+  int tramp[6];
+  void *pinfo;
+  struct gcc_ucontext *puc;
+};
+
 /* If PC is at a sigreturn trampoline, return a pointer to the
    regs.  Otherwise return NULL.  */
 
@@ -136,14 +145,7 @@ get_regs (struct _Unwind_Context *context)
 #endif
 	{
 	  /* This works for 2.4.21 and later kernels.  */
-	  struct rt_sigframe {
-	    char gap[SIGNAL_FRAMESIZE];
-	    struct gcc_ucontext uc;
-	    unsigned long pad[2];
-	    int tramp[6];
-	    void *pinfo;
-	    struct gcc_ucontext *puc;
-	  } *frame = (struct rt_sigframe *) context->cfa;
+	  struct rt_sigframe *frame = (struct rt_sigframe *) context->cfa;
 	  return frame->uc.regs;
 	}
     }
@@ -154,6 +156,12 @@ get_regs (struct _Unwind_Context *context)
 
 enum { SIGNAL_FRAMESIZE = 64 };
 
+struct rt_sigframe {
+  char gap[SIGNAL_FRAMESIZE + 16];
+  char siginfo[128];
+  struct gcc_ucontext uc;
+};
+
 static struct gcc_regs *
 get_regs (struct _Unwind_Context *context)
 {
@@ -176,11 +184,7 @@ get_regs (struct _Unwind_Context *context)
     }
   else if (pc[0] == 0x38006666 || pc[0] == 0x380000AC)
     {
-      struct rt_sigframe {
-	char gap[SIGNAL_FRAMESIZE + 16];
-	char siginfo[128];
-	struct gcc_ucontext uc;
-      } *frame = (struct rt_sigframe *) context->cfa;
+      struct rt_sigframe *frame = (struct rt_sigframe *) context->cfa;
       return frame->uc.regs;
     }
   return NULL;
@@ -203,7 +207,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 +356,73 @@ frob_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs ATT
     }
 #endif
 }
+
+#define MD_BACKCHAIN_FALLBACK ppc_backchain_fallback
+
+struct trace_arg
+{
+  /* Stores the list of addresses.  */
+  void **array;
+  struct unwind_link *unwind_link;
+  _Unwind_Word cfa;
+  /* Number of addresses currently stored.  */
+  int count;
+  /* Maximum number of addresses.  */
+  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  -> | previous frame--------> | previous frame--->...  --> NULL
+	    |                |        |                 |
+	    | cr save        |        | cr save	        |
+	    |                |        |                 |
+	    | (unused)       |        | lr save         |
+	    +----------------+        +-----------------+
+
+  The CR save is only present on 64-bit ABIs.
+*/
+struct frame_layout
+{
+  struct frame_layout *backchain;
+#ifdef __powerpc64__
+  long int cr_save;
+#endif
+  void *lr_save;
+};
+
+
+void ppc_backchain_fallback (struct _Unwind_Context *context, void *a)
+{
+  struct frame_layout *current;
+  struct trace_arg *arg = a;
+  int count;
+
+  /* Get the last address computed and start with the next.  */
+  current = context->cfa;
+  current = current->backchain;
+
+  for (count = arg->count; current != NULL; current = current->backchain)
+    {
+      arg->array[count] = current->lr_save;
+
+      /* Check if the symbol is the signal trampoline and get the interrupted
+	 symbol address from the trampoline saved area.  */
+      context->ra = current->lr_save;
+      if (current->lr_save && get_regs (context))
+	{
+	  struct rt_sigframe *sigframe = (struct rt_sigframe *) current;
+	  if (count + 1 == arg->size)
+	    break;
+	  arg->array[++count] = (void *) sigframe->uc.rsave.nip;
+	  current = (void *) sigframe->uc.rsave.gpr[1];
+	}
+      if (count++ >= arg->size)
+	break;
+    }
+
+  arg->count = count-1;
+}
diff --git a/libgcc/unwind.inc b/libgcc/unwind.inc
index aa48d104fd0..456a5ee682f 100644
--- a/libgcc/unwind.inc
+++ b/libgcc/unwind.inc
@@ -300,14 +300,24 @@ _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.  */	
+#ifdef MD_BACKCHAIN_FALLBACK
+      /* Do a backchain if there is no DWARF data.  */
+      if (code == _URC_NORMAL_STOP)
+	{
+	  MD_BACKCHAIN_FALLBACK(&context, trace_argument);
+	  break;
+	}
+#endif
+
+      /* We're done at end of stack.  */
       if (code == _URC_END_OF_STACK)
 	break;
 
-- 
2.31.1


             reply	other threads:[~2021-08-26 14:53 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-26 14:53 Raphael Moreira Zinsly [this message]
2021-09-14 13:11 ` Raphael M Zinsly
2021-09-28 19:50 ` Segher Boessenkool
2021-09-29 14:14   ` Raphael M Zinsly
2021-09-29 15:34     ` Segher Boessenkool

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210826145324.19505-1-rzinsly@linux.ibm.com \
    --to=rzinsly@linux.ibm.com \
    --cc=amodra@gmail.com \
    --cc=dje.gcc@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=segher@kernel.crashing.org \
    --cc=tuliom@linux.ibm.com \
    --cc=wschmidt@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).