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:
parent
942886743b
commit
d69b94bab0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=347943
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user