Module Name: src Committed By: ryo Date: Thu May 9 16:48:31 UTC 2019
Modified Files: src/sys/arch/sh3/sh3: db_trace.c Log Message: fix backtrace. it was broken. - use db_read_bytes() to avoid faults. - quite a few functions do not use frame pointers, therefore always detect stack depth without a frame pointer. however, since the framepointer(=r14) is used as a trapframe, the code to detect the frame pointer is still needed. - dump the contents of trapframe during backtracing. - KNF To generate a diff of this commit: cvs rdiff -u -r1.25 -r1.26 src/sys/arch/sh3/sh3/db_trace.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/sh3/sh3/db_trace.c diff -u src/sys/arch/sh3/sh3/db_trace.c:1.25 src/sys/arch/sh3/sh3/db_trace.c:1.26 --- src/sys/arch/sh3/sh3/db_trace.c:1.25 Sat Nov 9 02:23:57 2013 +++ src/sys/arch/sh3/sh3/db_trace.c Thu May 9 16:48:31 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: db_trace.c,v 1.25 2013/11/09 02:23:57 christos Exp $ */ +/* $NetBSD: db_trace.c,v 1.26 2019/05/09 16:48:31 ryo Exp $ */ /*- * Copyright (c) 2000 Tsubai Masanari. All rights reserved. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.25 2013/11/09 02:23:57 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.26 2019/05/09 16:48:31 ryo Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -37,16 +37,21 @@ __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v #include <ddb/db_access.h> #include <ddb/db_interface.h> #include <ddb/db_output.h> +#include <ddb/db_proc.h> #include <ddb/db_sym.h> #include <ddb/db_variables.h> volatile int db_trace_debug = 0; /* settabble from ddb */ -#define DPRINTF if (__predict_false(db_trace_debug)) (*print) - +#define DPRINTF(level, fmt, args...) \ + do { \ + if (__predict_false(db_trace_debug > (level))) { \ + print(fmt, ## args); \ + } \ + } while (0 /* CONSTCOND*/) extern char start[], etext[]; -static void db_nextframe(db_addr_t, db_addr_t *, db_addr_t *, - void (*)(const char *, ...)); +static bool db_nextframe(db_addr_t, db_addr_t, db_addr_t *, db_addr_t *, + db_addr_t *, void (*)(const char *, ...) __printflike(1, 2)); const struct db_variable db_regs[] = { { "r0", (long *)&ddb_regs.tf_r0, FCN_NULL }, @@ -74,13 +79,28 @@ const struct db_variable db_regs[] = { const struct db_variable * const db_eregs = db_regs + __arraycount(db_regs); +static void +dump_trapframe(struct trapframe *tf, + void (*print)(const char *, ...) __printflike(1, 2)) +{ + print(" sr=%08x gbr=%08x pc=%08x pr=%08x\n", + tf->tf_ssr, tf->tf_gbr, tf->tf_spc, tf->tf_pr); + print(" r0=%08x r1=%08x r2=%08x r3=%08x\n", + tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3); + print(" r4=%08x r6=%08x r7=%08x r8=%08x\n", + tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7); + print(" r5=%08x r9=%08x r10=%08x r11=%08x\n", + tf->tf_r8, tf->tf_r9, tf->tf_r10, tf->tf_r11); + print(" r12=%08x r13=%08x r14=%08x sp=r15=%08x\n", + tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15); +} void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, - const char *modif, void (*print)(const char *, ...)) + const char *modif, void (*print)(const char *, ...) __printflike(1, 2)) { struct trapframe *tf; - db_addr_t callpc, frame, lastframe; + db_addr_t func, pc, lastpc, pr, sp, fp; uint32_t vbr; bool lwpid = false; bool lwpaddr = false; @@ -106,17 +126,20 @@ db_stack_trace_print(db_expr_t addr, boo return; } - if (!have_addr) { tf = &ddb_regs; - frame = tf->tf_r14; - callpc = tf->tf_spc; - if (callpc == 0) { - (*print)("calling through null pointer?\n"); - callpc = tf->tf_pr; + fp = tf->tf_r14; + sp = tf->tf_r15; + pr = tf->tf_pr; + pc = tf->tf_spc; + if (pc == 0) { + print("calling through null pointer?\n"); + pc = tf->tf_pr; } - } - else if (lwpaddr || lwpid) { + DPRINTF(1, "# trapframe: pc=%lx pr=%lx fp=%lx sp=%lx\n", + pc, pr, fp, sp); + + } else if (lwpaddr || lwpid) { struct proc *p; struct lwp *l; struct pcb *pcb; @@ -124,121 +147,143 @@ db_stack_trace_print(db_expr_t addr, boo if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; - (*print)("trace: lwp addr %p pid %d ", - (void *)addr, p->p_pid); - } - else { + print("trace: lwp addr %p pid %d ", + (void *)addr, p->p_pid); + } else { pid_t pid = (pid_t)addr; - (*print)("trace: pid %d ", pid); - p = proc_find_raw(pid); + print("trace: pid %d ", pid); + p = db_proc_find(pid); if (p == NULL) { - (*print)("not found\n"); + print("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); } KASSERT(l != NULL); - (*print)("lid %d ", l->l_lid); + print("lid %d", l->l_lid); pcb = lwp_getpcb(l); tf = (struct trapframe *)pcb->pcb_sf.sf_r6_bank; - frame = pcb->pcb_sf.sf_r14; - callpc = pcb->pcb_sf.sf_pr; - (*print)("at %p\n", frame); - } - else { - /* XXX */ - db_printf("trace by frame address is not supported\n"); - return; + fp = pcb->pcb_sf.sf_r14; + sp = pcb->pcb_sf.sf_r15; + pr = pcb->pcb_sf.sf_pr; + pc = pcb->pcb_sf.sf_pr; + print(", fp=%lx, sp=%lx\n", fp, sp); + DPRINTF(1, "# lwp: pc=%lx pr=%lx fp=%lx sp=%lx\n", + pc, pr, fp, sp); + } else { + fp = 0; + sp = addr; + pr = 0; + /* + * Assume that the frame address (__builtin_frame_address) + * passed as an argument is the same level + * as this __builtin_return_address(). + */ + pc = (db_addr_t)__builtin_return_address(0); } - lastframe = 0; - while (count > 0 && frame != 0) { - /* Are we crossing a trap frame? */ - if ((callpc & ~PAGE_MASK) == vbr) { - /* r14 in exception vectors points to trap frame */ - tf = (void *)frame; + lastpc = 0; + while (count > 0 && pc != 0 && sp != 0) { + DPRINTF(2, "# trace: pc=%lx sp=%lx fp=%lx\n", pc, sp, fp); - frame = tf->tf_r14; - callpc = tf->tf_spc; + /* Are we crossing a trap frame? */ + if ((pc & ~PAGE_MASK) == vbr) { + struct trapframe trapframe; + tf = &trapframe; - (*print)("<EXPEVT %03x; SSR=%08x> at ", - tf->tf_expevt, tf->tf_ssr); - db_printsym(callpc, DB_STGY_PROC, print); - (*print)("\n"); + /* r14 in exception vectors points to trap frame */ + db_read_bytes((db_addr_t)fp, sizeof(*tf), (char *)tf); + pc = tf->tf_spc; + pr = tf->tf_pr; + fp = tf->tf_r14; + sp = tf->tf_r15; + + print("<EXPEVT %03x; SSR=%08x> at ", + tf->tf_expevt, tf->tf_ssr); + db_printsym(pc, DB_STGY_PROC, print); + print("\n"); - lastframe = 0; + print("[trapframe 0x%lx]\n", fp); + dump_trapframe(tf, print); /* XXX: don't venture into the userland yet */ if ((tf->tf_ssr & PSL_MD) == 0) break; } else { - db_addr_t oldfp; const char *name; db_expr_t offset; db_sym_t sym; + bool found; + sym = db_search_symbol(pc, DB_STGY_ANY, &offset); + if (sym == 0) { + print("symbol not found\n"); + break; + } + db_symbol_values(sym, &name, NULL); - DPRINTF(" (1) newpc 0x%lx, newfp 0x%lx\n", - callpc, frame); + func = pc - offset; - sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); - db_symbol_values(sym, &name, NULL); + DPRINTF(1, + " (1) func=%lx+%lx, pc=%lx, sp=%lx, fp=%lx\n", + func, offset, pc, sp, fp); - if (lastframe == 0 && sym == 0) { - (*print)("symbol not found\n"); + found = db_nextframe(func, pc, &fp, &pr, &sp, print); + if (!found && lastpc == pc) break; - } + lastpc = pc; - oldfp = frame; - - db_nextframe(callpc - offset, &frame, &callpc, print); - DPRINTF(" (2) newpc 0x%lx, newfp 0x%lx\n", - callpc, frame); - - /* leaf routine or interrupted early? */ - if (lastframe == 0 && callpc == 0) { - callpc = tf->tf_pr; /* PR still in register */ - - /* asm routine w/out frame? */ - if (frame == 0) - frame = oldfp; - DPRINTF(" (3) newpc 0x%lx, newfp 0x%lx\n", - callpc, frame); - } + DPRINTF(1, " (2) newpc=%lx, newsp=%lx, newfp=%lx\n", + pr, sp, fp); - (*print)("%s() at ", name ? name : ""); - db_printsym(callpc, DB_STGY_PROC, print); - (*print)("\n"); + DPRINTF(1, "sp=%lx ", sp); + print("%s() at ", name ? name : ""); + db_printsym(pr, DB_STGY_PROC, print); + print("\n"); - lastframe = frame; + pc = pr; + pr = 0; } count--; } } -static void +static bool db_nextframe( - db_addr_t pc, /* in: entry address of current function */ - db_addr_t *fp, /* in: current fp, out: parent fp */ + db_addr_t func, /* in: entry address of current function */ + db_addr_t curpc, /* in: current pc in the function */ + db_addr_t *fp, /* out: parent fp */ db_addr_t *pr, /* out: parent pr */ - void (*print)(const char *, ...)) + db_addr_t *sp, /* in: current sp, out: parent sp */ + void (*print)(const char *, ...) __printflike(1, 2)) { - int *frame = (void *)*fp; - int i, inst; + int *stack = (void *)*sp; + int i, inst, inst2; int depth, prdepth, fpdepth; + db_addr_t pc; + + if (__predict_false(db_trace_debug >= 2)) { + DPRINTF(2, "%s:%d: START: func=%lx=", __func__, __LINE__, func); + db_printsym(func, DB_STGY_PROC, print); + DPRINTF(2, " pc=%lx fp=%lx pr=%lx, sp=%lx\n", + curpc, *fp, *pr, *sp); + } + pc = func; depth = 0; prdepth = fpdepth = -1; if (pc < (db_addr_t)start || pc > (db_addr_t)etext) goto out; - for (i = 0; i < 30; i++) { + for (i = 0; i < 30 && pc < curpc; i++) { inst = db_get_value(pc, 2, false); + DPRINTF(2, "%s:%d: %lx insn=%04x depth=%d\n", + __func__, __LINE__, pc, inst, depth); pc += 2; - if (inst == 0x000b) /* rts - asm routines w/out frame */ + if (inst == 0x000b) /* rts - asm routines w/out frame */ break; if (inst == 0x6ef3) /* mov r15,r14 -- end of prologue */ @@ -262,26 +307,33 @@ db_nextframe( int8_t n = inst & 0xff; if (n >= 0) { - (*print)("add #n,r15 (n > 0)\n"); + /* XXX: in epilogue? ignore it */ + DPRINTF(2, + "%s:%d: %lx: add #%d,r15 (n > 0) ignored\n", + __func__, __LINE__, pc - 2, n); break; } - depth += -n/4; + depth += -n / 4; continue; } if ((inst & 0xf000) == 0x9000) { - if (db_get_value(pc, 2, false) == 0x3f38) { - /* "mov #n,r3; sub r3,r15" */ + inst2 = db_get_value(pc, 2, false); + if (((inst2 & 0xff0f) == 0x3f08) && + ((inst & 0x0f00) == ((inst2 & 0x00f0) << 4))) { + + /* mov <disp>,r?; sub r?,r15 */ unsigned int disp = (int)(inst & 0xff); - int r3; + vaddr_t addr; + int val; - r3 = (int)*(unsigned short *)(pc + (4 - 2) - + (disp << 1)); - if ((r3 & 0x00008000) == 0) - r3 &= 0x0000ffff; + addr = pc + (4 - 2) + (disp << 1); + db_read_bytes(addr, sizeof(val), (char *)&val); + if ((val & 0x00008000) == 0) + val &= 0x0000ffff; else - r3 |= 0xffff0000; - depth += (r3 / 4); + val |= 0xffff0000; + depth += (val / 4); pc += 2; continue; @@ -289,21 +341,59 @@ db_nextframe( } if (__predict_false(db_trace_debug > 1)) { - (*print)(" unknown insn at "); + print(" unknown insn at "); db_printsym(pc - 2, DB_STGY_PROC, print); - (*print)(":\t"); - db_disasm(pc - 2, 0); /* XXX: always uses db_printf */ + print(":\t"); + db_disasm(pc - 2, 0);/* XXX: always uses db_printf */ } } out: - if (fpdepth != -1) - *fp = frame[depth - fpdepth - 1]; - else - *fp = 0; + DPRINTF(2, "%s:%d: fpdepth=%d prdepth=%d depth=%d sp=%lx->%lx\n", + __func__, __LINE__, fpdepth, prdepth, depth, *sp, *sp - depth * 4); + + /* dump stack */ + if (__predict_false(db_trace_debug > 2) && + ((fpdepth != -1) || (prdepth != -1))) { + print("%s:%d: func=%lx pc=%lx\n", + __func__, __LINE__, func, curpc); + + for (int j = 0; j < prdepth + 32; j++) { + uint32_t v; + + db_read_bytes((db_addr_t)&stack[j], + sizeof(v), (char *)&v); + print(" STACK[%2d]: %p: %08x ", + j, &stack[j], v); + db_printsym(v, DB_STGY_PROC, print); + if (j == (depth - prdepth - 1)) + print(" # = pr"); + if (j == (depth - fpdepth - 1)) + print(" # = fp"); + print("\n"); + } + } + /* fetch fp and pr if exists in stack */ + if (fpdepth != -1) + db_read_bytes((db_addr_t)&stack[depth - fpdepth - 1], + sizeof(*fp), (char *)fp); if (prdepth != -1) - *pr = frame[depth - prdepth - 1]; - else - *pr = 0; + db_read_bytes((db_addr_t)&stack[depth - prdepth - 1], + sizeof(*pr), (char *)pr); + + /* adjust stack pointer, and update */ + stack += depth; + *sp = (db_addr_t)stack; + + if (__predict_false(db_trace_debug >= 2)) { + DPRINTF(2, "%s:%d: RESULT: fp=%lx pr=%lx(", + __func__, __LINE__, *fp, *pr); + db_printsym(*pr, DB_STGY_PROC, print); + DPRINTF(2, ") sp=%lx\n", *sp); + } + + if ((prdepth == -1) && (fpdepth == -1) && (depth == 0)) + return false; + return true; }