static void fbt_provide_module_user_syms(struct modctl *ctl) { unsigned int i; char *modname = ctl->mod_modname; dtrace_module_symbols_t* module_symbols = ctl->mod_user_symbols; if (module_symbols) { for (i=0; i<module_symbols->dtmodsyms_count; i++) { /* * symbol->dtsym_addr (the symbol address) passed in from * user space, is already slid for both kexts and kernel. */ dtrace_symbol_t* symbol = &module_symbols->dtmodsyms_symbols[i]; char* name = symbol->dtsym_name; /* Lop off omnipresent leading underscore. */ if (*name == '_') name += 1; /* * We're only blacklisting functions in the kernel for now. */ if (MOD_IS_MACH_KERNEL(ctl) && fbt_excluded(name)) continue; /* * Ignore symbols with a null address */ if (!symbol->dtsym_addr) continue; fbt_provide_probe(ctl, (uintptr_t)symbol->dtsym_addr, (uintptr_t)(symbol->dtsym_addr + symbol->dtsym_size), modname, name, (machine_inst_t*)(uintptr_t)symbol->dtsym_addr); } } }
int fbt_provide_module_function(linker_file_t lf, int symindx, linker_symval_t *symval, void *opaque) { fbt_probe_t *fbt, *retfbt; uint32_t *instr, *limit; const char *name; char *modname; modname = opaque; name = symval->name; /* Check if function is excluded from instrumentation */ if (fbt_excluded(name)) return (0); instr = (uint32_t *)(symval->value); limit = (uint32_t *)(symval->value + symval->size); /* Look for store double to ra register */ for (; instr < limit; instr++) { if ((*instr & LDSD_RA_SP_MASK) == SD_RA_SP) break; } if (instr >= limit) return (0); fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); fbt->fbtp_name = name; fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, name, FBT_ENTRY, 3, fbt); fbt->fbtp_patchpoint = instr; fbt->fbtp_ctl = lf; fbt->fbtp_loadcnt = lf->loadcnt; fbt->fbtp_savedval = *instr; fbt->fbtp_patchval = FBT_PATCHVAL; fbt->fbtp_rval = DTRACE_INVOP_SD; fbt->fbtp_symindx = symindx; fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; lf->fbt_nentries++; retfbt = NULL; again: for (; instr < limit; instr++) { if ((*instr & LDSD_RA_SP_MASK) == LD_RA_SP) { break; } } if (instr >= limit) return (0); /* * We have a winner! */ fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); fbt->fbtp_name = name; if (retfbt == NULL) { fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, name, FBT_RETURN, 3, fbt); } else { retfbt->fbtp_next = fbt; fbt->fbtp_id = retfbt->fbtp_id; } retfbt = fbt; fbt->fbtp_patchpoint = instr; fbt->fbtp_ctl = lf; fbt->fbtp_loadcnt = lf->loadcnt; fbt->fbtp_symindx = symindx; fbt->fbtp_rval = DTRACE_INVOP_LD; fbt->fbtp_savedval = *instr; fbt->fbtp_patchval = FBT_PATCHVAL; fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; lf->fbt_nentries++; instr++; goto again; }
int fbt_provide_module_function(linker_file_t lf, int symindx, linker_symval_t *symval, void *opaque) { fbt_probe_t *fbt, *retfbt; uint32_t *instr, *limit; const char *name; char *modname; int patchval; int rval; modname = opaque; name = symval->name; /* Check if function is excluded from instrumentation */ if (fbt_excluded(name)) return (0); instr = (uint32_t *)(symval->value); limit = (uint32_t *)(symval->value + symval->size); /* Look for sd operation */ for (; instr < limit; instr++) { /* Look for a non-compressed store of ra to sp */ if (match_opcode(*instr, (MATCH_SD | RS2_RA | RS1_SP), (MASK_SD | RS2_MASK | RS1_MASK))) { rval = DTRACE_INVOP_SD; patchval = FBT_PATCHVAL; break; } /* Look for a 'C'-compressed store of ra to sp. */ if (check_c_sdsp(&instr)) { rval = DTRACE_INVOP_C_SDSP; patchval = FBT_C_PATCHVAL; break; } } if (instr >= limit) return (0); fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); fbt->fbtp_name = name; fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, name, FBT_ENTRY, 3, fbt); fbt->fbtp_patchpoint = instr; fbt->fbtp_ctl = lf; fbt->fbtp_loadcnt = lf->loadcnt; fbt->fbtp_savedval = *instr; fbt->fbtp_patchval = patchval; fbt->fbtp_rval = rval; fbt->fbtp_symindx = symindx; fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; lf->fbt_nentries++; retfbt = NULL; again: for (; instr < limit; instr++) { /* Look for non-compressed return */ if (match_opcode(*instr, (MATCH_JALR | (X_RA << RS1_SHIFT)), (MASK_JALR | RD_MASK | RS1_MASK | IMM_MASK))) { rval = DTRACE_INVOP_RET; patchval = FBT_PATCHVAL; break; } /* Look for 'C'-compressed return */ if (check_c_ret(&instr)) { rval = DTRACE_INVOP_C_RET; patchval = FBT_C_PATCHVAL; break; } } if (instr >= limit) return (0); /* * We have a winner! */ fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); fbt->fbtp_name = name; if (retfbt == NULL) { fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, name, FBT_RETURN, 3, fbt); } else { retfbt->fbtp_probenext = fbt; fbt->fbtp_id = retfbt->fbtp_id; } retfbt = fbt; fbt->fbtp_patchpoint = instr; fbt->fbtp_ctl = lf; fbt->fbtp_loadcnt = lf->loadcnt; fbt->fbtp_symindx = symindx; fbt->fbtp_rval = rval; fbt->fbtp_savedval = *instr; fbt->fbtp_patchval = patchval; fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; lf->fbt_nentries++; instr++; goto again; }