svn commit: r271697 - in head/sys/cddl/dev: dtrace/powerpc fbt/powerpc
Justin Hibbits
jhibbits at FreeBSD.org
Wed Sep 17 02:43:48 UTC 2014
Author: jhibbits
Date: Wed Sep 17 02:43:47 2014
New Revision: 271697
URL: http://svnweb.freebsd.org/changeset/base/271697
Log:
Fix the stack tracing for dtrace/powerpc.
Summary:
Fix the stack tracing for dtrace/powerpc by using the trapexit/asttrapexit
return address sentinels instead of checking within the kernel address space.
As part of this, I had to add new inline functions. FBT traces the kernel, so
we have to have special case handling for this, since a trap will create a full
new trap frame, and there's no way to pass around the 'real' stack. I handle
this by special-casing 'aframes == 0' with the trap frame. If aframes counts
out to the trap frame, then assume we're looking for the full kernel trap frame,
so switch to the real stack pointer.
Test Plan: Tested on powerpc64
Reviewers: rpaulo, markj, nwhitehorn
Reviewed By: markj, nwhitehorn
Differential Revision: https://reviews.freebsd.org/D788
MFC after: 3 week
Relnotes: Yes
Modified:
head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
head/sys/cddl/dev/fbt/powerpc/fbt_isa.c
Modified: head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
==============================================================================
--- head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c Wed Sep 17 02:32:22 2014 (r271696)
+++ head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c Wed Sep 17 02:43:47 2014 (r271697)
@@ -52,9 +52,103 @@
/* Offset to LR Save word (ppc64). CR Save area sits between back chain and LR */
#define RETURN_OFFSET64 16
+#ifdef __powerpc64__
+#define OFFSET 4 /* Account for the TOC reload slot */
+#else
+#define OFFSET 0
+#endif
+
#define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \
(x) >= VM_MIN_KERNEL_ADDRESS)
+static __inline int
+dtrace_sp_inkernel(uintptr_t sp, int aframes)
+{
+ vm_offset_t callpc;
+
+#ifdef __powerpc64__
+ callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
+#else
+ callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
+#endif
+ if ((callpc & 3) || (callpc < 0x100))
+ return (0);
+
+ /*
+ * trapexit() and asttrapexit() are sentinels
+ * for kernel stack tracing.
+ *
+ * Special-case this for 'aframes == 0', because fbt sets aframes to the
+ * trap callchain depth, so we want to break out of it.
+ */
+ if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
+ callpc + OFFSET == (vm_offset_t) &asttrapexit) &&
+ aframes != 0)
+ return (0);
+
+ return (1);
+}
+
+static __inline uintptr_t
+dtrace_next_sp(uintptr_t sp)
+{
+ 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.
+ *
+ * Special-case this for 'aframes == 0', because fbt sets aframes to the
+ * trap callchain depth, so we want to break out of it.
+ */
+ if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
+ callpc + OFFSET == (vm_offset_t) &asttrapexit))
+ /* Access the trap frame */
+#ifdef __powerpc64__
+ return (*(uintptr_t *)sp + 48 + sizeof(register_t));
+#else
+ return (*(uintptr_t *)sp + 8 + sizeof(register_t));
+#endif
+
+ return (*(uintptr_t*)sp);
+}
+
+static __inline uintptr_t
+dtrace_get_pc(uintptr_t sp)
+{
+ 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.
+ *
+ * Special-case this for 'aframes == 0', because fbt sets aframes to the
+ * trap callchain depth, so we want to break out of it.
+ */
+ if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
+ callpc + OFFSET == (vm_offset_t) &asttrapexit))
+ /* Access the trap frame */
+#ifdef __powerpc64__
+ return (*(uintptr_t *)sp + 48 + offsetof(struct trapframe, lr));
+#else
+ return (*(uintptr_t *)sp + 8 + offsetof(struct trapframe, lr));
+#endif
+
+ return (callpc);
+}
+
greg_t
dtrace_getfp(void)
{
@@ -66,10 +160,11 @@ dtrace_getpcstack(pc_t *pcstack, int pcs
uint32_t *intrpc)
{
int depth = 0;
- register_t sp;
+ uintptr_t osp, sp;
vm_offset_t callpc;
pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
+ osp = PAGE_SIZE;
if (intrpc != 0)
pcstack[depth++] = (pc_t) intrpc;
@@ -78,17 +173,12 @@ dtrace_getpcstack(pc_t *pcstack, int pcs
sp = dtrace_getfp();
while (depth < pcstack_limit) {
- if (!INKERNEL((long) sp))
+ if (sp <= osp)
break;
-#ifdef __powerpc64__
- callpc = *(uintptr_t *)(sp + RETURN_OFFSET64);
-#else
- callpc = *(uintptr_t *)(sp + RETURN_OFFSET);
-#endif
-
- if (!INKERNEL(callpc))
+ if (!dtrace_sp_inkernel(sp, aframes))
break;
+ callpc = dtrace_get_pc(sp);
if (aframes > 0) {
aframes--;
@@ -100,7 +190,8 @@ dtrace_getpcstack(pc_t *pcstack, int pcs
pcstack[depth++] = callpc;
}
- sp = *(uintptr_t*)sp;
+ osp = sp;
+ sp = dtrace_next_sp(sp);
}
for (; depth < pcstack_limit; depth++) {
@@ -368,8 +459,11 @@ dtrace_getarg(int arg, int aframes)
* On ppc32 AIM, and booke, trapexit() is the immediately following
* label. On ppc64 AIM trapexit() follows a nop.
*/
- if (((long)(fp[1]) == (long)trapexit) ||
- (((long)(fp[1]) + 4 == (long)trapexit))) {
+#ifdef __powerpc64__
+ if ((long)(fp[2]) + 4 == (long)trapexit) {
+#else
+ if ((long)(fp[1]) == (long)trapexit) {
+#endif
/*
* In the case of powerpc, we will use the pointer to the regs
* structure that was pushed when we took the trap. To get this
@@ -433,23 +527,31 @@ int
dtrace_getstackdepth(int aframes)
{
int depth = 0;
- register_t sp;
+ uintptr_t osp, sp;
+ vm_offset_t callpc;
+ osp = PAGE_SIZE;
aframes++;
sp = dtrace_getfp();
depth++;
for(;;) {
- if (!INKERNEL((long) sp))
+ if (sp <= osp)
break;
- if (!INKERNEL((long) *(void **)sp))
+
+ if (!dtrace_sp_inkernel(sp, aframes))
break;
- depth++;
+
+ if (aframes == 0)
+ depth++;
+ else
+ aframes--;
+ osp = sp;
sp = *(uintptr_t *)sp;
}
if (depth < aframes)
- return 0;
- else
- return depth - aframes;
+ return (0);
+
+ return (depth);
}
ulong_t
Modified: head/sys/cddl/dev/fbt/powerpc/fbt_isa.c
==============================================================================
--- head/sys/cddl/dev/fbt/powerpc/fbt_isa.c Wed Sep 17 02:32:22 2014 (r271696)
+++ head/sys/cddl/dev/fbt/powerpc/fbt_isa.c Wed Sep 17 02:43:47 2014 (r271697)
@@ -147,7 +147,7 @@ fbt_provide_module_function(linker_file_
fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
fbt->fbtp_name = name;
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
- name, FBT_ENTRY, 3, fbt);
+ name, FBT_ENTRY, 7, fbt);
fbt->fbtp_patchpoint = instr;
fbt->fbtp_ctl = lf;
fbt->fbtp_loadcnt = lf->loadcnt;
@@ -210,7 +210,7 @@ again:
if (retfbt == NULL) {
fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
- name, FBT_RETURN, 5, fbt);
+ name, FBT_RETURN, 7, fbt);
} else {
retfbt->fbtp_next = fbt;
fbt->fbtp_id = retfbt->fbtp_id;
More information about the svn-src-head
mailing list