Date: Wed, 29 Feb 2012 21:08:30 GMT From: Oleksandr Tymoshenko <gonzo@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 207113 for review Message-ID: <201202292108.q1TL8UmB072548@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@207113?ac=10 Change 207113 by gonzo@gonzo_thinkpad on 2012/02/29 21:07:32 Move kernel backtrace code into dtrace_isa.c file Affected files ... .. //depot/projects/dtrace-mips/sys/cddl/dev/dtrace/mips/dtrace_asm.S#2 edit .. //depot/projects/dtrace-mips/sys/cddl/dev/dtrace/mips/dtrace_isa.c#8 edit .. //depot/projects/dtrace-mips/sys/conf/files.mips#3 edit .. //depot/projects/dtrace-mips/sys/mips/mips/backtrace.c#5 delete .. //depot/projects/dtrace-mips/sys/mips/mips/db_trace.c#3 edit Differences ... ==== //depot/projects/dtrace-mips/sys/cddl/dev/dtrace/mips/dtrace_asm.S#2 (text+ko) ==== @@ -297,3 +297,4 @@ j ra nop END(dtrace_caller) + ==== //depot/projects/dtrace-mips/sys/cddl/dev/dtrace/mips/dtrace_isa.c#8 (text+ko) ==== @@ -44,6 +44,7 @@ #include <machine/db_machdep.h> #include <machine/md_var.h> #include <machine/mips_opcode.h> +#include <machine/vmparam.h> #include <ddb/db_sym.h> #include <ddb/ddb.h> #include <sys/kdb.h> @@ -57,14 +58,13 @@ #define MAX_FUNCTION_SIZE 0x10000 #define MAX_PROLOGUE_SIZE 0x100 -int next_frame(register_t *pc, register_t *sp, - uintptr_t *args, int *valid_args); uint8_t dtrace_fuword8_nocheck(void *); uint16_t dtrace_fuword16_nocheck(void *); uint32_t dtrace_fuword32_nocheck(void *); uint64_t dtrace_fuword64_nocheck(void *); +static int dtrace_next_frame(register_t *pc, register_t *sp, uintptr_t *args, int *valid_args); static int dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra); void @@ -107,7 +107,7 @@ pcstack[depth++] = callpc; } - if (next_frame(&pc, &sp, NULL, NULL) < 0) + if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0) break; } @@ -229,7 +229,7 @@ : "r" (ra)); for (i = 0; i <= aframes + 1; i++) { - if (next_frame(&pc, &sp, args, valid) < 0) { + if (dtrace_next_frame(&pc, &sp, args, valid) < 0) { printf("%s: stack ends at frame #%d\n", __func__, i); return (0); } @@ -264,7 +264,7 @@ : "r" (ra)); for (;;) { - if (next_frame(&pc, &sp, NULL, NULL) < 0) + if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0) break; depth++; } @@ -283,6 +283,203 @@ } static int +dtrace_next_frame(register_t *pc, register_t *sp, + uintptr_t *args, int *valid_args) +{ + InstFmt i; + /* + * Arrays for a0..a3 registers and flags if content + * of these registers is valid, e.g. obtained from the stack + */ + uintptr_t va; + unsigned instr, mask; + unsigned int frames = 0; + int more, stksize; + register_t ra = 0; + int arg, r; + + /* + * Invalidate arguments values + */ + if (valid_args) { + for (r = 0; r < 8; r++) + valid_args[r] = 0; + } + + /* Jump here after a nonstandard (interrupt handler) frame */ + stksize = 0; + if (frames++ > 100) { + /* return breaks stackframe-size heuristics with gcc -O2 */ + goto error; /* XXX */ + } + + /* check for bad SP: could foul up next frame */ + if (!MIPS_IS_VALID_KERNELADDR(*sp)) { + goto error; + } + + /* check for bad PC */ + if (!MIPS_IS_VALID_KERNELADDR(*pc)) { + goto error; + } + + /* + * Find the beginning of the current subroutine by scanning + * backwards from the current PC for the end of the previous + * subroutine. + */ + va = *pc - sizeof(int); + while (1) { + instr = kdbpeek((int *)va); + + /* [d]addiu sp,sp,-X */ + if (((instr & 0xffff8000) == 0x27bd8000) + || ((instr & 0xffff8000) == 0x67bd8000)) + break; + + /* jr ra */ + if (instr == 0x03e00008) { + /* 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); + + /* scan forwards to find stack size and any saved registers */ + stksize = 0; + more = 3; + mask = 0; + for (; 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 */ + case 5:/* a1 */ + case 6:/* a2 */ + case 7:/* a3 */ +#if defined(__mips_n64) || defined(__mips_n32) + case 8:/* a4 */ + case 9:/* a5 */ + case 10:/* a6 */ + case 11:/* a7 */ +#endif + arg = i.IType.rt - 4; + if (args) + args[arg] = kdbpeek((int *)(*sp + (short)i.IType.imm)); + if (valid_args) + valid_args[arg] = 1; + 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 */ + case 5:/* a1 */ + case 6:/* a2 */ + case 7:/* a3 */ +#if defined(__mips_n64) || defined(__mips_n32) + case 8:/* a4 */ + case 9:/* a5 */ + case 10:/* a6 */ + case 11:/* a7 */ +#endif + arg = i.IType.rt - 4; + if (args) + args[arg] = kdbpeekd((int *)(*sp + (short)i.IType.imm)); + if (valid_args) + valid_args[arg] = 1; + break; + + case 31: /* ra */ + ra = kdbpeekd((int *)(*sp + (short)i.IType.imm)); + } + break; + + case OP_ADDI: + case OP_ADDIU: + case OP_DADDI: + case OP_DADDIU: + /* look for stack pointer adjustment */ + if (i.IType.rs != 29 || i.IType.rt != 29) + break; + stksize = -((short)i.IType.imm); + } + } + + if (!MIPS_IS_VALID_KERNELADDR(ra)) + return (-1); + + *pc = ra; + *sp += stksize; + + return (0); +error: + return (-1); +} + +static int dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra) { int offset, registers_on_stack; ==== //depot/projects/dtrace-mips/sys/conf/files.mips#3 (text+ko) ==== @@ -44,7 +44,6 @@ mips/mips/pm_machdep.c standard mips/mips/swtch.S standard mips/mips/tlb.c standard -mips/mips/backtrace.c standard mips/mips/bus_space_generic.c standard mips/mips/busdma_machdep.c standard ==== //depot/projects/dtrace-mips/sys/mips/mips/db_trace.c#3 (text+ko) ==== @@ -20,6 +20,7 @@ #include <machine/mips_opcode.h> #include <machine/pcb.h> #include <machine/trap.h> +#include <machine/vmparam.h> #include <ddb/ddb.h> #include <ddb/db_sym.h> @@ -49,14 +50,6 @@ */ #define MIPS_END_OF_FUNCTION(ins) ((ins) == 0x03e00008) -#if defined(__mips_n64) -# define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ - ((vm_offset_t)(reg) >= MIPS_XKPHYS_START)) -#else -# define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ - ((vm_offset_t)(reg) >= MIPS_KSEG0_START)) -#endif - /* * Functions ``special'' enough to print by name */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202292108.q1TL8UmB072548>
