Subject: mips ddb(4) trace fix
To: None <port-mips@NetBSD.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-cobalt
Date: 05/26/2007 12:57:47
I wrote:

> Here is (probably) a proper trace (with some ugly hacked kernel):

Is it okay to commit the attached patch to make trace
on ddb(4) work more properly?

Current code in arch/mips/mips/trap.c:stacktrace_subr()
scans "jr ra" (or "jr k0") instruction to find the
beginning of the current subroutine, but it often fails
because gcc is so aggressive nowadays as to reorder
instruction blocks.
Furthermore, gcc doesn't emit "jr ra" if panic() is called
at the end of function because it's declared as
__attribute__((__noreturn__)).

I just change it to use symbol table to get address of functions.
I guess it's a bit ugly but works better than current one..
---
Izumi Tsutsui

---
Index: trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/mips/trap.c,v
retrieving revision 1.211
diff -u -r1.211 trap.c
--- trap.c	25 May 2007 23:58:43 -0000	1.211
+++ trap.c	26 May 2007 03:53:21 -0000
@@ -772,6 +772,10 @@
 	int more, stksize;
 	unsigned int frames =  0;
 	int foundframesize = 0;
+#ifdef DDB
+	db_expr_t diff;
+	db_sym_t sym;
+#endif
 
 /* Jump here when done with a frame, to start a new one */
 loop:
@@ -798,9 +802,37 @@
 		goto done;
 	}
 
+#ifdef DDB
+	/*
+	 * Check the kernel symbol table to see the beginning of
+	 * the current subroutine.
+	 */
+	diff = 0;
+	sym = db_search_symbol(pc, DB_STGY_ANY, &diff);
+	if (sym != DB_SYM_NULL && diff == 0) {
+		/* check func(foo) __attribute__((__noreturn__)) case */
+		instr = kdbpeek(pc - 2 * sizeof(int));
+		i.word = instr;
+		if (i.JType.op == OP_JAL) {
+			sym = db_search_symbol(pc - sizeof(int),
+			    DB_STGY_ANY, &diff);
+			if (sym != DB_SYM_NULL && diff != 0)
+				diff += sizeof(int);
+		}
+	}
+	if (sym == DB_SYM_NULL) {
+		ra = 0;
+		goto done;
+	}
+	va = pc - diff;
+#else
 	/*
 	 * Find the beginning of the current subroutine by scanning backwards
 	 * from the current PC for the end of the previous subroutine.
+	 * 
+	 * XXX This won't work well because nowadays gcc is so aggressive
+	 *     as to reorder instruction blocks for branch-predict.
+	 *     (i.e. 'jr ra' wouldn't indicate the end of subroutine)
 	 */
 	va = pc;
 	do {
@@ -818,6 +850,7 @@
 	/* skip over nulls which might separate .o files */
 	while ((instr = kdbpeek(va)) == 0)
 		va += sizeof(int);
+#endif
 	subr = va;
 
 	/* scan forwards to find stack size and any saved registers */

---