Implement DTrace for PowerPC. This includes both 32-bit and 64-bit.

There is one known issue:  Some probes will display an error message along the
lines of:  "Invalid address (0)"

I tested this with both a simple dtrace probe and dtruss on a few different
binaries on 32-bit.  I only compiled 64-bit, did not run it, but I don't expect
problems without the modules loaded.  Volunteers are welcome.

MFC after:	1 month
This commit is contained in:
Justin Hibbits 2012-11-07 23:45:09 +00:00
parent 44f17a8111
commit c757049235
23 changed files with 1365 additions and 5 deletions

View File

@ -0,0 +1,75 @@
/*
* 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.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <libgen.h>
#include <dt_impl.h>
#include <dt_pid.h>
/*ARGSUSED*/
int
dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
{
dt_dprintf("%s: unimplemented\n", __func__);
return (DT_PROC_ERR);
}
int
dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
{
dt_dprintf("%s: unimplemented\n", __func__);
return (DT_PROC_ERR);
}
/*ARGSUSED*/
int
dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
{
dt_dprintf("%s: unimplemented\n", __func__);
return (DT_PROC_ERR);
}
/*ARGSUSED*/
int
dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
{
dt_dprintf("%s: unimplemented\n", __func__);
return (DT_PROC_ERR);
}

View File

@ -19,7 +19,8 @@ _libzpool= libzpool
.endif
.endif
.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || ${MACHINE_CPUARCH} == "mips"
.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || \
${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc"
_drti= drti
_libdtrace= libdtrace
.endif

View File

@ -74,6 +74,10 @@ CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/mips
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/mips
.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/mips
.elif ${MACHINE_CPUARCH} == "powerpc"
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/powerpc
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/powerpc
.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/powerpc
.else
# temporary hack
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel

View File

@ -25,4 +25,10 @@ _lockstat= lockstat
_dtrace= dtrace
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
_dtrace= dtrace
_dtruss= dtruss
_lockstat= lockstat
.endif
.include <bsd.subdir.mk>

View File

@ -207,6 +207,11 @@ _libproc= libproc
_librtld_db= librtld_db
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
_libproc= libproc
_librtld_db= librtld_db
.endif
.if ${MK_OPENSSL} != "no"
_libmp= libmp
.endif

View File

@ -47,6 +47,9 @@ __FBSDID("$FreeBSD$");
#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

View File

@ -60,6 +60,8 @@ proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue)
*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 @@ proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue)
*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 @@ proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue)
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 @@ proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue)
regs.r_esp = regvalue;
#elif defined(__mips__)
regs.r_regs[PC] = regvalue;
#elif defined(__powerpc__)
regs.fixreg[1] = regvalue;
#endif
break;
default:

View File

@ -235,7 +235,7 @@ static dtrace_dynvar_t dtrace_dynhash_sink; /* end of dynamic hash chains */
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 @@ dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags,
#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

View File

@ -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
*/

View File

@ -0,0 +1,49 @@
/*
* 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
#define FASTTRAP_INSTR 0x0FFFDDDD
#ifdef __cplusplus
}
#endif
#endif /* _FASTTRAP_ISA_H */

View File

@ -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$
*/
/*
* 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,%r0
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,%r0
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)

View File

@ -0,0 +1,534 @@
/*
* 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$
*/
/*
* 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/sysent.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>
#include "regset.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 RETURN_OFFSET64 8
#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)
{
proc_t *p = curproc;
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;
if (SV_PROC_FLAG(p, SV_ILP32)) {
pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
sp = dtrace_fuword32((void *)sp);
}
else {
pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
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 = tf->lr;
}
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.
*/
if (SV_PROC_FLAG(p, SV_ILP32)) {
pc = dtrace_fuword32((void *) sp);
}
else
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;
if (SV_PROC_FLAG(p, SV_ILP32)) {
pc = dtrace_fuword32((void *)sp);
}
else {
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 */
{
if (SV_PROC_FLAG(p, SV_ILP32)) {
pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
sp = dtrace_fuword32((void *)sp);
}
else {
pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
sp = dtrace_fuword64((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));
}

View File

@ -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$
*
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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);
}

View File

@ -0,0 +1,63 @@
/*
* 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$
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#ifndef _REGSET_H
#define _REGSET_H
/*
* #pragma ident "@(#)regset.h 1.11 05/06/08 SMI"
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* XXXDTRACE: define registers properly
*/
#if 0
#define REG_PC PC
#define REG_FP EBP
#define REG_SP SP
#define REG_PS EFL
#define REG_R0 EAX
#define REG_R1 EDX
#endif
#ifdef __cplusplus
}
#endif
#endif /* _REGSET_H */

View File

@ -45,7 +45,8 @@
#include <sys/dtrace.h>
#include <sys/lockstat.h>
#if defined(__i386__) || defined(__amd64__) || defined(__mips__)
#if defined(__i386__) || defined(__amd64__) || \
defined(__mips__) || defined(__powerpc__)
#define LOCKSTAT_AFRAMES 1
#else
#error "architecture not supported"

View File

@ -119,6 +119,13 @@
#define PROF_ARTIFICIAL_FRAMES 3
#endif
#ifdef __powerpc__
/*
* This value is bogus just to make module compilable on powerpc
*/
#define PROF_ARTIFICIAL_FRAMES 3
#endif
typedef struct profile_probe {
char prof_name[PROF_NAMELEN];
dtrace_id_t prof_id;

View File

@ -788,10 +788,15 @@ _exca= exca
_nvram= powermac_nvram
_pccard= pccard
_sound= sound
_cyclic= cyclic
_dtrace= dtrace
_opensolaris= opensolaris
.endif
.if ${MACHINE_ARCH} == "powerpc64"
.if ${MK_CDDL} != "no" || defined(ALL_MODULES)
_cyclic= cyclic
_dtrace= dtrace
_opensolaris= opensolaris
.endif
.if ${MK_ZFS} != "no" || defined(ALL_MODULES)

View File

@ -10,12 +10,14 @@ SUBDIR= dtmalloc \
dtraceall \
dtrace_test \
dtio \
lockstat \
profile \
prototype \
sdt \
systrace
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
SUBDIR+= fasttrap fbt lockstat profile systrace_linux32
SUBDIR+= fasttrap fbt systrace_linux32
.endif
.if ${MACHINE_CPUARCH} == "amd64"
SUBDIR+= systrace_freebsd32

View File

@ -65,6 +65,8 @@
#include <machine/spr.h>
#include <machine/asm.h>
#include "opt_kdtrace.h"
/* Locate the per-CPU data structure */
#define GET_CPUINFO(r) \
mfsprg0 r

View File

@ -65,6 +65,8 @@
#include <machine/spr.h>
#include <machine/asm.h>
#include "opt_kdtrace.h"
/* Locate the per-CPU data structure */
#define GET_CPUINFO(r) \
mfsprg0 r

View File

@ -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 @@ struct powerpc_exception {
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 @@ trap(struct trapframe *frame)
}
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 @@ trap_pfault(struct trapframe *frame, int user)
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

View File

@ -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, 4
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, 4
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

View File

@ -274,6 +274,26 @@ restore_kernsrs:
mtsrr1 %r3; \
mfsprg3 %r3 /* restore r3 */
#ifdef KDTRACE_HOOKS
.data
.globl dtrace_invop_jump_addr
.align 8
.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 8
.type dtrace_invop_calltrap_addr, @object
.size dtrace_invop_calltrap_addr, 8
dtrace_invop_calltrap_addr:
.word 0
.word 0
.text
#endif
#ifdef SMP
/*
* Processor reset exception handler. These are typically