svn commit: r248463 - in user/attilio/vmcontention: contrib/binutils/gas/config lib/libc/stdlib sys/cddl/contrib/opensolaris/uts/common/sys sys/cddl/dev/dtrace/powerpc sys/cddl/dev/fbt sys/dev/ath ...
Attilio Rao
attilio at FreeBSD.org
Mon Mar 18 11:06:35 UTC 2013
Author: attilio
Date: Mon Mar 18 09:45:10 2013
New Revision: 248463
URL: http://svnweb.freebsd.org/changeset/base/248463
Log:
MFC
Added:
user/attilio/vmcontention/sys/cddl/dev/fbt/fbt_powerpc.c
- copied unchanged from r248462, head/sys/cddl/dev/fbt/fbt_powerpc.c
Modified:
user/attilio/vmcontention/contrib/binutils/gas/config/tc-arm.c
user/attilio/vmcontention/lib/libc/stdlib/realpath.3
user/attilio/vmcontention/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_asm.S
user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c
user/attilio/vmcontention/sys/dev/ath/if_ath_rx_edma.c
user/attilio/vmcontention/sys/dev/ath/if_ath_sysctl.c
user/attilio/vmcontention/sys/dev/sis/if_sis.c
user/attilio/vmcontention/sys/dev/sis/if_sisreg.h
user/attilio/vmcontention/sys/dev/usb/usbdevs
user/attilio/vmcontention/sys/dev/usb/wlan/if_run.c
user/attilio/vmcontention/sys/modules/dtrace/Makefile
user/attilio/vmcontention/sys/modules/dtrace/dtraceall/dtraceall.c
user/attilio/vmcontention/sys/modules/dtrace/fbt/Makefile
user/attilio/vmcontention/sys/powerpc/aim/trap.c
user/attilio/vmcontention/sys/powerpc/aim/trap_subr32.S
user/attilio/vmcontention/sys/powerpc/aim/trap_subr64.S
Directory Properties:
user/attilio/vmcontention/ (props changed)
user/attilio/vmcontention/contrib/binutils/ (props changed)
user/attilio/vmcontention/lib/libc/ (props changed)
user/attilio/vmcontention/sys/ (props changed)
user/attilio/vmcontention/sys/cddl/contrib/opensolaris/ (props changed)
user/attilio/vmcontention/sys/conf/ (props changed)
Modified: user/attilio/vmcontention/contrib/binutils/gas/config/tc-arm.c
==============================================================================
--- user/attilio/vmcontention/contrib/binutils/gas/config/tc-arm.c Mon Mar 18 09:39:51 2013 (r248462)
+++ user/attilio/vmcontention/contrib/binutils/gas/config/tc-arm.c Mon Mar 18 09:45:10 2013 (r248463)
@@ -651,6 +651,7 @@ struct asm_opcode
#define BAD_ARGS _("bad arguments to instruction")
#define BAD_PC _("r15 not allowed here")
+#define BAD_SP _("r13 not allowed here")
#define BAD_COND _("instruction cannot be conditional")
#define BAD_OVERLAP _("registers may not be the same")
#define BAD_HIREG _("lo register required")
@@ -659,6 +660,7 @@ struct asm_opcode
#define BAD_BRANCH _("branch must be last instruction in IT block")
#define BAD_NOT_IT _("instruction not allowed in IT block")
#define BAD_FPU _("selected FPU does not support instruction")
+#define BAD_VMRS _("APSR_nzcv may only be used with fpscr")
static struct hash_control *arm_ops_hsh;
static struct hash_control *arm_cond_hsh;
@@ -5164,10 +5166,6 @@ parse_neon_mov (char **str, int *which_o
Case 10: VMOV.F32 <Sd>, #<imm>
Case 11: VMOV.F64 <Dd>, #<imm> */
inst.operands[i].immisfloat = 1;
- else if (parse_big_immediate (&ptr, i) == SUCCESS)
- /* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
- Case 3: VMOV<c><q>.<dt> <Dd>, #<imm> */
- ;
else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype,
&optype)) != FAIL)
{
@@ -5207,6 +5205,10 @@ parse_neon_mov (char **str, int *which_o
inst.operands[i++].present = 1;
}
}
+ else if (parse_big_immediate (&ptr, i) == SUCCESS)
+ /* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
+ Case 3: VMOV<c><q>.<dt> <Dd>, #<imm> */
+ ;
else
{
first_error (_("expected <Rm> or <Dm> or <Qm> operand"));
@@ -7095,6 +7097,68 @@ do_vfp_nsyn_msr (void)
return SUCCESS;
}
+static int
+do_vfp_vmrs (void)
+{
+ int rt;
+
+ /* The destination register can be r0-r14 or APSR_nzcv */
+ if (inst.operands[0].reg > 14)
+ {
+ inst.error = BAD_PC;
+ return FAIL;
+ }
+
+ /* If the destination is r13 and not in ARM mode then unprefictable */
+ if (thumb_mode && inst.operands[0].reg == REG_SP)
+ {
+ inst.error = BAD_SP;
+ return FAIL;
+ }
+
+ /* If the destination is APSR_nzcv */
+ if (inst.operands[0].isvec && inst.operands[1].reg != 1)
+ {
+ inst.error = BAD_VMRS;
+ return FAIL;
+ }
+
+ if (inst.operands[0].isvec)
+ rt = 15;
+ else
+ rt = inst.operands[0].reg;
+
+ /* Or in the registers to use */
+ inst.instruction |= rt << 12;
+ inst.instruction |= inst.operands[1].reg << 16;
+
+ return SUCCESS;
+}
+
+static int
+do_vfp_vmsr (void)
+{
+ /* The destination register can be r0-r14 or APSR_nzcv */
+ if (inst.operands[1].reg > 14)
+ {
+ inst.error = BAD_PC;
+ return FAIL;
+ }
+
+ /* If the destination is r13 and not in ARM mode then unprefictable */
+ if (thumb_mode && inst.operands[0].reg == REG_SP)
+ {
+ inst.error = BAD_SP;
+ return FAIL;
+ }
+
+ /* Or in the registers to use */
+ inst.instruction |= inst.operands[1].reg << 12;
+ inst.instruction |= inst.operands[0].reg << 16;
+
+ return SUCCESS;
+}
+
static void
do_mrs (void)
{
@@ -15726,6 +15790,8 @@ static const struct asm_opcode insns[] =
cCE(ftouizs, ebc0ac0, 2, (RVS, RVS), vfp_sp_monadic),
cCE(fmrx, ef00a10, 2, (RR, RVC), rd_rn),
cCE(fmxr, ee00a10, 2, (RVC, RR), rn_rd),
+ cCE(vmrs, ef00a10, 2, (APSR_RR, RVC), vfp_vmrs),
+ cCE(vmsr, ee00a10, 2, (RVC, RR), vfp_vmsr),
/* Memory operations. */
cCE(flds, d100a00, 2, (RVS, ADDRGLDC), vfp_sp_ldst),
Modified: user/attilio/vmcontention/lib/libc/stdlib/realpath.3
==============================================================================
--- user/attilio/vmcontention/lib/libc/stdlib/realpath.3 Mon Mar 18 09:39:51 2013 (r248462)
+++ user/attilio/vmcontention/lib/libc/stdlib/realpath.3 Mon Mar 18 09:45:10 2013 (r248463)
@@ -42,7 +42,7 @@
.Sh SYNOPSIS
.In stdlib.h
.Ft "char *"
-.Fn realpath "const char *pathname" "char *resolved_path"
+.Fn realpath "const char * restrict pathname" "char * restrict resolved_path"
.Sh DESCRIPTION
The
.Fn realpath
Modified: user/attilio/vmcontention/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
==============================================================================
--- user/attilio/vmcontention/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h Mon Mar 18 09:39:51 2013 (r248462)
+++ user/attilio/vmcontention/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h Mon Mar 18 09:45:10 2013 (r248463)
@@ -2313,10 +2313,10 @@ extern int dtrace_mach_aframes(void);
#if defined(__i386) || defined(__amd64)
extern int dtrace_instr_size(uchar_t *instr);
extern int dtrace_instr_size_isa(uchar_t *, model_t, int *);
-extern void dtrace_invop_add(int (*)(uintptr_t, uintptr_t *, uintptr_t));
-extern void dtrace_invop_remove(int (*)(uintptr_t, uintptr_t *, uintptr_t));
extern void dtrace_invop_callsite(void);
#endif
+extern void dtrace_invop_add(int (*)(uintptr_t, uintptr_t *, uintptr_t));
+extern void dtrace_invop_remove(int (*)(uintptr_t, uintptr_t *, uintptr_t));
#ifdef __sparc
extern int dtrace_blksuword32(uintptr_t, uint32_t *, int);
@@ -2349,6 +2349,15 @@ extern void dtrace_helpers_destroy(proc_
#define DTRACE_INVOP_NOP 4
#define DTRACE_INVOP_RET 5
+#elif defined(__powerpc__)
+
+#define DTRACE_INVOP_RET 1
+#define DTRACE_INVOP_BCTR 2
+#define DTRACE_INVOP_BLR 3
+#define DTRACE_INVOP_JUMP 4
+#define DTRACE_INVOP_MFLR_R0 5
+#define DTRACE_INVOP_NOP 6
+
#endif
#ifdef __cplusplus
Modified: user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_asm.S
==============================================================================
--- user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_asm.S Mon Mar 18 09:39:51 2013 (r248462)
+++ user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_asm.S Mon Mar 18 09:45:10 2013 (r248463)
@@ -85,10 +85,10 @@ ASENTRY_NOPROF(dtrace_cas32)
1:
lwarx %r0,0,%r3
cmpw %r4,%r0
- bne 2f
+ bne 2f
stwcx. %r5,0,%r3
- bne 1b
-2: mr %r3,%r0
+ bne 1b
+2: mr %r3,%r0
blr
END(dtrace_cas32)
@@ -100,22 +100,15 @@ ASENTRY_NOPROF(dtrace_casptr)
1:
lwarx %r0,0,%r3
cmpw %r4,%r0
- bne 2f
+ bne 2f
stwcx. %r5,0,%r3
- bne 1b
-2: mr %r3,%r0
+ bne 1b
+2: mr %r3,%r0
blr
END(dtrace_casptr)
/*
-uintptr_t
-dtrace_fulword(void *addr)
-*/
-ASENTRY_NOPROF(dtrace_fulword)
-END(dtrace_fulword)
-
-/*
XXX: unoptimized
void
dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
@@ -127,7 +120,7 @@ ASENTRY_NOPROF(dtrace_copy)
lbzu %r3,1(%r7)
stbu %r3,1(%r8)
addme %r5,%r5
- beq 2f
+ beq 2f
2:
blr
END(dtrace_copy)
@@ -144,42 +137,19 @@ ASENTRY_NOPROF(dtrace_copystr)
lbzu %r3,1(%r7)
stbu %r3,1(%r8)
addme %r5,%r5
- beq 2f
- or %r3,%r3,%r3
- beq 2f
+ beq 2f
+ or %r3,%r3,%r3
+ beq 2f
andi. %r0,%r5,0x0fff
- beq 2f
- lwz %r0,0(%r6)
+ beq 2f
+ lwz %r0,0(%r6)
andi. %r0,%r0,CPU_DTRACE_BADADDR
- beq 1b
+ 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 at l
- addis %r3,%r3,dtrace_invop_jump_addr at 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 at l
- addis %r3,%r3,dtrace_invop_jump_addr at 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
Modified: user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c
==============================================================================
--- user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c Mon Mar 18 09:39:51 2013 (r248462)
+++ user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c Mon Mar 18 09:45:10 2013 (r248463)
@@ -567,3 +567,17 @@ dtrace_fuword64(void *uaddr)
}
return ret;
}
+
+uintptr_t
+dtrace_fulword(void *uaddr)
+{
+ uintptr_t ret = 0;
+
+ if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
+ if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+ cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
+ }
+ }
+ return ret;
+}
Modified: user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c
==============================================================================
--- user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c Mon Mar 18 09:39:51 2013 (r248462)
+++ user/attilio/vmcontention/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c Mon Mar 18 09:45:10 2013 (r248463)
@@ -49,8 +49,11 @@ __FBSDID("$FreeBSD$");
extern uintptr_t dtrace_in_probe_addr;
extern int dtrace_in_probe;
extern dtrace_id_t dtrace_probeid_error;
+extern int (*dtrace_invop_jump_addr)(struct trapframe *);
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
+void dtrace_invop_init(void);
+void dtrace_invop_uninit(void);
typedef struct dtrace_invop_hdlr {
int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
@@ -72,6 +75,44 @@ dtrace_invop(uintptr_t addr, uintptr_t *
return (0);
}
+void
+dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
+{
+ dtrace_invop_hdlr_t *hdlr;
+
+ hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP);
+ hdlr->dtih_func = func;
+ hdlr->dtih_next = dtrace_invop_hdlr;
+ dtrace_invop_hdlr = hdlr;
+}
+
+void
+dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
+{
+ dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
+
+ for (;;) {
+ if (hdlr == NULL)
+ panic("attempt to remove non-existent invop handler");
+
+ if (hdlr->dtih_func == func)
+ break;
+
+ prev = hdlr;
+ hdlr = hdlr->dtih_next;
+ }
+
+ if (prev == NULL) {
+ ASSERT(dtrace_invop_hdlr == hdlr);
+ dtrace_invop_hdlr = hdlr->dtih_next;
+ } else {
+ ASSERT(dtrace_invop_hdlr != hdlr);
+ prev->dtih_next = hdlr->dtih_next;
+ }
+
+ kmem_free(hdlr, 0);
+}
+
/*ARGSUSED*/
void
@@ -199,3 +240,36 @@ dtrace_probe_error(dtrace_state_t *state
(uintptr_t)epid,
(uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs);
}
+
+static int
+dtrace_invop_start(struct trapframe *frame)
+{
+ switch (dtrace_invop(frame->srr0, (uintptr_t *)frame, frame->fixreg[3])) {
+ case DTRACE_INVOP_JUMP:
+ break;
+ case DTRACE_INVOP_BCTR:
+ frame->srr0 = frame->ctr;
+ break;
+ case DTRACE_INVOP_BLR:
+ frame->srr0 = frame->lr;
+ break;
+ case DTRACE_INVOP_MFLR_R0:
+ frame->fixreg[0] = frame->lr ;
+ break;
+ default:
+ return (-1);
+ break;
+ }
+
+ return (0);
+}
+
+void dtrace_invop_init(void)
+{
+ dtrace_invop_jump_addr = dtrace_invop_start;
+}
+
+void dtrace_invop_uninit(void)
+{
+ dtrace_invop_jump_addr = 0;
+}
Copied: user/attilio/vmcontention/sys/cddl/dev/fbt/fbt_powerpc.c (from r248462, head/sys/cddl/dev/fbt/fbt_powerpc.c)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ user/attilio/vmcontention/sys/cddl/dev/fbt/fbt_powerpc.c Mon Mar 18 09:45:10 2013 (r248463, copy of r248462, head/sys/cddl/dev/fbt/fbt_powerpc.c)
@@ -0,0 +1,1321 @@
+/*
+ * 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
+ *
+ * Portions Copyright 2006-2008 John Birrell jb at freebsd.org
+ * Portions Copyright 2013 Justin Hibbits jhibbits at freebsd.org
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * Copyright 2006 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/conf.h>
+#include <sys/cpuvar.h>
+#include <sys/fcntl.h>
+#include <sys/filio.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/kmem.h>
+#include <sys/kthread.h>
+#include <sys/limits.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/selinfo.h>
+#include <sys/smp.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/uio.h>
+#include <sys/unistd.h>
+#include <machine/stdarg.h>
+
+#include <sys/dtrace.h>
+#include <sys/dtrace_bsd.h>
+
+static MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing");
+
+#define FBT_PATCHVAL 0x7c810808
+#define FBT_MFLR_R0 0x7c0802a6
+#define FBT_MTLR_R0 0x7c0803a6
+#define FBT_BLR 0x4e800020
+#define FBT_BCTR 0x4e800030
+#define FBT_BRANCH 0x48000000
+#define FBT_BR_MASK 0x03fffffc
+#define FBT_IS_JUMP(instr) ((instr & ~FBT_BR_MASK) == FBT_BRANCH)
+
+static d_open_t fbt_open;
+static int fbt_unload(void);
+static void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
+static void fbt_provide_module(void *, modctl_t *);
+static void fbt_destroy(void *, dtrace_id_t, void *);
+static void fbt_enable(void *, dtrace_id_t, void *);
+static void fbt_disable(void *, dtrace_id_t, void *);
+static void fbt_load(void *);
+static void fbt_suspend(void *, dtrace_id_t, void *);
+static void fbt_resume(void *, dtrace_id_t, void *);
+
+#define FBT_ENTRY "entry"
+#define FBT_RETURN "return"
+#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
+#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
+
+static struct cdevsw fbt_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = fbt_open,
+ .d_name = "fbt",
+};
+
+static dtrace_pattr_t fbt_attr = {
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+};
+
+static dtrace_pops_t fbt_pops = {
+ NULL,
+ fbt_provide_module,
+ fbt_enable,
+ fbt_disable,
+ fbt_suspend,
+ fbt_resume,
+ fbt_getargdesc,
+ NULL,
+ NULL,
+ fbt_destroy
+};
+
+typedef struct fbt_probe {
+ struct fbt_probe *fbtp_hashnext;
+ uint32_t *fbtp_patchpoint;
+ int8_t fbtp_rval;
+ uint32_t fbtp_patchval;
+ uint32_t fbtp_savedval;
+ uintptr_t fbtp_roffset;
+ dtrace_id_t fbtp_id;
+ const char *fbtp_name;
+ modctl_t *fbtp_ctl;
+ int fbtp_loadcnt;
+ int fbtp_primary;
+ int fbtp_invop_cnt;
+ int fbtp_symindx;
+ struct fbt_probe *fbtp_next;
+} fbt_probe_t;
+
+static struct cdev *fbt_cdev;
+static dtrace_provider_id_t fbt_id;
+static fbt_probe_t **fbt_probetab;
+static int fbt_probetab_size;
+static int fbt_probetab_mask;
+static int fbt_verbose = 0;
+
+static int
+fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
+{
+ struct trapframe *frame = (struct trapframe *)stack;
+ solaris_cpu_t *cpu = &solaris_cpu[curcpu];
+ fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
+ uintptr_t tmp;
+
+ for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
+ if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
+ fbt->fbtp_invop_cnt++;
+ if (fbt->fbtp_roffset == 0) {
+ cpu->cpu_dtrace_caller = addr;
+
+ dtrace_probe(fbt->fbtp_id, frame->fixreg[3],
+ frame->fixreg[4], frame->fixreg[5],
+ frame->fixreg[6], frame->fixreg[7]);
+
+ cpu->cpu_dtrace_caller = 0;
+ } else {
+
+ dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
+ rval, 0, 0, 0);
+ /*
+ * The caller doesn't have the fbt item, so
+ * fixup tail calls here.
+ */
+ if (fbt->fbtp_rval == DTRACE_INVOP_JUMP) {
+ frame->srr0 = (uintptr_t)fbt->fbtp_patchpoint;
+ tmp = fbt->fbtp_savedval & FBT_BR_MASK;
+ /* Sign extend. */
+ if (tmp & 0x02000000)
+ tmp |= 0xFC000000;
+ frame->srr0 += tmp;
+ }
+ cpu->cpu_dtrace_caller = 0;
+ }
+
+ return (fbt->fbtp_rval);
+ }
+ }
+
+ return (0);
+}
+
+static int
+fbt_provide_module_function(linker_file_t lf, int symindx,
+ linker_symval_t *symval, void *opaque)
+{
+ char *modname = opaque;
+ const char *name = symval->name;
+ fbt_probe_t *fbt, *retfbt;
+ int j;
+ int size;
+ u_int32_t *instr, *limit;
+
+ if (strncmp(name, "dtrace_", 7) == 0 &&
+ strncmp(name, "dtrace_safe_", 12) != 0) {
+ /*
+ * Anything beginning with "dtrace_" may be called
+ * from probe context unless it explicitly indicates
+ * that it won't be called from probe context by
+ * using the prefix "dtrace_safe_".
+ */
+ return (0);
+ }
+
+ if (name[0] == '_' && name[1] == '_')
+ return (0);
+
+ size = symval->size;
+
+ instr = (u_int32_t *) symval->value;
+ limit = (u_int32_t *) symval->value + symval->size;
+
+ for (; instr < limit; instr++)
+ if (*instr == FBT_MFLR_R0)
+ break;
+
+ if (*instr != FBT_MFLR_R0);
+ return (0);
+
+ fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
+ fbt->fbtp_name = name;
+ fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
+ name, FBT_ENTRY, 3, fbt);
+ fbt->fbtp_patchpoint = instr;
+ fbt->fbtp_ctl = lf;
+ fbt->fbtp_loadcnt = lf->loadcnt;
+ fbt->fbtp_savedval = *instr;
+ fbt->fbtp_patchval = FBT_PATCHVAL;
+ fbt->fbtp_rval = DTRACE_INVOP_MFLR_R0;
+ fbt->fbtp_symindx = symindx;
+
+ fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
+ fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
+
+ lf->fbt_nentries++;
+
+ retfbt = NULL;
+again:
+ if (instr >= limit)
+ return (0);
+
+ /*
+ * We (desperately) want to avoid erroneously instrumenting a
+ * jump table To determine if we're looking at a true instruction
+ * sequence or an inline jump table that happens to contain the same
+ * byte sequences, we resort to some heuristic sleeze: we treat this
+ * instruction as being contained within a pointer, and see if that
+ * pointer points to within the body of the function. If it does, we
+ * refuse to instrument it.
+ */
+ {
+ uint32_t *ptr;
+
+ ptr = *(uint32_t **)instr;
+
+ if (ptr >= (uint32_t *) symval->value && ptr < limit) {
+ instr++;
+ goto again;
+ }
+ }
+
+ if (*instr == FBT_MFLR_R0)
+ return (0);
+
+ if (*instr != FBT_MTLR_R0) {
+ instr++;
+ goto again;
+ }
+
+ instr++;
+
+ for (j = 0; j < 12 && instr < limit; j++, instr++) {
+ if ((*instr == FBT_BCTR) || (*instr == FBT_BLR) |
+ FBT_IS_JUMP(*instr))
+ break;
+ }
+
+ if (!(*instr == FBT_BCTR || *instr == FBT_BLR || FBT_IS_JUMP(*instr)))
+ goto again;
+
+ /*
+ * We have a winner!
+ */
+ fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
+ fbt->fbtp_name = name;
+
+ if (retfbt == NULL) {
+ fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
+ name, FBT_RETURN, 3, fbt);
+ } else {
+ retfbt->fbtp_next = fbt;
+ fbt->fbtp_id = retfbt->fbtp_id;
+ }
+
+ retfbt = fbt;
+ fbt->fbtp_patchpoint = instr;
+ fbt->fbtp_ctl = lf;
+ fbt->fbtp_loadcnt = lf->loadcnt;
+ fbt->fbtp_symindx = symindx;
+
+ if (*instr == FBT_BCTR)
+ fbt->fbtp_rval = DTRACE_INVOP_BCTR;
+ else if (*instr == FBT_BLR)
+ fbt->fbtp_rval = DTRACE_INVOP_RET;
+ else
+ fbt->fbtp_rval = DTRACE_INVOP_JUMP;
+
+ fbt->fbtp_savedval = *instr;
+ fbt->fbtp_patchval = FBT_PATCHVAL;
+ fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
+ fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
+
+ lf->fbt_nentries++;
+
+ instr += size;
+ goto again;
+}
+
+static void
+fbt_provide_module(void *arg, modctl_t *lf)
+{
+ char modname[MAXPATHLEN];
+ int i;
+ size_t len;
+
+ strlcpy(modname, lf->filename, sizeof(modname));
+ len = strlen(modname);
+ if (len > 3 && strcmp(modname + len - 3, ".ko") == 0)
+ modname[len - 3] = '\0';
+
+ /*
+ * Employees of dtrace and their families are ineligible. Void
+ * where prohibited.
+ */
+ if (strcmp(modname, "dtrace") == 0)
+ return;
+
+ /*
+ * The cyclic timer subsystem can be built as a module and DTrace
+ * depends on that, so it is ineligible too.
+ */
+ if (strcmp(modname, "cyclic") == 0)
+ return;
+
+ /*
+ * To register with DTrace, a module must list 'dtrace' as a
+ * dependency in order for the kernel linker to resolve
+ * symbols like dtrace_register(). All modules with such a
+ * dependency are ineligible for FBT tracing.
+ */
+ for (i = 0; i < lf->ndeps; i++)
+ if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0)
+ return;
+
+ if (lf->fbt_nentries) {
+ /*
+ * This module has some FBT entries allocated; we're afraid
+ * to screw with it.
+ */
+ return;
+ }
+
+ /*
+ * List the functions in the module and the symbol values.
+ */
+ (void) linker_file_function_listall(lf, fbt_provide_module_function, modname);
+}
+
+static void
+fbt_destroy(void *arg, dtrace_id_t id, void *parg)
+{
+ fbt_probe_t *fbt = parg, *next, *hash, *last;
+ modctl_t *ctl;
+ int ndx;
+
+ do {
+ ctl = fbt->fbtp_ctl;
+
+ ctl->fbt_nentries--;
+
+ /*
+ * Now we need to remove this probe from the fbt_probetab.
+ */
+ ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
+ last = NULL;
+ hash = fbt_probetab[ndx];
+
+ while (hash != fbt) {
+ ASSERT(hash != NULL);
+ last = hash;
+ hash = hash->fbtp_hashnext;
+ }
+
+ if (last != NULL) {
+ last->fbtp_hashnext = fbt->fbtp_hashnext;
+ } else {
+ fbt_probetab[ndx] = fbt->fbtp_hashnext;
+ }
+
+ next = fbt->fbtp_next;
+ free(fbt, M_FBT);
+
+ fbt = next;
+ } while (fbt != NULL);
+}
+
+static void
+fbt_enable(void *arg, dtrace_id_t id, void *parg)
+{
+ fbt_probe_t *fbt = parg;
+ modctl_t *ctl = fbt->fbtp_ctl;
+
+ ctl->nenabled++;
+
+ /*
+ * Now check that our modctl has the expected load count. If it
+ * doesn't, this module must have been unloaded and reloaded -- and
+ * we're not going to touch it.
+ */
+ if (ctl->loadcnt != fbt->fbtp_loadcnt) {
+ if (fbt_verbose) {
+ printf("fbt is failing for probe %s "
+ "(module %s reloaded)",
+ fbt->fbtp_name, ctl->filename);
+ }
+
+ return;
+ }
+
+ for (; fbt != NULL; fbt = fbt->fbtp_next) {
+ *fbt->fbtp_patchpoint = fbt->fbtp_patchval;
+ }
+}
+
+static void
+fbt_disable(void *arg, dtrace_id_t id, void *parg)
+{
+ fbt_probe_t *fbt = parg;
+ modctl_t *ctl = fbt->fbtp_ctl;
+
+ ASSERT(ctl->nenabled > 0);
+ ctl->nenabled--;
+
+ if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+ return;
+
+ for (; fbt != NULL; fbt = fbt->fbtp_next)
+ *fbt->fbtp_patchpoint = fbt->fbtp_savedval;
+}
+
+static void
+fbt_suspend(void *arg, dtrace_id_t id, void *parg)
+{
+ fbt_probe_t *fbt = parg;
+ modctl_t *ctl = fbt->fbtp_ctl;
+
+ ASSERT(ctl->nenabled > 0);
+
+ if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+ return;
+
+ for (; fbt != NULL; fbt = fbt->fbtp_next)
+ *fbt->fbtp_patchpoint = fbt->fbtp_savedval;
+}
+
+static void
+fbt_resume(void *arg, dtrace_id_t id, void *parg)
+{
+ fbt_probe_t *fbt = parg;
+ modctl_t *ctl = fbt->fbtp_ctl;
+
+ ASSERT(ctl->nenabled > 0);
+
+ if ((ctl->loadcnt != fbt->fbtp_loadcnt))
+ return;
+
+ for (; fbt != NULL; fbt = fbt->fbtp_next)
+ *fbt->fbtp_patchpoint = fbt->fbtp_patchval;
+}
+
+static int
+fbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc)
+{
+ const Elf_Sym *symp = lc->symtab;;
+ const char *name;
+ const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
+ const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
+ int i;
+ uint32_t *ctfoff;
+ uint32_t objtoff = hp->cth_objtoff;
+ uint32_t funcoff = hp->cth_funcoff;
+ ushort_t info;
+ ushort_t vlen;
+
+ /* Sanity check. */
+ if (hp->cth_magic != CTF_MAGIC) {
+ printf("Bad magic value in CTF data of '%s'\n",lf->pathname);
+ return (EINVAL);
+ }
+
+ if (lc->symtab == NULL) {
+ printf("No symbol table in '%s'\n",lf->pathname);
+ return (EINVAL);
+ }
+
+ if ((ctfoff = malloc(sizeof(uint32_t) * lc->nsym, M_LINKER, M_WAITOK)) == NULL)
+ return (ENOMEM);
+
+ *lc->ctfoffp = ctfoff;
+
+ for (i = 0; i < lc->nsym; i++, ctfoff++, symp++) {
+ if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) {
+ *ctfoff = 0xffffffff;
+ continue;
+ }
+
+ if (symp->st_name < lc->strcnt)
+ name = lc->strtab + symp->st_name;
+ else
+ name = "(?)";
+
+ switch (ELF_ST_TYPE(symp->st_info)) {
+ case STT_OBJECT:
+ if (objtoff >= hp->cth_funcoff ||
+ (symp->st_shndx == SHN_ABS && symp->st_value == 0)) {
+ *ctfoff = 0xffffffff;
+ break;
+ }
+
+ *ctfoff = objtoff;
+ objtoff += sizeof (ushort_t);
+ break;
+
+ case STT_FUNC:
+ if (funcoff >= hp->cth_typeoff) {
+ *ctfoff = 0xffffffff;
+ break;
+ }
+
+ *ctfoff = funcoff;
+
+ info = *((const ushort_t *)(ctfdata + funcoff));
+ vlen = CTF_INFO_VLEN(info);
+
+ /*
+ * If we encounter a zero pad at the end, just skip it.
+ * Otherwise skip over the function and its return type
+ * (+2) and the argument list (vlen).
+ */
+ if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0)
+ funcoff += sizeof (ushort_t); /* skip pad */
+ else
+ funcoff += sizeof (ushort_t) * (vlen + 2);
+ break;
+
+ default:
+ *ctfoff = 0xffffffff;
+ break;
+ }
+ }
+
+ return (0);
+}
+
+static ssize_t
+fbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep,
+ ssize_t *incrementp)
+{
+ ssize_t size, increment;
+
+ if (version > CTF_VERSION_1 &&
+ tp->ctt_size == CTF_LSIZE_SENT) {
+ size = CTF_TYPE_LSIZE(tp);
+ increment = sizeof (ctf_type_t);
+ } else {
+ size = tp->ctt_size;
+ increment = sizeof (ctf_stype_t);
+ }
+
+ if (sizep)
+ *sizep = size;
+ if (incrementp)
+ *incrementp = increment;
+
+ return (size);
+}
+
+static int
+fbt_typoff_init(linker_ctf_t *lc)
+{
+ const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
+ const ctf_type_t *tbuf;
+ const ctf_type_t *tend;
+ const ctf_type_t *tp;
+ const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
+ int ctf_typemax = 0;
+ uint32_t *xp;
+ ulong_t pop[CTF_K_MAX + 1] = { 0 };
+
+
+ /* Sanity check. */
+ if (hp->cth_magic != CTF_MAGIC)
+ return (EINVAL);
+
+ tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff);
+ tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff);
+
+ int child = hp->cth_parname != 0;
+
+ /*
+ * We make two passes through the entire type section. In this first
+ * pass, we count the number of each type and the total number of types.
+ */
+ for (tp = tbuf; tp < tend; ctf_typemax++) {
+ ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
+ ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-user
mailing list