Re: [PATCH 1/23] Make register values available to panic notifiers

From: David Howells
Date: Wed Apr 14 2010 - 19:52:35 EST


David VomLehn <dvomlehn@xxxxxxxxx> wrote:

> > Can the use of va_start() clobber lots of registers, thereby rendering the
> > exercise pointless on some arches?
> >
>
> The implementations I'm familiar with only need one or two registers. What
> it *does* do is to force the contents of registers being used to pass
> argument values onto the stack. This is roughly what gcc does for asm()
> statements when you tell it registers are clobbered.

How about something like Sparc, where you can pass up to 8 arguments (if I
remember correctly) in registers. I'm not sure how Sparc handles varargs
functions, though.

> > Also, can the save_ptregs() function be out of line asm? The FRV
> > constructed inline statement is huge (and wrong).
>
> With this implementation it has to be inline. One use of the saved registers
> is to backtrace the stack.

Indeed, but you've probably already lost that by using va_start().

> If you call a function to save the registers, the stack pointer and program
> counter would be those of the called function, which will not be valid after
> it returns.

Well, they'll be the context of panic() in your implementation.

> I expect that you could come up with an alternative out-of-line function

Yes. The easiest way might be to write the saver in assembly and call it from
within an inline asm statement.

> --on every processor I know, you could backtrace one frame to get reasonable
> values for those registers,. Unfortunately, you would run the risk of
> clobbering other registers by doing the function call. The more you change
> register values from those in the function that calls panic(), the less
> useful this becomes.

Indeed, but the more things panic() does, the more likely it is to clobber
registers anyway.

Note, also: panic() is __attribute__((noreturn)), which means that the
compiler calling it is not required to save the return address or registers
before jumping to panic() or even in panic() itself.

> In this case, I think an inline function is worth the effort to get working.

As I mentioned above, you can use asm for this. For instance, you can write
an inline asm statement that saves onto the stack the registers that need to
be clobbered to make a jump, then make the jump, and then have the saver
routine retrieve the register values from the stack and place them in the
storage area.

In fact, you could insert a prologue wrapper on panic() with a bit of asm to
save the registers, for example on FRV:

panic:
subi sp,#-8,sp
stdi.p gr4,@(sp,#0) # save GR4/GR5 on stack
addi sp,#8,gr5
sethi.p %hi(__panic_reg_save),gr4 # get the save space addr
setlo %lo(__panic_reg_save),gr4
sti gr5,@(gr4,#REG_SP)) # save orig stack pointer
stdi gr2,@(gr4,#REG_GR(2)) # save GR2/GR3
ldi @(sp,#0),gr5
sti gr5,@(gr4,#REG_GR(4)) # save orig GR4
ldi @(sp,#4),gr5
sti gr5,@(gr4,#REG_GR(5)) # save orig GR5
stdi gr6,@(gr4,#REG_GR(6)) # save GR6/GR7
stdi gr8,@(gr4,#REG_GR(8)) # save GR8/GR9
...
lddi.p @(sp,#0),gr4 # restore GR4/GR5 from stack
addi sp,#8,sp
bra real_panic # chain

Then real_panic() would be the original C panic function.

> (I'd be interested in know more details about how things are broken in the
> FRV)

Most load/store instructions come in two types, and you need to modify the
opcode according to the addressing mode and indicate that you're interpolating
a memory dereference argument rather than an address:

asm("ldd%I1 %M1,%0"
: "=e"(counter)
: "m"(v->counter));

You're also trying to load data into GR0 which won't achieve anything. GR0 is
hardwired to 0. It's used as the target of instructions where you don't care
about the calculated result (eg: compare is implemented as subtract to GR0),
and as a source of 0.

David
--
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/