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"

Reply via email to