* [PATCH v3] libgcc: Add a backchain fallback to _Unwind_Backtrace() on PowerPC
@ 2021-10-05 18:32 Raphael Moreira Zinsly
2021-10-05 22:03 ` Segher Boessenkool
0 siblings, 1 reply; 4+ messages in thread
From: Raphael Moreira Zinsly @ 2021-10-05 18:32 UTC (permalink / raw)
To: gcc-patches
Cc: segher, dje.gcc, amodra, wschmidt, tuliom, Raphael Moreira Zinsly
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 | 24 +++++
libgcc/config/rs6000/linux-unwind.h | 102 +++++++++++++++---
libgcc/unwind.inc | 14 ++-
3 files changed, 124 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..affa9b2efec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/unwind-backchain.c
@@ -0,0 +1,24 @@
+/* -linux* targets have a fallback for the absence of unwind tables, thus are
+ the only ones we can guarantee backtrace returns all addresses. */
+/* { dg-do run { target { *-*-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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v3] libgcc: Add a backchain fallback to _Unwind_Backtrace() on PowerPC
2021-10-05 18:32 [PATCH v3] libgcc: Add a backchain fallback to _Unwind_Backtrace() on PowerPC Raphael Moreira Zinsly
@ 2021-10-05 22:03 ` Segher Boessenkool
2021-10-06 13:09 ` Raphael M Zinsly
0 siblings, 1 reply; 4+ messages in thread
From: Segher Boessenkool @ 2021-10-05 22:03 UTC (permalink / raw)
To: Raphael Moreira Zinsly; +Cc: gcc-patches, dje.gcc, amodra, wschmidt, tuliom
On Tue, Oct 05, 2021 at 03:32:52PM -0300, Raphael Moreira Zinsly wrote:
> 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 | 24 +++++
> libgcc/config/rs6000/linux-unwind.h | 102 +++++++++++++++---
> libgcc/unwind.inc | 14 ++-
> 3 files changed, 124 insertions(+), 16 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/powerpc/unwind-backchain.c
So what is new or different in v3 compared to v2?
Segher
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v3] libgcc: Add a backchain fallback to _Unwind_Backtrace() on PowerPC
2021-10-05 22:03 ` Segher Boessenkool
@ 2021-10-06 13:09 ` Raphael M Zinsly
2021-10-06 15:23 ` Segher Boessenkool
0 siblings, 1 reply; 4+ messages in thread
From: Raphael M Zinsly @ 2021-10-06 13:09 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: gcc-patches, dje.gcc, amodra, wschmidt, tuliom
On 05/10/2021 19:03, Segher Boessenkool wrote:
> On Tue, Oct 05, 2021 at 03:32:52PM -0300, Raphael Moreira Zinsly wrote:
>> 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 | 24 +++++
>> libgcc/config/rs6000/linux-unwind.h | 102 +++++++++++++++---
>> libgcc/unwind.inc | 14 ++-
>> 3 files changed, 124 insertions(+), 16 deletions(-)
>> create mode 100644 gcc/testsuite/gcc.target/powerpc/unwind-backchain.c
>
> So what is new or different in v3 compared to v2?
>
gcc/testsuite/gcc.target/powerpc/unwind-backchain.c:
- Added a comment explaining why test only on *-linux targets.
- Changed the dejagnu target from powerpc*-*-linux* to *-*-linux*.
--
Raphael Moreira Zinsly
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v3] libgcc: Add a backchain fallback to _Unwind_Backtrace() on PowerPC
2021-10-06 13:09 ` Raphael M Zinsly
@ 2021-10-06 15:23 ` Segher Boessenkool
0 siblings, 0 replies; 4+ messages in thread
From: Segher Boessenkool @ 2021-10-06 15:23 UTC (permalink / raw)
To: Raphael M Zinsly; +Cc: gcc-patches, dje.gcc, amodra, wschmidt, tuliom
On Wed, Oct 06, 2021 at 10:09:31AM -0300, Raphael M Zinsly wrote:
> On 05/10/2021 19:03, Segher Boessenkool wrote:
> >So what is new or different in v3 compared to v2?
>
> gcc/testsuite/gcc.target/powerpc/unwind-backchain.c:
> - Added a comment explaining why test only on *-linux targets.
> - Changed the dejagnu target from powerpc*-*-linux* to *-*-linux*.
I said in v2 that it is fine with that changed, so: okay for trunk :-)
Thanks!
Segher
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-10-06 15:24 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-05 18:32 [PATCH v3] libgcc: Add a backchain fallback to _Unwind_Backtrace() on PowerPC Raphael Moreira Zinsly
2021-10-05 22:03 ` Segher Boessenkool
2021-10-06 13:09 ` Raphael M Zinsly
2021-10-06 15:23 ` Segher Boessenkool
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).