Module Name: src Committed By: riastradh Date: Wed Feb 12 01:10:16 UTC 2020
Modified Files: src/external/cddl/osnet/dev/dtrace/aarch64: dtrace_isa.c Log Message: Teach dtrace about el1_trap_exit frames on aarch64. Implement dtrace_getarg and dtrace_getreg while here. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 \ src/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c diff -u src/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c:1.1 src/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c:1.2 --- src/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c:1.1 Tue Dec 3 22:10:56 2019 +++ src/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c Wed Feb 12 01:10:16 2020 @@ -89,52 +89,60 @@ void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { - struct unwind_state state; - int scp_offset; - register_t sp, fp; - int depth; - - depth = 0; - - if (intrpc != 0) { - pcstack[depth++] = (pc_t) intrpc; + extern const char el1_trap_exit[]; + const register_t *fp; + int i = 0; + + if (intrpc) { + if (i < pcstack_limit) + pcstack[i++] = (pc_t)intrpc; } - aframes++; - - __asm __volatile("mov %0, sp" : "=&r" (sp)); - - state.fp = (uint64_t)__builtin_frame_address(0); - state.sp = sp; - state.pc = (uint64_t)dtrace_getpcstack; - - while (depth < pcstack_limit) { - if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) - break; - - fp = state.fp; - state.sp = fp + 0x10; - /* FP to previous frame (X29) */ - state.fp = *(register_t *)(fp); - /* LR (X30) */ - state.pc = *(register_t *)(fp + 8) - 4; - - /* - * NB: Unlike some other architectures, we don't need to - * explicitly insert cpu_dtrace_caller as it appears in the - * normal kernel stack trace rather than a special trap frame. - */ - if (aframes > 0) { + /* + * fp[0] = x29 (saved frame pointer) + * fp[1] = x30 (saved link register == return address) + */ + fp = __builtin_frame_address(0); + while (i < pcstack_limit && INKERNEL(fp[0]) && INKERNEL(fp[1])) { + /* Skip the specified number of artificial frames. */ + if (aframes > 0) aframes--; + else + pcstack[i++] = fp[1]; + + /* Check whether this frame is handling a trap. */ + if (fp[1] == (register_t)el1_trap_exit) { + /* + * Trap from kernel. The trapframe is the + * saved frame pointer of the call to the trap + * handler whose return address is + * el1_trap_exit. The frame pointer of the + * interrupted code is in x29 stashed in the + * trapframe, alongside its pc. + */ + const struct trapframe *tf = (const void *)fp[0]; + /* x29 = frame pointer */ + fp = (const void *)tf->tf_regs.r_reg[29]; + if (INKERNEL(tf->tf_pc)) { + if (i >= pcstack_limit) + break; + if (aframes > 0) + aframes--; + else + pcstack[i++] = tf->tf_pc; + } } else { - pcstack[depth++] = state.pc; + /* + * Not a trap. Keep going with fp[0] as the + * parent frame pointer. + */ + fp = (const void *)fp[0]; } - } - for (; depth < pcstack_limit; depth++) { - pcstack[depth] = 0; - } + /* Zero the rest of the return address stack. (Paranoia?) */ + while (i < pcstack_limit) + pcstack[i++] = 0; } static int @@ -282,48 +290,78 @@ dtrace_getufpstack(uint64_t *pcstack, ui uint64_t dtrace_getarg(int arg, int aframes) { + extern const char el1_trap_exit[]; + const register_t *fp; + const struct trapframe *tf = NULL; + int i = 0; - printf("IMPLEMENT ME: %s\n", __func__); + /* + * The first arguments are passed in x0,...,x7. The rest are + * on the stack, too much trouble to figure out. + * + * XXX Shouldn't we ask ctf or dwarf or something to figure + * this stuff out for us? + */ + KASSERT(arg >= 0); + if (arg >= 8) + return 0; + + fp = __builtin_frame_address(0); + while (i < 1000 && INKERNEL(fp[0]) && INKERNEL(fp[1])) { + if (aframes > 0) + aframes--; + else + i++; + if (fp[1] == (register_t)el1_trap_exit) { + tf = (const void *)fp[0]; + break; + } else { + fp = (const void *)fp[0]; + } + } - return (0); + /* If we didn't find a trap frame, give up. */ + if (tf == NULL) + return 0; + + /* Arg0, arg1, ..., arg7 are in registers x0, x1, ..., x7. */ + return tf->tf_regs.r_reg[arg]; } int dtrace_getstackdepth(int aframes) { - struct unwind_state state; - int scp_offset; - register_t sp; - int depth; - int done; - - depth = 1; - done = 0; - - __asm __volatile("mov %0, sp" : "=&r" (sp)); - - state.fp = (uint64_t)__builtin_frame_address(0); - state.sp = sp; - state.pc = (uint64_t)dtrace_getstackdepth; - - do { - done = unwind_frame(&state); - if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) - break; - depth++; - } while (!done); + extern const char el1_trap_exit[]; + const register_t *fp; + int i = 0; + + fp = __builtin_frame_address(0); + while (i < 1000 && INKERNEL(fp[0]) && INKERNEL(fp[1])) { + if (aframes > 0) + aframes--; + else + i++; + if (fp[1] == (register_t)el1_trap_exit) { + const struct trapframe *tf = (const void *)fp[0]; + fp = (const void *)tf->tf_regs.r_reg[29]; + if (aframes > 0) + aframes--; + else + i++; + } else { + fp = (const void *)fp[0]; + } + } - if (depth < aframes) - return (0); - else - return (depth - aframes); + return i; } ulong_t -dtrace_getreg(struct trapframe *rp, uint_t reg) +dtrace_getreg(struct trapframe *tf, uint_t reg) { - printf("IMPLEMENT ME: %s\n", __func__); + if (reg < 32) + return tf->tf_regs.r_reg[reg]; return (0); }