powerpc/dtrace: Fix dtrace powerpc asm, and simplify stack walking

Fix some execution bugs in the dtrace powerpc asm.  addme pulls in the carry
flag which we don't want, and the result wasn't recorded anyways, so the
following beq to check for exit condition wasn't checking the right
condition.

Simplify the stack walking in dtrace_isa.c, so there's only a single walker
that handles both pc and sp.  This should make it easier to follow, and any
bugfix that may be needed for walking only needs to be made in one place
instead of two now.

MFC after:	2 weeks
This commit is contained in:
Justin Hibbits 2019-04-13 03:32:21 +00:00
parent 77eb50c7a3
commit e9aae3496e
2 changed files with 23 additions and 43 deletions

View File

@ -148,14 +148,19 @@ dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
volatile uint16_t *flags)
*/
ASENTRY_NOPROF(dtrace_copystr)
addme %r7,%r3
addme %r8,%r4
subi %r7,%r3,1
subi %r8,%r4,1
1:
lbzu %r3,1(%r7)
stbu %r3,1(%r8)
addme %r5,%r5
subi %r5,%r5,1
#ifdef __powerpc64__
cmpldi %r5,0
#else
cmplwi %r5,0
#endif
beq 2f
or %r3,%r3,%r3
cmplwi %r3,0
beq 2f
andi. %r0,%r5,0x0fff
beq 2f

View File

@ -94,11 +94,10 @@ dtrace_sp_inkernel(uintptr_t sp)
return (1);
}
static __inline uintptr_t
dtrace_next_sp(uintptr_t sp)
static __inline void
dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
{
vm_offset_t callpc;
uintptr_t *r1;
struct trapframe *frame;
#ifdef __powerpc64__
@ -115,39 +114,17 @@ dtrace_next_sp(uintptr_t sp)
callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
/* Access the trap frame */
frame = (struct trapframe *)(sp + FRAME_OFFSET);
r1 = (uintptr_t *)frame->fixreg[1];
if (r1 == NULL)
return (0);
return (*r1);
if (nsp != NULL)
*nsp = frame->fixreg[1];
if (pc != NULL)
*pc = frame->srr0;
}
return (*(uintptr_t*)sp);
}
static __inline uintptr_t
dtrace_get_pc(uintptr_t sp)
{
struct trapframe *frame;
vm_offset_t callpc;
#ifdef __powerpc64__
callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
#else
callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
#endif
/*
* trapexit() and asttrapexit() are sentinels
* for kernel stack tracing.
*/
if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
/* Access the trap frame */
frame = (struct trapframe *)(sp + FRAME_OFFSET);
return (frame->srr0);
}
return (callpc);
if (nsp != NULL)
*nsp = *(uintptr_t *)sp;
if (pc != NULL)
*pc = callpc;
}
greg_t
@ -179,7 +156,8 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
if (!dtrace_sp_inkernel(sp))
break;
callpc = dtrace_get_pc(sp);
osp = sp;
dtrace_next_sp_pc(osp, &sp, &callpc);
if (aframes > 0) {
aframes--;
@ -190,9 +168,6 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
else {
pcstack[depth++] = callpc;
}
osp = sp;
sp = dtrace_next_sp(sp);
}
for (; depth < pcstack_limit; depth++) {
@ -546,7 +521,7 @@ dtrace_getstackdepth(int aframes)
else
aframes--;
osp = sp;
sp = dtrace_next_sp(sp);
dtrace_next_sp_pc(sp, &sp, NULL);
}
if (depth < aframes)
return (0);