Esempio n. 1
0
/*ARGSUSED*/
static void
fbt_destroy(void *arg, dtrace_id_t id, void *parg)
{
	fbt_probe_t *fbt = parg, *next, *hash, *last;
	struct modctl *ctl = fbt->fbtp_ctl;
	struct module *mp = ctl;
	int ndx;

	do {
//printk("refc=%d load=%d\n", get_refcount(mp), fbt->fbtp_loadcnt);
		if (mp != NULL && get_refcount(mp) == fbt->fbtp_loadcnt) {
			if ((get_refcount(mp) == fbt->fbtp_loadcnt &&
			    mp->state == MODULE_STATE_LIVE)) {
			    	par_module_t *pmp = par_alloc(PARD_FBT, mp, sizeof *pmp, NULL);
				if (pmp && --pmp->fbt_nentries == 0)
					par_free(PARD_FBT, pmp);
			}
		}

		/*
		 * Now we need to remove this probe from the fbt_probetab.
		 */
		ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
		last = NULL;
		hash = fbt_probetab[ndx];

		while (hash != fbt) {
			ASSERT(hash != NULL);
			last = hash;
			hash = hash->fbtp_hashnext;
		}

		if (last != NULL) {
			last->fbtp_hashnext = fbt->fbtp_hashnext;
		} else {
			fbt_probetab[ndx] = fbt->fbtp_hashnext;
		}

		next = fbt->fbtp_next;
		kmem_free(fbt, sizeof (fbt_probe_t));

		fbt = next;
	} while (fbt != NULL);
}
Esempio n. 2
0
/*ARGSUSED*/
static void
instr_provide_module(void *arg, struct modctl *ctl)
{	int	i;
	struct module *mp = (struct module *) ctl;
	char *modname = mp->name;
	char	*str = mp->strtab;
	char	*name;
    	par_module_t *pmp;

	int	init;
	/***********************************************/
	/*   Possible  memleak  here...we  allocate a  */
	/*   parallel  struct, but need to free if we  */
	/*   are offloaded.			       */
	/***********************************************/
	pmp = par_alloc(mp, sizeof *pmp, &init);
	if (pmp->fbt_nentries) {
		/*
		 * This module has some FBT entries allocated; we're afraid
		 * to screw with it.
		 */
		return;
	}

	if (dtrace_here) 
		printk("%s(%d):modname=%s num_symtab=%u\n", __FILE__, __LINE__, modname, (unsigned) mp->num_symtab);
	if (strcmp(modname, "dtracedrv") == 0)
		return;

	for (i = 1; i < mp->num_symtab; i++) {
		uint8_t *instr, *limit;
		Elf_Sym *sym = (Elf_Sym *) &mp->symtab[i];
int dtrace_here = 0;
if (strcmp(modname, "dummy") == 0) dtrace_here = 1;

		name = str + sym->st_name;
		if (sym->st_name == NULL || *name == '\0')
			continue;

		/***********************************************/
		/*   Linux re-encodes the symbol types.	       */
		/***********************************************/
		if (sym->st_info != 't' && sym->st_info != 'T')
			continue;

//		if (strstr(name, "init")) 
//			continue;
//if (sym->st_info != 'T') {printk("skip -- %02d %c:%s\n", i, sym->st_info, name); continue;}

#if 0
		if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
			continue;


		/*
		 * Weak symbols are not candidates.  This could be made to
		 * work (where weak functions and their underlying function
		 * appear as two disjoint probes), but it's not simple.
		 */
		if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
			continue;
#endif

		if (strstr(name, "dtrace_") == name &&
		    strstr(name, "dtrace_safe_") != name) {
			/*
			 * Anything beginning with "dtrace_" may be called
			 * from probe context unless it explitly indicates
			 * that it won't be called from probe context by
			 * using the prefix "dtrace_safe_".
			 */
			continue;
		}

		if (strstr(name, "dtracedrv_") == name)
			continue;

		if (strstr(name, "kdi_") == name ||
		    strstr(name, "kprobe") == name) {
			/*
			 * Anything beginning with "kdi_" is a part of the
			 * kernel debugger interface and may be called in
			 * arbitrary context -- including probe context.
			 */
			continue;
		}

		if (strcmp(name, "_init") == 0)
			continue;

		if (strcmp(name, "_fini") == 0)
			continue;

		instr = (uint8_t *)sym->st_value;
		limit = (uint8_t *)(sym->st_value + sym->st_size);
//printk("trying -- %02d %c:%s\n", i, sym->st_info, name);
//HERE();

		/***********************************************/
		/*   Ignore the init function of modules - we  */
		/*   will  never  execute them now the module  */
		/*   is loaded, and we dont want to be poking  */
		/*   potential  pages  which  dont  exist  in  */
		/*   memory or which are being used for data.  */
		/***********************************************/
		if (instr == (uint8_t *) mp->init)
			continue;

		/***********************************************/
		/*   We  do have syms that appear to point to  */
		/*   unmapped  pages.  Maybe  these are freed  */
		/*   pages after a driver loads. Double check  */
		/*   -  if /proc/kallsyms says its not there,  */
		/*   then ignore it. 			       */
		/***********************************************/
		if (!validate_ptr(instr))
			continue;

		/***********************************************/
		/*   Look  at the section this symbol is in -  */
		/*   we   dont   want   sections   which  can  */
		/*   disappear   or   have   disappeared  (eg  */
		/*   .init).				       */
		/*   					       */
		/*   I'm  not sure I follow this code for all  */
		/*   kernel  releases - if we have the field,  */
		/*   it should have a fixed meaning, but some  */
		/*   modules  have  bogus  section attributes  */
		/*   pointers   (maybe   pointers   to  freed  */
		/*   segments?). Lets be careful out there.    */
		/*   					       */
		/*   20090425  Ok  - heres the deal. In 2.6.9  */
		/*   (at   least)   the   section   table  is  */
		/*   allocated  but  only  for sections which  */
		/*   are  SHF_ALLOC.  This means the array of  */
		/*   sections    cannot    be    indexed   by  */
		/*   sym->st_shndx since the mappings are now  */
		/*   bogus  (kernel  doesnt adjust the symbol  */
		/*   section  indexes). What we need to do is  */
		/*   attempt to find the section by address.   */
		/***********************************************/
		if (!instr_in_text_seg(mp, name, sym))
			continue;

		/***********************************************/
		/*   We are good to go...		       */
		/***********************************************/
		instr_provide_function(mp, pmp,
			modname, name, 
			(uint8_t *) sym->st_value, 
			instr, limit, i);
		}
}
Esempio n. 3
0
/*ARGSUSED*/
static void
fbt_provide_module(void *arg, struct modctl *ctl)
{	int	i;
	struct module *mp = (struct module *) ctl;
	char *modname = mp->name;
	char	*str = mp->strtab;
	char	*name;
    	par_module_t *pmp;
	int	ret;

# if 0
	struct module *mp = ctl->mod_mp;
	char *str = mp->strings;
	int nsyms = mp->nsyms;
	Shdr *symhdr = mp->symhdr;
	char *name;
	size_t symsize;

	/*
	 * Employees of dtrace and their families are ineligible.  Void
	 * where prohibited.
	 */
	if (strcmp(modname, "dtrace") == 0)
		return;

TODO();
	if (ctl->mod_requisites != NULL) {
		struct modctl_list *list;

		list = (struct modctl_list *)ctl->mod_requisites;

		for (; list != NULL; list = list->modl_next) {
			if (strcmp(list->modl_modp->mod_modname, "dtrace") == 0)
				return;
		}
	}

TODO();
	/*
	 * KMDB is ineligible for instrumentation -- it may execute in
	 * any context, including probe context.
	 */
	if (strcmp(modname, "kmdbmod") == 0)
		return;

	if (str == NULL || symhdr == NULL || symhdr->sh_addr == NULL) {
		/*
		 * If this module doesn't (yet) have its string or symbol
		 * table allocated, clear out.
		 */
		return;
	}

	symsize = symhdr->sh_entsize;

# endif

	int	init;

	if (strcmp(modname, "dtracedrv") == 0)
		return;

	/***********************************************/
	/*   Possible  memleak  here...we  allocate a  */
	/*   parallel  struct, but need to free if we  */
	/*   are offloaded.			       */
	/***********************************************/
	pmp = par_alloc(PARD_FBT, mp, sizeof *pmp, &init);
	if (pmp == NULL || pmp->fbt_nentries) {
		/*
		 * This module has some FBT entries allocated; we're afraid
		 * to screw with it.
		 */
		return;
	}

	if (dtrace_here) 
		printk("%s(%d):modname=%s num_symtab=%u\n", dtrace_basename(__FILE__), __LINE__, modname, (unsigned) mp->num_symtab);

	for (i = 1; i < mp->num_symtab; i++) {
		uint8_t *instr, *limit;
		Elf_Sym *sym = (Elf_Sym *) &mp->symtab[i];
int dtrace_here = 0;
if (strcmp(modname, "dummy") == 0) dtrace_here = 1;

		name = str + sym->st_name;
		if (sym->st_name == NULL || *name == '\0')
			continue;

		/***********************************************/
		/*   Linux re-encodes the symbol types.	       */
		/***********************************************/
		if (sym->st_info != 't' && sym->st_info != 'T')
			continue;

//		if (strstr(name, "init")) 
//			continue;
//if (sym->st_info != 'T') {printk("skip -- %02d %c:%s\n", i, sym->st_info, name); continue;}

#if 0
		if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
			continue;


		/*
		 * Weak symbols are not candidates.  This could be made to
		 * work (where weak functions and their underlying function
		 * appear as two disjoint probes), but it's not simple.
		 */
		if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
			continue;
#endif

		if (strstr(name, "dtrace_") == name &&
		    strstr(name, "dtrace_safe_") != name) {
			/*
			 * Anything beginning with "dtrace_" may be called
			 * from probe context unless it explitly indicates
			 * that it won't be called from probe context by
			 * using the prefix "dtrace_safe_".
			 */
			continue;
		}

		if (strstr(name, "dtracedrv_") == name)
			continue;

		if (strstr(name, "kdi_") == name ||
		    strstr(name, "kprobe") == name) {
			/*
			 * Anything beginning with "kdi_" is a part of the
			 * kernel debugger interface and may be called in
			 * arbitrary context -- including probe context.
			 */
			continue;
		}

		/*
		 * Due to 4524008, _init and _fini may have a bloated st_size.
		 * While this bug was fixed quite some time ago, old drivers
		 * may be lurking.  We need to develop a better solution to
		 * this problem, such that correct _init and _fini functions
		 * (the vast majority) may be correctly traced.  One solution
		 * may be to scan through the entire symbol table to see if
		 * any symbol overlaps with _init.  If none does, set a bit in
		 * the module structure that this module has correct _init and
		 * _fini sizes.  This will cause some pain the first time a
		 * module is scanned, but at least it would be O(N) instead of
		 * O(N log N)...
		 */
		if (strcmp(name, "_init") == 0)
			continue;

		if (strcmp(name, "_fini") == 0)
			continue;

		/*
		 * In order to be eligible, the function must begin with the
		 * following sequence:
		 *
		 * 	pushl	%esp
		 *	movl	%esp, %ebp
		 *
		 * Note that there are two variants of encodings that generate
		 * the movl; we must check for both.  For 64-bit, we would
		 * normally insist that a function begin with the following
		 * sequence:
		 *
		 *	pushq	%rbp
		 *	movq	%rsp, %rbp
		 *
		 * However, the compiler for 64-bit often splits these two
		 * instructions -- and the first instruction in the function
		 * is often not the pushq.  As a result, on 64-bit we look
		 * for any "pushq %rbp" in the function and we instrument
		 * this with a breakpoint instruction.
		 */
		instr = (uint8_t *)sym->st_value;
		limit = (uint8_t *)(sym->st_value + sym->st_size);
//printk("trying -- %02d %c:%s\n", i, sym->st_info, name);
//HERE();

		/***********************************************/
		/*   If  we  were  called because a module is  */
		/*   loaded  after  dtrace,  then mp contains  */
		/*   references to the .init section. We want  */
		/*   to  ignore these because the pages where  */
		/*   the  code resides will go away. Not only  */
		/*   dont   we   want   to   put   probes  on  */
		/*   non-existant pages, but /proc/dtrace/fbt  */
		/*   will  have problems and, fbt_enable will  */
		/*   if  that  page is now used by some other  */
		/*   driver.				       */
		/***********************************************/
		if (mp->module_init && mp->init_size &&
		    instr >= (uint8_t *) mp->module_init && 
		    instr < (uint8_t *) mp->module_init + mp->init_size) {
		    	continue;
		}

		/***********************************************/
		/*   We  do have syms that appear to point to  */
		/*   unmapped  pages.  Maybe  these are freed  */
		/*   pages after a driver loads. Double check  */
		/*   -  if /proc/kallsyms says its not there,  */
		/*   then ignore it. 			       */
		/***********************************************/
		if (!validate_ptr(instr))
			continue;

		/***********************************************/
		/*   Look  at the section this symbol is in -  */
		/*   we   dont   want   sections   which  can  */
		/*   disappear   or   have   disappeared  (eg  */
		/*   .init).				       */
		/*   					       */
		/*   I'm  not sure I follow this code for all  */
		/*   kernel  releases - if we have the field,  */
		/*   it should have a fixed meaning, but some  */
		/*   modules  have  bogus  section attributes  */
		/*   pointers   (maybe   pointers   to  freed  */
		/*   segments?). Lets be careful out there.    */
		/*   					       */
		/*   20090425  Ok  - heres the deal. In 2.6.9  */
		/*   (at   least)   the   section   table  is  */
		/*   allocated  but  only  for sections which  */
		/*   are  SHF_ALLOC.  This means the array of  */
		/*   sections    cannot    be    indexed   by  */
		/*   sym->st_shndx since the mappings are now  */
		/*   bogus  (kernel  doesnt adjust the symbol  */
		/*   section  indexes). What we need to do is  */
		/*   attempt to find the section by address.   */
		/***********************************************/
		ret = instr_in_text_seg(mp, name, sym);
		if (!ret)
			continue;

		/***********************************************/
		/*   We are good to go...		       */
		/***********************************************/
		fbt_provide_function(mp, pmp,
			modname, name, 
			(uint8_t *) sym->st_value, 
			instr, limit, i);
	}
}