1299118Sbr/* 2299118Sbr * CDDL HEADER START 3299118Sbr * 4299118Sbr * The contents of this file are subject to the terms of the 5299118Sbr * Common Development and Distribution License (the "License"). 6299118Sbr * You may not use this file except in compliance with the License. 7299118Sbr * 8299118Sbr * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9299118Sbr * or http://www.opensolaris.org/os/licensing. 10299118Sbr * See the License for the specific language governing permissions 11299118Sbr * and limitations under the License. 12299118Sbr * 13299118Sbr * When distributing Covered Code, include this CDDL HEADER in each 14299118Sbr * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15299118Sbr * If applicable, add the following below this CDDL HEADER, with the 16299118Sbr * fields enclosed by brackets "[]" replaced with your own identifying 17299118Sbr * information: Portions Copyright [yyyy] [name of copyright owner] 18299118Sbr * 19299118Sbr * CDDL HEADER END 20299118Sbr * 21299118Sbr * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 22299118Sbr * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org 23299118Sbr * Portions Copyright 2013 Howard Su howardsu@freebsd.org 24299118Sbr * Portions Copyright 2015-2016 Ruslan Bukin <br@bsdpad.com> 25299118Sbr * 26299118Sbr * $FreeBSD: stable/11/sys/cddl/dev/fbt/mips/fbt_isa.c 332566 2018-04-16 14:39:04Z lidl $ 27299118Sbr */ 28299118Sbr 29299118Sbr/* 30299118Sbr * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 31299118Sbr * Use is subject to license terms. 32299118Sbr */ 33299118Sbr 34299118Sbr#include <sys/cdefs.h> 35299118Sbr#include <sys/param.h> 36299118Sbr#include <sys/dtrace.h> 37299118Sbr 38299118Sbr#include <machine/cpuregs.h> 39299118Sbr#include <machine/cache.h> 40299118Sbr 41299118Sbr#include "fbt.h" 42299118Sbr 43299118Sbr#define FBT_PATCHVAL (MIPS_BREAK_INSTR) 44299118Sbr#define FBT_ENTRY "entry" 45299118Sbr#define FBT_RETURN "return" 46299118Sbr 47299118Sbrint 48299118Sbrfbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval) 49299118Sbr{ 50299118Sbr solaris_cpu_t *cpu; 51299118Sbr fbt_probe_t *fbt; 52299118Sbr 53299118Sbr cpu = &solaris_cpu[curcpu]; 54299118Sbr fbt = fbt_probetab[FBT_ADDR2NDX(addr)]; 55299118Sbr 56299118Sbr for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { 57299118Sbr if ((uintptr_t)fbt->fbtp_patchpoint == addr) { 58299118Sbr cpu->cpu_dtrace_caller = addr; 59299118Sbr 60299118Sbr dtrace_probe(fbt->fbtp_id, frame->a0, 61299118Sbr frame->a1, frame->a2, 62299118Sbr frame->a3, frame->a4); 63299118Sbr 64299118Sbr cpu->cpu_dtrace_caller = 0; 65299118Sbr return (fbt->fbtp_savedval); 66299118Sbr } 67299118Sbr } 68299118Sbr 69299118Sbr return (0); 70299118Sbr} 71299118Sbr 72299118Sbrvoid 73299118Sbrfbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val) 74299118Sbr{ 75299118Sbr 76299118Sbr *fbt->fbtp_patchpoint = val; 77299118Sbr mips_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4); 78299118Sbr} 79299118Sbr 80299118Sbrint 81299118Sbrfbt_provide_module_function(linker_file_t lf, int symindx, 82299118Sbr linker_symval_t *symval, void *opaque) 83299118Sbr{ 84299118Sbr fbt_probe_t *fbt, *retfbt; 85299118Sbr uint32_t *instr, *limit; 86299118Sbr const char *name; 87299118Sbr char *modname; 88299118Sbr 89299118Sbr modname = opaque; 90299118Sbr name = symval->name; 91299118Sbr 92299118Sbr /* Check if function is excluded from instrumentation */ 93299118Sbr if (fbt_excluded(name)) 94299118Sbr return (0); 95299118Sbr 96299118Sbr instr = (uint32_t *)(symval->value); 97299118Sbr limit = (uint32_t *)(symval->value + symval->size); 98299118Sbr 99299118Sbr /* Look for store double to ra register */ 100299118Sbr for (; instr < limit; instr++) { 101299118Sbr if ((*instr & LDSD_RA_SP_MASK) == SD_RA_SP) 102299118Sbr break; 103299118Sbr } 104299118Sbr 105299118Sbr if (instr >= limit) 106299118Sbr return (0); 107299118Sbr 108299118Sbr fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 109299118Sbr fbt->fbtp_name = name; 110299118Sbr fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 111299118Sbr name, FBT_ENTRY, 3, fbt); 112299118Sbr fbt->fbtp_patchpoint = instr; 113299118Sbr fbt->fbtp_ctl = lf; 114299118Sbr fbt->fbtp_loadcnt = lf->loadcnt; 115299118Sbr fbt->fbtp_savedval = *instr; 116299118Sbr fbt->fbtp_patchval = FBT_PATCHVAL; 117299118Sbr fbt->fbtp_rval = DTRACE_INVOP_SD; 118299118Sbr fbt->fbtp_symindx = symindx; 119299118Sbr 120299118Sbr fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 121299118Sbr fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 122299118Sbr 123299118Sbr lf->fbt_nentries++; 124299118Sbr 125299118Sbr retfbt = NULL; 126299118Sbragain: 127299118Sbr for (; instr < limit; instr++) { 128299118Sbr if ((*instr & LDSD_RA_SP_MASK) == LD_RA_SP) { 129299118Sbr break; 130299118Sbr } 131299118Sbr } 132299118Sbr 133299118Sbr if (instr >= limit) 134299118Sbr return (0); 135299118Sbr 136299118Sbr /* 137299118Sbr * We have a winner! 138299118Sbr */ 139299118Sbr fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 140299118Sbr fbt->fbtp_name = name; 141299118Sbr if (retfbt == NULL) { 142299118Sbr fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 143299118Sbr name, FBT_RETURN, 3, fbt); 144299118Sbr } else { 145299118Sbr retfbt->fbtp_next = fbt; 146299118Sbr fbt->fbtp_id = retfbt->fbtp_id; 147299118Sbr } 148299118Sbr retfbt = fbt; 149299118Sbr 150299118Sbr fbt->fbtp_patchpoint = instr; 151299118Sbr fbt->fbtp_ctl = lf; 152299118Sbr fbt->fbtp_loadcnt = lf->loadcnt; 153299118Sbr fbt->fbtp_symindx = symindx; 154299118Sbr fbt->fbtp_rval = DTRACE_INVOP_LD; 155299118Sbr fbt->fbtp_savedval = *instr; 156299118Sbr fbt->fbtp_patchval = FBT_PATCHVAL; 157299118Sbr fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 158299118Sbr fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 159299118Sbr 160299118Sbr lf->fbt_nentries++; 161299118Sbr 162299118Sbr instr++; 163299118Sbr goto again; 164299118Sbr} 165