Deleted Added
full compact
fbt.c (268869) fbt.c (270067)
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

--- 6 unchanged lines hidden (view full) ---

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 *
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

--- 6 unchanged lines hidden (view full) ---

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: head/sys/cddl/dev/fbt/fbt.c 268869 2014-07-19 02:27:31Z markj $
23 * $FreeBSD: head/sys/cddl/dev/fbt/fbt.c 270067 2014-08-16 21:42:55Z markj $
24 *
25 */
26
27/*
28 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
30 */
31

--- 24 unchanged lines hidden (view full) ---

56#include <sys/sysproto.h>
57#include <sys/uio.h>
58#include <sys/unistd.h>
59#include <machine/stdarg.h>
60
61#include <sys/dtrace.h>
62#include <sys/dtrace_bsd.h>
63
24 *
25 */
26
27/*
28 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
30 */
31

--- 24 unchanged lines hidden (view full) ---

56#include <sys/sysproto.h>
57#include <sys/uio.h>
58#include <sys/unistd.h>
59#include <machine/stdarg.h>
60
61#include <sys/dtrace.h>
62#include <sys/dtrace_bsd.h>
63
64static MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing");
64#include "fbt.h"
65
65
66#define FBT_PUSHL_EBP 0x55
67#define FBT_MOVL_ESP_EBP0_V0 0x8b
68#define FBT_MOVL_ESP_EBP1_V0 0xec
69#define FBT_MOVL_ESP_EBP0_V1 0x89
70#define FBT_MOVL_ESP_EBP1_V1 0xe5
71#define FBT_REX_RSP_RBP 0x48
66MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing");
72
67
73#define FBT_POPL_EBP 0x5d
74#define FBT_RET 0xc3
75#define FBT_RET_IMM16 0xc2
76#define FBT_LEAVE 0xc9
68dtrace_provider_id_t fbt_id;
69fbt_probe_t **fbt_probetab;
70int fbt_probetab_mask;
77
71
78#ifdef __amd64__
79#define FBT_PATCHVAL 0xcc
80#else
81#define FBT_PATCHVAL 0xf0
82#endif
83
84static d_open_t fbt_open;
85static int fbt_unload(void);
86static void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
87static void fbt_provide_module(void *, modctl_t *);
88static void fbt_destroy(void *, dtrace_id_t, void *);
89static void fbt_enable(void *, dtrace_id_t, void *);
90static void fbt_disable(void *, dtrace_id_t, void *);
91static void fbt_load(void *);
92static void fbt_suspend(void *, dtrace_id_t, void *);
93static void fbt_resume(void *, dtrace_id_t, void *);
94
72static d_open_t fbt_open;
73static int fbt_unload(void);
74static void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
75static void fbt_provide_module(void *, modctl_t *);
76static void fbt_destroy(void *, dtrace_id_t, void *);
77static void fbt_enable(void *, dtrace_id_t, void *);
78static void fbt_disable(void *, dtrace_id_t, void *);
79static void fbt_load(void *);
80static void fbt_suspend(void *, dtrace_id_t, void *);
81static void fbt_resume(void *, dtrace_id_t, void *);
82
95#define FBT_ENTRY "entry"
96#define FBT_RETURN "return"
97#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
98#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
99
100static struct cdevsw fbt_cdevsw = {
101 .d_version = D_VERSION,
102 .d_open = fbt_open,
103 .d_name = "fbt",
104};
105
106static dtrace_pattr_t fbt_attr = {
107{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },

--- 11 unchanged lines hidden (view full) ---

119 fbt_suspend,
120 fbt_resume,
121 fbt_getargdesc,
122 NULL,
123 NULL,
124 fbt_destroy
125};
126
83static struct cdevsw fbt_cdevsw = {
84 .d_version = D_VERSION,
85 .d_open = fbt_open,
86 .d_name = "fbt",
87};
88
89static dtrace_pattr_t fbt_attr = {
90{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },

--- 11 unchanged lines hidden (view full) ---

102 fbt_suspend,
103 fbt_resume,
104 fbt_getargdesc,
105 NULL,
106 NULL,
107 fbt_destroy
108};
109
127typedef struct fbt_probe {
128 struct fbt_probe *fbtp_hashnext;
129 uint8_t *fbtp_patchpoint;
130 int8_t fbtp_rval;
131 uint8_t fbtp_patchval;
132 uint8_t fbtp_savedval;
133 uintptr_t fbtp_roffset;
134 dtrace_id_t fbtp_id;
135 const char *fbtp_name;
136 modctl_t *fbtp_ctl;
137 int fbtp_loadcnt;
138 int fbtp_primary;
139 int fbtp_invop_cnt;
140 int fbtp_symindx;
141 struct fbt_probe *fbtp_next;
142} fbt_probe_t;
143
144static struct cdev *fbt_cdev;
110static struct cdev *fbt_cdev;
145static dtrace_provider_id_t fbt_id;
146static fbt_probe_t **fbt_probetab;
147static int fbt_probetab_size;
111static int fbt_probetab_size;
148static int fbt_probetab_mask;
149static int fbt_verbose = 0;
150
151static void
152fbt_doubletrap(void)
153{
154 fbt_probe_t *fbt;
155 int i;
156
157 for (i = 0; i < fbt_probetab_size; i++) {
158 fbt = fbt_probetab[i];
159
160 for (; fbt != NULL; fbt = fbt->fbtp_next)
161 *fbt->fbtp_patchpoint = fbt->fbtp_savedval;
162 }
163}
164
112static int fbt_verbose = 0;
113
114static void
115fbt_doubletrap(void)
116{
117 fbt_probe_t *fbt;
118 int i;
119
120 for (i = 0; i < fbt_probetab_size; i++) {
121 fbt = fbt_probetab[i];
122
123 for (; fbt != NULL; fbt = fbt->fbtp_next)
124 *fbt->fbtp_patchpoint = fbt->fbtp_savedval;
125 }
126}
127
165static int
166fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
167{
168 solaris_cpu_t *cpu = &solaris_cpu[curcpu];
169 uintptr_t stack0, stack1, stack2, stack3, stack4;
170 fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
171
172 for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
173 if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
174 fbt->fbtp_invop_cnt++;
175 if (fbt->fbtp_roffset == 0) {
176 int i = 0;
177 /*
178 * When accessing the arguments on the stack,
179 * we must protect against accessing beyond
180 * the stack. We can safely set NOFAULT here
181 * -- we know that interrupts are already
182 * disabled.
183 */
184 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
185 cpu->cpu_dtrace_caller = stack[i++];
186 stack0 = stack[i++];
187 stack1 = stack[i++];
188 stack2 = stack[i++];
189 stack3 = stack[i++];
190 stack4 = stack[i++];
191 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
192 CPU_DTRACE_BADADDR);
193
194 dtrace_probe(fbt->fbtp_id, stack0, stack1,
195 stack2, stack3, stack4);
196
197 cpu->cpu_dtrace_caller = 0;
198 } else {
199#ifdef __amd64__
200 /*
201 * On amd64, we instrument the ret, not the
202 * leave. We therefore need to set the caller
203 * to assure that the top frame of a stack()
204 * action is correct.
205 */
206 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
207 cpu->cpu_dtrace_caller = stack[0];
208 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
209 CPU_DTRACE_BADADDR);
210#endif
211
212 dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
213 rval, 0, 0, 0);
214 cpu->cpu_dtrace_caller = 0;
215 }
216
217 return (fbt->fbtp_rval);
218 }
219 }
220
221 return (0);
222}
223
224static int
225fbt_provide_module_function(linker_file_t lf, int symindx,
226 linker_symval_t *symval, void *opaque)
227{
228 char *modname = opaque;
229 const char *name = symval->name;
230 fbt_probe_t *fbt, *retfbt;
231 int j;
232 int size;
233 u_int8_t *instr, *limit;
234
235 if ((strncmp(name, "dtrace_", 7) == 0 &&
236 strncmp(name, "dtrace_safe_", 12) != 0) ||
237 strcmp(name, "trap_check") == 0) {
238 /*
239 * Anything beginning with "dtrace_" may be called
240 * from probe context unless it explicitly indicates
241 * that it won't be called from probe context by
242 * using the prefix "dtrace_safe_".
243 *
244 * Additionally, we avoid instrumenting trap_check() to avoid
245 * the possibility of generating a fault in probe context before
246 * DTrace's fault handler is called.
247 */
248 return (0);
249 }
250
251 if (name[0] == '_' && name[1] == '_')
252 return (0);
253
254 size = symval->size;
255
256 instr = (u_int8_t *) symval->value;
257 limit = (u_int8_t *) symval->value + symval->size;
258
259#ifdef __amd64__
260 while (instr < limit) {
261 if (*instr == FBT_PUSHL_EBP)
262 break;
263
264 if ((size = dtrace_instr_size(instr)) <= 0)
265 break;
266
267 instr += size;
268 }
269
270 if (instr >= limit || *instr != FBT_PUSHL_EBP) {
271 /*
272 * We either don't save the frame pointer in this
273 * function, or we ran into some disassembly
274 * screw-up. Either way, we bail.
275 */
276 return (0);
277 }
278#else
279 if (instr[0] != FBT_PUSHL_EBP)
280 return (0);
281
282 if (!(instr[1] == FBT_MOVL_ESP_EBP0_V0 &&
283 instr[2] == FBT_MOVL_ESP_EBP1_V0) &&
284 !(instr[1] == FBT_MOVL_ESP_EBP0_V1 &&
285 instr[2] == FBT_MOVL_ESP_EBP1_V1))
286 return (0);
287#endif
288
289 fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
290 fbt->fbtp_name = name;
291 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
292 name, FBT_ENTRY, 3, fbt);
293 fbt->fbtp_patchpoint = instr;
294 fbt->fbtp_ctl = lf;
295 fbt->fbtp_loadcnt = lf->loadcnt;
296 fbt->fbtp_rval = DTRACE_INVOP_PUSHL_EBP;
297 fbt->fbtp_savedval = *instr;
298 fbt->fbtp_patchval = FBT_PATCHVAL;
299 fbt->fbtp_symindx = symindx;
300
301 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
302 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
303
304 lf->fbt_nentries++;
305
306 retfbt = NULL;
307again:
308 if (instr >= limit)
309 return (0);
310
311 /*
312 * If this disassembly fails, then we've likely walked off into
313 * a jump table or some other unsuitable area. Bail out of the
314 * disassembly now.
315 */
316 if ((size = dtrace_instr_size(instr)) <= 0)
317 return (0);
318
319#ifdef __amd64__
320 /*
321 * We only instrument "ret" on amd64 -- we don't yet instrument
322 * ret imm16, largely because the compiler doesn't seem to
323 * (yet) emit them in the kernel...
324 */
325 if (*instr != FBT_RET) {
326 instr += size;
327 goto again;
328 }
329#else
330 if (!(size == 1 &&
331 (*instr == FBT_POPL_EBP || *instr == FBT_LEAVE) &&
332 (*(instr + 1) == FBT_RET ||
333 *(instr + 1) == FBT_RET_IMM16))) {
334 instr += size;
335 goto again;
336 }
337#endif
338
339 /*
340 * We (desperately) want to avoid erroneously instrumenting a
341 * jump table, especially given that our markers are pretty
342 * short: two bytes on x86, and just one byte on amd64. To
343 * determine if we're looking at a true instruction sequence
344 * or an inline jump table that happens to contain the same
345 * byte sequences, we resort to some heuristic sleeze: we
346 * treat this instruction as being contained within a pointer,
347 * and see if that pointer points to within the body of the
348 * function. If it does, we refuse to instrument it.
349 */
350 for (j = 0; j < sizeof (uintptr_t); j++) {
351 caddr_t check = (caddr_t) instr - j;
352 uint8_t *ptr;
353
354 if (check < symval->value)
355 break;
356
357 if (check + sizeof (caddr_t) > (caddr_t)limit)
358 continue;
359
360 ptr = *(uint8_t **)check;
361
362 if (ptr >= (uint8_t *) symval->value && ptr < limit) {
363 instr += size;
364 goto again;
365 }
366 }
367
368 /*
369 * We have a winner!
370 */
371 fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
372 fbt->fbtp_name = name;
373
374 if (retfbt == NULL) {
375 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
376 name, FBT_RETURN, 3, fbt);
377 } else {
378 retfbt->fbtp_next = fbt;
379 fbt->fbtp_id = retfbt->fbtp_id;
380 }
381
382 retfbt = fbt;
383 fbt->fbtp_patchpoint = instr;
384 fbt->fbtp_ctl = lf;
385 fbt->fbtp_loadcnt = lf->loadcnt;
386 fbt->fbtp_symindx = symindx;
387
388#ifndef __amd64__
389 if (*instr == FBT_POPL_EBP) {
390 fbt->fbtp_rval = DTRACE_INVOP_POPL_EBP;
391 } else {
392 ASSERT(*instr == FBT_LEAVE);
393 fbt->fbtp_rval = DTRACE_INVOP_LEAVE;
394 }
395 fbt->fbtp_roffset =
396 (uintptr_t)(instr - (uint8_t *) symval->value) + 1;
397
398#else
399 ASSERT(*instr == FBT_RET);
400 fbt->fbtp_rval = DTRACE_INVOP_RET;
401 fbt->fbtp_roffset =
402 (uintptr_t)(instr - (uint8_t *) symval->value);
403#endif
404
405 fbt->fbtp_savedval = *instr;
406 fbt->fbtp_patchval = FBT_PATCHVAL;
407 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
408 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
409
410 lf->fbt_nentries++;
411
412 instr += size;
413 goto again;
414}
415
416static void
417fbt_provide_module(void *arg, modctl_t *lf)
418{
419 char modname[MAXPATHLEN];
420 int i;
421 size_t len;
422
423 strlcpy(modname, lf->filename, sizeof(modname));

--- 95 unchanged lines hidden (view full) ---

519 printf("fbt is failing for probe %s "
520 "(module %s reloaded)",
521 fbt->fbtp_name, ctl->filename);
522 }
523
524 return;
525 }
526
128static void
129fbt_provide_module(void *arg, modctl_t *lf)
130{
131 char modname[MAXPATHLEN];
132 int i;
133 size_t len;
134
135 strlcpy(modname, lf->filename, sizeof(modname));

--- 95 unchanged lines hidden (view full) ---

231 printf("fbt is failing for probe %s "
232 "(module %s reloaded)",
233 fbt->fbtp_name, ctl->filename);
234 }
235
236 return;
237 }
238
527 for (; fbt != NULL; fbt = fbt->fbtp_next) {
528 *fbt->fbtp_patchpoint = fbt->fbtp_patchval;
529 }
239 for (; fbt != NULL; fbt = fbt->fbtp_next)
240 fbt_patch_tracepoint(fbt, fbt->fbtp_patchval);
530}
531
532static void
533fbt_disable(void *arg, dtrace_id_t id, void *parg)
534{
535 fbt_probe_t *fbt = parg;
536 modctl_t *ctl = fbt->fbtp_ctl;
537
538 ASSERT(ctl->nenabled > 0);
539 ctl->nenabled--;
540
541 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
542 return;
543
544 for (; fbt != NULL; fbt = fbt->fbtp_next)
241}
242
243static void
244fbt_disable(void *arg, dtrace_id_t id, void *parg)
245{
246 fbt_probe_t *fbt = parg;
247 modctl_t *ctl = fbt->fbtp_ctl;
248
249 ASSERT(ctl->nenabled > 0);
250 ctl->nenabled--;
251
252 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
253 return;
254
255 for (; fbt != NULL; fbt = fbt->fbtp_next)
545 *fbt->fbtp_patchpoint = fbt->fbtp_savedval;
256 fbt_patch_tracepoint(fbt, fbt->fbtp_patchval);
546}
547
548static void
549fbt_suspend(void *arg, dtrace_id_t id, void *parg)
550{
551 fbt_probe_t *fbt = parg;
552 modctl_t *ctl = fbt->fbtp_ctl;
553
554 ASSERT(ctl->nenabled > 0);
555
556 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
557 return;
558
559 for (; fbt != NULL; fbt = fbt->fbtp_next)
257}
258
259static void
260fbt_suspend(void *arg, dtrace_id_t id, void *parg)
261{
262 fbt_probe_t *fbt = parg;
263 modctl_t *ctl = fbt->fbtp_ctl;
264
265 ASSERT(ctl->nenabled > 0);
266
267 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
268 return;
269
270 for (; fbt != NULL; fbt = fbt->fbtp_next)
560 *fbt->fbtp_patchpoint = fbt->fbtp_savedval;
271 fbt_patch_tracepoint(fbt, fbt->fbtp_patchval);
561}
562
563static void
564fbt_resume(void *arg, dtrace_id_t id, void *parg)
565{
566 fbt_probe_t *fbt = parg;
567 modctl_t *ctl = fbt->fbtp_ctl;
568
569 ASSERT(ctl->nenabled > 0);
570
571 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
572 return;
573
574 for (; fbt != NULL; fbt = fbt->fbtp_next)
272}
273
274static void
275fbt_resume(void *arg, dtrace_id_t id, void *parg)
276{
277 fbt_probe_t *fbt = parg;
278 modctl_t *ctl = fbt->fbtp_ctl;
279
280 ASSERT(ctl->nenabled > 0);
281
282 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
283 return;
284
285 for (; fbt != NULL; fbt = fbt->fbtp_next)
575 *fbt->fbtp_patchpoint = fbt->fbtp_patchval;
286 fbt_patch_tracepoint(fbt, fbt->fbtp_patchval);
576}
577
578static int
579fbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc)
580{
581 const Elf_Sym *symp = lc->symtab;;
582 const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
583 const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);

--- 852 unchanged lines hidden ---
287}
288
289static int
290fbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc)
291{
292 const Elf_Sym *symp = lc->symtab;;
293 const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
294 const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);

--- 852 unchanged lines hidden ---