Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Dec 2016 03:27:11 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310445 - in head/sys/mips: include mips
Message-ID:  <201612230327.uBN3RBC1099442@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Fri Dec 23 03:27:11 2016
New Revision: 310445
URL: https://svnweb.freebsd.org/changeset/base/310445

Log:
  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

Modified:
  head/sys/mips/include/trap.h
  head/sys/mips/mips/db_trace.c
  head/sys/mips/mips/exception.S

Modified: head/sys/mips/include/trap.h
==============================================================================
--- head/sys/mips/include/trap.h	Fri Dec 23 03:23:14 2016	(r310444)
+++ head/sys/mips/include/trap.h	Fri Dec 23 03:27:11 2016	(r310445)
@@ -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);

Modified: head/sys/mips/mips/db_trace.c
==============================================================================
--- head/sys/mips/mips/db_trace.c	Fri Dec 23 03:23:14 2016	(r310444)
+++ head/sys/mips/mips/db_trace.c	Fri Dec 23 03:27:11 2016	(r310445)
@@ -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 @@ loop:
 	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 @@ loop:
 		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 @@ done:
 	    (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 {

Modified: head/sys/mips/mips/exception.S
==============================================================================
--- head/sys/mips/mips/exception.S	Fri Dec 23 03:23:14 2016	(r310444)
+++ head/sys/mips/mips/exception.S	Fri Dec 23 03:27:11 2016	(r310445)
@@ -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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612230327.uBN3RBC1099442>