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:
parent
44f17a8111
commit
c757049235
75
cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
Normal file
75
cddl/contrib/opensolaris/lib/libdtrace/powerpc/dt_isadep.c
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -25,4 +25,10 @@ _lockstat= lockstat
|
||||
_dtrace= dtrace
|
||||
.endif
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "powerpc"
|
||||
_dtrace= dtrace
|
||||
_dtruss= dtruss
|
||||
_lockstat= lockstat
|
||||
.endif
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
49
sys/cddl/contrib/opensolaris/uts/powerpc/sys/fasttrap_isa.h
Normal file
49
sys/cddl/contrib/opensolaris/uts/powerpc/sys/fasttrap_isa.h
Normal 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 */
|
269
sys/cddl/dev/dtrace/powerpc/dtrace_asm.S
Normal file
269
sys/cddl/dev/dtrace/powerpc/dtrace_asm.S
Normal 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)
|
||||
|
534
sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
Normal file
534
sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
Normal 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));
|
||||
}
|
201
sys/cddl/dev/dtrace/powerpc/dtrace_subr.c
Normal file
201
sys/cddl/dev/dtrace/powerpc/dtrace_subr.c
Normal 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);
|
||||
}
|
63
sys/cddl/dev/dtrace/powerpc/regset.h
Normal file
63
sys/cddl/dev/dtrace/powerpc/regset.h
Normal 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 */
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user