diff options
author | jake <jake@FreeBSD.org> | 2001-08-10 04:23:41 +0000 |
---|---|---|
committer | jake <jake@FreeBSD.org> | 2001-08-10 04:23:41 +0000 |
commit | 02f57a4a09bd776d4a381c67077247de458e7945 (patch) | |
tree | 1197d83a327dc3a3a85d1e2c78e1fda8ca3a5425 | |
parent | 46fd39a86697e1ce34cb9c0437329d1befec1ceb (diff) | |
download | FreeBSD-src-02f57a4a09bd776d4a381c67077247de458e7945.zip FreeBSD-src-02f57a4a09bd776d4a381c67077247de458e7945.tar.gz |
Add code to handle stack traces that go all the way back to userland.
Use a better algorithm for finding out if an address is in the kernel.
Submitted by: tmm
-rw-r--r-- | sys/sparc64/sparc64/db_trace.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/sys/sparc64/sparc64/db_trace.c b/sys/sparc64/sparc64/db_trace.c index edadcf1..5a1bdad 100644 --- a/sys/sparc64/sparc64/db_trace.c +++ b/sys/sparc64/sparc64/db_trace.c @@ -46,9 +46,6 @@ #include <ddb/db_variables.h> #include <ddb/db_watch.h> -#define INKERNEL(va) \ - ((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS) - static db_varfcn_t db_show_in0; static db_varfcn_t db_show_in1; static db_varfcn_t db_show_in2; @@ -66,9 +63,16 @@ static db_varfcn_t db_show_local5; static db_varfcn_t db_show_local6; static db_varfcn_t db_show_local7; -static void db_print_trap(struct trapframe *); +static int db_print_trap(struct trapframe *); extern char tl1_trap[]; +extern char tl0_trap_flushed[]; +extern char tl0_trap_withstack[]; +extern char _start[]; +extern char _end[]; + +#define INKERNEL(va) \ + ((va) >= (u_long)_start && (va) <= (u_long)_end) struct db_variable db_regs[] = { { "g0", &ddb_regs.tf_global[0], FCN_NULL }, @@ -116,8 +120,10 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, db_addr_t npc; db_addr_t pc; int trap; + int user; trap = 0; + user = 0; npc = 0; if (count == -1) count = 1024; @@ -126,24 +132,32 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, fp = (struct frame *)(kfp->kf_cfp + SPOFF); } else fp = (struct frame *)(addr + SPOFF); - while (count-- && INKERNEL((vm_offset_t)fp)) { + while (count-- && !user) { pc = (db_addr_t)db_get_value((db_addr_t)&fp->f_pc, sizeof(db_addr_t), FALSE); if (trap) { pc = npc; trap = 0; } + if (!INKERNEL((vm_offset_t)pc)) + break; sym = db_search_symbol(pc, DB_STGY_ANY, &offset); - db_symbol_values(sym, &name, &value); + if (sym == C_DB_SYM_NULL) { + value = 0; + name = NULL; + } else + db_symbol_values(sym, &name, &value); if (name == NULL) name = "(null)"; - if (value == (u_long)tl1_trap) { + if (value == (u_long)tl1_trap || + value == (u_long)tl0_trap_flushed || + value == (u_long)tl0_trap_withstack) { nfp = db_get_value((db_addr_t)&fp->f_fp, sizeof(u_long), FALSE) + SPOFF; tf = (struct trapframe *)(nfp + sizeof(*fp)); npc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(u_long), FALSE); - db_print_trap(tf); + user = db_print_trap(tf); trap = 1; } else { db_printf("%s() at ", name); @@ -155,7 +169,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, } } -static void +static int db_print_trap(struct trapframe *tf) { struct mmuframe *mf; @@ -165,6 +179,8 @@ db_print_trap(struct trapframe *tf) type = db_get_value((db_addr_t)&tf->tf_type, sizeof(u_long), FALSE); db_printf("-- %s trap (%s) -- ", type & T_KERNEL ? "kernel" : "user", trap_msg[type & ~T_KERNEL]); + if ((type & T_KERNEL) == 0) + db_printf("tpc = %p, tnpc = %p ", tf->tf_tpc, tf->tf_tnpc); switch (type & ~T_KERNEL) { case T_ALIGN: mf = (struct mmuframe *)db_get_value((db_addr_t)&tf->tf_arg, @@ -177,6 +193,7 @@ db_print_trap(struct trapframe *tf) break; } db_printf("\n"); + return ((type & T_KERNEL) == 0); } DB_COMMAND(down, db_frame_down) |