static int io_prov_return(pf_info_t *infp, uint8_t *instr, int size) { sdt_probe_t *sdp; sdt_provider_t *prov; uint8_t *offset; char *name; sdt_probe_t *retsdt = infp->retptr; printk("io_prov_return called %s:%s %p sz=%x\n", infp->modname, infp->name, instr, size); for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { if (strcmp(prov->sdtp_name, infp->modname) == 0) break; } name = kstrdup(infp->name2, KM_SLEEP); sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); /***********************************************/ /* Daisy chain the return exit points so we */ /* dont end up firing all of them when we */ /* return from the probe. */ /***********************************************/ if (retsdt == NULL) { sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, infp->func, NULL, name, 0, sdp); infp->retptr = sdp; } else { retsdt->sdp_next = sdp; sdp->sdp_id = retsdt->sdp_id; } sdp->sdp_name = name; sdp->sdp_namelen = strlen(name); sdp->sdp_inslen = size; sdp->sdp_provider = prov; sdp->sdp_flags = infp->flags; sdp->sdp_entry = FALSE; /***********************************************/ /* Add the entry to the hash table. */ /***********************************************/ offset = instr; sdp->sdp_hashnext = sdt_probetab[SDT_ADDR2NDX(offset)]; sdt_probetab[SDT_ADDR2NDX(offset)] = sdp; sdp->sdp_patchval = PATCHVAL; sdp->sdp_patchpoint = (uint8_t *)offset; sdp->sdp_savedval = *sdp->sdp_patchpoint; return 1; }
void sdt_destroy(void *arg, dtrace_id_t id, void *parg) { sdt_probe_t *sdp = parg; PDATA(sdp->sdp_module)->sdt_probe_cnt--; while (sdp != NULL) { sdt_probe_t *old = sdp, *last, *hash; int ndx; ndx = SDT_ADDR2NDX(sdp->sdp_patchpoint); last = NULL; hash = sdt_probetab[ndx]; while (hash != sdp) { ASSERT(hash != NULL); last = hash; hash = hash->sdp_hashnext; } if (last != NULL) last->sdp_hashnext = sdp->sdp_hashnext; else sdt_probetab[ndx] = sdp->sdp_hashnext; kfree(sdp->sdp_name); sdp = sdp->sdp_next; kfree(old); } }
static int io_prov_entry(pf_info_t *infp, uint8_t *instr, int size, int modrm) { sdt_probe_t *sdp; sdt_provider_t *prov; uint8_t *offset; char *name; printk("io_prov_entry called %s:%s\n", infp->modname, infp->name); for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { if (strcmp(prov->sdtp_name, infp->modname) == 0) break; } name = kstrdup(infp->name, KM_SLEEP); sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, infp->func, NULL, name, 0, sdp); sdp->sdp_name = name; sdp->sdp_namelen = strlen(name); sdp->sdp_inslen = size; sdp->sdp_modrm = modrm; sdp->sdp_provider = prov; sdp->sdp_flags = infp->flags; sdp->sdp_entry = TRUE; /***********************************************/ /* Add the entry to the hash table. */ /***********************************************/ offset = instr; sdp->sdp_hashnext = sdt_probetab[SDT_ADDR2NDX(offset)]; sdt_probetab[SDT_ADDR2NDX(offset)] = sdp; sdp->sdp_patchval = PATCHVAL; sdp->sdp_patchpoint = (uint8_t *)offset; sdp->sdp_savedval = *sdp->sdp_patchpoint; infp->retptr = NULL; return 1; }
/*ARGSUSED*/ static void sdt_destroy(void *arg, dtrace_id_t id, void *parg) { #pragma unused(arg,id) sdt_probe_t *sdp = parg, *old, *last, *hash; int ndx; #if !defined(__APPLE__) /* * APPLE NOTE: sdt probes for kexts not yet implemented */ struct modctl *ctl = sdp->sdp_ctl; if (ctl != NULL && ctl->mod_loadcnt == sdp->sdp_loadcnt) { if ((ctl->mod_loadcnt == sdp->sdp_loadcnt && ctl->mod_loaded)) { ((struct module *)(ctl->mod_mp))->sdt_nprobes--; } } #endif /* __APPLE__ */ while (sdp != NULL) { old = sdp; /* * Now we need to remove this probe from the sdt_probetab. */ ndx = SDT_ADDR2NDX(sdp->sdp_patchpoint); last = NULL; hash = sdt_probetab[ndx]; while (hash != sdp) { ASSERT(hash != NULL); last = hash; hash = hash->sdp_hashnext; } if (last != NULL) { last->sdp_hashnext = sdp->sdp_hashnext; } else { sdt_probetab[ndx] = sdp->sdp_hashnext; } kmem_free(sdp->sdp_name, sdp->sdp_namelen); sdp = sdp->sdp_next; kmem_free(old, sizeof (sdt_probe_t)); } }
/*ARGSUSED*/ static int sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax, trap_instr_t *tinfo) { uintptr_t stack0, stack1, stack2, stack3, stack4; int i = 0; sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; #ifdef __amd64 /* * On amd64, stack[0] contains the dereferenced stack pointer, * stack[1] contains savfp, stack[2] contains savpc. We want * to step over these entries. */ i += 3; #endif for (; sdt != NULL; sdt = sdt->sdp_hashnext) { if ((uintptr_t)sdt->sdp_patchpoint == addr) { /***********************************************/ /* Dont fire probe if this is unsafe. */ /***********************************************/ if (!tinfo->t_doprobe) return (DTRACE_INVOP_NOP); /* * When accessing the arguments on the stack, we must * protect against accessing beyond the stack. We can * safely set NOFAULT here -- we know that interrupts * are already disabled. */ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); stack0 = stack[i++]; stack1 = stack[i++]; stack2 = stack[i++]; stack3 = stack[i++]; stack4 = stack[i++]; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); dtrace_probe(sdt->sdp_id, stack0, stack1, stack2, stack3, stack4); return (DTRACE_INVOP_NOP); } } return (0); }
/*ARGSUSED*/ int sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) { #pragma unused(eax) sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; for (; sdt != NULL; sdt = sdt->sdp_hashnext) { if ((uintptr_t)sdt->sdp_patchpoint == addr) { x86_saved_state64_t *regs = (x86_saved_state64_t *)stack; dtrace_probe(sdt->sdp_id, regs->rdi, regs->rsi, regs->rdx, regs->rcx, regs->r8); return (DTRACE_INVOP_NOP); } } return (0); }
/*ARGSUSED*/ static void __sdt_provide_module(void *arg, struct modctl *ctl) { #pragma unused(arg) struct module *mp = (struct module *)ctl->mod_address; char *modname = ctl->mod_modname; sdt_probedesc_t *sdpd; sdt_probe_t *sdp, *old; sdt_provider_t *prov; int len; /* * One for all, and all for one: if we haven't yet registered all of * our providers, we'll refuse to provide anything. */ for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { if (prov->sdtp_id == DTRACE_PROVNONE) return; } if (!mp || mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL) return; for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { const char *name = sdpd->sdpd_name, *func; char *nname; int i, j; dtrace_id_t id; for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { const char *prefpart, *prefix = prov->sdtp_prefix; if ((prefpart = strstr(name, prefix))) { name = prefpart + strlen(prefix); break; } } nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP); for (i = 0, j = 0; name[j] != '\0'; i++) { if (name[j] == '_' && name[j + 1] == '_') { nname[i] = '-'; j += 2; } else { nname[i] = name[j++]; } } nname[i] = '\0'; sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); sdp->sdp_loadcnt = ctl->mod_loadcnt; sdp->sdp_ctl = ctl; sdp->sdp_name = nname; sdp->sdp_namelen = len; sdp->sdp_provider = prov; func = sdpd->sdpd_func; if (func == NULL) func = "<unknown>"; /* * We have our provider. Now create the probe. */ if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, func, nname)) != DTRACE_IDNONE) { old = dtrace_probe_arg(prov->sdtp_id, id); ASSERT(old != NULL); sdp->sdp_next = old->sdp_next; sdp->sdp_id = id; old->sdp_next = sdp; } else { sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, modname, func, nname, SDT_AFRAMES, sdp); mp->sdt_nprobes++; } #if 0 printf ("__sdt_provide_module: sdpd=0x%p sdp=0x%p name=%s, id=%d\n", sdpd, sdp, nname, sdp->sdp_id); #endif sdp->sdp_hashnext = sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)]; sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; sdp->sdp_patchval = SDT_PATCHVAL; sdp->sdp_patchpoint = (sdt_instr_t *)sdpd->sdpd_offset; sdp->sdp_savedval = *sdp->sdp_patchpoint; } }
/*ARGSUSED*/ static void sdt_provide_module(void *arg, struct modctl *ctl) { # if defined(sun) struct module *mp = ctl->mod_mp; char *modname = ctl->mod_modname; sdt_probedesc_t *sdpd; sdt_probe_t *sdp, *old; sdt_provider_t *prov; /* * One for all, and all for one: if we haven't yet registered all of * our providers, we'll refuse to provide anything. */ for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { if (prov->sdtp_id == DTRACE_PROVNONE) return; } if (mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL) return; for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { char *name = sdpd->sdpd_name, *func, *nname; int i, j, len; sdt_provider_t *prov; ulong_t offs; dtrace_id_t id; for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { char *prefix = prov->sdtp_prefix; if (strncmp(name, prefix, strlen(prefix)) == 0) { name += strlen(prefix); break; } } nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP); for (i = 0, j = 0; name[j] != '\0'; i++) { if (name[j] == '_' && name[j + 1] == '_') { nname[i] = '-'; j += 2; } else { nname[i] = name[j++]; } } nname[i] = '\0'; sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); sdp->sdp_loadcnt = ctl->mod_loadcnt; sdp->sdp_ctl = ctl; sdp->sdp_name = nname; sdp->sdp_namelen = len; sdp->sdp_provider = prov; func = kobj_searchsym(mp, sdpd->sdpd_offset, &offs); if (func == NULL) func = "<unknown>"; /* * We have our provider. Now create the probe. */ if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, func, nname)) != DTRACE_IDNONE) { old = dtrace_probe_arg(prov->sdtp_id, id); ASSERT(old != NULL); sdp->sdp_next = old->sdp_next; sdp->sdp_id = id; old->sdp_next = sdp; } else { sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, modname, func, nname, 3, sdp); mp->sdt_nprobes++; } sdp->sdp_hashnext = sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)]; sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; sdp->sdp_patchval = SDT_PATCHVAL; sdp->sdp_patchpoint = (uint8_t *)sdpd->sdpd_offset; sdp->sdp_savedval = *sdp->sdp_patchpoint; } # endif }
/*ARGSUSED*/ static int sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax, trap_instr_t *tinfo) { uintptr_t stack0, stack1, stack2, stack3, stack4; sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; struct pt_regs *regs; for (; sdt != NULL; sdt = sdt->sdp_hashnext) { //printk("sdt_invop %p %p\n", sdt->sdp_patchpoint, addr); if (sdt->sdp_enabled && (uintptr_t)sdt->sdp_patchpoint == addr) { tinfo->t_opcode = sdt->sdp_savedval; tinfo->t_inslen = sdt->sdp_inslen; tinfo->t_modrm = sdt->sdp_modrm; /***********************************************/ /* Dont fire probe if this is unsafe. */ /***********************************************/ if (!tinfo->t_doprobe) return (DTRACE_INVOP_NOP); /* * When accessing the arguments on the stack, we must * protect against accessing beyond the stack. We can * safely set NOFAULT here -- we know that interrupts * are already disabled. */ regs = (struct pt_regs *) stack; DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); stack0 = regs->c_arg0; stack1 = regs->c_arg1; stack2 = regs->c_arg2; stack3 = regs->c_arg3; stack4 = regs->c_arg4; /***********************************************/ /* Not sure if this is re-entrant safe. */ /* Might need a per-cpu buffer to */ /* write/read from. */ /***********************************************/ /***********************************************/ /* Dont do this for the return probe - the */ /* arguments are going to be junk and we */ /* will hang/panic the kernel. At some */ /* point we need something better than a */ /* entry/return indicator -- maybe an enum */ /* type. */ /***********************************************/ if (sdt->sdp_entry) { stack0 = (uintptr_t) create_buf_t((struct file *) stack0, (void *) stack1, /* uaddr */ (size_t) stack2, /* size */ (long long) stack3 /* offset */); } DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); //printk("probe %p: %p %p %p %p %p\n", &addr, stack0, stack1, stack2, stack3, stack4); dtrace_probe(sdt->sdp_id, stack0, stack0, stack0, 0, 0); // dtrace_probe(sdt->sdp_id, stack0, stack1, // stack2, stack3, stack4); return (DTRACE_INVOP_NOP); } } //printk("none in invop for dsdt\n"); return (0); }
void sdt_provide_module(void *arg, struct module *mp) { char *modname = mp->name; dtrace_mprovider_t *prov; sdt_probedesc_t *sdpd; sdt_probe_t *sdp, *prv; int idx, len; /* * Nothing to do if the module SDT probes were already created. */ if (PDATA(mp)->sdt_probe_cnt != 0) return; /* * Nothing to do if there are no SDT probes. */ if (mp->sdt_probec == 0) return; /* * Do not provide any probes unless all SDT providers have been created * for this meta-provider. */ for (prov = sdt_providers; prov->dtmp_name != NULL; prov++) { if (prov->dtmp_id == DTRACE_PROVNONE) return; } if (!sdt_provide_module_arch(arg, mp)) return; for (idx = 0, sdpd = mp->sdt_probes; idx < mp->sdt_probec; idx++, sdpd++) { char *name = sdpd->sdpd_name, *nname; int i, j; dtrace_mprovider_t *prov; dtrace_id_t id; for (prov = sdt_providers; prov->dtmp_pref != NULL; prov++) { char *prefix = prov->dtmp_pref; int len = strlen(prefix); if (strncmp(name, prefix, len) == 0) { name += len; break; } } nname = kmalloc(len = strlen(name) + 1, GFP_KERNEL); if (nname == NULL) { pr_warn("Unable to create probe %s: out-of-memory\n", name); continue; } for (i = j = 0; name[j] != '\0'; i++) { if (name[j] == '_' && name[j + 1] == '_') { nname[i] = '-'; j += 2; } else nname[i] = name[j++]; } nname[i] = '\0'; sdp = kzalloc(sizeof(sdt_probe_t), GFP_KERNEL); if (sdp == NULL) { pr_warn("Unable to create probe %s: out-of-memory\n", nname); continue; } sdp->sdp_loadcnt = 1; /* FIXME */ sdp->sdp_module = mp; sdp->sdp_name = nname; sdp->sdp_namelen = len; sdp->sdp_provider = prov; if ((id = dtrace_probe_lookup(prov->dtmp_id, modname, sdpd->sdpd_func, nname)) != DTRACE_IDNONE) { prv = dtrace_probe_arg(prov->dtmp_id, id); ASSERT(prv != NULL); sdp->sdp_next = prv->sdp_next; sdp->sdp_id = id; prv->sdp_next = sdp; } else { sdp->sdp_id = dtrace_probe_create(prov->dtmp_id, modname, sdpd->sdpd_func, nname, SDT_AFRAMES, sdp); PDATA(mp)->sdt_probe_cnt++; } sdp->sdp_hashnext = sdt_probetab[ SDT_ADDR2NDX(sdpd->sdpd_offset)]; sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; sdp->sdp_patchpoint = (asm_instr_t *)sdpd->sdpd_offset; sdt_provide_probe_arch(sdp, mp, idx); } }