--- include/db_machdep.h (revision 198604) +++ include/db_machdep.h (local) @@ -95,5 +95,6 @@ void db_dump_tlb(int, int); db_addr_t branch_taken(int inst, db_addr_t pc); void stacktrace_subr(db_regs_t *, int (*)(const char *, ...)); +int kdbpeek(int *); #endif /* !_MIPS_DB_MACHDEP_H_ */ --- include/md_var.h (revision 198604) +++ include/md_var.h (local) @@ -49,6 +49,7 @@ void fork_trampoline(void); void cpu_swapin(struct proc *); uintptr_t MipsEmulateBranch(struct trapframe *, uintptr_t, int, uintptr_t); +void MipsSwitchFPState(struct thread *, struct trapframe *); u_long kvtop(void *addr); int is_physical_memory(vm_offset_t addr); int is_cacheable_mem(vm_offset_t pa); --- include/trap.h (revision 198604) +++ include/trap.h (local) @@ -108,6 +108,18 @@ #endif +void MipsFPTrap(u_int, u_int, u_int); +void MipsKernGenException(void); +void MipsKernIntr(void); +void MipsKernTLBInvalidException(void); +void MipsTLBInvalidException(void); +void MipsTLBMissException(void); +void MipsUserGenException(void); +void MipsUserIntr(void); +void MipsUserTLBInvalidException(void); + +u_int trap(struct trapframe *); + #ifndef LOCORE /* XXX */ int check_address(void *); void platform_trap_enter(void); --- mips/db_trace.c (revision 198604) +++ mips/db_trace.c (local) @@ -17,10 +17,345 @@ #include #include +#include #include +#include #include +extern char _locore[]; +extern char _locoreEnd[]; +extern char edata[]; + +/* + * A function using a stack frame has the following instruction as the first + * one: addiu sp,sp,- + * + * 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) + +/* + * kdbpeekD(addr) - skip one word starting at 'addr', then read the second word + */ +#define kdbpeekD(addr) kdbpeek(((int *)(addr)) + 1) + +/* + * Functions ``special'' enough to print by name + */ +#ifdef __STDC__ +#define Name(_fn) { (void*)_fn, # _fn } +#else +#define Name(_fn) { _fn, "_fn"} +#endif +static struct { + void *addr; + char *name; +} names[] = { + + Name(trap), + Name(MipsKernGenException), + Name(MipsUserGenException), + Name(MipsKernIntr), + Name(MipsUserIntr), + Name(cpu_switch), + { + 0, 0 + } +}; + +/* + * Map a function address to a string name, if known; or a hex string. + */ +static char * +fn_name(uintptr_t addr) +{ + static char buf[17]; + int i = 0; + +#ifdef DDB + db_expr_t diff; + c_db_sym_t sym; + char *symname; + + diff = 0; + symname = NULL; + sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff); + db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0); + if (symname && diff == 0) + return (symname); +#endif + + for (i = 0; names[i].name; i++) + if (names[i].addr == (void *)addr) + return (names[i].name); + sprintf(buf, "%jx", (uintmax_t)addr); + return (buf); +} + +void +stacktrace_subr(struct trapframe *regs, int (*printfn) (const char *,...)) +{ + InstFmt i; + uintptr_t a0, a1, a2, a3, pc, sp, fp, ra, va, subr; + unsigned instr, mask; + unsigned int frames = 0; + int more, stksize; + + /* get initial values from the exception frame */ + sp = regs->sp; + pc = regs->pc; + fp = regs->s8; + ra = regs->ra; /* May be a 'leaf' function */ + a0 = regs->a0; + a1 = regs->a1; + a2 = regs->a2; + a3 = regs->a3; + +/* Jump here when done with a frame, to start a new one */ +loop: + +/* Jump here after a nonstandard (interrupt handler) frame */ + stksize = 0; + subr = 0; + if (frames++ > 100) { + (*printfn) ("\nstackframe count exceeded\n"); + /* return breaks stackframe-size heuristics with gcc -O2 */ + goto finish; /* XXX */ + } + /* check for bad SP: could foul up next frame */ + /*XXX MIPS64 bad: this hard-coded SP is lame */ + if (sp & 3 || sp < 0x80000000) { + (*printfn) ("SP 0x%x: not in kernel\n", sp); + ra = 0; + subr = 0; + goto done; + } +#define Between(x, y, z) \ + ( ((x) <= (y)) && ((y) < (z)) ) +#define pcBetween(a,b) \ + Between((uintptr_t)a, pc, (uintptr_t)b) + + /* + * Check for current PC in exception handler code that don't have a + * preceding "j ra" at the tail of the preceding function. Depends + * on relative ordering of functions in exception.S, swtch.S. + */ + if (pcBetween(MipsKernGenException, MipsUserGenException)) + subr = (uintptr_t)MipsKernGenException; + else if (pcBetween(MipsUserGenException, MipsKernIntr)) + subr = (uintptr_t)MipsUserGenException; + else if (pcBetween(MipsKernIntr, MipsUserIntr)) + subr = (uintptr_t)MipsKernIntr; + else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) + subr = (uintptr_t)MipsUserIntr; + else if (pcBetween(MipsTLBInvalidException, + MipsKernTLBInvalidException)) + subr = (uintptr_t)MipsTLBInvalidException; + else if (pcBetween(MipsKernTLBInvalidException, + MipsUserTLBInvalidException)) + subr = (uintptr_t)MipsKernTLBInvalidException; + else if (pcBetween(MipsUserTLBInvalidException, MipsTLBMissException)) + subr = (uintptr_t)MipsUserTLBInvalidException; + else if (pcBetween(cpu_switch, MipsSwitchFPState)) + subr = (uintptr_t)cpu_switch; + else if (pcBetween(_locore, _locoreEnd)) { + subr = (uintptr_t)_locore; + ra = 0; + goto done; + } + /* check for bad PC */ + /*XXX MIPS64 bad: These hard coded constants are lame */ + if (pc & 3 || pc < (uintptr_t)0x80000000 || pc >= (uintptr_t)edata) { + (*printfn) ("PC 0x%x: not in kernel\n", pc); + ra = 0; + goto done; + } + /* + * Find the beginning of the current subroutine by scanning + * backwards from the current PC for the end of the previous + * subroutine. + */ + if (!subr) { + va = pc - sizeof(int); + 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); + } + + /* skip over nulls which might separate .o files */ + while ((instr = kdbpeek((int *)va)) == 0) + va += sizeof(int); + subr = va; + } + /* scan forwards to find stack size and any saved registers */ + stksize = 0; + more = 3; + mask = 0; + for (va = subr; more; va += sizeof(int), + more = (more == 3) ? 3 : more - 1) { + /* stop if hit our current position */ + if (va >= pc) + break; + instr = kdbpeek((int *)va); + i.word = instr; + switch (i.JType.op) { + case OP_SPECIAL: + switch (i.RType.func) { + case OP_JR: + case OP_JALR: + more = 2; /* stop after next instruction */ + break; + + case OP_SYSCALL: + case OP_BREAK: + more = 1; /* stop now */ + }; + break; + + case OP_BCOND: + case OP_J: + case OP_JAL: + case OP_BEQ: + case OP_BNE: + case OP_BLEZ: + case OP_BGTZ: + more = 2; /* stop after next instruction */ + break; + + case OP_COP0: + case OP_COP1: + case OP_COP2: + case OP_COP3: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + more = 2; /* stop after next instruction */ + }; + break; + + case OP_SW: + /* look for saved registers on the stack */ + if (i.IType.rs != 29) + break; + /* only restore the first one */ + if (mask & (1 << i.IType.rt)) + break; + mask |= (1 << i.IType.rt); + switch (i.IType.rt) { + case 4:/* a0 */ + a0 = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 5:/* a1 */ + a1 = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 6:/* a2 */ + a2 = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 7:/* a3 */ + a3 = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 30: /* fp */ + fp = kdbpeek((int *)(sp + (short)i.IType.imm)); + break; + + case 31: /* ra */ + ra = kdbpeek((int *)(sp + (short)i.IType.imm)); + } + break; + + case OP_SD: + /* look for saved registers on the stack */ + if (i.IType.rs != 29) + break; + /* only restore the first one */ + if (mask & (1 << i.IType.rt)) + break; + mask |= (1 << i.IType.rt); + switch (i.IType.rt) { + case 4:/* a0 */ + a0 = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 5:/* a1 */ + a1 = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 6:/* a2 */ + a2 = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 7:/* a3 */ + a3 = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 30: /* fp */ + fp = kdbpeekD((int *)(sp + (short)i.IType.imm)); + break; + + case 31: /* ra */ + ra = kdbpeekD((int *)(sp + (short)i.IType.imm)); + } + break; + + case OP_ADDI: + case OP_ADDIU: + /* look for stack pointer adjustment */ + if (i.IType.rs != 29 || i.IType.rt != 29) + break; + stksize = -((short)i.IType.imm); + } + } + +done: + (*printfn) ("%s+%x (%x,%x,%x,%x) ra %x sz %d\n", + fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize); + + if (ra) { + if (pc == ra && stksize == 0) + (*printfn) ("stacktrace: loop!\n"); + else { + pc = ra; + sp += stksize; + ra = 0; + goto loop; + } + } else { +finish: + if (curproc) + (*printfn) ("pid %d\n", curproc->p_pid); + else + (*printfn) ("curproc NULL\n"); + } +} + + int db_md_set_watchpoint(db_expr_t addr, db_expr_t size) { --- mips/trap.c (revision 198604) +++ mips/trap.c (local) @@ -78,6 +78,7 @@ #include #include #include +#include #include #include #include @@ -102,23 +103,13 @@ extern unsigned onfault_table[]; -extern void MipsKernGenException(void); -extern void MipsUserGenException(void); -extern void MipsKernIntr(void); -extern void MipsUserIntr(void); -extern void MipsTLBInvalidException(void); -extern void MipsKernTLBInvalidException(void); -extern void MipsUserTLBInvalidException(void); -extern void MipsTLBMissException(void); static void log_bad_page_fault(char *, struct trapframe *, int); static void log_frame_dump(struct trapframe *frame); static void get_mapping_info(vm_offset_t, pd_entry_t **, pt_entry_t **); #ifdef TRAP_DEBUG static void trap_frame_dump(struct trapframe *frame); - #endif -extern char edata[]; void (*machExceptionTable[]) (void)= { /* @@ -230,37 +221,17 @@ #if !defined(SMP) && (defined(DDB) || defined(DEBUG)) struct trapdebug trapdebug[TRAPSIZE], *trp = trapdebug; - #endif #if defined(DDB) || defined(DEBUG) void stacktrace(struct trapframe *); void logstacktrace(struct trapframe *); -int kdbpeek(int *); - -/* extern functions printed by name in stack backtraces */ -extern void MipsTLBMiss(void); -extern void MipsUserSyscallException(void); -extern char _locore[]; -extern char _locoreEnd[]; - -#endif /* DDB || DEBUG */ - -extern void MipsSwitchFPState(struct thread *, struct trapframe *); -extern void MipsFPTrap(u_int, u_int, u_int); - -u_int trap(struct trapframe *); -u_int MipsEmulateBranch(struct trapframe *, uintptr_t, int, uintptr_t); +#endif #define KERNLAND(x) ((int)(x) < 0) #define DELAYBRANCH(x) ((int)(x) < 0) /* - * kdbpeekD(addr) - skip one word starting at 'addr', then read the second word - */ -#define kdbpeekD(addr) kdbpeek(((int *)(addr)) + 1) - -/* * MIPS load/store access type */ enum { @@ -1227,28 +1198,6 @@ #if defined(DDB) || defined(DEBUG) /* - * A function using a stack frame has the following instruction as the first - * one: addiu sp,sp,- - * - * 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 */ -static char *fn_name(uintptr_t addr); - -/* * Print a stack backtrace. */ void @@ -1256,311 +1205,7 @@ { stacktrace_subr(regs, printf); } - -void -stacktrace_subr(struct trapframe *regs, int (*printfn) (const char *,...)) -{ - InstFmt i; - uintptr_t a0, a1, a2, a3, pc, sp, fp, ra, va, subr; - unsigned instr, mask; - unsigned int frames = 0; - int more, stksize; - - /* get initial values from the exception frame */ - sp = regs->sp; - pc = regs->pc; - fp = regs->s8; - ra = regs->ra; /* May be a 'leaf' function */ - a0 = regs->a0; - a1 = regs->a1; - a2 = regs->a2; - a3 = regs->a3; - -/* Jump here when done with a frame, to start a new one */ -loop: - -/* Jump here after a nonstandard (interrupt handler) frame */ - stksize = 0; - subr = 0; - if (frames++ > 100) { - (*printfn) ("\nstackframe count exceeded\n"); - /* return breaks stackframe-size heuristics with gcc -O2 */ - goto finish; /* XXX */ - } - /* check for bad SP: could foul up next frame */ - /*XXX MIPS64 bad: this hard-coded SP is lame */ - if (sp & 3 || sp < 0x80000000) { - (*printfn) ("SP 0x%x: not in kernel\n", sp); - ra = 0; - subr = 0; - goto done; - } -#define Between(x, y, z) \ - ( ((x) <= (y)) && ((y) < (z)) ) -#define pcBetween(a,b) \ - Between((uintptr_t)a, pc, (uintptr_t)b) - - /* - * Check for current PC in exception handler code that don't have a - * preceding "j ra" at the tail of the preceding function. Depends - * on relative ordering of functions in exception.S, swtch.S. - */ - if (pcBetween(MipsKernGenException, MipsUserGenException)) - subr = (uintptr_t)MipsKernGenException; - else if (pcBetween(MipsUserGenException, MipsKernIntr)) - subr = (uintptr_t)MipsUserGenException; - else if (pcBetween(MipsKernIntr, MipsUserIntr)) - subr = (uintptr_t)MipsKernIntr; - else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) - subr = (uintptr_t)MipsUserIntr; - else if (pcBetween(MipsTLBInvalidException, - MipsKernTLBInvalidException)) - subr = (uintptr_t)MipsTLBInvalidException; - else if (pcBetween(MipsKernTLBInvalidException, - MipsUserTLBInvalidException)) - subr = (uintptr_t)MipsKernTLBInvalidException; - else if (pcBetween(MipsUserTLBInvalidException, MipsTLBMissException)) - subr = (uintptr_t)MipsUserTLBInvalidException; - else if (pcBetween(cpu_switch, MipsSwitchFPState)) - subr = (uintptr_t)cpu_switch; - else if (pcBetween(_locore, _locoreEnd)) { - subr = (uintptr_t)_locore; - ra = 0; - goto done; - } - /* check for bad PC */ - /*XXX MIPS64 bad: These hard coded constants are lame */ - if (pc & 3 || pc < (uintptr_t)0x80000000 || pc >= (uintptr_t)edata) { - (*printfn) ("PC 0x%x: not in kernel\n", pc); - ra = 0; - goto done; - } - /* - * Find the beginning of the current subroutine by scanning - * backwards from the current PC for the end of the previous - * subroutine. - */ - if (!subr) { - va = pc - sizeof(int); - 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); - } - - /* skip over nulls which might separate .o files */ - while ((instr = kdbpeek((int *)va)) == 0) - va += sizeof(int); - subr = va; - } - /* scan forwards to find stack size and any saved registers */ - stksize = 0; - more = 3; - mask = 0; - for (va = subr; more; va += sizeof(int), - more = (more == 3) ? 3 : more - 1) { - /* stop if hit our current position */ - if (va >= pc) - break; - instr = kdbpeek((int *)va); - i.word = instr; - switch (i.JType.op) { - case OP_SPECIAL: - switch (i.RType.func) { - case OP_JR: - case OP_JALR: - more = 2; /* stop after next instruction */ - break; - - case OP_SYSCALL: - case OP_BREAK: - more = 1; /* stop now */ - }; - break; - - case OP_BCOND: - case OP_J: - case OP_JAL: - case OP_BEQ: - case OP_BNE: - case OP_BLEZ: - case OP_BGTZ: - more = 2; /* stop after next instruction */ - break; - - case OP_COP0: - case OP_COP1: - case OP_COP2: - case OP_COP3: - switch (i.RType.rs) { - case OP_BCx: - case OP_BCy: - more = 2; /* stop after next instruction */ - }; - break; - - case OP_SW: - /* look for saved registers on the stack */ - if (i.IType.rs != 29) - break; - /* only restore the first one */ - if (mask & (1 << i.IType.rt)) - break; - mask |= (1 << i.IType.rt); - switch (i.IType.rt) { - case 4:/* a0 */ - a0 = kdbpeek((int *)(sp + (short)i.IType.imm)); - break; - - case 5:/* a1 */ - a1 = kdbpeek((int *)(sp + (short)i.IType.imm)); - break; - - case 6:/* a2 */ - a2 = kdbpeek((int *)(sp + (short)i.IType.imm)); - break; - - case 7:/* a3 */ - a3 = kdbpeek((int *)(sp + (short)i.IType.imm)); - break; - - case 30: /* fp */ - fp = kdbpeek((int *)(sp + (short)i.IType.imm)); - break; - - case 31: /* ra */ - ra = kdbpeek((int *)(sp + (short)i.IType.imm)); - } - break; - - case OP_SD: - /* look for saved registers on the stack */ - if (i.IType.rs != 29) - break; - /* only restore the first one */ - if (mask & (1 << i.IType.rt)) - break; - mask |= (1 << i.IType.rt); - switch (i.IType.rt) { - case 4:/* a0 */ - a0 = kdbpeekD((int *)(sp + (short)i.IType.imm)); - break; - - case 5:/* a1 */ - a1 = kdbpeekD((int *)(sp + (short)i.IType.imm)); - break; - - case 6:/* a2 */ - a2 = kdbpeekD((int *)(sp + (short)i.IType.imm)); - break; - - case 7:/* a3 */ - a3 = kdbpeekD((int *)(sp + (short)i.IType.imm)); - break; - - case 30: /* fp */ - fp = kdbpeekD((int *)(sp + (short)i.IType.imm)); - break; - - case 31: /* ra */ - ra = kdbpeekD((int *)(sp + (short)i.IType.imm)); - } - break; - - case OP_ADDI: - case OP_ADDIU: - /* look for stack pointer adjustment */ - if (i.IType.rs != 29 || i.IType.rt != 29) - break; - stksize = -((short)i.IType.imm); - } - } - -done: - (*printfn) ("%s+%x (%x,%x,%x,%x) ra %x sz %d\n", - fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize); - - if (ra) { - if (pc == ra && stksize == 0) - (*printfn) ("stacktrace: loop!\n"); - else { - pc = ra; - sp += stksize; - ra = 0; - goto loop; - } - } else { -finish: - if (curproc) - (*printfn) ("pid %d\n", curproc->p_pid); - else - (*printfn) ("curproc NULL\n"); - } -} - -/* - * Functions ``special'' enough to print by name - */ -#ifdef __STDC__ -#define Name(_fn) { (void*)_fn, # _fn } -#else -#define Name(_fn) { _fn, "_fn"} #endif -static struct { - void *addr; - char *name; -} names[] = { - - Name(trap), - Name(MipsKernGenException), - Name(MipsUserGenException), - Name(MipsKernIntr), - Name(MipsUserIntr), - Name(cpu_switch), - { - 0, 0 - } -}; - -/* - * Map a function address to a string name, if known; or a hex string. - */ -static char * -fn_name(uintptr_t addr) -{ - static char buf[17]; - int i = 0; - -#ifdef DDB - db_expr_t diff; - c_db_sym_t sym; - char *symname; - - diff = 0; - symname = NULL; - sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff); - db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0); - if (symname && diff == 0) - return (symname); -#endif - - for (i = 0; names[i].name; i++) - if (names[i].addr == (void *)addr) - return (names[i].name); - sprintf(buf, "%jx", (uintmax_t)addr); - return (buf); -} - -#endif /* DDB */ static void log_frame_dump(struct trapframe *frame)