svn commit: r318167 - in head/sys: cddl/dev/dtrace/powerpc powerpc/booke

Justin Hibbits jhibbits at FreeBSD.org
Thu May 11 00:23:53 UTC 2017


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


More information about the svn-src-all mailing list