Teach DDB how to unwind across a kernel stack overflow.
Kernel stack overflows in MIPS call panic() directly from an assembly handler after storing the interrupted context's registers in a trapframe. Rather than inferring the location of ra, sp, and pc from the instruction stream, recognize the pc of a kernel stack overflow and pull the registers from the trapframe. Sponsored by: DARPA / AFRL
This commit is contained in:
parent
7a6d450d66
commit
7212e5d8bf
@ -111,6 +111,7 @@ void trapDump(char *msg);
|
||||
void MipsFPTrap(u_int, u_int, u_int);
|
||||
void MipsKernGenException(void);
|
||||
void MipsKernIntr(void);
|
||||
void MipsKStackOverflow(void);
|
||||
void MipsTLBInvalidException(void);
|
||||
void MipsTLBMissException(void);
|
||||
void MipsUserGenException(void);
|
||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/stack.h>
|
||||
#include <sys/sysent.h>
|
||||
|
||||
#include <machine/asm.h>
|
||||
#include <machine/db_machdep.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/mips_opcode.h>
|
||||
@ -157,7 +158,6 @@ stacktrace_subr(register_t pc, register_t sp, register_t ra,
|
||||
valid_args[2] = 0;
|
||||
valid_args[3] = 0;
|
||||
next_ra = 0;
|
||||
/* Jump here after a nonstandard (interrupt handler) frame */
|
||||
stksize = 0;
|
||||
subr = 0;
|
||||
if (frames++ > 100) {
|
||||
@ -213,6 +213,15 @@ stacktrace_subr(register_t pc, register_t sp, register_t ra,
|
||||
ra = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a kernel stack overflow, skip to the output and
|
||||
* afterwards pull the previous registers out of the trapframe
|
||||
* instead of decoding the function prologue.
|
||||
*/
|
||||
if (pc == (uintptr_t)MipsKStackOverflow)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Find the beginning of the current subroutine by scanning
|
||||
* backwards from the current PC for the end of the previous
|
||||
@ -389,7 +398,21 @@ stacktrace_subr(register_t pc, register_t sp, register_t ra,
|
||||
(uintmax_t)(u_register_t) sp,
|
||||
stksize);
|
||||
|
||||
if (ra) {
|
||||
if (pc == (uintptr_t)MipsKStackOverflow) {
|
||||
#define TF_REG(base, reg) ((base) + CALLFRAME_SIZ + ((reg) * SZREG))
|
||||
#if defined(__mips_n64) || defined(__mips_n32)
|
||||
pc = kdbpeekd((int *)TF_REG(sp, PC));
|
||||
ra = kdbpeekd((int *)TF_REG(sp, RA));
|
||||
sp = kdbpeekd((int *)TF_REG(sp, SP));
|
||||
#else
|
||||
pc = kdbpeek((int *)TF_REG(sp, PC));
|
||||
ra = kdbpeek((int *)TF_REG(sp, RA));
|
||||
sp = kdbpeek((int *)TF_REG(sp, SP));
|
||||
#endif
|
||||
#undef TF_REG
|
||||
(*printfn) ("--- Kernel Stack Overflow ---\n");
|
||||
goto loop;
|
||||
} else if (ra) {
|
||||
if (pc == ra && stksize == 0)
|
||||
(*printfn) ("stacktrace: loop!\n");
|
||||
else {
|
||||
|
@ -1019,6 +1019,8 @@ tlb_insert_random:
|
||||
* of this handler. Otherwise the ddb backtrace code will think that
|
||||
* the panic() was called from MipsTLBMissException.
|
||||
*/
|
||||
.globl MipsKStackOverflow
|
||||
MipsKStackOverflow:
|
||||
nop
|
||||
|
||||
.set pop
|
||||
|
Loading…
Reference in New Issue
Block a user