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 MipsFPTrap(u_int, u_int, u_int);
|
||||||
void MipsKernGenException(void);
|
void MipsKernGenException(void);
|
||||||
void MipsKernIntr(void);
|
void MipsKernIntr(void);
|
||||||
|
void MipsKStackOverflow(void);
|
||||||
void MipsTLBInvalidException(void);
|
void MipsTLBInvalidException(void);
|
||||||
void MipsTLBMissException(void);
|
void MipsTLBMissException(void);
|
||||||
void MipsUserGenException(void);
|
void MipsUserGenException(void);
|
||||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/stack.h>
|
#include <sys/stack.h>
|
||||||
#include <sys/sysent.h>
|
#include <sys/sysent.h>
|
||||||
|
|
||||||
|
#include <machine/asm.h>
|
||||||
#include <machine/db_machdep.h>
|
#include <machine/db_machdep.h>
|
||||||
#include <machine/md_var.h>
|
#include <machine/md_var.h>
|
||||||
#include <machine/mips_opcode.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[2] = 0;
|
||||||
valid_args[3] = 0;
|
valid_args[3] = 0;
|
||||||
next_ra = 0;
|
next_ra = 0;
|
||||||
/* Jump here after a nonstandard (interrupt handler) frame */
|
|
||||||
stksize = 0;
|
stksize = 0;
|
||||||
subr = 0;
|
subr = 0;
|
||||||
if (frames++ > 100) {
|
if (frames++ > 100) {
|
||||||
@ -213,6 +213,15 @@ stacktrace_subr(register_t pc, register_t sp, register_t ra,
|
|||||||
ra = 0;
|
ra = 0;
|
||||||
goto done;
|
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
|
* Find the beginning of the current subroutine by scanning
|
||||||
* backwards from the current PC for the end of the previous
|
* 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,
|
(uintmax_t)(u_register_t) sp,
|
||||||
stksize);
|
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)
|
if (pc == ra && stksize == 0)
|
||||||
(*printfn) ("stacktrace: loop!\n");
|
(*printfn) ("stacktrace: loop!\n");
|
||||||
else {
|
else {
|
||||||
|
@ -1019,6 +1019,8 @@ tlb_insert_random:
|
|||||||
* of this handler. Otherwise the ddb backtrace code will think that
|
* of this handler. Otherwise the ddb backtrace code will think that
|
||||||
* the panic() was called from MipsTLBMissException.
|
* the panic() was called from MipsTLBMissException.
|
||||||
*/
|
*/
|
||||||
|
.globl MipsKStackOverflow
|
||||||
|
MipsKStackOverflow:
|
||||||
nop
|
nop
|
||||||
|
|
||||||
.set pop
|
.set pop
|
||||||
|
Loading…
Reference in New Issue
Block a user