Use the kernel symbol table to see the beginning of the current
subroutine to get more proper backtrace on ddb(4). In the previous code it scans backwards from the current PC for the end of the previous subroutine and checks "jr ra" or "jr k0" instructions, but it often fails because gcc is so aggressive nowadays as to reorder instruction blocks to create efficient code path by branch predict etc. and "jr ra" is not always located at the end of subroutines. No objection on port-mips.
This commit is contained in:
parent
cd07663368
commit
82e46da13f
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: trap.c,v 1.211 2007/05/25 23:58:43 tsutsui Exp $ */
|
||||
/* $NetBSD: trap.c,v 1.212 2007/05/29 12:03:45 tsutsui Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
@ -78,7 +78,7 @@
|
||||
|
||||
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.211 2007/05/25 23:58:43 tsutsui Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.212 2007/05/29 12:03:45 tsutsui Exp $");
|
||||
|
||||
#include "opt_cputype.h" /* which mips CPU levels do we support? */
|
||||
#include "opt_ktrace.h"
|
||||
@ -772,6 +772,10 @@ stacktrace_subr(int a0, int a1, int a2, int a3,
|
||||
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 @@ loop:
|
||||
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 @@ mips3_eret:
|
||||
/* 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 */
|
||||
|
Loading…
Reference in New Issue
Block a user