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:
John Baldwin 2016-12-23 03:27:11 +00:00
parent 7a6d450d66
commit 7212e5d8bf
3 changed files with 28 additions and 2 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -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