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