diff options
author | jhibbits <jhibbits@FreeBSD.org> | 2014-09-14 22:03:41 +0000 |
---|---|---|
committer | jhibbits <jhibbits@FreeBSD.org> | 2014-09-14 22:03:41 +0000 |
commit | 3872faab0157ae97ca9647fdffcfc3e640e6b8ec (patch) | |
tree | 618cc88951b47ec45a0d869496e289dfa01134de /sys/dev/hwpmc/hwpmc_powerpc.c | |
parent | 4c51a2212236e79a65ec9962d39ec638154a5c54 (diff) | |
download | FreeBSD-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.c | 40 |
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__ |