1*b78ee15eSRuslan Bukin /* 2*b78ee15eSRuslan Bukin * CDDL HEADER START 3*b78ee15eSRuslan Bukin * 4*b78ee15eSRuslan Bukin * The contents of this file are subject to the terms of the 5*b78ee15eSRuslan Bukin * Common Development and Distribution License (the "License"). 6*b78ee15eSRuslan Bukin * You may not use this file except in compliance with the License. 7*b78ee15eSRuslan Bukin * 8*b78ee15eSRuslan Bukin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*b78ee15eSRuslan Bukin * or http://www.opensolaris.org/os/licensing. 10*b78ee15eSRuslan Bukin * See the License for the specific language governing permissions 11*b78ee15eSRuslan Bukin * and limitations under the License. 12*b78ee15eSRuslan Bukin * 13*b78ee15eSRuslan Bukin * When distributing Covered Code, include this CDDL HEADER in each 14*b78ee15eSRuslan Bukin * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*b78ee15eSRuslan Bukin * If applicable, add the following below this CDDL HEADER, with the 16*b78ee15eSRuslan Bukin * fields enclosed by brackets "[]" replaced with your own identifying 17*b78ee15eSRuslan Bukin * information: Portions Copyright [yyyy] [name of copyright owner] 18*b78ee15eSRuslan Bukin * 19*b78ee15eSRuslan Bukin * CDDL HEADER END 20*b78ee15eSRuslan Bukin * 21*b78ee15eSRuslan Bukin * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 22*b78ee15eSRuslan Bukin * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org 23*b78ee15eSRuslan Bukin * Portions Copyright 2013 Howard Su howardsu@freebsd.org 24*b78ee15eSRuslan Bukin * Portions Copyright 2015 Ruslan Bukin <br@bsdpad.com> 25*b78ee15eSRuslan Bukin * 26*b78ee15eSRuslan Bukin * $FreeBSD$ 27*b78ee15eSRuslan Bukin */ 28*b78ee15eSRuslan Bukin 29*b78ee15eSRuslan Bukin /* 30*b78ee15eSRuslan Bukin * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 31*b78ee15eSRuslan Bukin * Use is subject to license terms. 32*b78ee15eSRuslan Bukin */ 33*b78ee15eSRuslan Bukin 34*b78ee15eSRuslan Bukin #include <sys/cdefs.h> 35*b78ee15eSRuslan Bukin #include <sys/param.h> 36*b78ee15eSRuslan Bukin 37*b78ee15eSRuslan Bukin #include <sys/dtrace.h> 38*b78ee15eSRuslan Bukin 39*b78ee15eSRuslan Bukin #include "fbt.h" 40*b78ee15eSRuslan Bukin 41*b78ee15eSRuslan Bukin #define AARCH64_BRK 0xd4200000 42*b78ee15eSRuslan Bukin #define AARCH64_BRK_IMM16_SHIFT 5 43*b78ee15eSRuslan Bukin #define AARCH64_BRK_IMM16_VAL (0x40d << AARCH64_BRK_IMM16_SHIFT) 44*b78ee15eSRuslan Bukin #define FBT_PATCHVAL (AARCH64_BRK | AARCH64_BRK_IMM16_VAL) 45*b78ee15eSRuslan Bukin #define FBT_ENTRY "entry" 46*b78ee15eSRuslan Bukin #define FBT_RETURN "return" 47*b78ee15eSRuslan Bukin 48*b78ee15eSRuslan Bukin int 49*b78ee15eSRuslan Bukin fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval) 50*b78ee15eSRuslan Bukin { 51*b78ee15eSRuslan Bukin struct trapframe *frame; 52*b78ee15eSRuslan Bukin solaris_cpu_t *cpu; 53*b78ee15eSRuslan Bukin fbt_probe_t *fbt; 54*b78ee15eSRuslan Bukin 55*b78ee15eSRuslan Bukin frame = (struct trapframe *)stack; 56*b78ee15eSRuslan Bukin cpu = &solaris_cpu[curcpu]; 57*b78ee15eSRuslan Bukin fbt = fbt_probetab[FBT_ADDR2NDX(addr)]; 58*b78ee15eSRuslan Bukin 59*b78ee15eSRuslan Bukin for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { 60*b78ee15eSRuslan Bukin if ((uintptr_t)fbt->fbtp_patchpoint == addr) { 61*b78ee15eSRuslan Bukin fbt->fbtp_invop_cnt++; 62*b78ee15eSRuslan Bukin cpu->cpu_dtrace_caller = addr; 63*b78ee15eSRuslan Bukin 64*b78ee15eSRuslan Bukin dtrace_probe(fbt->fbtp_id, frame->tf_x[0], 65*b78ee15eSRuslan Bukin frame->tf_x[1], frame->tf_x[2], 66*b78ee15eSRuslan Bukin frame->tf_x[3], frame->tf_x[4]); 67*b78ee15eSRuslan Bukin 68*b78ee15eSRuslan Bukin cpu->cpu_dtrace_caller = 0; 69*b78ee15eSRuslan Bukin return (fbt->fbtp_savedval); 70*b78ee15eSRuslan Bukin } 71*b78ee15eSRuslan Bukin } 72*b78ee15eSRuslan Bukin 73*b78ee15eSRuslan Bukin return (0); 74*b78ee15eSRuslan Bukin } 75*b78ee15eSRuslan Bukin 76*b78ee15eSRuslan Bukin void 77*b78ee15eSRuslan Bukin fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val) 78*b78ee15eSRuslan Bukin { 79*b78ee15eSRuslan Bukin 80*b78ee15eSRuslan Bukin *fbt->fbtp_patchpoint = val; 81*b78ee15eSRuslan Bukin cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4); 82*b78ee15eSRuslan Bukin } 83*b78ee15eSRuslan Bukin 84*b78ee15eSRuslan Bukin int 85*b78ee15eSRuslan Bukin fbt_provide_module_function(linker_file_t lf, int symindx, 86*b78ee15eSRuslan Bukin linker_symval_t *symval, void *opaque) 87*b78ee15eSRuslan Bukin { 88*b78ee15eSRuslan Bukin fbt_probe_t *fbt, *retfbt; 89*b78ee15eSRuslan Bukin uint32_t *target, *start; 90*b78ee15eSRuslan Bukin uint32_t *instr, *limit; 91*b78ee15eSRuslan Bukin const char *name; 92*b78ee15eSRuslan Bukin char *modname; 93*b78ee15eSRuslan Bukin int offs; 94*b78ee15eSRuslan Bukin 95*b78ee15eSRuslan Bukin modname = opaque; 96*b78ee15eSRuslan Bukin name = symval->name; 97*b78ee15eSRuslan Bukin 98*b78ee15eSRuslan Bukin /* Check if function is excluded from instrumentation */ 99*b78ee15eSRuslan Bukin if (fbt_excluded(name)) 100*b78ee15eSRuslan Bukin return (0); 101*b78ee15eSRuslan Bukin 102*b78ee15eSRuslan Bukin instr = (uint32_t *)(symval->value); 103*b78ee15eSRuslan Bukin limit = (uint32_t *)(symval->value + symval->size); 104*b78ee15eSRuslan Bukin 105*b78ee15eSRuslan Bukin /* Look for stp (pre-indexed) operation */ 106*b78ee15eSRuslan Bukin for (; instr < limit; instr++) { 107*b78ee15eSRuslan Bukin if ((*instr & LDP_STP_MASK) == STP_64) 108*b78ee15eSRuslan Bukin break; 109*b78ee15eSRuslan Bukin } 110*b78ee15eSRuslan Bukin 111*b78ee15eSRuslan Bukin if (instr >= limit) 112*b78ee15eSRuslan Bukin return (0); 113*b78ee15eSRuslan Bukin 114*b78ee15eSRuslan Bukin fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 115*b78ee15eSRuslan Bukin fbt->fbtp_name = name; 116*b78ee15eSRuslan Bukin fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 117*b78ee15eSRuslan Bukin name, FBT_ENTRY, 3, fbt); 118*b78ee15eSRuslan Bukin fbt->fbtp_patchpoint = instr; 119*b78ee15eSRuslan Bukin fbt->fbtp_ctl = lf; 120*b78ee15eSRuslan Bukin fbt->fbtp_loadcnt = lf->loadcnt; 121*b78ee15eSRuslan Bukin fbt->fbtp_savedval = *instr; 122*b78ee15eSRuslan Bukin fbt->fbtp_patchval = FBT_PATCHVAL; 123*b78ee15eSRuslan Bukin fbt->fbtp_rval = DTRACE_INVOP_PUSHM; 124*b78ee15eSRuslan Bukin fbt->fbtp_symindx = symindx; 125*b78ee15eSRuslan Bukin 126*b78ee15eSRuslan Bukin fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 127*b78ee15eSRuslan Bukin fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 128*b78ee15eSRuslan Bukin 129*b78ee15eSRuslan Bukin lf->fbt_nentries++; 130*b78ee15eSRuslan Bukin 131*b78ee15eSRuslan Bukin retfbt = NULL; 132*b78ee15eSRuslan Bukin again: 133*b78ee15eSRuslan Bukin for (; instr < limit; instr++) { 134*b78ee15eSRuslan Bukin if (*instr == RET_INSTR) 135*b78ee15eSRuslan Bukin break; 136*b78ee15eSRuslan Bukin else if ((*instr & B_MASK) == B_INSTR) { 137*b78ee15eSRuslan Bukin offs = (*instr & B_DATA_MASK); 138*b78ee15eSRuslan Bukin offs *= 4; 139*b78ee15eSRuslan Bukin target = (instr + offs); 140*b78ee15eSRuslan Bukin start = (uint32_t *)symval->value; 141*b78ee15eSRuslan Bukin if (target >= limit || target < start) 142*b78ee15eSRuslan Bukin break; 143*b78ee15eSRuslan Bukin } 144*b78ee15eSRuslan Bukin } 145*b78ee15eSRuslan Bukin 146*b78ee15eSRuslan Bukin if (instr >= limit) 147*b78ee15eSRuslan Bukin return (0); 148*b78ee15eSRuslan Bukin 149*b78ee15eSRuslan Bukin /* 150*b78ee15eSRuslan Bukin * We have a winner! 151*b78ee15eSRuslan Bukin */ 152*b78ee15eSRuslan Bukin fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 153*b78ee15eSRuslan Bukin fbt->fbtp_name = name; 154*b78ee15eSRuslan Bukin if (retfbt == NULL) { 155*b78ee15eSRuslan Bukin fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 156*b78ee15eSRuslan Bukin name, FBT_RETURN, 3, fbt); 157*b78ee15eSRuslan Bukin } else { 158*b78ee15eSRuslan Bukin retfbt->fbtp_next = fbt; 159*b78ee15eSRuslan Bukin fbt->fbtp_id = retfbt->fbtp_id; 160*b78ee15eSRuslan Bukin } 161*b78ee15eSRuslan Bukin retfbt = fbt; 162*b78ee15eSRuslan Bukin 163*b78ee15eSRuslan Bukin fbt->fbtp_patchpoint = instr; 164*b78ee15eSRuslan Bukin fbt->fbtp_ctl = lf; 165*b78ee15eSRuslan Bukin fbt->fbtp_loadcnt = lf->loadcnt; 166*b78ee15eSRuslan Bukin fbt->fbtp_symindx = symindx; 167*b78ee15eSRuslan Bukin if ((*instr & B_MASK) == B_INSTR) 168*b78ee15eSRuslan Bukin fbt->fbtp_rval = DTRACE_INVOP_B; 169*b78ee15eSRuslan Bukin else 170*b78ee15eSRuslan Bukin fbt->fbtp_rval = DTRACE_INVOP_RET; 171*b78ee15eSRuslan Bukin fbt->fbtp_savedval = *instr; 172*b78ee15eSRuslan Bukin fbt->fbtp_patchval = FBT_PATCHVAL; 173*b78ee15eSRuslan Bukin fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 174*b78ee15eSRuslan Bukin fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 175*b78ee15eSRuslan Bukin 176*b78ee15eSRuslan Bukin lf->fbt_nentries++; 177*b78ee15eSRuslan Bukin 178*b78ee15eSRuslan Bukin instr++; 179*b78ee15eSRuslan Bukin goto again; 180*b78ee15eSRuslan Bukin } 181