powerpc/dtrace: Actually fix stack traces

Fix stack unwinding such that requesting N stack frames in lockstat will
actually give you N frames, not anywhere from 0-3 as had been before.

lockstat prints the mutex function instead of the caller as the reported
locker, but the stack frame is detailed enough to find the real caller.

MFC after:	2 weeks
This commit is contained in:
Justin Hibbits 2019-05-17 19:57:08 +00:00
parent 942886743b
commit d69b94bab0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=347943
2 changed files with 25 additions and 22 deletions

View File

@ -179,3 +179,13 @@ ASENTRY_NOPROF(dtrace_caller)
li %r3, -1
blr
END(dtrace_caller)
/*
greg_t
dtrace_getfp(void)
*/
ASENTRY_NOPROF(dtrace_getfp)
mr %r3,%r31
blr
END(dtrace_getfp)

View File

@ -61,8 +61,10 @@
#define FRAME_OFFSET 8
#endif
#define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \
(x) >= VM_MIN_KERNEL_ADDRESS)
#define INKERNEL(x) (((x) <= VM_MAX_KERNEL_ADDRESS && \
(x) >= VM_MIN_KERNEL_ADDRESS) || \
(PMAP_HAS_DMAP && (x) >= DMAP_BASE_ADDRESS && \
(x) <= DMAP_MAX_ADDRESS))
static __inline int
dtrace_sp_inkernel(uintptr_t sp)
@ -70,6 +72,9 @@ dtrace_sp_inkernel(uintptr_t sp)
struct trapframe *frame;
vm_offset_t callpc;
/* Not within the kernel, or not aligned. */
if (!INKERNEL(sp) || (sp & 0xf) != 0)
return (0);
#ifdef __powerpc64__
callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
#else
@ -84,8 +89,6 @@ dtrace_sp_inkernel(uintptr_t sp)
*/
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);
@ -119,6 +122,7 @@ dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
*nsp = frame->fixreg[1];
if (pc != NULL)
*pc = frame->srr0;
return;
}
if (nsp != NULL)
@ -127,12 +131,6 @@ dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
*pc = callpc;
}
greg_t
dtrace_getfp(void)
{
return (greg_t)__builtin_frame_address(0);
}
void
dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
uint32_t *intrpc)
@ -148,7 +146,7 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
aframes++;
sp = dtrace_getfp();
sp = (uintptr_t)__builtin_frame_address(0);
while (depth < pcstack_limit) {
if (sp <= osp)
@ -418,7 +416,7 @@ uint64_t
dtrace_getarg(int arg, int aframes)
{
uintptr_t val;
uintptr_t *fp = (uintptr_t *)dtrace_getfp();
uintptr_t *fp = (uintptr_t *)__builtin_frame_address(0);
uintptr_t *stack;
int i;
@ -432,8 +430,8 @@ dtrace_getarg(int arg, int aframes)
fp = (uintptr_t *)*fp;
/*
* On ppc32 AIM, and booke, trapexit() is the immediately following
* label. On ppc64 AIM trapexit() follows a nop.
* On ppc32 trapexit() is the immediately following label. On
* ppc64 AIM trapexit() follows a nop.
*/
#ifdef __powerpc64__
if ((long)(fp[2]) + 4 == (long)trapexit) {
@ -506,9 +504,7 @@ dtrace_getstackdepth(int aframes)
vm_offset_t callpc;
osp = PAGE_SIZE;
aframes++;
sp = dtrace_getfp();
depth++;
sp = (uintptr_t)__builtin_frame_address(0);
for(;;) {
if (sp <= osp)
break;
@ -516,17 +512,14 @@ dtrace_getstackdepth(int aframes)
if (!dtrace_sp_inkernel(sp))
break;
if (aframes == 0)
depth++;
else
aframes--;
depth++;
osp = sp;
dtrace_next_sp_pc(sp, &sp, NULL);
}
if (depth < aframes)
return (0);
return (depth);
return (depth - aframes);
}
ulong_t