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
This commit is contained in:
Justin Hibbits 2014-07-03 06:52:26 +00:00
parent 7ddad071a5
commit e42edd4db6

View File

@ -55,20 +55,22 @@ int
pmc_save_kernel_callchain(uintptr_t *cc, int maxsamples, pmc_save_kernel_callchain(uintptr_t *cc, int maxsamples,
struct trapframe *tf) struct trapframe *tf)
{ {
uintptr_t *osp, *sp;
int frames = 0; int frames = 0;
uintptr_t *sp;
cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
osp = NULL;
for (; frames < maxsamples; frames++) { for (; frames < maxsamples; frames++) {
if (!INKERNEL(sp)) if (!INKERNEL(sp) || sp <= osp)
break; break;
#ifdef __powerpc64__ #ifdef __powerpc64__
cc[frames++] = sp[2]; cc[frames] = sp[2];
#else #else
cc[frames++] = sp[1]; cc[frames] = sp[1];
#endif #endif
osp = sp;
sp = (uintptr_t *)*sp; sp = (uintptr_t *)*sp;
} }
return (frames); return (frames);
@ -184,26 +186,28 @@ int
pmc_save_user_callchain(uintptr_t *cc, int maxsamples, pmc_save_user_callchain(uintptr_t *cc, int maxsamples,
struct trapframe *tf) struct trapframe *tf)
{ {
uintptr_t *sp; uintptr_t *osp, *sp;
int frames = 0; int frames = 0;
cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
osp = NULL;
for (; frames < maxsamples; frames++) { for (; frames < maxsamples; frames++) {
if (!INUSER(sp)) if (!INUSER(sp) || sp <= osp)
break; break;
osp = sp;
#ifdef __powerpc64__ #ifdef __powerpc64__
/* Check if 32-bit mode. */ /* Check if 32-bit mode. */
if (!(tf->srr1 & PSL_SF)) { 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); sp = (uintptr_t *)(uintptr_t)fuword32(sp);
} else { } else {
cc[frames++] = fuword(sp + 2); cc[frames] = fuword(sp + 2);
sp = (uintptr_t *)fuword(sp); sp = (uintptr_t *)fuword(sp);
} }
#else #else
cc[frames++] = fuword32((uint32_t *)sp + 1); cc[frames] = fuword32((uint32_t *)sp + 1);
sp = (uintptr_t *)fuword32(sp); sp = (uintptr_t *)fuword32(sp);
#endif #endif
} }