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

📄 fbt.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident	"@(#)fbt.c	1.8	04/12/18 SMI"#include <sys/errno.h>#include <sys/stat.h>#include <sys/modctl.h>#include <sys/conf.h>#include <sys/systm.h>#include <sys/ddi.h>#include <sys/sunddi.h>#include <sys/cpuvar.h>#include <sys/kmem.h>#include <sys/strsubr.h>#include <sys/dtrace.h>#include <sys/kobj.h>#include <sys/modctl.h>#include <sys/atomic.h>#include <vm/seg_kmem.h>#include <sys/stack.h>#include <sys/ctf_api.h>#include <sys/sysmacros.h>static dev_info_t		*fbt_devi;static dtrace_provider_id_t	fbt_id;static uintptr_t		fbt_trampoline;static caddr_t			fbt_trampoline_window;static size_t			fbt_trampoline_size;static int			fbt_verbose = 0;/* * Various interesting bean counters. */static int			fbt_entry;static int			fbt_ret;static int			fbt_retl;static int			fbt_retl_jmptab;static int			fbt_retl_twoinstr;static int			fbt_retl_tailcall;static int			fbt_retl_tailjmpl;static int			fbt_leaf_functions;extern char			stubs_base[];extern char			stubs_end[];#define	FBT_REG_G0		0#define	FBT_REG_G1		1#define	FBT_REG_O0		8#define	FBT_REG_O1		9#define	FBT_REG_O2		10#define	FBT_REG_O3		11#define	FBT_REG_O4		12#define	FBT_REG_O5		13#define	FBT_REG_O6		14#define	FBT_REG_O7		15#define	FBT_REG_I0		24#define	FBT_REG_I1		25#define	FBT_REG_I2		26#define	FBT_REG_I3		27#define	FBT_REG_I4		28#define	FBT_REG_I7		31#define	FBT_REG_L0		16#define	FBT_REG_L1		17#define	FBT_REG_L2		18#define	FBT_REG_L3		19#define	FBT_REG_ISGLOBAL(r)	((r) < 8)#define	FBT_REG_ISOUTPUT(r)	((r) >= 8 && (r) < 16)#define	FBT_REG_ISLOCAL(r)	((r) >= 16 && (r) < 24)#define	FBT_REG_ISVOLATILE(r)	\	((FBT_REG_ISGLOBAL(r) || FBT_REG_ISOUTPUT(r)) && (r) != FBT_REG_G0)#define	FBT_REG_NLOCALS		8#define	FBT_REG_MARKLOCAL(locals, r)	\	if (FBT_REG_ISLOCAL(r)) \		(locals)[(r) - FBT_REG_L0] = 1;#define	FBT_REG_INITLOCALS(local, locals)	\	for ((local) = 0; (local) < FBT_REG_NLOCALS; (local)++)  \		(locals)[(local)] = 0; \	(local) = FBT_REG_L0#define	FBT_REG_ALLOCLOCAL(local, locals)	\	while ((locals)[(local) - FBT_REG_L0]) \		(local)++; \	(locals)[(local) - FBT_REG_L0] = 1;#define	FBT_OP_MASK		0xc0000000#define	FBT_OP_SHIFT		30#define	FBT_OP(val)		((val) & FBT_FMT1_MASK)#define	FBT_SIMM13_MASK		0x1fff#define	FBT_SIMM13_MAX		((int32_t)0xfff)#define	FBT_IMM22_MASK		0x3fffff#define	FBT_IMM22_SHIFT		10#define	FBT_IMM10_MASK		0x3ff#define	FBT_DISP30_MASK		0x3fffffff#define	FBT_DISP30(from, to)	\	(((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP30_MASK)#define	FBT_DISP22_MASK		0x3fffff#define	FBT_DISP22(from, to)	\	(((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP22_MASK)#define	FBT_OP0			(((uint32_t)0) << FBT_OP_SHIFT)#define	FBT_OP1			(((uint32_t)1) << FBT_OP_SHIFT)#define	FBT_OP2			(((uint32_t)2) << FBT_OP_SHIFT)#define	FBT_ILLTRAP		0#define	FBT_ANNUL_SHIFT		29#define	FBT_ANNUL		(1 << FBT_ANNUL_SHIFT)#define	FBT_FMT3_OP3_SHIFT	19#define	FBT_FMT3_OP_MASK	0xc1f80000#define	FBT_FMT3_OP(val)	((val) & FBT_FMT3_OP_MASK)#define	FBT_FMT3_RD_SHIFT	25#define	FBT_FMT3_RD_MASK	(0x1f << FBT_FMT3_RD_SHIFT)#define	FBT_FMT3_RD(val)	\	(((val) & FBT_FMT3_RD_MASK) >> FBT_FMT3_RD_SHIFT)#define	FBT_FMT3_RS1_SHIFT	14#define	FBT_FMT3_RS1_MASK	(0x1f << FBT_FMT3_RS1_SHIFT)#define	FBT_FMT3_RS1(val)	\	(((val) & FBT_FMT3_RS1_MASK) >> FBT_FMT3_RS1_SHIFT)#define	FBT_FMT3_RS1_SET(val, rs1) \	(val) = ((val) & ~FBT_FMT3_RS1_MASK) | ((rs1) << FBT_FMT3_RS1_SHIFT)#define	FBT_FMT3_RS2_SHIFT	0#define	FBT_FMT3_RS2_MASK	(0x1f << FBT_FMT3_RS2_SHIFT)#define	FBT_FMT3_RS2(val)	\	(((val) & FBT_FMT3_RS2_MASK) >> FBT_FMT3_RS2_SHIFT)#define	FBT_FMT3_RS2_SET(val, rs2) \	(val) = ((val) & ~FBT_FMT3_RS2_MASK) | ((rs2) << FBT_FMT3_RS2_SHIFT)#define	FBT_FMT3_IMM_SHIFT	13#define	FBT_FMT3_IMM		(1 << FBT_FMT3_IMM_SHIFT)#define	FBT_FMT3_SIMM13_MASK	FBT_SIMM13_MASK#define	FBT_FMT3_ISIMM(val)	((val) & FBT_FMT3_IMM)#define	FBT_FMT3_SIMM13(val)	((val) & FBT_FMT3_SIMM13_MASK)#define	FBT_FMT2_OP2_SHIFT	22#define	FBT_FMT2_OP2_MASK	(0x7 << FBT_FMT2_OP2_SHIFT)#define	FBT_FMT2_RD_SHIFT	25#define	FBT_FMT1_OP(val)	((val) & FBT_OP_MASK)#define	FBT_FMT1_DISP30(val)	((val) & FBT_DISP30_MASK)#define	FBT_FMT2_OP2_BCC	(0x02 << FBT_FMT2_OP2_SHIFT)#define	FBT_FMT2_OP2_SETHI	(0x04 << FBT_FMT2_OP2_SHIFT)#define	FBT_FMT2_COND_SHIFT	25#define	FBT_FMT2_COND_BA	(0x8 << FBT_FMT2_COND_SHIFT)#define	FBT_FMT2_COND_BL	(0x3 << FBT_FMT2_COND_SHIFT)#define	FBT_FMT2_COND_BGE	(0xb << FBT_FMT2_COND_SHIFT)#define	FBT_OP_RESTORE		(FBT_OP2 | (0x3d << FBT_FMT3_OP3_SHIFT))#define	FBT_OP_SAVE		(FBT_OP2 | (0x3c << FBT_FMT3_OP3_SHIFT))#define	FBT_OP_JMPL		(FBT_OP2 | (0x38 << FBT_FMT3_OP3_SHIFT))#define	FBT_OP_CALL		FBT_OP1#define	FBT_OP_SETHI		(FBT_OP0 | FBT_FMT2_OP2_SETHI)#define	FBT_OP_ADD		(FBT_OP2 | (0x00 << FBT_FMT3_OP3_SHIFT))#define	FBT_OP_OR		(FBT_OP2 | (0x02 << FBT_FMT3_OP3_SHIFT))#define	FBT_OP_SUB		(FBT_OP2 | (0x04 << FBT_FMT3_OP3_SHIFT))#define	FBT_OP_CC		(FBT_OP2 | (0x10 << FBT_FMT3_OP3_SHIFT))#define	FBT_OP_BA		(FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BA)#define	FBT_OP_BL		(FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BL)#define	FBT_OP_BGE		(FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BGE)#define	FBT_ORLO(rs, val, rd) \	(FBT_OP_OR | ((rs) << FBT_FMT3_RS1_SHIFT) | \	((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_IMM10_MASK))#define	FBT_ORSIMM13(rs, val, rd) \	(FBT_OP_OR | ((rs) << FBT_FMT3_RS1_SHIFT) | \	((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK))#define	FBT_ADDSIMM13(rs, val, rd) \	(FBT_OP_ADD | ((rs) << FBT_FMT3_RS1_SHIFT) | \	((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK))#define	FBT_ADD(rs1, rs2, rd) \	(FBT_OP_ADD | ((rs1) << FBT_FMT3_RS1_SHIFT) | \	((rs2) << FBT_FMT3_RS2_SHIFT) | ((rd) << FBT_FMT3_RD_SHIFT))#define	FBT_CMP(rs1, rs2) \	(FBT_OP_SUB | FBT_OP_CC | ((rs1) << FBT_FMT3_RS1_SHIFT) | \	((rs2) << FBT_FMT3_RS2_SHIFT) | (FBT_REG_G0 << FBT_FMT3_RD_SHIFT))#define	FBT_MOV(rs, rd) \	(FBT_OP_OR | (FBT_REG_G0 << FBT_FMT3_RS1_SHIFT) | \	((rs) << FBT_FMT3_RS2_SHIFT) | ((rd) << FBT_FMT3_RD_SHIFT))#define	FBT_SETHI(val, reg)	\	(FBT_OP_SETHI | (reg << FBT_FMT2_RD_SHIFT) | \	((val >> FBT_IMM22_SHIFT) & FBT_IMM22_MASK))#define	FBT_CALL(orig, dest)	(FBT_OP_CALL | FBT_DISP30(orig, dest))#define	FBT_RET \	(FBT_OP_JMPL | (FBT_REG_I7 << FBT_FMT3_RS1_SHIFT) | \	(FBT_REG_G0 << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | (sizeof (pc_t) << 1))#define	FBT_SAVEIMM(rd, val, rs1)	\	(FBT_OP_SAVE | ((rs1) << FBT_FMT3_RS1_SHIFT) | \	((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK))#define	FBT_RESTORE(rd, rs1, rs2)	\	(FBT_OP_RESTORE | ((rs1) << FBT_FMT3_RS1_SHIFT) | \	((rd) << FBT_FMT3_RD_SHIFT) | ((rs2) << FBT_FMT3_RS2_SHIFT))#define	FBT_BA(orig, dest)	(FBT_OP_BA | FBT_DISP22(orig, dest))#define	FBT_BAA(orig, dest)	(FBT_BA(orig, dest) | FBT_ANNUL)#define	FBT_BL(orig, dest)	(FBT_OP_BL | FBT_DISP22(orig, dest))#define	FBT_BGE(orig, dest)	(FBT_OP_BGE | FBT_DISP22(orig, dest))#define	FBT_BDEST(va, instr)	((uintptr_t)(va) + \	(((int32_t)(((instr) & FBT_DISP22_MASK) << 10)) >> 8))/* * We're only going to treat a save as safe if (a) both rs1 and rd are * %sp and (b) if the instruction has a simm, the value isn't 0. */#define	FBT_IS_SAVE(instr)	\	(FBT_FMT3_OP(instr) == FBT_OP_SAVE && \	FBT_FMT3_RD(instr) == FBT_REG_O6 && \	FBT_FMT3_RS1(instr) == FBT_REG_O6 && \	!(FBT_FMT3_ISIMM(instr) && FBT_FMT3_SIMM13(instr) == 0))#define	FBT_IS_BA(instr)	(((instr) & ~FBT_DISP22_MASK) == FBT_OP_BA)#define	FBT_ENTRY	"entry"#define	FBT_RETURN	"return"#define	FBT_ESTIMATE_ID		(UINT32_MAX)#define	FBT_COUNTER(id, count)	if ((id) != FBT_ESTIMATE_ID) (count)++#define	FBT_ENTENT_MAXSIZE	(12 * sizeof (uint32_t))#define	FBT_RETENT_MAXSIZE	(11 * sizeof (uint32_t))#define	FBT_RETLENT_MAXSIZE	(23 * sizeof (uint32_t))#define	FBT_ENT_MAXSIZE		\	MAX(MAX(FBT_ENTENT_MAXSIZE, FBT_RETENT_MAXSIZE), FBT_RETLENT_MAXSIZE)typedef struct fbt_probe {	char		*fbtp_name;	dtrace_id_t	fbtp_id;	uintptr_t	fbtp_addr;	struct modctl	*fbtp_ctl;	int		fbtp_loadcnt;	int		fbtp_symndx;	int		fbtp_primary;	int		fbtp_return;	uint32_t	*fbtp_patchpoint;	uint32_t	fbtp_patchval;	uint32_t	fbtp_savedval;	struct fbt_probe *fbtp_next;} fbt_probe_t;typedef struct fbt_trampoline {	uintptr_t	fbtt_va;	uintptr_t	fbtt_limit;	uintptr_t	fbtt_next;} fbt_trampoline_t;static caddr_tfbt_trampoline_map(uintptr_t tramp, size_t size){	uintptr_t offs;	ASSERT(fbt_trampoline_window == NULL);	ASSERT(fbt_trampoline_size == 0);	ASSERT(fbt_trampoline == NULL);	size += tramp & PAGEOFFSET;	fbt_trampoline = tramp & PAGEMASK;	fbt_trampoline_size = (size + PAGESIZE - 1) & PAGEMASK;	fbt_trampoline_window =	    vmem_alloc(heap_arena, fbt_trampoline_size, VM_SLEEP);	for (offs = 0; offs < fbt_trampoline_size; offs += PAGESIZE) {		hat_devload(kas.a_hat, fbt_trampoline_window + offs, PAGESIZE,		    hat_getpfnum(kas.a_hat, (caddr_t)fbt_trampoline + offs),		    PROT_READ | PROT_WRITE,		    HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);	}	return (fbt_trampoline_window + (tramp & PAGEOFFSET));}static voidfbt_trampoline_unmap(){	ASSERT(fbt_trampoline_window != NULL);	ASSERT(fbt_trampoline_size != 0);	ASSERT(fbt_trampoline != NULL);	membar_enter();	sync_icache((caddr_t)fbt_trampoline, fbt_trampoline_size);	sync_icache(fbt_trampoline_window, fbt_trampoline_size);	hat_unload(kas.a_hat, fbt_trampoline_window, fbt_trampoline_size,	    HAT_UNLOAD_UNLOCK);	vmem_free(heap_arena, fbt_trampoline_window, fbt_trampoline_size);	fbt_trampoline_window = NULL;	fbt_trampoline = NULL;	fbt_trampoline_size = 0;}static uintptr_tfbt_patch_entry(uint32_t *instr, uint32_t id, fbt_trampoline_t *tramp,    int nargs){	uint32_t *tinstr = (uint32_t *)tramp->fbtt_next;	uint32_t save = *instr;	uintptr_t va = tramp->fbtt_va;	uintptr_t base = tramp->fbtt_next;	if (tramp->fbtt_next + FBT_ENTENT_MAXSIZE > tramp->fbtt_limit) {		/*		 * There isn't sufficient room for this entry; return failure.		 */		return (0);	}	FBT_COUNTER(id, fbt_entry);	if (FBT_IS_SAVE(save)) {		*tinstr++ = save;	} else {		*tinstr++ = FBT_SAVEIMM(FBT_REG_O6, -SA(MINFRAME), FBT_REG_O6);	}	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 (nargs >= 1)		*tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O1);	if (nargs >= 2)		*tinstr++ = FBT_MOV(FBT_REG_I1, FBT_REG_O2);	if (nargs >= 3)		*tinstr++ = FBT_MOV(FBT_REG_I2, FBT_REG_O3);	if (nargs >= 4)		*tinstr++ = FBT_MOV(FBT_REG_I3, FBT_REG_O4);	if (nargs >= 5)		*tinstr++ = FBT_MOV(FBT_REG_I4, FBT_REG_O5);	if (FBT_IS_SAVE(save)) {		uintptr_t ret = (uintptr_t)instr - 4;		*tinstr++ = FBT_SETHI(ret, FBT_REG_G1);		*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe);		tinstr++;		*tinstr++ = FBT_ORLO(FBT_REG_G1, ret, FBT_REG_O7);	} else {		uintptr_t slot = *--tinstr;		uintptr_t ret = (uintptr_t)instr + 4;		uint32_t delay = *instr;		*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe);		tinstr++;		*tinstr++ = slot;		*tinstr++ = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0);		if (FBT_IS_BA(save)) {			/*			 * This is a special case:  we'll return directly			 * to the destination of the branch, putting the			 * save in the delay slot.			 */			ret = FBT_BDEST(instr, *instr);			delay = *(instr + 1);		}		*tinstr = FBT_BA((uintptr_t)tinstr - base + va, ret);		tinstr++;		*tinstr++ = delay;	}	tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next;	tramp->fbtt_next = (uintptr_t)tinstr;	return (1);}/* * We are patching control-transfer/restore couplets.  There are two variants * of couplet: * * (a)	jmpl		rs1 + (rs2 | offset), rd *	restore		rs1, rs2 | imm, rd * * (b)	call		displacement *	restore		rs1, rs2 | imm, rd * * If rd from the jmpl in (a) is something other than %g0 (a ret) or %o7 (a * call through a register), we fail. * * Note that rs1 and rs2 in the restore are potentially outputs and/or globals. * Because these registers cannot be relied upon across the call to * dtrace_probe(), we move rs1 into an unused local, ls0, and rs2 into an * unused local, ls1, and restructure the restore to be: * *	restore		ls0, ls1, rd * * Likewise, rs1 and rs2 in the jmpl of case (a) may be outputs and/or globals. * If the jmpl uses outputs or globals, we restructure it to be: * * 	jmpl		ls2 + (ls3 | offset), (%g0 | %o7) * *//*ARGSUSED*/static intfbt_canpatch_return(uint32_t *instr, int offset){	int rd;	if (FBT_FMT3_OP(*(instr + 1)) != FBT_OP_RESTORE)		return (0);	if (FBT_FMT1_OP(*instr) == FBT_OP_CALL)		return (1);	if (FBT_FMT3_OP(*instr) != FBT_OP_JMPL)		return (0);	rd = FBT_FMT3_RD(*instr);	if (rd == FBT_REG_I7 || rd == FBT_REG_O7 || rd == FBT_REG_G0)		return (1);	/*	 * We have encountered a jmpl that is storing the calling %pc in	 * some register besides %i7, %o7 or %g0.  This is strange; emit	 * a warning and fail.	 */	cmn_err(CE_NOTE, "strange jmpl at %p", (void *)instr);	return (0);}static intfbt_canpatch_retl(uint32_t *instr, int offset){	if (FBT_FMT1_OP(*instr) == FBT_OP_CALL ||	    (FBT_FMT3_OP(*instr) == FBT_OP_JMPL &&	    FBT_FMT3_RD(*instr) == FBT_REG_O7)) {		/*		 * If this is a call (or a jmpl that links into %o7), we can		 * patch it iff the next instruction uses %o7 as a destination		 * register.  Because there is an ABI responsibility to		 * restore %o7 to the value before the call/jmpl, we don't		 * particularly care how this routine is managing to restore		 * it (mov, add, ld or divx for all we care).  If it doesn't		 * seem to be restoring it at all, however, we'll refuse		 * to patch it.		 */		uint32_t delay = *(instr + 1);		uint32_t op, rd;		op = FBT_FMT1_OP(delay);		rd = FBT_FMT3_RD(delay);		if (op != FBT_OP2 || rd != FBT_REG_O7) {			cmn_err(CE_NOTE, "strange leaf jmpl/call "			    "delay at %p", (void *)(instr + 1));			return (0);		}		return (1);	}	if (offset == sizeof (uint32_t)) {		/*		 * If this is the second instruction in the function, we're		 * going to allow it to be patched if the first instruction		 * is a patchable return-from-leaf instruction.		 */		if (fbt_canpatch_retl(instr - 1, 0))			return (1);	}	if (FBT_FMT3_OP(*instr) != FBT_OP_JMPL)		return (0);	if (FBT_FMT3_RD(*instr) != FBT_REG_G0)		return (0);	return (1);}/*ARGSUSED*/static uint32_tfbt_patch_return(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;	uint32_t cti = *instr, restore = *(instr + 1), rs1, dest;	uintptr_t va = tramp->fbtt_va;	uintptr_t base = tramp->fbtt_next;	uint32_t locals[FBT_REG_NLOCALS], local;	if (tramp->fbtt_next + FBT_RETENT_MAXSIZE > tramp->fbtt_limit) {		/*		 * There isn't sufficient room for this entry; return failure.		 */		return (FBT_ILLTRAP);	}	FBT_COUNTER(id, fbt_ret);	FBT_REG_INITLOCALS(local, locals);	/*	 * Mark the locals used in the jmpl.	 */	if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) {		uint32_t rs1 = FBT_FMT3_RS1(cti);		FBT_REG_MARKLOCAL(locals, rs1);		if (!FBT_FMT3_ISIMM(cti)) {			uint32_t rs2 = FBT_FMT3_RS2(cti);			FBT_REG_MARKLOCAL(locals, rs2);

⌨️ 快捷键说明

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