summaryrefslogtreecommitdiffstats
path: root/sys/dev/hwpmc/hwpmc_powerpc.c
diff options
context:
space:
mode:
authorjhibbits <jhibbits@FreeBSD.org>2014-09-14 22:03:41 +0000
committerjhibbits <jhibbits@FreeBSD.org>2014-09-14 22:03:41 +0000
commit3872faab0157ae97ca9647fdffcfc3e640e6b8ec (patch)
tree618cc88951b47ec45a0d869496e289dfa01134de /sys/dev/hwpmc/hwpmc_powerpc.c
parent4c51a2212236e79a65ec9962d39ec638154a5c54 (diff)
downloadFreeBSD-src-3872faab0157ae97ca9647fdffcfc3e640e6b8ec.zip
FreeBSD-src-3872faab0157ae97ca9647fdffcfc3e640e6b8ec.tar.gz
Fix PowerPC backtraces. Since kernel and user have completely separate address
spaces, rather than a split address, we actually can't check for being within the kernel's address range. Instead, do what other backtraces do, and use trapexit()/asttrapexit() as the stack sentinel. MFC after: 3 weeks
Diffstat (limited to 'sys/dev/hwpmc/hwpmc_powerpc.c')
-rw-r--r--sys/dev/hwpmc/hwpmc_powerpc.c40
1 files changed, 27 insertions, 13 deletions
diff --git a/sys/dev/hwpmc/hwpmc_powerpc.c b/sys/dev/hwpmc/hwpmc_powerpc.c
index 4628059..ad251d3 100644
--- a/sys/dev/hwpmc/hwpmc_powerpc.c
+++ b/sys/dev/hwpmc/hwpmc_powerpc.c
@@ -40,14 +40,15 @@ __FBSDID("$FreeBSD$");
#include <machine/pte.h>
#include <machine/sr.h>
#include <machine/cpu.h>
-#include <machine/vmparam.h> /* For VM_MIN_KERNEL_ADDRESS/VM_MAX_KERNEL_ADDRESS */
+#include <machine/stack.h>
#include "hwpmc_powerpc.h"
-#define INKERNEL(x) (((vm_offset_t)(x)) <= VM_MAX_KERNEL_ADDRESS && \
- ((vm_offset_t)(x)) >= VM_MIN_KERNEL_ADDRESS)
-#define INUSER(x) (((vm_offset_t)(x)) <= VM_MAXUSER_ADDRESS && \
- ((vm_offset_t)(x)) >= VM_MIN_ADDRESS)
+#ifdef __powerpc64__
+#define OFFSET 4 /* Account for the TOC reload slot */
+#else
+#define OFFSET 0
+#endif
struct powerpc_cpu **powerpc_pcpu;
@@ -56,20 +57,33 @@ pmc_save_kernel_callchain(uintptr_t *cc, int maxsamples,
struct trapframe *tf)
{
uintptr_t *osp, *sp;
+ uintptr_t pc;
int frames = 0;
cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
- osp = NULL;
+ osp = (uintptr_t *)PAGE_SIZE;
for (; frames < maxsamples; frames++) {
- if (!INKERNEL(sp) || sp <= osp)
+ if (sp <= osp)
break;
-#ifdef __powerpc64__
- cc[frames] = sp[2];
-#else
- cc[frames] = sp[1];
-#endif
+ #ifdef __powerpc64__
+ pc = sp[2];
+ #else
+ pc = sp[1];
+ #endif
+ if ((pc & 3) || (pc < 0x100))
+ break;
+
+ /*
+ * trapexit() and asttrapexit() are sentinels
+ * for kernel stack tracing.
+ * */
+ if (pc + OFFSET == (uintptr_t) &trapexit ||
+ pc + OFFSET == (uintptr_t) &asttrapexit)
+ break;
+
+ cc[frames] = pc;
osp = sp;
sp = (uintptr_t *)*sp;
}
@@ -194,7 +208,7 @@ pmc_save_user_callchain(uintptr_t *cc, int maxsamples,
osp = NULL;
for (; frames < maxsamples; frames++) {
- if (!INUSER(sp) || sp <= osp)
+ if (sp <= osp)
break;
osp = sp;
#ifdef __powerpc64__
OpenPOWER on IntegriCloud