⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fbt.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 3 页
字号:
		}	}	/*	 * And mark the locals used in the restore.	 */	rs1 = FBT_FMT3_RS1(restore);	FBT_REG_MARKLOCAL(locals, rs1);	if (!FBT_FMT3_ISIMM(restore)) {		uint32_t rs2 = FBT_FMT3_RS2(restore);		FBT_REG_MARKLOCAL(locals, rs2);	}	if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) {		uint32_t rs1 = FBT_FMT3_RS1(cti);		if (FBT_REG_ISVOLATILE(rs1)) {			FBT_REG_ALLOCLOCAL(local, locals);			FBT_FMT3_RS1_SET(cti, local);			*tinstr++ = FBT_MOV(rs1, local);		}		if (!FBT_FMT3_ISIMM(cti)) {			uint32_t rs2 = FBT_FMT3_RS2(cti);			if (FBT_REG_ISVOLATILE(rs2)) {				FBT_REG_ALLOCLOCAL(local, locals);				FBT_FMT3_RS2_SET(cti, local);				*tinstr++ = FBT_MOV(rs2, local);			}		}	}	rs1 = FBT_FMT3_RS1(restore);	if (FBT_REG_ISVOLATILE(rs1)) {		FBT_REG_ALLOCLOCAL(local, locals);		FBT_FMT3_RS1_SET(restore, local);		*tinstr++ = FBT_MOV(rs1, local);	}	if (!FBT_FMT3_ISIMM(restore)) {		uint32_t rs2 = FBT_FMT3_RS2(restore);		if (FBT_REG_ISVOLATILE(rs2)) {			FBT_REG_ALLOCLOCAL(local, locals);			FBT_FMT3_RS2_SET(restore, local);			*tinstr++ = FBT_MOV(rs2, local);		}	}	if (id > (uint32_t)FBT_SIMM13_MAX) {		*tinstr++ = FBT_SETHI(id, FBT_REG_O0);		*tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0);	} else {		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0);	}	if (offset > (uint32_t)FBT_SIMM13_MAX) {		*tinstr++ = FBT_SETHI(offset, FBT_REG_O1);		*tinstr++ = FBT_ORLO(FBT_REG_O1, offset, FBT_REG_O1);	} else {		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, offset, FBT_REG_O1);	}	*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe);	tinstr++;	if (FBT_FMT3_RD(restore) == FBT_REG_O0) {		/*		 * If the destination register of the restore is %o0, we		 * need to perform the implied calculation to derive the		 * return value.		 */		uint32_t add = (restore & ~FBT_FMT3_OP_MASK) | FBT_OP_ADD;		add &= ~FBT_FMT3_RD_MASK;		*tinstr++ = add | (FBT_REG_O2 << FBT_FMT3_RD_SHIFT);	} else {		*tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O2);	}	/*	 * If the control transfer instruction is %pc-relative (i.e. a	 * call), we need to reset it appropriately.	 */	if (FBT_FMT1_OP(cti) == FBT_OP_CALL) {		dest = (uintptr_t)instr + (FBT_FMT1_DISP30(cti) << 2);		*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dest);		tinstr++;	} else {		*tinstr++ = cti;	}	*tinstr++ = restore;	tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next;	tramp->fbtt_next = (uintptr_t)tinstr;	return (FBT_BAA(instr, va));}static uint32_tfbt_patch_retl(uint32_t *instr, uint32_t *funcbase, uint32_t *funclim,    int offset, uint32_t id, fbt_trampoline_t *tramp){	uint32_t *tinstr = (uint32_t *)tramp->fbtt_next;	uintptr_t va = tramp->fbtt_va;	uintptr_t base = tramp->fbtt_next;	uint32_t cti = *instr, dest;	int annul = 0;	FBT_COUNTER(id, fbt_retl);	if (tramp->fbtt_next + FBT_RETLENT_MAXSIZE > tramp->fbtt_limit) {		/*		 * There isn't sufficient room for this entry; return failure.		 */		return (FBT_ILLTRAP);	}	if (offset == sizeof (uint32_t) && fbt_canpatch_retl(instr - 1, 0)) {		*tinstr++ = *instr;		annul = 1;		FBT_COUNTER(id, fbt_retl_twoinstr);	} else {		if (FBT_FMT3_OP(cti) == FBT_OP_JMPL &&		    FBT_FMT3_RD(cti) != FBT_REG_O7 &&		    FBT_FMT3_RS1(cti) != FBT_REG_O7) {			annul = 1;			*tinstr++ = *(instr + 1);		}	}	*tinstr++ = FBT_SAVEIMM(FBT_REG_O6, -SA(MINFRAME), FBT_REG_O6);	if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) {		uint32_t rs1, rs2, o2i = FBT_REG_I0 - FBT_REG_O0;		/*		 * If we have a jmpl and it's in terms of output registers, we		 * need to rewrite it to be in terms of the corresponding input		 * registers.  If it's in terms of the globals, we'll rewrite		 * it to be in terms of locals.		 */		rs1 = FBT_FMT3_RS1(cti);		if (FBT_REG_ISOUTPUT(rs1))			rs1 += o2i;		if (FBT_REG_ISGLOBAL(rs1)) {			*tinstr++ = FBT_MOV(rs1, FBT_REG_L0);			rs1 = FBT_REG_L0;		}		FBT_FMT3_RS1_SET(cti, rs1);		if (!FBT_FMT3_ISIMM(cti)) {			rs2 = FBT_FMT3_RS2(cti);			if (FBT_REG_ISOUTPUT(rs2))				rs2 += o2i;			if (FBT_REG_ISGLOBAL(rs2)) {				*tinstr++ = FBT_MOV(rs2, FBT_REG_L1);				rs2 = FBT_REG_L1;			}			FBT_FMT3_RS2_SET(cti, rs2);		}		/*		 * Now we need to check the rd and source register for the jmpl;		 * If neither rd nor the source register is %o7, then we might		 * have a jmp that is actually part of a jump table.  We need		 * to generate the code to compare it to the base and limit of		 * the function.		 */		if (FBT_FMT3_RD(cti) != FBT_REG_O7 && rs1 != FBT_REG_I7) {			uintptr_t base = (uintptr_t)funcbase;			uintptr_t limit = (uintptr_t)funclim;			FBT_COUNTER(id, fbt_retl_jmptab);			if (FBT_FMT3_ISIMM(cti)) {				*tinstr++ = FBT_ADDSIMM13(rs1,				    FBT_FMT3_SIMM13(cti), FBT_REG_L2);			} else {				*tinstr++ = FBT_ADD(rs1, rs2, FBT_REG_L2);			}			*tinstr++ = FBT_SETHI(base, FBT_REG_L3);			*tinstr++ = FBT_ORLO(FBT_REG_L3, base, FBT_REG_L3);			*tinstr++ = FBT_CMP(FBT_REG_L2, FBT_REG_L3);			*tinstr++ = FBT_BL(0, 8 * sizeof (uint32_t));			*tinstr++ = FBT_SETHI(limit, FBT_REG_L3);			*tinstr++ = FBT_ORLO(FBT_REG_L3, limit, FBT_REG_L3);			*tinstr++ = FBT_CMP(FBT_REG_L2, FBT_REG_L3);			*tinstr++ = FBT_BGE(0, 4 * sizeof (uint32_t));			*tinstr++ = FBT_SETHI(0, FBT_REG_G0);			*tinstr++ = cti;			*tinstr++ = FBT_RESTORE(FBT_REG_G0,			    FBT_REG_G0, FBT_REG_G0);		}	}	if (id > (uint32_t)FBT_SIMM13_MAX) {		*tinstr++ = FBT_SETHI(id, FBT_REG_O0);		*tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0);	} else {		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0);	}	if (offset > (uint32_t)FBT_SIMM13_MAX) {		*tinstr++ = FBT_SETHI(offset, FBT_REG_O1);		*tinstr++ = FBT_ORLO(FBT_REG_O1, offset, FBT_REG_O1);	} else {		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, offset, FBT_REG_O1);	}	*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe);	tinstr++;	*tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O2);	/*	 * If the control transfer instruction is %pc-relative (i.e. a	 * call), we need to reset it appropriately.	 */	if (FBT_FMT1_OP(cti) == FBT_OP_CALL) {		FBT_COUNTER(id, fbt_retl_tailcall);		dest = (uintptr_t)instr + (FBT_FMT1_DISP30(cti) << 2);		*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dest);		tinstr++;		annul = 1;	} else {		if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) {			*tinstr++ = cti;			if (FBT_FMT3_RD(cti) == FBT_REG_O7) {				FBT_COUNTER(id, fbt_retl_tailjmpl);				annul = 1;			}		} else {			*tinstr++ = FBT_RET;		}	}	*tinstr++ = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0);	tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next;	tramp->fbtt_next = (uintptr_t)tinstr;	return (annul ? FBT_BAA(instr, va) : FBT_BA(instr, va));}/*ARGSUSED*/static voidfbt_provide_module(void *arg, struct modctl *ctl){	struct module *mp = ctl->mod_mp;	char *modname = ctl->mod_modname;	char *str = mp->strings;	int nsyms = mp->nsyms;	Shdr *symhdr = mp->symhdr;	size_t symsize;	char *name;	int i;	fbt_probe_t *fbt, *retfbt;	fbt_trampoline_t tramp;	uintptr_t offset;	int primary = 0;	ctf_file_t *fp = NULL;	int error;	int estimate = 1;	uint32_t faketramp[50];	size_t fbt_size = 0;	/*	 * Employees of dtrace and their families are ineligible.  Void	 * where prohibited.	 */	if (strcmp(modname, "dtrace") == 0)		return;	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;		}	}	/*	 * 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;	if (mp->fbt_nentries) {		/*		 * This module has some FBT entries allocated; we're afraid		 * to screw with it.		 */		return;	}	if (mp->fbt_tab != NULL)		estimate = 0;	/*	 * This is a hack for unix/genunix/krtld.	 */	primary = vmem_contains(heap_arena, (void *)ctl,	    sizeof (struct modctl)) == 0;	kobj_textwin_alloc(mp);	/*	 * Open the CTF data for the module.  We'll use this to determine the	 * functions that can be instrumented.  Note that this call can fail,	 * in which case we'll use heuristics to determine the functions that	 * can be instrumented.  (But in particular, leaf functions will not be	 * instrumented.)	 */	fp = ctf_modopen(mp, &error);forreal:	if (!estimate) {		tramp.fbtt_next =		    (uintptr_t)fbt_trampoline_map((uintptr_t)mp->fbt_tab,		    mp->fbt_size);		tramp.fbtt_limit = tramp.fbtt_next + mp->fbt_size;		tramp.fbtt_va = (uintptr_t)mp->fbt_tab;	}	for (i = 1; i < nsyms; i++) {		ctf_funcinfo_t f;		uint32_t *instr, *base, *limit;		Sym *sym = (Sym *)(symhdr->sh_addr + i * symsize);		int have_ctf = 0, is_leaf = 0, nargs, cti = 0;		int (*canpatch)(uint32_t *, int);		uint32_t (*patch)(uint32_t *, uint32_t *, uint32_t *, int,		    uint32_t, fbt_trampoline_t *);		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;		name = str + sym->st_name;		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, "kdi_") == 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 (strstr(name, "__relocatable") != NULL) {			/*			 * Anything with the string "__relocatable" anywhere			 * in the function name is considered to be a function			 * that may be manually relocated before execution.			 * Because FBT uses a PC-relative technique for			 * instrumentation, these functions cannot safely			 * be instrumented by us.			 */			continue;		}		if (strstr(name, "ip_ocsum") == name) {			/*			 * The ip_ocsum_* family of routines are all ABI			 * violators.  (They expect incoming arguments in the			 * globals!)  Break the ABI?  No soup for you!			 */			continue;		}		/*		 * We want to scan the function for one (and only one) save.		 * Any more indicates that something fancy is going on.		 */		base = (uint32_t *)sym->st_value;		limit = (uint32_t *)(sym->st_value + sym->st_size);		/*		 * We don't want to interpose on the module stubs.		 */		if (base >= (uint32_t *)stubs_base &&		    base <= (uint32_t *)stubs_end)			continue;		/*		 * We can't safely trace a zero-length function...		 */		if (base == limit)			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;		instr = base;		/*		 * While we try hard to only trace safe functions (that is,		 * functions at TL=0), one unsafe function manages to otherwise		 * appear safe:  prom_trap().  We could discover prom_trap()		 * if we added an additional rule:  in order to trace a		 * function, we must either (a) discover a restore or (b)		 * determine that the function does not have any unlinked		 * control transfers to another function (i.e., the function		 * never returns).  Unfortunately, as of this writing, one		 * legitimate function (resume_from_zombie()) transfers		 * control to a different function (_resume_from_idle())		 * without executing a restore.  Barring a rule to figure out		 * that resume_from_zombie() is safe while prom_trap() is not,		 * we resort to hard-coding prom_trap() here.		 */		if (strcmp(name, "prom_trap") == 0)			continue;		if (fp != NULL && ctf_func_info(fp, i, &f) != CTF_ERR) {			nargs = f.ctc_argc;			have_ctf = 1;		} else {			nargs = 32;		}		/*		 * If the first instruction of the function is a branch and		 * it's not a branch-always-not-annulled, we're going to refuse		 * to patch it.		 */		if ((*instr & FBT_OP_MASK) == FBT_OP0 &&		    (*instr & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI) {			if (!FBT_IS_BA(*instr)) {				if (have_ctf) {					cmn_err(CE_NOTE, "cannot instrument %s:"					    " begins with non-ba CTI", name);				}				continue;			}		}		while (!FBT_IS_SAVE(*instr)) {			/*			 * Before we assume that this is a leaf routine, check			 * forward in the basic block for a save.			 */			int op = *instr & FBT_OP_MASK;			int op2 = *instr & FBT_FMT2_OP2_MASK;			if (op == FBT_OP0 && op2 != FBT_FMT2_OP2_SETHI) {				/*				 * This is a CTI.  If we see a subsequent				 * save, we will refuse to process this				 * routine unless both of the following are				 * true:				 *				 *  (a)	The branch is not annulled				 *				 *  (b)	The subsequent save is in the delay				 *	slot of the branch				 */				if ((*instr & FBT_ANNUL) ||				    !FBT_IS_SAVE(*(instr + 1))) {					cti = 1;				} else {					instr++;					break;				}			}			if (op == FBT_OP1)				cti = 1;			if (++instr == limit)				break;		}		if (instr < limit && cti) {			/*			 * If we found a CTI before the save, we need to not			 * do anything.  But if we have CTF information, this			 * is weird enough that it merits a message.			 */			if (!have_ctf)				continue;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -