Hi Nathan, Would you please submit this to Russell's patch tracking system: https://www.arm.linux.org.uk/developer/patches/ login -> add new patch. On Mon, Jul 6, 2020 at 11:27 AM Nathan Huckleberry <nhuck@xxxxxxxxxx> wrote: > > Since clang does not push pc and sp in function prologues, the current > implementation of unwind_frame does not work. By using the previous > frame's lr/fp instead of saved pc/sp we get valid unwinds on clang-built > kernels. > > The bounds check on next frame pointer must be changed as well since > there are 8 less bytes between frames. > > This fixes /proc/<pid>/stack. > > Link: https://github.com/ClangBuiltLinux/linux/issues/912 > Reported-by: Miles Chen <miles.chen@xxxxxxxxxxxx> > Tested-by: Miles Chen <miles.chen@xxxxxxxxxxxx> > Cc: stable@xxxxxxxxxxxxxxx > Reviewed-by: Nick Desaulniers <ndesaulniers@xxxxxxxxxx> > Signed-off-by: Nathan Huckleberry <nhuck@xxxxxxxxxx> > --- > arch/arm/kernel/stacktrace.c | 24 ++++++++++++++++++++++++ > 1 file changed, 24 insertions(+) > > diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c > index cc726afea023..76ea4178a55c 100644 > --- a/arch/arm/kernel/stacktrace.c > +++ b/arch/arm/kernel/stacktrace.c > @@ -22,6 +22,19 @@ > * A simple function epilogue looks like this: > * ldm sp, {fp, sp, pc} > * > + * When compiled with clang, pc and sp are not pushed. A simple function > + * prologue looks like this when built with clang: > + * > + * stmdb {..., fp, lr} > + * add fp, sp, #x > + * sub sp, sp, #y > + * > + * A simple function epilogue looks like this when built with clang: > + * > + * sub sp, fp, #x > + * ldm {..., fp, pc} > + * > + * > * Note that with framepointer enabled, even the leaf functions have the same > * prologue and epilogue, therefore we can ignore the LR value in this case. > */ > @@ -34,6 +47,16 @@ int notrace unwind_frame(struct stackframe *frame) > low = frame->sp; > high = ALIGN(low, THREAD_SIZE); > > +#ifdef CONFIG_CC_IS_CLANG > + /* check current frame pointer is within bounds */ > + if (fp < low + 4 || fp > high - 4) > + return -EINVAL; > + > + frame->sp = frame->fp; > + frame->fp = *(unsigned long *)(fp); > + frame->pc = frame->lr; > + frame->lr = *(unsigned long *)(fp + 4); > +#else > /* check current frame pointer is within bounds */ > if (fp < low + 12 || fp > high - 4) > return -EINVAL; > @@ -42,6 +65,7 @@ int notrace unwind_frame(struct stackframe *frame) > frame->fp = *(unsigned long *)(fp - 12); > frame->sp = *(unsigned long *)(fp - 8); > frame->pc = *(unsigned long *)(fp - 4); > +#endif > > return 0; > } > -- > 2.27.0.212.ge8ba1cc988-goog > -- Thanks, ~Nick Desaulniers