Date: Tue, 9 Oct 2012 19:08:38 -0400 From: Justin Hibbits <chmeeedalf@gmail.com> To: freebsd-ppc@freebsd.org Subject: CFT: Dtrace on PowerPC Message-ID: <20121009190838.283976e1@narn.knownspace>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
After a few days of development, and a few weeks of testing, here's
Dtrace on PowerPC. There is only one known issue that I know of so
far: dtruss kernel panics through an assertion. I have to investigate
this some more, but some dtrace -n "<probe>" testing works.
- Justin
[-- Attachment #2 --]
Index: lib/Makefile
===================================================================
--- lib/Makefile (revision 241162)
+++ lib/Makefile (working copy)
@@ -209,6 +209,8 @@
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
+_libproc= libproc
+_librtld_db= librtld_db
_libsmb= libsmb
.endif
Index: lib/libproc/proc_regs.c
===================================================================
--- lib/libproc/proc_regs.c (revision 241162)
+++ lib/libproc/proc_regs.c (working copy)
@@ -60,6 +60,8 @@
*regvalue = regs.r_eip;
#elif defined(__mips__)
*regvalue = regs.r_regs[PC];
+#elif defined(__powerpc__)
+ *regvalue = regs.pc;
#endif
break;
case REG_SP:
@@ -69,6 +71,8 @@
*regvalue = regs.r_esp;
#elif defined(__mips__)
*regvalue = regs.r_regs[SP];
+#elif defined(__powerpc__)
+ *regvalue = regs.fixreg[1];
#endif
break;
default:
@@ -99,6 +103,8 @@
regs.r_eip = regvalue;
#elif defined(__mips__)
regs.r_regs[PC] = regvalue;
+#elif defined(__powerpc__)
+ regs.pc = regvalue;
#endif
break;
case REG_SP:
@@ -108,6 +114,8 @@
regs.r_esp = regvalue;
#elif defined(__mips__)
regs.r_regs[PC] = regvalue;
+#elif defined(__powerpc__)
+ regs.fixreg[1] = regvalue;
#endif
break;
default:
Index: lib/libproc/proc_bkpt.c
===================================================================
--- lib/libproc/proc_bkpt.c (revision 241162)
+++ lib/libproc/proc_bkpt.c (working copy)
@@ -47,6 +47,9 @@
#elif defined(__mips__)
#define BREAKPOINT_INSTR 0xd /* break */
#define BREAKPOINT_INSTR_SZ 4
+#elif defined(__powerpc__)
+#define BREAKPOINT_INSTR 0x7fe00008 /* trap */
+#define BREAKPOINT_INSTR_SZ 4
#else
#error "Add support for your architecture"
#endif
Index: sys/modules/Makefile
===================================================================
--- sys/modules/Makefile (revision 241162)
+++ sys/modules/Makefile (working copy)
@@ -799,6 +799,9 @@
_pccard= pccard
_smbfs= smbfs
_sound= sound
+_cyclic= cyclic
+_dtrace= dtrace
+_opensolaris= opensolaris
.endif
.if ${MACHINE_ARCH} == "powerpc64"
Index: sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c (revision 0)
+++ sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c (working copy)
@@ -0,0 +1,30 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * XXX: Placeholder for PowerPC fasttrap code
+ */
Index: sys/cddl/contrib/opensolaris/uts/powerpc/sys/fasttrap_isa.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/powerpc/sys/fasttrap_isa.h (revision 0)
+++ sys/cddl/contrib/opensolaris/uts/powerpc/sys/fasttrap_isa.h (working copy)
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FASTTRAP_ISA_H
+#define _FASTTRAP_ISA_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * XXXDTRACE: placehodler for PowerPC fasttrap stuff
+ */
+
+typedef uint32_t fasttrap_instr_t;
+#define FASTTRAP_SUNWDTRACE_SIZE 64
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FASTTRAP_ISA_H */
Index: sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c (revision 241162)
+++ sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c (working copy)
@@ -235,7 +235,7 @@
static struct mtx dtrace_unr_mtx;
MTX_SYSINIT(dtrace_unr_mtx, &dtrace_unr_mtx, "Unique resource identifier", MTX_DEF);
int dtrace_in_probe; /* non-zero if executing a probe */
-#if defined(__i386__) || defined(__amd64__) || defined(__mips__)
+#if defined(__i386__) || defined(__amd64__) || defined(__mips__) || defined(__powerpc__)
uintptr_t dtrace_in_probe_addr; /* Address of invop when already in probe */
#endif
#endif
@@ -10762,7 +10762,7 @@
#else
int i;
-#if defined(__amd64__) || defined(__mips__)
+#if defined(__amd64__) || defined(__mips__) || defined(__powerpc__)
/*
* FreeBSD isn't good at limiting the amount of memory we
* ask to malloc, so let's place a limit here before trying
Index: sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
===================================================================
--- sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (revision 0)
+++ sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (working copy)
@@ -0,0 +1,508 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD: head/sys/cddl/dev/dtrace/amd64/dtrace_isa.c 211608 2010-08-22 10:53:32Z rpaulo $
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/stack.h>
+#include <sys/pcpu.h>
+
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/reg.h>
+#include <machine/stack.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+uint8_t dtrace_fuword8_nocheck(void *);
+uint16_t dtrace_fuword16_nocheck(void *);
+uint32_t dtrace_fuword32_nocheck(void *);
+uint64_t dtrace_fuword64_nocheck(void *);
+
+/* Offset to the LR Save word (ppc32) */
+#define RETURN_OFFSET 4
+
+#define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \
+ (x) >= VM_MIN_KERNEL_ADDRESS)
+
+greg_t
+dtrace_getfp(void)
+{
+ return (greg_t)__builtin_frame_address(0);
+}
+
+void
+dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
+ uint32_t *intrpc)
+{
+ int depth = 0;
+ register_t sp;
+ vm_offset_t callpc;
+ pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
+
+ if (intrpc != 0)
+ pcstack[depth++] = (pc_t) intrpc;
+
+ aframes++;
+
+ sp = dtrace_getfp();
+
+ while (depth < pcstack_limit) {
+ if (!INKERNEL((long) sp))
+ break;
+
+ callpc = *(uintptr_t *)(sp + RETURN_OFFSET);
+
+ if (!INKERNEL(callpc))
+ break;
+
+ if (aframes > 0) {
+ aframes--;
+ if ((aframes == 0) && (caller != 0)) {
+ pcstack[depth++] = caller;
+ }
+ }
+ else {
+ pcstack[depth++] = callpc;
+ }
+
+ sp = *(uintptr_t*)sp;
+ }
+
+ for (; depth < pcstack_limit; depth++) {
+ pcstack[depth] = 0;
+ }
+}
+
+static int
+dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
+ uintptr_t sp)
+{
+ int ret = 0;
+
+ ASSERT(pcstack == NULL || pcstack_limit > 0);
+
+ while (pc != 0) {
+ ret++;
+ if (pcstack != NULL) {
+ *pcstack++ = (uint64_t)pc;
+ pcstack_limit--;
+ if (pcstack_limit <= 0)
+ break;
+ }
+
+ if (sp == 0)
+ break;
+
+ pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET));
+ sp = dtrace_fuword64((void *)sp);
+ }
+
+ return (ret);
+}
+
+void
+dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
+{
+ proc_t *p = curproc;
+ struct trapframe *tf;
+ uintptr_t pc, sp;
+ volatile uint16_t *flags =
+ (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
+ int n;
+
+ if (*flags & CPU_DTRACE_FAULT)
+ return;
+
+ if (pcstack_limit <= 0)
+ return;
+
+ /*
+ * If there's no user context we still need to zero the stack.
+ */
+ if (p == NULL || (tf = curthread->td_frame) == NULL)
+ goto zero;
+
+ *pcstack++ = (uint64_t)p->p_pid;
+ pcstack_limit--;
+
+ if (pcstack_limit <= 0)
+ return;
+
+ pc = tf->srr0;
+ sp = tf->fixreg[1];
+
+ if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
+ /*
+ * In an entry probe. The frame pointer has not yet been
+ * pushed (that happens in the function prologue). The
+ * best approach is to add the current pc as a missing top
+ * of stack and back the pc up to the caller, which is stored
+ * at the current stack pointer address since the call
+ * instruction puts it there right before the branch.
+ */
+
+ *pcstack++ = (uint64_t)pc;
+ pcstack_limit--;
+ if (pcstack_limit <= 0)
+ return;
+
+ pc = dtrace_fuword32((void *) sp);
+ }
+
+ n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
+ ASSERT(n >= 0);
+ ASSERT(n <= pcstack_limit);
+
+ pcstack += n;
+ pcstack_limit -= n;
+
+zero:
+ while (pcstack_limit-- > 0)
+ *pcstack++ = 0;
+}
+
+int
+dtrace_getustackdepth(void)
+{
+ proc_t *p = curproc;
+ struct trapframe *tf;
+ uintptr_t pc, sp;
+ int n = 0;
+
+ if (p == NULL || (tf = curthread->td_frame) == NULL)
+ return (0);
+
+ if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
+ return (-1);
+
+ pc = tf->srr0;
+ sp = tf->fixreg[1];
+
+ if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
+ /*
+ * In an entry probe. The frame pointer has not yet been
+ * pushed (that happens in the function prologue). The
+ * best approach is to add the current pc as a missing top
+ * of stack and back the pc up to the caller, which is stored
+ * at the current stack pointer address since the call
+ * instruction puts it there right before the branch.
+ */
+
+ pc = dtrace_fuword64((void *) sp);
+ n++;
+ }
+
+ n += dtrace_getustack_common(NULL, 0, pc, sp);
+
+ return (n);
+}
+
+void
+dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
+{
+ proc_t *p = curproc;
+ struct trapframe *tf;
+ uintptr_t pc, sp;
+ volatile uint16_t *flags =
+ (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
+#ifdef notyet /* XXX signal stack */
+ uintptr_t oldcontext;
+ size_t s1, s2;
+#endif
+
+ if (*flags & CPU_DTRACE_FAULT)
+ return;
+
+ if (pcstack_limit <= 0)
+ return;
+
+ /*
+ * If there's no user context we still need to zero the stack.
+ */
+ if (p == NULL || (tf = curthread->td_frame) == NULL)
+ goto zero;
+
+ *pcstack++ = (uint64_t)p->p_pid;
+ pcstack_limit--;
+
+ if (pcstack_limit <= 0)
+ return;
+
+ pc = tf->srr0;
+ sp = tf->fixreg[1];
+
+#ifdef notyet /* XXX signal stack */
+ oldcontext = lwp->lwp_oldcontext;
+ s1 = sizeof (struct xframe) + 2 * sizeof (long);
+ s2 = s1 + sizeof (siginfo_t);
+#endif
+
+ if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
+ *pcstack++ = (uint64_t)pc;
+ *fpstack++ = 0;
+ pcstack_limit--;
+ if (pcstack_limit <= 0)
+ return;
+
+ pc = dtrace_fuword64((void *)sp);
+ }
+
+ while (pc != 0) {
+ *pcstack++ = (uint64_t)pc;
+ *fpstack++ = sp;
+ pcstack_limit--;
+ if (pcstack_limit <= 0)
+ break;
+
+ if (sp == 0)
+ break;
+
+#ifdef notyet /* XXX signal stack */
+ if (oldcontext == sp + s1 || oldcontext == sp + s2) {
+ ucontext_t *ucp = (ucontext_t *)oldcontext;
+ greg_t *gregs = ucp->uc_mcontext.gregs;
+
+ sp = dtrace_fulword(&gregs[REG_FP]);
+ pc = dtrace_fulword(&gregs[REG_PC]);
+
+ oldcontext = dtrace_fulword(&ucp->uc_link);
+ } else
+#endif /* XXX */
+ {
+ pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
+ sp = dtrace_fuword32((void *)sp);
+ }
+
+ /*
+ * This is totally bogus: if we faulted, we're going to clear
+ * the fault and break. This is to deal with the apparently
+ * broken Java stacks on x86.
+ */
+ if (*flags & CPU_DTRACE_FAULT) {
+ *flags &= ~CPU_DTRACE_FAULT;
+ break;
+ }
+ }
+
+zero:
+ while (pcstack_limit-- > 0)
+ *pcstack++ = 0;
+}
+
+/*ARGSUSED*/
+uint64_t
+dtrace_getarg(int arg, int aframes)
+{
+ return (0);
+}
+
+#ifdef notyet
+{
+ int depth = 0;
+ register_t sp;
+ vm_offset_t callpc;
+ pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
+
+ if (intrpc != 0)
+ pcstack[depth++] = (pc_t) intrpc;
+
+ aframes++;
+
+ sp = dtrace_getfp();
+
+ while (depth < pcstack_limit) {
+ if (!INKERNEL((long) frame))
+ break;
+
+ callpc = *(void **)(sp + RETURN_OFFSET);
+
+ if (!INKERNEL(callpc))
+ break;
+
+ if (aframes > 0) {
+ aframes--;
+ if ((aframes == 0) && (caller != 0)) {
+ pcstack[depth++] = caller;
+ }
+ }
+ else {
+ pcstack[depth++] = callpc;
+ }
+
+ sp = *(void **)sp;
+ }
+
+ for (; depth < pcstack_limit; depth++) {
+ pcstack[depth] = 0;
+ }
+}
+#endif
+
+int
+dtrace_getstackdepth(int aframes)
+{
+ int depth = 0;
+ register_t sp;
+
+ aframes++;
+ sp = dtrace_getfp();
+ depth++;
+ for(;;) {
+ if (!INKERNEL((long) sp))
+ break;
+ if (!INKERNEL((long) *(void **)sp))
+ break;
+ depth++;
+ sp = *(uintptr_t *)sp;
+ }
+ if (depth < aframes)
+ return 0;
+ else
+ return depth - aframes;
+}
+
+ulong_t
+dtrace_getreg(struct trapframe *rp, uint_t reg)
+{
+ if (reg < 32)
+ return (rp->fixreg[reg]);
+
+ switch (reg) {
+ case 33:
+ return (rp->lr);
+ case 34:
+ return (rp->cr);
+ case 35:
+ return (rp->xer);
+ case 36:
+ return (rp->ctr);
+ case 37:
+ return (rp->srr0);
+ case 38:
+ return (rp->srr1);
+ case 39:
+ return (rp->exc);
+ default:
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
+ return (0);
+ }
+}
+
+static int
+dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
+{
+ ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
+
+ if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+ cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
+ return (0);
+ }
+
+ return (1);
+}
+
+void
+dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+ volatile uint16_t *flags)
+{
+ if (dtrace_copycheck(uaddr, kaddr, size))
+ dtrace_copy(uaddr, kaddr, size);
+}
+
+void
+dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
+ volatile uint16_t *flags)
+{
+ if (dtrace_copycheck(uaddr, kaddr, size))
+ dtrace_copy(kaddr, uaddr, size);
+}
+
+void
+dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
+ volatile uint16_t *flags)
+{
+ if (dtrace_copycheck(uaddr, kaddr, size))
+ dtrace_copystr(uaddr, kaddr, size, flags);
+}
+
+void
+dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
+ volatile uint16_t *flags)
+{
+ if (dtrace_copycheck(uaddr, kaddr, size))
+ dtrace_copystr(kaddr, uaddr, size, flags);
+}
+
+uint8_t
+dtrace_fuword8(void *uaddr)
+{
+ if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+ return (0);
+ }
+ return (dtrace_fuword8_nocheck(uaddr));
+}
+
+uint16_t
+dtrace_fuword16(void *uaddr)
+{
+ if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+ return (0);
+ }
+ return (dtrace_fuword16_nocheck(uaddr));
+}
+
+uint32_t
+dtrace_fuword32(void *uaddr)
+{
+ if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+ return (0);
+ }
+ return (dtrace_fuword32_nocheck(uaddr));
+}
+
+uint64_t
+dtrace_fuword64(void *uaddr)
+{
+ if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+ return (0);
+ }
+ return (dtrace_fuword64_nocheck(uaddr));
+}
Index: sys/cddl/dev/dtrace/powerpc/dtrace_asm.S
===================================================================
--- sys/cddl/dev/dtrace/powerpc/dtrace_asm.S (revision 0)
+++ sys/cddl/dev/dtrace/powerpc/dtrace_asm.S (working copy)
@@ -0,0 +1,269 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD: head/sys/cddl/dev/dtrace/mips/dtrace_asm.S 233484 2012-03-26 01:26:33Z gonzo $
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "assym.s"
+
+#define _ASM
+
+#include <sys/cpuvar_defs.h>
+#include <sys/dtrace.h>
+
+#include <machine/asm.h>
+/*
+#include <machine/cpu.h>
+*/
+
+/*
+ * Primitives
+ */
+
+ .text
+
+/*
+void dtrace_membar_producer(void)
+*/
+ASENTRY_NOPROF(dtrace_membar_producer)
+ blr
+END(dtrace_membar_producer)
+
+/*
+void dtrace_membar_consumer(void)
+*/
+ASENTRY_NOPROF(dtrace_membar_consumer)
+ blr
+END(dtrace_membar_consumer)
+
+/*
+dtrace_icookie_t dtrace_interrupt_disable(void)
+*/
+ASENTRY_NOPROF(dtrace_interrupt_disable)
+ mfmsr %r3
+ andi. %r0,%r3,~PSL_EE@l
+ mtmsr %r0
+ blr
+END(dtrace_interrupt_disable)
+
+/*
+void dtrace_interrupt_enable(dtrace_icookie_t cookie)
+*/
+ASENTRY_NOPROF(dtrace_interrupt_enable)
+ mtmsr %r3
+ blr
+END(dtrace_interrupt_enable)
+
+/*
+uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
+*/
+ASENTRY_NOPROF(dtrace_cas32)
+1:
+ lwarx %r0,0,%r3
+ cmpw %r4,%r6
+ bne 2f
+ stwcx. %r5,0,%r3
+ bne 1b
+2: mr %r3,%r0
+ blr
+END(dtrace_cas32)
+
+/*
+void *
+dtrace_casptr(void *target, void *cmp, void *new)
+*/
+ASENTRY_NOPROF(dtrace_casptr)
+1:
+ lwarx %r0,0,%r3
+ cmpw %r4,%r6
+ bne 2f
+ stwcx. %r5,0,%r3
+ bne 1b
+2: mr %r3,%r0
+ blr
+END(dtrace_casptr)
+
+
+/*
+uintptr_t
+dtrace_fulword(void *addr)
+*/
+ASENTRY_NOPROF(dtrace_fulword)
+END(dtrace_fulword)
+
+/*
+uint8_t
+dtrace_fuword8_nocheck(void *addr)
+*/
+ASENTRY_NOPROF(dtrace_fuword8_nocheck)
+ lbz %r3,0(%r3)
+ blr
+END(dtrace_fuword8_nocheck)
+
+/*
+uint16_t
+dtrace_fuword16_nocheck(void *addr)
+*/
+ASENTRY_NOPROF(dtrace_fuword16_nocheck)
+ lhz %r3,0(%r3)
+ blr
+END(dtrace_fuword16_nocheck)
+
+/*
+uint32_t
+dtrace_fuword32_nocheck(void *addr)
+*/
+ASENTRY_NOPROF(dtrace_fuword32_nocheck)
+ lwz %r3,0(%r3)
+ blr
+END(dtrace_fuword32_nocheck)
+
+/*
+uint64_t
+dtrace_fuword64_nocheck(void *addr)
+*/
+ASENTRY_NOPROF(dtrace_fuword64_nocheck)
+#if defined(__powerpc64__)
+ ld %r3,0(%r3)
+#else
+ lwz %r5,0(%r3)
+ lwz %r4,4(%r3)
+ mr %r3,%r5
+#endif
+ blr
+END(dtrace_fuword64_nocheck)
+
+/*
+XXX: unoptimized
+void
+dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
+*/
+ASENTRY_NOPROF(dtrace_copy)
+ addme %r7,%r3
+ addme %r8,%r4
+1:
+ lbzu %r3,1(%r7)
+ stbu %r3,1(%r8)
+ addme %r5,%r5
+ beq 2f
+2:
+ blr
+END(dtrace_copy)
+
+/*
+void
+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
+1:
+ lbzu %r3,1(%r7)
+ stbu %r3,1(%r8)
+ addme %r5,%r5
+ beq 2f
+ or %r3,%r3,%r3
+ beq 2f
+ andi. %r0,%r5,0x0fff
+ beq 2f
+ lwz %r0,0(%r6)
+ andi. %r0,%r0,CPU_DTRACE_BADADDR
+ beq 1b
+2:
+ blr
+END(dtrace_copystr)
+
+/*
+void dtrace_invop_init(void)
+*/
+ASENTRY_NOPROF(dtrace_invop_init)
+ /* XXX: impement it properly -- implement dtrace_invop_start */
+ li %r0,0
+ li %r3,dtrace_invop_jump_addr@l
+ addis %r3,%r3,dtrace_invop_jump_addr@ha
+ stw %r0,0(%r3)
+ blr
+END(dtrace_invop_init)
+
+/*
+void dtrace_invop_uninit(void)
+*/
+ASENTRY_NOPROF(dtrace_invop_uninit)
+ li %r0,0
+ li %r3,dtrace_invop_jump_addr@l
+ addis %r3,%r3,dtrace_invop_jump_addr@ha
+ stw %r0,0(%r3)
+ blr
+END(dtrace_invop_uninit)
+
+/*
+ * The panic() and cmn_err() functions invoke vpanic() as a common entry point
+ * into the panic code implemented in panicsys(). vpanic() is responsible
+ * for passing through the format string and arguments, and constructing a
+ * regs structure on the stack into which it saves the current register
+ * values. If we are not dying due to a fatal trap, these registers will
+ * then be preserved in panicbuf as the current processor state. Before
+ * invoking panicsys(), vpanic() activates the first panic trigger (see
+ * common/os/panic.c) and switches to the panic_stack if successful. Note that
+ * DTrace takes a slightly different panic path if it must panic from probe
+ * context. Instead of calling panic, it calls into dtrace_vpanic(), which
+ * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
+ * branches back into vpanic().
+ */
+
+/*
+void
+vpanic(const char *format, va_list alist)
+*/
+ASENTRY_NOPROF(vpanic) /* Initial stack layout: */
+
+vpanic_common:
+ blr
+END(vpanic)
+
+
+
+/*
+void
+dtrace_vpanic(const char *format, va_list alist)
+*/
+ASENTRY_NOPROF(dtrace_vpanic) /* Initial stack layout: */
+
+#if 0
+ bl dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */
+#endif
+ b vpanic_common
+END(dtrace_vpanic)
+
+/*
+uintptr_t
+dtrace_caller(int aframes)
+*/
+ASENTRY_NOPROF(dtrace_caller)
+ li %r3, -1
+ blr
+END(dtrace_caller)
+
Index: sys/cddl/dev/dtrace/powerpc/dtrace_subr.c
===================================================================
--- sys/cddl/dev/dtrace/powerpc/dtrace_subr.c (revision 0)
+++ sys/cddl/dev/dtrace/powerpc/dtrace_subr.c (working copy)
@@ -0,0 +1,201 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD: head/sys/cddl/dev/dtrace/mips/dtrace_subr.c 233409 2012-03-24 05:14:37Z gonzo $
+ *
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/cddl/dev/dtrace/mips/dtrace_subr.c 233409 2012-03-24 05:14:37Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kmem.h>
+#include <sys/smp.h>
+#include <sys/dtrace_impl.h>
+#include <sys/dtrace_bsd.h>
+#include <machine/clock.h>
+#include <machine/frame.h>
+#include <machine/trap.h>
+#include <vm/pmap.h>
+
+#define DELAYBRANCH(x) ((int)(x) < 0)
+
+extern uintptr_t dtrace_in_probe_addr;
+extern int dtrace_in_probe;
+extern dtrace_id_t dtrace_probeid_error;
+
+int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
+
+typedef struct dtrace_invop_hdlr {
+ int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
+ struct dtrace_invop_hdlr *dtih_next;
+} dtrace_invop_hdlr_t;
+
+dtrace_invop_hdlr_t *dtrace_invop_hdlr;
+
+int
+dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
+{
+ dtrace_invop_hdlr_t *hdlr;
+ int rval;
+
+ for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
+ if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0)
+ return (rval);
+
+ return (0);
+}
+
+
+/*ARGSUSED*/
+void
+dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
+{
+ /*
+ * No toxic regions?
+ */
+}
+
+void
+dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
+{
+ cpuset_t cpus;
+
+ if (cpu == DTRACE_CPUALL)
+ cpus = all_cpus;
+ else
+ CPU_SETOF(cpu, &cpus);
+
+ smp_rendezvous_cpus(cpus, smp_no_rendevous_barrier, func,
+ smp_no_rendevous_barrier, arg);
+}
+
+static void
+dtrace_sync_func(void)
+{
+}
+
+void
+dtrace_sync(void)
+{
+ dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
+}
+
+/*
+ * DTrace needs a high resolution time function which can
+ * be called from a probe context and guaranteed not to have
+ * instrumented with probes itself.
+ *
+ * Returns nanoseconds since boot.
+ */
+uint64_t
+dtrace_gethrtime()
+{
+ struct timespec curtime;
+
+ nanouptime(&curtime);
+
+ return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
+
+}
+
+uint64_t
+dtrace_gethrestime(void)
+{
+ struct timespec curtime;
+
+ getnanotime(&curtime);
+
+ return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
+}
+
+/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */
+int
+dtrace_trap(struct trapframe *frame, u_int type)
+{
+ /*
+ * A trap can occur while DTrace executes a probe. Before
+ * executing the probe, DTrace blocks re-scheduling and sets
+ * a flag in it's per-cpu flags to indicate that it doesn't
+ * want to fault. On returning from the probe, the no-fault
+ * flag is cleared and finally re-scheduling is enabled.
+ *
+ * Check if DTrace has enabled 'no-fault' mode:
+ *
+ */
+ if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) {
+ /*
+ * There are only a couple of trap types that are expected.
+ * All the rest will be handled in the usual way.
+ */
+ switch (type) {
+ /* Page fault. */
+ case EXC_DSI:
+ case EXC_DSE:
+ /* Flag a bad address. */
+ cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
+ cpu_core[curcpu].cpuc_dtrace_illval = frame->cpu.aim.dar;
+
+ /*
+ * Offset the instruction pointer to the instruction
+ * following the one causing the fault.
+ */
+ frame->srr0 += sizeof(int);
+ return (1);
+ case EXC_ISI:
+ case EXC_ISE:
+ /* Flag a bad address. */
+ cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
+ cpu_core[curcpu].cpuc_dtrace_illval = frame->srr0;
+
+ /*
+ * Offset the instruction pointer to the instruction
+ * following the one causing the fault.
+ */
+ frame->srr0 += sizeof(int);
+ return (1);
+ default:
+ /* Handle all other traps in the usual way. */
+ break;
+ }
+ }
+
+ /* Handle the trap in the usual way. */
+ return (0);
+}
+
+void
+dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
+ int fault, int fltoffs, uintptr_t illval)
+{
+
+ dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state,
+ (uintptr_t)epid,
+ (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs);
+}
Index: sys/powerpc/aim/trap.c
===================================================================
--- sys/powerpc/aim/trap.c (revision 241162)
+++ sys/powerpc/aim/trap.c (working copy)
@@ -35,6 +35,7 @@
__FBSDID("$FreeBSD$");
#include "opt_hwpmc_hooks.h"
+#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/kdb.h>
@@ -104,6 +105,33 @@
char *name;
};
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/*
+ * This is a hook which is initialised by the dtrace module
+ * to handle traps which might occur during DTrace probe
+ * execution.
+ */
+dtrace_trap_func_t dtrace_trap_func;
+
+dtrace_doubletrap_func_t dtrace_doubletrap_func;
+
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque.
+ */
+systrace_probe_func_t systrace_probe_func;
+
+/*
+ * These hooks are necessary for the pid, usdt and fasttrap providers.
+ */
+dtrace_fasttrap_probe_ptr_t dtrace_fasttrap_probe_ptr;
+dtrace_pid_probe_ptr_t dtrace_pid_probe_ptr;
+dtrace_return_probe_ptr_t dtrace_return_probe_ptr;
+#endif
+
static struct powerpc_exception powerpc_exceptions[] = {
{ 0x0100, "system reset" },
{ 0x0200, "machine check" },
@@ -176,6 +204,28 @@
}
else
#endif
+#ifdef KDTRACE_HOOKS
+ /*
+ * A trap can occur while DTrace executes a probe. Before
+ * executing the probe, DTrace blocks re-scheduling and sets
+ * a flag in it's per-cpu flags to indicate that it doesn't
+ * want to fault. On returning from the probe, the no-fault
+ * flag is cleared and finally re-scheduling is enabled.
+ *
+ * If the DTrace kernel module has registered a trap handler,
+ * call it and if it returns non-zero, assume that it has
+ * handled the trap and modified the trap frame so that this
+ * function can return normally.
+ */
+ /*
+ * XXXDTRACE: add fasttrap and pid probes handlers here (if ever)
+ */
+ if (!user) {
+ if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type))
+ return;
+ }
+#endif
+
if (user) {
td->td_pticks = 0;
td->td_frame = frame;
@@ -617,6 +667,9 @@
PROC_LOCK(p);
--p->p_lock;
PROC_UNLOCK(p);
+ /*
+ * XXXDTRACE: add dtrace_doubletrap_func here?
+ */
} else {
/*
* Don't have to worry about process locking or stacks in the
Index: sys/powerpc/aim/locore32.S
===================================================================
--- sys/powerpc/aim/locore32.S (revision 241162)
+++ sys/powerpc/aim/locore32.S (working copy)
@@ -64,7 +64,10 @@
#include <machine/param.h>
#include <machine/spr.h>
#include <machine/asm.h>
+#include <machine/hid.h>
+#include "opt_kdtrace.h"
+
/* Locate the per-CPU data structure */
#define GET_CPUINFO(r) \
mfsprg0 r
Index: sys/powerpc/aim/trap_subr32.S
===================================================================
--- sys/powerpc/aim/trap_subr32.S (revision 241162)
+++ sys/powerpc/aim/trap_subr32.S (working copy)
@@ -240,6 +240,26 @@
mfsprg2 %r2; /* restore r2 & r3 */ \
mfsprg3 %r3
+#ifdef KDTRACE_HOOKS
+ .data
+ .globl dtrace_invop_jump_addr
+ .align 4
+ .type dtrace_invop_jump_addr, @object
+ .size dtrace_invop_jump_addr, 8
+dtrace_invop_jump_addr:
+ .word 0
+ .word 0
+ .globl dtrace_invop_calltrap_addr
+ .align 4
+ .type dtrace_invop_calltrap_addr, @object
+ .size dtrace_invop_calltrap_addr, 8
+dtrace_invop_calltrap_addr:
+ .word 0
+ .word 0
+
+ .text
+#endif
+
/*
* The next two routines are 64-bit glue code. The first is used to test if
* we are on a 64-bit system. By copying it to the illegal instruction
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20121009190838.283976e1>
