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:
parent
7ddad071a5
commit
e42edd4db6
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user