summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorjhibbits <jhibbits@FreeBSD.org>2014-07-03 06:52:26 +0000
committerjhibbits <jhibbits@FreeBSD.org>2014-07-03 06:52:26 +0000
commit9f9f2874f668cfc964a2d62f908e115c4c9b6211 (patch)
tree21109791fc3b6a9503a507b9644ad1f567e119ed /sys/dev
parent41f8871f5e1d1169f1609bb6ed00d7626ffbd9ad (diff)
downloadFreeBSD-src-9f9f2874f668cfc964a2d62f908e115c4c9b6211.zip
FreeBSD-src-9f9f2874f668cfc964a2d62f908e115c4c9b6211.tar.gz
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
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/hwpmc/hwpmc_powerpc.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/sys/dev/hwpmc/hwpmc_powerpc.c b/sys/dev/hwpmc/hwpmc_powerpc.c
index 19207cd..4628059 100644
--- a/sys/dev/hwpmc/hwpmc_powerpc.c
+++ b/sys/dev/hwpmc/hwpmc_powerpc.c
@@ -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
}
OpenPOWER on IntegriCloud