Is this related to the general panic discussed in freebsd-current?

Andrew Turner andrew at fubar.geek.nz
Fri May 10 08:51:57 UTC 2013


On Thu, 9 May 2013 22:17:09 -0700
Tim Kientzle <kientzle at freebsd.org> wrote:

> 
> On May 6, 2013, at 4:47 AM, Andrew Turner wrote:
> 
> > On Sun, 5 May 2013 22:39:56 -0700
> > Tim Kientzle <kientzle at freebsd.org> wrote:
> >> Here's a version of stack_capture that allows a Clang-built
> >> OABI kernel with WITNESS enabled to boot:
> >> 
> >> /* In sys/arm/arm/stack_machdep.c */
> >> static void
> >> stack_capture(struct stack *st, u_int32_t *frame)
> >> {
> >>        vm_offset_t callpc;
> >> 
> >>        stack_zero(st);
> >>        while (INKERNEL(frame)) {
> >>                callpc = frame[1];
> >>                if (stack_put(st, callpc) == -1)
> >>                        break;
> >>                frame = (u_int32_t *)(frame[0]);
> >>        }
> >> }
> > It looks like this should work in most cases where fp and lr are
> > next to each other (ip and sp are between them but doesn't need to
> > be saved).
> 
> Disassembling an EABI kernel, there are 7930 'push' instructions with
> fp and lr next to each other and only 220 without, so it looks like
> the EABI kernel uses this frame convention as well.
It looks like this is a product of cang/llvm. There is no mention of
the frame pointer that I can find in the EABI documentation and gcc
doesn't appear to generate the 'push' instruction with fp.

We can't rely on fp being stored or valid on EABI.

> So what do you think of the following?

I suspect we need to call stack_zero in all cases. I would thing the
following would work:

static void
stack_capture(struct stack *st, u_int32_t *frame)
{
#if !defined(__ARM_EABI__) && !defined(__clang__)
        vm_offset_t callpc;
#endif

        stack_zero(st);
#if !defined(__ARM_EABI__) && !defined(__clang__)
        while (1) {
                if (!INKERNEL(frame))
                        break;
                callpc = frame[FR_SCP];
                if (stack_put(st, callpc) == -1)
                        break;
                frame = (u_int32_t *)(frame[FR_RFP]);
        }
#endif
}

Alternatively the call to stack_zero could be pushed up into the two
functions that call stack_capture.

Looking at the code it appears stack_save_td also uses the frame
pointer to get the stack location, however as this would be unused this
is less of an issue.

Andrew


More information about the freebsd-arm mailing list