Re: [PATCH] arm: Add unwinding annotations for 64bit divisionfunctions

From: Dave Martin
Date: Wed Sep 21 2011 - 07:39:28 EST


On Mon, Sep 19, 2011 at 06:55:39PM -0700, Laura Abbott wrote:
>
> On Mon, September 19, 2011 4:22 pm, Nicolas Pitre wrote:
> > On Mon, 19 Sep 2011, Laura Abbott wrote:
> >
> >> The 64bit division functions never had unwinding annotations
> >> added. This prevents a backtrace from being printed within
> >> the function and if a division by 0 occurs. Add the annotations.
> >>
> >> Signed-off-by: Laura Abbott <lauraa@xxxxxxxxxxxxxx>
> >> ---
> >> arch/arm/lib/div64.S | 8 ++++++++
> >> 1 files changed, 8 insertions(+), 0 deletions(-)
> >>
> >> diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S
> >> index faa7748..e55c484 100644
> >> --- a/arch/arm/lib/div64.S
> >> +++ b/arch/arm/lib/div64.S
> >> @@ -13,6 +13,7 @@
> >> */
> >>
> >> #include <linux/linkage.h>
> >> +#include <asm/unwind.h>
> >>
> >> #ifdef __ARMEB__
> >> #define xh r0
> >> @@ -44,6 +45,7 @@
> >> */
> >>
> >> ENTRY(__do_div64)
> >> +UNWIND(.fnstart)
> >>
> >> @ Test for easy paths first.
> >> subs ip, r4, #1
> >> @@ -189,7 +191,12 @@ ENTRY(__do_div64)
> >> moveq yh, xh
> >> moveq xh, #0
> >> moveq pc, lr
> >> +UNWIND(.fnend)
> >>
> >> +UNWIND(.fnstart)
> >> +UNWIND(.pad #4)
> >> +UNWIND(.save {lr})
> >> +Ldiv0_64:
> >
> > Why this phony fnend+fnstart here?
> >
> If a division by 0 occurs, we need to be able to access the saved LR on
> the stack which is setup right before calling the __div0 function. This
> can't go at the top of __do_div64 because if we try to do a backtrace from
> within __do_div64 the annotation won't be correct as the LR was never
> saved on the stack. (yes, __do_div64 is all register math but it's still
> possible to take a prefetch abort in the middle of that function. Taking a
> prefetch abort in the middle of __do_div64 is what found this issue in the
> first place.) This setup handles both cases correctly.

Talking to Catalin a bit more, it sounds like prefetch aborts should not
happen in kernel code, and data aborts should not happen when accessing
the kernel stack. If either of these happens, there's no guarantee that
the kernel will be able to recover from the situation fully, so
backtracing may not be the primary concern.

The kinds of situation that the backtracer _can_ cope with are:

a) explicit, synchonous backtrace requests (BUG() etc. within C
functions)

b) aborts when accessing random memory (but not the stack) outside the
function progolgue/epilogue sequences (i.e., so that the state the
unwind info described actually matches reality)

If you get a data abort when accessing the kernel stack, the backtracer
probably won't work at all, because it relies on the same stack. Faults
during prologue/epilogue sequences can't be handled correctly because
the unwind annotations don't descirbe the interim state during these
sequences. There is no general way to use the unwinder annotations to
describe fully how the state evolves during prologue/epilogue sequences.


So, having thought about it, it may be that having the extra .fnstart/
.fnend pair doesn't really help that much after all.

For this code, we do want the unwind state to be properly recorded for
the "bl __div0" call site after Ldiv0_64; but we probably don't need to
worry about backtracing from any other point in this code -- partly
becuase the probably of needing to do it is very low, and partly because
we will likely fail to produce a backtrace in this situation. If this
is a reasonable assumption, then a single unwind annotation block should
be sufficient:

ENTRY(__do_div64)
UNWIND(.fnstart)
subs ip, r4, #1
@ ...

moveq pc, lr

UNWIND(.pad #4)
UNWIND(.save {lr}
stmfd sp!, {r0, lr}
@ ...

bl __div0

@ ...
UNWIND(.fnend)

The location of the .pad and .save is of course not meaningful for the
unwind data: only their respective order, and the fact that they appear
between the .fnstart/.fnend directives. Putting them next to the stmfd
just makes the code easier to read.


The extra annotations in the original patch are harmless, though.

Cheers
---Dave
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/