1/* $NetBSD: fbt_isa.c,v 1.1 2021/03/29 05:17:09 simonb Exp $ */ 2 3/* 4 * CDDL HEADER START 5 * 6 * The contents of this file are subject to the terms of the 7 * Common Development and Distribution License (the "License"). 8 * You may not use this file except in compliance with the License. 9 * 10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11 * or http://www.opensolaris.org/os/licensing. 12 * See the License for the specific language governing permissions 13 * and limitations under the License. 14 * 15 * When distributing Covered Code, include this CDDL HEADER in each 16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17 * If applicable, add the following below this CDDL HEADER, with the 18 * fields enclosed by brackets "[]" replaced with your own identifying 19 * information: Portions Copyright [yyyy] [name of copyright owner] 20 * 21 * CDDL HEADER END 22 * 23 * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 24 * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org 25 * Portions Copyright 2013 Howard Su howardsu@freebsd.org 26 * Portions Copyright 2015-2016 Ruslan Bukin <br@bsdpad.com> 27 * 28 * $FreeBSD$ 29 */ 30 31/* 32 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 33 * Use is subject to license terms. 34 */ 35 36#include <sys/cdefs.h> 37#include <sys/param.h> 38#include <sys/cpu.h> 39#include <sys/kmem.h> 40#include <sys/module.h> 41 42#include <sys/dtrace.h> 43 44#include <machine/regnum.h> 45#include <machine/locore.h> 46 47#include <mips/cache.h> 48 49#include "fbt.h" 50 51#ifdef __FreeBSD__ 52#define CURRENT_CPU curcpu 53#endif 54#ifdef __NetBSD__ 55#define CURRENT_CPU cpu_index(curcpu()) 56#endif 57 58#define FBT_PATCHVAL (MIPS_BREAK_INSTR) 59#define FBT_ENTRY "entry" 60#define FBT_RETURN "return" 61 62int 63fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval) 64{ 65 solaris_cpu_t *cpu; 66 fbt_probe_t *fbt; 67 68 cpu = &solaris_cpu[CURRENT_CPU]; 69 fbt = fbt_probetab[FBT_ADDR2NDX(addr)]; 70 71 for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { 72 if ((uintptr_t)fbt->fbtp_patchpoint == addr) { 73 cpu->cpu_dtrace_caller = addr; 74 75 dtrace_probe(fbt->fbtp_id, frame->tf_regs[_R_A0], 76 frame->tf_regs[_R_A1], frame->tf_regs[_R_A2], 77 frame->tf_regs[_R_A3], frame->tf_regs[_R_A4]); 78 79 cpu->cpu_dtrace_caller = 0; 80 return (fbt->fbtp_savedval); 81 } 82 } 83 84 return (0); 85} 86 87void 88fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val) 89{ 90 91 *fbt->fbtp_patchpoint = val; 92 mips_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4); 93} 94 95#if defined(__FreeBSD__) 96int 97fbt_provide_module_function(linker_file_t lf, int symindx, 98 linker_symval_t *symval, void *opaque) 99#elif defined(__NetBSD__) 100int 101fbt_provide_module_cb(const char *name, int symindx, void *value, 102 uint32_t symsize, int type, void *opaque) 103#else 104#error unsupported platform 105#endif 106{ 107 fbt_probe_t *fbt, *retfbt; 108 uint32_t *instr, *limit; 109 110#ifdef __FreeBSD__ 111 const char *name; 112 char *modname; 113 114 modname = opaque; 115 name = symval->name; 116 117 instr = (uint32_t *)(symval->value); 118 limit = (uint32_t *)(symval->value + symval->size); 119#endif 120#ifdef __NetBSD__ 121 struct fbt_ksyms_arg *fka = opaque; 122 modctl_t *mod = fka->fka_mod; 123 const char *modname = module_name(mod); 124 125 /* got a function? */ 126 if (ELF_ST_TYPE(type) != STT_FUNC) 127 return 0; 128 129 instr = (uint32_t *)(value); 130 limit = (uint32_t *)((uintptr_t)value + symsize); 131#endif 132 133 /* Check if function is excluded from instrumentation */ 134 if (fbt_excluded(name)) 135 return (0); 136 137 /* Look for store double to ra register */ 138 for (; instr < limit; instr++) { 139 if ((*instr & LDSD_RA_SP_MASK) == SD_RA_SP) 140 break; 141 } 142 143 if (instr >= limit) 144 return (0); 145 146#ifdef __FreeBSD__ 147 fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 148#endif 149#ifdef __NetBSD__ 150 fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP); 151#endif 152 fbt->fbtp_name = name; 153 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 154 name, FBT_ENTRY, 3, fbt); 155 fbt->fbtp_patchpoint = instr; 156#ifdef __FreeBSD__ 157 fbt->fbtp_ctl = lf; 158 fbt->fbtp_loadcnt = lf->loadcnt; 159#endif 160#ifdef __NetBSD__ 161 fbt->fbtp_ctl = mod; 162#endif 163 fbt->fbtp_savedval = *instr; 164 fbt->fbtp_patchval = FBT_PATCHVAL; 165 fbt->fbtp_rval = DTRACE_INVOP_SD; 166 fbt->fbtp_symindx = symindx; 167 168 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 169 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 170 171#ifdef __FreeBSD__ 172 lf->fbt_nentries++; 173#endif 174 175 retfbt = NULL; 176again: 177 for (; instr < limit; instr++) { 178 if ((*instr & LDSD_RA_SP_MASK) == LD_RA_SP) { 179 break; 180 } 181 } 182 183 if (instr >= limit) 184 return (0); 185 186 /* 187 * We have a winner! 188 */ 189#ifdef __FreeBSD__ 190 fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 191#endif 192#ifdef __NetBSD__ 193 fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP); 194#endif 195 fbt->fbtp_name = name; 196 if (retfbt == NULL) { 197 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 198 name, FBT_RETURN, 3, fbt); 199 } else { 200#ifdef __FreeBSD__ 201 retfbt->fbtp_probenext = fbt; 202#endif 203#ifdef __NetBSD__ 204 fbt->fbtp_ctl = mod; 205#endif 206 fbt->fbtp_id = retfbt->fbtp_id; 207 } 208 retfbt = fbt; 209 210 fbt->fbtp_patchpoint = instr; 211#ifdef __FreeBSD__ 212 fbt->fbtp_ctl = lf; 213 fbt->fbtp_loadcnt = lf->loadcnt; 214#endif 215#ifdef __NetBSD__ 216 fbt->fbtp_ctl = mod; 217#endif 218 fbt->fbtp_symindx = symindx; 219 fbt->fbtp_rval = DTRACE_INVOP_LD; 220 fbt->fbtp_savedval = *instr; 221 fbt->fbtp_patchval = FBT_PATCHVAL; 222 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 223 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 224 225#ifdef __FreeBSD__ 226 lf->fbt_nentries++; 227#endif 228 229 instr++; 230 goto again; 231} 232