diff options
author | neel <neel@FreeBSD.org> | 2010-02-20 07:34:37 +0000 |
---|---|---|
committer | neel <neel@FreeBSD.org> | 2010-02-20 07:34:37 +0000 |
commit | 60c69691d99826c120ca6df1743d4b5b303ace57 (patch) | |
tree | 932de22dd87cd6d4debe86c2904481a7f62686d8 | |
parent | 130eee4fb0ef62479a79ef17b87abd711e658054 (diff) | |
download | FreeBSD-src-60c69691d99826c120ca6df1743d4b5b303ace57.zip FreeBSD-src-60c69691d99826c120ca6df1743d4b5b303ace57.tar.gz |
Fix DDB backtrace that includes a kernel exception frame.
The backtrace code tries to look for an instruction of the form "sw ra, x(sp)"
to figure out the program counter of the calling function. When we generate
the kernel exception frame we store the 'ra' at the time of the exception
using an instruction of the same form. The problem is that the 'ra' at the
time of the exception is not the same as the 'program counter' at the time
of the exception.
The fix is to save the 'exception program counter' register by staging
it through the 'ra' register.
-rw-r--r-- | sys/mips/mips/exception.S | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S index 262701e..eff484a 100644 --- a/sys/mips/mips/exception.S +++ b/sys/mips/mips/exception.S @@ -275,6 +275,15 @@ SlowFault: mtc0 a0, COP_0_STATUS_REG #endif +/* + * Save CPU and CP0 register state. + * + * This is straightforward except for saving the exception program + * counter. The ddb backtrace code looks for the first instruction + * matching the form "sw ra, (off)sp" to figure out the address of the + * calling function. So we must make sure that we save the exception + * PC by staging it through 'ra' as opposed to any other register. + */ #define SAVE_CPU \ SAVE_REG(AT, AST, sp) ;\ .set at ; \ @@ -314,9 +323,12 @@ SlowFault: SAVE_REG(v1, MULHI, sp) ;\ SAVE_REG(a0, SR, sp) ;\ SAVE_REG(a1, CAUSE, sp) ;\ - SAVE_REG(ra, RA, sp) ;\ SAVE_REG(a2, BADVADDR, sp) ;\ - SAVE_REG(a3, PC, sp) ;\ + move t0, ra ;\ + move ra, a3 ;\ + SAVE_REG(ra, PC, sp) ;\ + move ra, t0 ;\ + SAVE_REG(ra, RA, sp) ;\ PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\ SAVE_REG(v0, SP, sp) ;\ CLEAR_STATUS ;\ |