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