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