xref: /netbsd-src/external/cddl/osnet/dev/fbt/mips/fbt_isa.c (revision b5c47949a45ac972130c38cf13dfd8afb1f09285)
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