1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
22 *
23 * $FreeBSD$
24 *
25 */
26
27 /*
28 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
30 */
31
32 #include <sys/cdefs.h>
33 #include <sys/param.h>
34
35 #include <sys/dtrace.h>
36
37 #include <machine/cpufunc.h>
38 #include <machine/md_var.h>
39
40 #include "fbt.h"
41
42 #define FBT_PUSHL_EBP 0x55
43 #define FBT_MOVL_ESP_EBP0_V0 0x8b
44 #define FBT_MOVL_ESP_EBP1_V0 0xec
45 #define FBT_MOVL_ESP_EBP0_V1 0x89
46 #define FBT_MOVL_ESP_EBP1_V1 0xe5
47 #define FBT_REX_RSP_RBP 0x48
48
49 #define FBT_POPL_EBP 0x5d
50 #define FBT_RET 0xc3
51 #define FBT_RET_IMM16 0xc2
52 #define FBT_LEAVE 0xc9
53
54 #ifdef __amd64__
55 #define FBT_PATCHVAL 0xcc
56 #else
57 #define FBT_PATCHVAL 0xf0
58 #endif
59
60 #define FBT_ENTRY "entry"
61 #define FBT_RETURN "return"
62
63 int
64 fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t scratch __unused)
65 {
66 solaris_cpu_t *cpu;
67 uintptr_t *stack;
68 uintptr_t arg0, arg1, arg2, arg3, arg4, rval;
69 fbt_probe_t *fbt;
70 int8_t fbtrval;
71
72 #ifdef __amd64__
73 stack = (uintptr_t *)frame->tf_rsp;
74 rval = frame->tf_rax;
75 #else
76 /* Skip hardware-saved registers. */
77 stack = (uintptr_t *)frame->tf_isp + 3;
78 rval = frame->tf_eax;
79 #endif
80
81 cpu = &solaris_cpu[curcpu];
82 fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
83 for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
84 if ((uintptr_t)fbt->fbtp_patchpoint != addr)
85 continue;
86 fbtrval = fbt->fbtp_rval;
87
88 /*
89 * Report the address of the breakpoint for the benefit
90 * of consumers fetching register values with regs[].
91 */
92 #ifdef __i386__
93 frame->tf_eip--;
94 #else
95 frame->tf_rip--;
96 #endif
97 for (; fbt != NULL; fbt = fbt->fbtp_tracenext) {
98 ASSERT(fbt->fbtp_rval == fbtrval);
99 if (fbt->fbtp_roffset == 0) {
100 #ifdef __amd64__
101 /* fbt->fbtp_rval == DTRACE_INVOP_PUSHQ_RBP */
102 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
103 cpu->cpu_dtrace_caller = stack[0];
104 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
105 CPU_DTRACE_BADADDR);
106
107 arg0 = frame->tf_rdi;
108 arg1 = frame->tf_rsi;
109 arg2 = frame->tf_rdx;
110 arg3 = frame->tf_rcx;
111 arg4 = frame->tf_r8;
112 #else
113 int i = 0;
114
115 /*
116 * When accessing the arguments on the stack,
117 * we must protect against accessing beyond
118 * the stack. We can safely set NOFAULT here
119 * -- we know that interrupts are already
120 * disabled.
121 */
122 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
123 cpu->cpu_dtrace_caller = stack[i++];
124 arg0 = stack[i++];
125 arg1 = stack[i++];
126 arg2 = stack[i++];
127 arg3 = stack[i++];
128 arg4 = stack[i++];
129 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
130 CPU_DTRACE_BADADDR);
131 #endif
132
133 dtrace_probe(fbt->fbtp_id, arg0, arg1,
134 arg2, arg3, arg4);
135
136 cpu->cpu_dtrace_caller = 0;
137 } else {
138 #ifdef __amd64__
139 /*
140 * On amd64, we instrument the ret, not the
141 * leave. We therefore need to set the caller
142 * to ensure that the top frame of a stack()
143 * action is correct.
144 */
145 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
146 cpu->cpu_dtrace_caller = stack[0];
147 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
148 CPU_DTRACE_BADADDR);
149 #endif
150
151 dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
152 rval, 0, 0, 0);
153 cpu->cpu_dtrace_caller = 0;
154 }
155 }
156 /* Advance to the instruction following the breakpoint. */
157 #ifdef __i386__
158 frame->tf_eip++;
159 #else
160 frame->tf_rip++;
161 #endif
162 return (fbtrval);
163 }
164
165 return (0);
166 }
167
168 void
169 fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
170 {
171 register_t intr;
172 bool old_wp;
173
174 intr = intr_disable();
175 old_wp = disable_wp();
176 *fbt->fbtp_patchpoint = val;
177 restore_wp(old_wp);
178 intr_restore(intr);
179 }
180
181 int
182 fbt_provide_module_function(linker_file_t lf, int symindx,
183 linker_symval_t *symval, void *opaque)
184 {
185 char *modname = opaque;
186 const char *name = symval->name;
187 fbt_probe_t *fbt, *hash, *retfbt;
188 int j;
189 int size;
190 uint8_t *instr, *limit;
191
192 if (fbt_excluded(name))
193 return (0);
194
195 /*
196 * trap_check() is a wrapper for DTrace's fault handler, so we don't
197 * want to be able to instrument it.
198 */
199 if (strcmp(name, "trap_check") == 0)
200 return (0);
201
202 size = symval->size;
203
204 instr = (uint8_t *) symval->value;
205 limit = (uint8_t *) symval->value + symval->size;
206
207 #ifdef __amd64__
208 while (instr < limit) {
209 if (*instr == FBT_PUSHL_EBP)
210 break;
211
212 if ((size = dtrace_instr_size(instr)) <= 0)
213 break;
214
215 instr += size;
216 }
217
218 if (instr >= limit || *instr != FBT_PUSHL_EBP) {
219 /*
220 * We either don't save the frame pointer in this
221 * function, or we ran into some disassembly
222 * screw-up. Either way, we bail.
223 */
224 return (0);
225 }
226 #else
227 if (instr[0] != FBT_PUSHL_EBP)
228 return (0);
229
230 if (!(instr[1] == FBT_MOVL_ESP_EBP0_V0 &&
231 instr[2] == FBT_MOVL_ESP_EBP1_V0) &&
232 !(instr[1] == FBT_MOVL_ESP_EBP0_V1 &&
233 instr[2] == FBT_MOVL_ESP_EBP1_V1))
234 return (0);
235 #endif
236
237 fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
238 fbt->fbtp_name = name;
239 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
240 name, FBT_ENTRY, 3, fbt);
241 fbt->fbtp_patchpoint = instr;
242 fbt->fbtp_ctl = lf;
243 fbt->fbtp_loadcnt = lf->loadcnt;
244 fbt->fbtp_rval = DTRACE_INVOP_PUSHL_EBP;
245 fbt->fbtp_savedval = *instr;
246 fbt->fbtp_patchval = FBT_PATCHVAL;
247 fbt->fbtp_symindx = symindx;
248
249 for (hash = fbt_probetab[FBT_ADDR2NDX(instr)]; hash != NULL;
250 hash = hash->fbtp_hashnext) {
251 if (hash->fbtp_patchpoint == fbt->fbtp_patchpoint) {
252 fbt->fbtp_tracenext = hash->fbtp_tracenext;
253 hash->fbtp_tracenext = fbt;
254 break;
255 }
256 }
257 if (hash == NULL) {
258 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
259 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
260 }
261
262 lf->fbt_nentries++;
263
264 retfbt = NULL;
265 again:
266 if (instr >= limit)
267 return (0);
268
269 /*
270 * If this disassembly fails, then we've likely walked off into
271 * a jump table or some other unsuitable area. Bail out of the
272 * disassembly now.
273 */
274 if ((size = dtrace_instr_size(instr)) <= 0)
275 return (0);
276
277 #ifdef __amd64__
278 /*
279 * We only instrument "ret" on amd64 -- we don't yet instrument
280 * ret imm16, largely because the compiler doesn't seem to
281 * (yet) emit them in the kernel...
282 */
283 if (*instr != FBT_RET) {
284 instr += size;
285 goto again;
286 }
287 #else
288 if (!(size == 1 &&
289 (*instr == FBT_POPL_EBP || *instr == FBT_LEAVE) &&
290 (*(instr + 1) == FBT_RET ||
291 *(instr + 1) == FBT_RET_IMM16))) {
292 instr += size;
293 goto again;
294 }
295 #endif
296
297 /*
298 * We (desperately) want to avoid erroneously instrumenting a
299 * jump table, especially given that our markers are pretty
300 * short: two bytes on x86, and just one byte on amd64. To
301 * determine if we're looking at a true instruction sequence
302 * or an inline jump table that happens to contain the same
303 * byte sequences, we resort to some heuristic sleeze: we
304 * treat this instruction as being contained within a pointer,
305 * and see if that pointer points to within the body of the
306 * function. If it does, we refuse to instrument it.
307 */
308 for (j = 0; j < sizeof (uintptr_t); j++) {
309 caddr_t check = (caddr_t) instr - j;
310 uint8_t *ptr;
311
312 if (check < symval->value)
313 break;
314
315 if (check + sizeof (caddr_t) > (caddr_t)limit)
316 continue;
317
318 ptr = *(uint8_t **)check;
319
320 if (ptr >= (uint8_t *) symval->value && ptr < limit) {
321 instr += size;
322 goto again;
323 }
324 }
325
326 /*
327 * We have a winner!
328 */
329 fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
330 fbt->fbtp_name = name;
331
332 if (retfbt == NULL) {
333 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
334 name, FBT_RETURN, 3, fbt);
335 } else {
336 retfbt->fbtp_probenext = fbt;
337 fbt->fbtp_id = retfbt->fbtp_id;
338 }
339
340 retfbt = fbt;
341 fbt->fbtp_patchpoint = instr;
342 fbt->fbtp_ctl = lf;
343 fbt->fbtp_loadcnt = lf->loadcnt;
344 fbt->fbtp_symindx = symindx;
345
346 #ifndef __amd64__
347 if (*instr == FBT_POPL_EBP) {
348 fbt->fbtp_rval = DTRACE_INVOP_POPL_EBP;
349 } else {
350 ASSERT(*instr == FBT_LEAVE);
351 fbt->fbtp_rval = DTRACE_INVOP_LEAVE;
352 }
353 fbt->fbtp_roffset =
354 (uintptr_t)(instr - (uint8_t *) symval->value) + 1;
355
356 #else
357 ASSERT(*instr == FBT_RET);
358 fbt->fbtp_rval = DTRACE_INVOP_RET;
359 fbt->fbtp_roffset =
360 (uintptr_t)(instr - (uint8_t *) symval->value);
361 #endif
362
363 fbt->fbtp_savedval = *instr;
364 fbt->fbtp_patchval = FBT_PATCHVAL;
365 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
366 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
367
368 lf->fbt_nentries++;
369
370 instr += size;
371 goto again;
372 }
Cache object: 692a606e58772e965875b2e03b782ea5
|