On 2017/05/24 10:05PM, Mark Wielaard wrote: > This adds a minimal fallback unwinder for ppc64[le] in case we cannot find > CFI for a particular address. It simply always sets the program counter to > the link register, picks the previous stack pointer from the backchain, > and the previous link register from the LR save area. > > This isn't enough for some more complex situations like signal frames, > but it is only used when we don't have CFI and seems to work nicely > in the case of perf with libdw powerpc support: > https://lkml.org/lkml/2017/5/18/998 > > Signed-off-by: Mark Wielaard <m...@klomp.org>
Mark, Thanks for adding this! I am not entirely familiar with how this works, but... > --- > backends/Makefile.am | 2 +- > backends/ppc64_init.c | 1 + > backends/ppc64_unwind.c | 76 > +++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 78 insertions(+), 1 deletion(-) > create mode 100644 backends/ppc64_unwind.c > > diff --git a/backends/Makefile.am b/backends/Makefile.am > index ff80a82..ac45a45 100644 > --- a/backends/Makefile.am > +++ b/backends/Makefile.am > @@ -98,7 +98,7 @@ am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os) > > ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \ > ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \ > - ppc_cfi.c ppc_initreg.c ppc64_resolve_sym.c > + ppc_cfi.c ppc_initreg.c ppc64_unwind.c ppc64_resolve_sym.c > libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS) > am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os) > > diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c > index 11d3a77..e567033 100644 > --- a/backends/ppc64_init.c > +++ b/backends/ppc64_init.c > @@ -73,6 +73,7 @@ ppc64_init (Elf *elf __attribute__ ((unused)), > eh->frame_nregs = (114 - 1) + 32; > HOOK (eh, set_initial_registers_tid); > HOOK (eh, dwarf_to_regno); > + HOOK (eh, unwind); > HOOK (eh, resolve_sym_value); > > /* Find the function descriptor .opd table for resolve_sym_value. */ > diff --git a/backends/ppc64_unwind.c b/backends/ppc64_unwind.c > new file mode 100644 > index 0000000..f7dffd6 > --- /dev/null > +++ b/backends/ppc64_unwind.c > @@ -0,0 +1,76 @@ > +/* Get previous frame state for an existing frame state. > + Copyright (C) 2017 Red Hat, Inc. > + This file is part of elfutils. > + > + This file is free software; you can redistribute it and/or modify > + it under the terms of either > + > + * the GNU Lesser General Public License as published by the Free > + Software Foundation; either version 3 of the License, or (at > + your option) any later version > + > + or > + > + * the GNU General Public License as published by the Free > + Software Foundation; either version 2 of the License, or (at > + your option) any later version > + > + or both in parallel, as here. > + > + elfutils is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + General Public License for more details. > + > + You should have received copies of the GNU General Public License and > + the GNU Lesser General Public License along with this program. If > + not, see <http://www.gnu.org/licenses/>. */ > + > +#ifdef HAVE_CONFIG_H > +# include <config.h> > +#endif > + > +#define BACKEND ppc64_ > + > +#define LR_REG 65 /* Not 108, see ppc_dwarf_to_regno. */ > +#define SP_REG 1 > + > +#define LR_OFFSET 16 > + > +#include "libebl_CPU.h" > + > +/* Simplistic fallback frame unwinder. SP points to the backchain (contains > + address of previous stack pointer). At SP offset 16 is the LR save area > + (contains the value of the previous LR). */ > + > +bool > +EBLHOOK(unwind) (Ebl *ebl __attribute__ ((unused)), > + Dwarf_Addr pc __attribute__ ((unused)), > + ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t > *getfunc, > + ebl_pid_memory_read_t *readfunc, void *arg, > + bool *signal_framep __attribute__ ((unused))) > +{ > + Dwarf_Word sp, newSp, lr, newLr; > + > + /* Stack pointer points to the backchain which contains the previous sp. > */ > + if (! getfunc (SP_REG, 1, &sp, arg)) > + sp = 0; > + > + /* Link register contains previous program counter. */ > + if (! getfunc (LR_REG, 1, &lr, arg) > + || lr == 0 > + || ! setfunc (-1, 1, &lr, arg)) > + return false; > + > + if (! readfunc(sp, &newSp, arg)) > + newSp = 0; > + > + if (! readfunc(sp + LR_OFFSET, &newLr, arg)) should this be newSp + LR_OFFSET, since the LR save area is in the caller's stack frame? - Naveen > + newLr = 0; > + > + setfunc(SP_REG, 1, &newSp, arg); > + setfunc(LR_REG, 1, &newLr, arg); > + > + /* Sanity check the stack grows down. */ > + return newSp > sp; > +} > -- > 1.8.3.1 >