xref: /netbsd-src/external/cddl/osnet/dev/fbt/mips/fbt_isa.c (revision b5c47949a45ac972130c38cf13dfd8afb1f09285)
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 
62 int
fbt_invop(uintptr_t addr,struct trapframe * frame,uintptr_t rval)63 fbt_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 
87 void
fbt_patch_tracepoint(fbt_probe_t * fbt,fbt_patchval_t val)88 fbt_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__)
96 int
fbt_provide_module_function(linker_file_t lf,int symindx,linker_symval_t * symval,void * opaque)97 fbt_provide_module_function(linker_file_t lf, int symindx,
98     linker_symval_t *symval, void *opaque)
99 #elif defined(__NetBSD__)
100 int
101 fbt_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;
176 again:
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