From owner-svn-src-user@FreeBSD.ORG Mon Mar 18 11:06:35 2013 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 46C8481A; Mon, 18 Mar 2013 11:06:35 +0000 (UTC) (envelope-from attilio@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 2A542A71; Mon, 18 Mar 2013 11:06:35 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r2I9jCbV085588; Mon, 18 Mar 2013 09:45:12 GMT (envelope-from attilio@svn.freebsd.org) Received: (from attilio@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r2I9jBpL085576; Mon, 18 Mar 2013 09:45:11 GMT (envelope-from attilio@svn.freebsd.org) Message-Id: <201303180945.r2I9jBpL085576@svn.freebsd.org> From: Attilio Rao Date: Mon, 18 Mar 2013 09:45:11 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: 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 ... X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Mar 2013 11:06:35 -0000 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 , # Case 11: VMOV.F64
, # */ inst.operands[i].immisfloat = 1; - else if (parse_big_immediate (&ptr, i) == SUCCESS) - /* Case 2: VMOV.
, # - Case 3: VMOV.
, # */ - ; 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.
, # + Case 3: VMOV.
, # */ + ; else { first_error (_("expected or or 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@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 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@freebsd.org + * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org + * + * $FreeBSD$ + * + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 ***