Author: jhibbits Date: Thu May 11 00:23:51 2017 New Revision: 318167 URL: https://svnweb.freebsd.org/changeset/base/318167
Log: Fix stack tracing in dtrace for powerpc The current method only sort of works, and usually doesn't work reliably. Also, on Book-E the return address from DEBUG exceptions is not the sentinel addresses, so it won't exit the loop correctly. Fix this by better handling trap frames during unwinding, and using the common trap handler for debug traps, as the code in that segment is identical between the two. MFC after: 1 week Modified: head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c head/sys/powerpc/booke/trap_subr.S Modified: head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c ============================================================================== --- head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c Wed May 10 23:32:31 2017 (r318166) +++ head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c Thu May 11 00:23:51 2017 (r318167) @@ -38,6 +38,7 @@ #include <machine/frame.h> #include <machine/md_var.h> +#include <machine/psl.h> #include <machine/reg.h> #include <machine/stack.h> @@ -54,16 +55,19 @@ #ifdef __powerpc64__ #define OFFSET 4 /* Account for the TOC reload slot */ +#define FRAME_OFFSET 48 #else #define OFFSET 0 +#define FRAME_OFFSET 8 #endif #define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \ (x) >= VM_MIN_KERNEL_ADDRESS) static __inline int -dtrace_sp_inkernel(uintptr_t sp, int aframes) +dtrace_sp_inkernel(uintptr_t sp) { + struct trapframe *frame; vm_offset_t callpc; #ifdef __powerpc64__ @@ -77,14 +81,15 @@ dtrace_sp_inkernel(uintptr_t sp, int afr /* * trapexit() and asttrapexit() are sentinels * for kernel stack tracing. - * - * Special-case this for 'aframes == 0', because fbt sets aframes to the - * trap callchain depth, so we want to break out of it. */ - if ((callpc + OFFSET == (vm_offset_t) &trapexit || - callpc + OFFSET == (vm_offset_t) &asttrapexit) && - aframes != 0) - return (0); + if (callpc + OFFSET == (vm_offset_t) &trapexit || + callpc + OFFSET == (vm_offset_t) &asttrapexit) { + if (sp == 0) + return (0); + frame = (struct trapframe *)(sp + FRAME_OFFSET); + + return ((frame->srr1 & PSL_PR) == 0); + } return (1); } @@ -93,6 +98,7 @@ static __inline uintptr_t dtrace_next_sp(uintptr_t sp) { vm_offset_t callpc; + struct trapframe *frame; #ifdef __powerpc64__ callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); @@ -103,18 +109,13 @@ dtrace_next_sp(uintptr_t sp) /* * trapexit() and asttrapexit() are sentinels * for kernel stack tracing. - * - * Special-case this for 'aframes == 0', because fbt sets aframes to the - * trap callchain depth, so we want to break out of it. */ if ((callpc + OFFSET == (vm_offset_t) &trapexit || - callpc + OFFSET == (vm_offset_t) &asttrapexit)) - /* Access the trap frame */ -#ifdef __powerpc64__ - return (*(uintptr_t *)sp + 48 + sizeof(register_t)); -#else - return (*(uintptr_t *)sp + 8 + sizeof(register_t)); -#endif + callpc + OFFSET == (vm_offset_t) &asttrapexit)) { + /* Access the trap frame */ + frame = (struct trapframe *)(sp + FRAME_OFFSET); + return (*(uintptr_t *)(frame->fixreg[1])); + } return (*(uintptr_t*)sp); } @@ -122,6 +123,7 @@ dtrace_next_sp(uintptr_t sp) static __inline uintptr_t dtrace_get_pc(uintptr_t sp) { + struct trapframe *frame; vm_offset_t callpc; #ifdef __powerpc64__ @@ -133,18 +135,13 @@ dtrace_get_pc(uintptr_t sp) /* * trapexit() and asttrapexit() are sentinels * for kernel stack tracing. - * - * Special-case this for 'aframes == 0', because fbt sets aframes to the - * trap callchain depth, so we want to break out of it. */ if ((callpc + OFFSET == (vm_offset_t) &trapexit || - callpc + OFFSET == (vm_offset_t) &asttrapexit)) - /* Access the trap frame */ -#ifdef __powerpc64__ - return (*(uintptr_t *)sp + 48 + offsetof(struct trapframe, lr)); -#else - return (*(uintptr_t *)sp + 8 + offsetof(struct trapframe, lr)); -#endif + callpc + OFFSET == (vm_offset_t) &asttrapexit)) { + /* Access the trap frame */ + frame = (struct trapframe *)(sp + FRAME_OFFSET); + return (frame->srr0); + } return (callpc); } @@ -176,7 +173,7 @@ dtrace_getpcstack(pc_t *pcstack, int pcs if (sp <= osp) break; - if (!dtrace_sp_inkernel(sp, aframes)) + if (!dtrace_sp_inkernel(sp)) break; callpc = dtrace_get_pc(sp); @@ -537,7 +534,7 @@ dtrace_getstackdepth(int aframes) if (sp <= osp) break; - if (!dtrace_sp_inkernel(sp, aframes)) + if (!dtrace_sp_inkernel(sp)) break; if (aframes == 0) Modified: head/sys/powerpc/booke/trap_subr.S ============================================================================== --- head/sys/powerpc/booke/trap_subr.S Wed May 10 23:32:31 2017 (r318166) +++ head/sys/powerpc/booke/trap_subr.S Thu May 11 00:23:51 2017 (r318167) @@ -981,12 +981,12 @@ int_debug_int: LOAD %r4,0(%r5) /* interrupt_vector_base in r4 */ add %r4,%r4,%r5 CMPL cr0, %r3, %r4 - blt 1f + blt trap_common LOAD %r4,4(%r5) /* interrupt_vector_top in r4 */ add %r4,%r4,%r5 addi %r4,%r4,4 CMPL cr0, %r3, %r4 - bge 1f + bge trap_common /* Disable single-stepping for the interrupt handlers. */ LOAD %r3, FRAME_SRR1+CALLSIZE(%r1); rlwinm %r3, %r3, 0, 23, 21 @@ -999,16 +999,6 @@ int_debug_int: mtspr SPR_SRR1, %r4 mtlr %r14 blr -1: - GET_TOCBASE(%r2) - addi %r3, %r1, CALLSIZE - bl CNAME(trap) - TOC_RESTORE - /* - * Handle ASTs, needed for proper support of single-stepping. - * We actually need to return to the process with an rfi. - */ - b trapexit /***************************************************************************** * Common trap code _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"