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