Author: jhibbits
Date: Thu Jul  3 06:52:26 2014
New Revision: 268207
URL: http://svnweb.freebsd.org/changeset/base/268207

Log:
  Fix a bug in hwpmc(4) callchain retrieval, for both user and kernel.
  
  The array index for the callchain is getting double-incremented -- both in the
  loop and the storing.  It should only be incremented in one location.
  
  Also, constrain the stack pointer range check.
  
  MFC after:    2 weeks

Modified:
  head/sys/dev/hwpmc/hwpmc_powerpc.c

Modified: head/sys/dev/hwpmc/hwpmc_powerpc.c
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_powerpc.c  Thu Jul  3 06:44:55 2014        
(r268206)
+++ head/sys/dev/hwpmc/hwpmc_powerpc.c  Thu Jul  3 06:52:26 2014        
(r268207)
@@ -55,20 +55,22 @@ int
 pmc_save_kernel_callchain(uintptr_t *cc, int maxsamples,
     struct trapframe *tf)
 {
+       uintptr_t *osp, *sp;
        int frames = 0;
-       uintptr_t *sp;
 
        cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
        sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
+       osp = NULL;
 
        for (; frames < maxsamples; frames++) {
-               if (!INKERNEL(sp))
+               if (!INKERNEL(sp) || sp <= osp)
                        break;
 #ifdef __powerpc64__
-               cc[frames++] = sp[2];
+               cc[frames] = sp[2];
 #else
-               cc[frames++] = sp[1];
+               cc[frames] = sp[1];
 #endif
+               osp = sp;
                sp = (uintptr_t *)*sp;
        }
        return (frames);
@@ -184,26 +186,28 @@ int
 pmc_save_user_callchain(uintptr_t *cc, int maxsamples,
     struct trapframe *tf)
 {
-       uintptr_t *sp;
+       uintptr_t *osp, *sp;
        int frames = 0;
 
        cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
        sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
+       osp = NULL;
 
        for (; frames < maxsamples; frames++) {
-               if (!INUSER(sp))
+               if (!INUSER(sp) || sp <= osp)
                        break;
+               osp = sp;
 #ifdef __powerpc64__
                /* Check if 32-bit mode. */
                if (!(tf->srr1 & PSL_SF)) {
-                       cc[frames++] = fuword32((uint32_t *)sp + 1);
+                       cc[frames] = fuword32((uint32_t *)sp + 1);
                        sp = (uintptr_t *)(uintptr_t)fuword32(sp);
                } else {
-                       cc[frames++] = fuword(sp + 2);
+                       cc[frames] = fuword(sp + 2);
                        sp = (uintptr_t *)fuword(sp);
                }
 #else
-               cc[frames++] = fuword32((uint32_t *)sp + 1);
+               cc[frames] = fuword32((uint32_t *)sp + 1);
                sp = (uintptr_t *)fuword32(sp);
 #endif
        }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to