Beispiel #1
0
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;
}
Beispiel #2
0
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);
	}
}
Beispiel #3
0
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;
}
Beispiel #4
0
/*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);
}
Beispiel #6
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);
}
Beispiel #7
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
}
Beispiel #9
0
/*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);
}
Beispiel #10
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);
	}
}