Diffs to fix ddb backtrace

Neelkanth Natu neelnatu at yahoo.com
Tue Jul 14 00:27:10 UTC 2009


Hi,

This diff fixes a problem I encountered with ddb backtrace.
	
The problem with looking for just 'j ra' instruction to find out the
end of the previous function is that gcc does not emit that
instruction for functions that are not supposed to return (for e.g.
boot() or panic()). This is especially bad because the backtrace
generated by calling panic() is unusable because boot() is right
above panic() in the object file.
	
This change looks for start of a function by looking for an instruction
of the form: addiu sp,sp,-<frame_size>
	
It so happens that gcc emits this as the first instruction for all
functions that use the stack. We keep the 'j ra' method around for
functions that don't use the stack.

For e.g. here is backtrace output without the fix:
mountroot> 
panic: Root mount failed, startup aborted.
KDB: enter: panic
[thread pid 1 tid 100001 ]
Stopped at      kdb_enter+0x50: lui     at,0x8043
db> bt
Tracing pid 1 tid 100001 td 0xc7847000
kdb_enter+50 (0,0,0,0) ra 80234d2c sz 24
80234378+9b4 (0,0,0,0) ra 803cbb98 sz 80
803a37b0+283e8 (0,0,0,0) ra 0 sz 0
pid 1

And this is the backtrace with the fix:
mountroot> 
panic: Root mount failed, startup aborted.
KDB: enter: panic
[thread pid 1 tid 100001 ]
Stopped at      kdb_enter+0x50: lui     at,0x8043
db> bt
Tracing pid 1 tid 100001 td 0xc7847000
kdb_enter+50 (0,0,0,0) ra 80234d2c sz 24
panic+f8 (0,a,8059ffe4,0) ra 802be12c sz 40
vfs_mountroot+518 (0,a,8059ffe4,0) ra 801f1464 sz 96
801f13f0+74 (0,a,8059ffe4,0) ra 8020d338 sz 96
fork_exit+b0 (0,a,8059ffe4,0) ra 80395300 sz 40
fork_trampoline+10 (0,a,8059ffe4,0) ra 0 sz 0
pid 1

best
Neel

==== //depot/user/neelnatu/projects_mips/src/sys/mips/mips/trap.c#1 - /amd/svlusr02.eng.netapp.com/vol/home24/neelnatu/p4/projects_mips/src/sys/mips/mips/trap.c ====
@@ -1229,7 +1229,25 @@
 
 
 #if defined(DDB) || defined(DEBUG)
-#define	MIPS_JR_RA	0x03e00008	/* instruction code for jr ra */
+/*
+ * A function using a stack frame has the following instruction as the first
+ * one: addiu sp,sp,-<frame_size>
+ *
+ * We make use of this to detect starting address of a function. This works
+ * better than using 'j ra' instruction to signify end of the previous
+ * function (for e.g. functions like boot() or panic() do not actually
+ * emit a 'j ra' instruction).
+ *
+ * XXX the abi does not require that the addiu instruction be the first one.
+ */
+#define	MIPS_START_OF_FUNCTION(ins)	(((ins) & 0xffff8000) == 0x27bd8000)
+
+/*
+ * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction
+ *
+ * XXX gcc doesn't do this true for functions with __noreturn__ attribute.
+ */
+#define	MIPS_END_OF_FUNCTION(ins)	((ins) == 0x03e00008)
 
 /* forward */
 char *fn_name(unsigned addr);
@@ -1326,9 +1344,21 @@
 	 */
 	if (!subr) {
 		va = pc - sizeof(int);
-		while ((instr = kdbpeek((int *)va)) != MIPS_JR_RA)
+		while (1) {
+			instr = kdbpeek((int *)va);
+
+			if (MIPS_START_OF_FUNCTION(instr))
+				break;
+
+			if (MIPS_END_OF_FUNCTION(instr)) {
+				/* skip over branch-delay slot instruction */
+				va += 2 * sizeof(int);
+				break;
+			}
+
 			va -= sizeof(int);
-		va += 2 * sizeof(int);	/* skip back over branch & delay slot */
+		}
+
 		/* skip over nulls which might separate .o files */
 		while ((instr = kdbpeek((int *)va)) == 0)
 			va += sizeof(int);



      


More information about the freebsd-mips mailing list