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