svn commit: r368347 - head/sys/mips/mips

John Baldwin jhb at FreeBSD.org
Fri Dec 4 20:14:26 UTC 2020


Author: jhb
Date: Fri Dec  4 20:14:25 2020
New Revision: 368347
URL: https://svnweb.freebsd.org/changeset/base/368347

Log:
  Various fixes for the MIPS DDB stack unwinder.
  
  - Fix kernel stack unwinding end-of-function false-positive
  
    The kernel stack unwinder assumes that any jr $ra indicates the end
    of the current function. However, modern compilers generate code
    that contains jr $ra at various places inside the function.
  
  - Handle LLD inter-function padding when looking for the start of a
    function.
  
  - Use call site for symbol name/offset when unwinding
  
    Currently we use the return address, which will normally just give
    an output that's off by 8 from the actual call site.  However, for
    tail calls, this is particularly bad, as we end up printing the
    symbol name for the function that comes after the one that made the
    call.  Instead we should go back two instructions from the return
    address for the unwound program counter.
  
  Submitted by:   arichardson (1, 2), jrtc27 (3)
  Reviewed by:	arichardson
  Obtained from:	CheriBSD
  Sponsored by:	DARPA
  Differential Revision:	https://reviews.freebsd.org/D27363

Modified:
  head/sys/mips/mips/db_trace.c

Modified: head/sys/mips/mips/db_trace.c
==============================================================================
--- head/sys/mips/mips/db_trace.c	Fri Dec  4 19:35:43 2020	(r368346)
+++ head/sys/mips/mips/db_trace.c	Fri Dec  4 20:14:25 2020	(r368347)
@@ -67,11 +67,10 @@ extern char edata[];
 	|| (((ins) & 0xffff8000) == 0x67bd8000))
 
 /*
- * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
- *
- * XXX gcc doesn't do this for functions with __noreturn__ attribute.
+ * LLD will insert invalid instruction traps between functions.
+ * Currently this is 0xefefefef but it may change in the future.
  */
-#define	MIPS_END_OF_FUNCTION(ins)	((ins) == 0x03e00008)
+#define	MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(ins)	((ins) == 0xefefefef)
 
 #if defined(__mips_n64)
 #	define	MIPS_IS_VALID_KERNELADDR(reg)	((((reg) & 3) == 0) && \
@@ -183,27 +182,32 @@ loop:
 	 * subroutine.
 	 */
 	if (!subr) {
-		va = pc - sizeof(int);
+		va = pc;
 		while (1) {
 			instr = kdbpeek((int *)va);
 
-			if (MIPS_START_OF_FUNCTION(instr))
+			/* LLD fills padding between functions with 0xefefefef */
+			if (MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(instr))
 				break;
 
-			if (MIPS_END_OF_FUNCTION(instr)) {
-				/* skip over branch-delay slot instruction */
-				va += 2 * sizeof(int);
+			if (MIPS_START_OF_FUNCTION(instr))
 				break;
-			}
 
  			va -= sizeof(int);
 		}
 
-		/* skip over nulls which might separate .o files */
-		while ((instr = kdbpeek((int *)va)) == 0)
+		/*
+		 * Skip over nulls/trap padding which might separate
+		 * object files or functions.
+		 */
+		instr = kdbpeek((int *)va);
+		while (instr == 0 || MIPS_LLD_PADDING_BETWEEN_FUNCTIONS(instr)) {
 			va += sizeof(int);
+			instr = kdbpeek((int *)va);
+		}
 		subr = va;
 	}
+
 	/* scan forwards to find stack size and any saved registers */
 	stksize = 0;
 	more = 3;
@@ -374,10 +378,16 @@ done:
 		    (uintmax_t)cause, (uintmax_t)badvaddr);
 		goto loop;
 	} else if (ra) {
-		if (pc == ra && stksize == 0)
+		/*
+		 * We subtract two instructions from ra to convert it
+		 * from a return address to a calling address,
+		 * accounting for the delay slot.
+		 */
+		register_t next_pc = ra - 2 * sizeof(int);
+		if (pc == next_pc && stksize == 0)
 			db_printf("stacktrace: loop!\n");
 		else {
-			pc = ra;
+			pc = next_pc;
 			sp += stksize;
 			ra = next_ra;
 			goto loop;


More information about the svn-src-head mailing list