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

📄 dtrace.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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	"@(#)dtrace.c	1.28	04/12/18 SMI"/* * DTrace - Dynamic Tracing for Solaris * * This is the implementation of the Solaris Dynamic Tracing framework * (DTrace).  The user-visible interface to DTrace is described at length in * the "Solaris Dynamic Tracing Guide".  The interfaces between the libdtrace * library, the in-kernel DTrace framework, and the DTrace providers are * described in the block comments in the <sys/dtrace.h> header file.  The * internal architecture of DTrace is described in the block comments in the * <sys/dtrace_impl.h> header file.  The comments contained within the DTrace * implementation very much assume mastery of all of these sources; if one has * an unanswered question about the implementation, one should consult them * first. * * The functions here are ordered roughly as follows: * *   - Probe context functions *   - Probe hashing functions *   - Non-probe context utility functions *   - Matching functions *   - Provider-to-Framework API functions *   - Probe management functions *   - DIF object functions *   - Format functions *   - Predicate functions *   - ECB functions *   - Buffer functions *   - Enabling functions *   - DOF functions *   - Anonymous enabling functions *   - Consumer state functions *   - Helper functions *   - Hook functions *   - Driver cookbook functions * * Each group of functions begins with a block comment labelled the "DTrace * [Group] Functions", allowing one to find each block by searching forward * on capital-f functions. */#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/sysmacros.h>#include <sys/dtrace_impl.h>#include <sys/atomic.h>#include <sys/cmn_err.h>#include <sys/mutex_impl.h>#include <sys/rwlock_impl.h>#include <sys/ctf_api.h>#include <sys/panic.h>#include <sys/priv_impl.h>#include <sys/policy.h>#include <sys/cred_impl.h>#include <sys/procfs_isa.h>#include <sys/taskq.h>#include <sys/mkdev.h>#include <sys/kdi.h>#include <sys/zone.h>/* * DTrace Tunable Variables * * The following variables may be tuned by adding a line to /etc/system that * includes both the name of the DTrace module ("dtrace") and the name of the * variable.  For example: * *   set dtrace:dtrace_destructive_disallow = 1 * * In general, the only variables that one should be tuning this way are those * that affect system-wide DTrace behavior, and for which the default behavior * is undesirable.  Most of these variables are tunable on a per-consumer * basis using DTrace options, and need not be tuned on a system-wide basis. */int		dtrace_destructive_disallow = 0;dtrace_optval_t	dtrace_nonroot_maxsize = (16 * 1024 * 1024);size_t		dtrace_difo_maxsize = (256 * 1024);dtrace_optval_t	dtrace_dof_maxsize = (256 * 1024);size_t		dtrace_global_maxsize = (16 * 1024);size_t		dtrace_actions_max = (16 * 1024);dtrace_optval_t	dtrace_helper_actions_max = 32;dtrace_optval_t	dtrace_helper_providers_max = 32;dtrace_optval_t	dtrace_dstate_defsize = (1 * 1024 * 1024);size_t		dtrace_strsize_default = 256;dtrace_optval_t	dtrace_cleanrate_default = 9900990;		/* 101 hz */dtrace_optval_t	dtrace_cleanrate_min = 200000;			/* 5000 hz */dtrace_optval_t	dtrace_cleanrate_max = (uint64_t)60 * NANOSEC;	/* 1/minute */dtrace_optval_t	dtrace_aggrate_default = NANOSEC;		/* 1 hz */dtrace_optval_t	dtrace_statusrate_default = NANOSEC;		/* 1 hz */dtrace_optval_t dtrace_statusrate_max = (hrtime_t)10 * NANOSEC;	 /* 6/minute */dtrace_optval_t	dtrace_switchrate_default = NANOSEC;		/* 1 hz */dtrace_optval_t	dtrace_nspec_default = 1;dtrace_optval_t	dtrace_specsize_default = 32 * 1024;dtrace_optval_t dtrace_stackframes_default = 20;dtrace_optval_t dtrace_ustackframes_default = 20;dtrace_optval_t dtrace_jstackframes_default = 50;dtrace_optval_t dtrace_jstackstrsize_default = 512;int		dtrace_msgdsize_max = 128;hrtime_t	dtrace_chill_max = 500 * (NANOSEC / MILLISEC);	/* 500 ms */hrtime_t	dtrace_chill_interval = NANOSEC;		/* 1000 ms */int		dtrace_devdepth_max = 32;int		dtrace_err_verbose;hrtime_t	dtrace_deadman_interval = NANOSEC;hrtime_t	dtrace_deadman_timeout = (hrtime_t)10 * NANOSEC;hrtime_t	dtrace_deadman_user = (hrtime_t)30 * NANOSEC;/* * DTrace External Variables * * As dtrace(7D) is a kernel module, any DTrace variables are obviously * available to DTrace consumers via the backtick (`) syntax.  One of these, * dtrace_zero, is made deliberately so:  it is provided as a source of * well-known, zero-filled memory.  While this variable is not documented, * it is used by some translators as an implementation detail. */const char	dtrace_zero[256] = { 0 };	/* zero-filled memory *//* * DTrace Internal Variables */static dev_info_t	*dtrace_devi;		/* device info */static vmem_t		*dtrace_arena;		/* probe ID arena */static vmem_t		*dtrace_minor;		/* minor number arena */static taskq_t		*dtrace_taskq;		/* task queue */static dtrace_probe_t	**dtrace_probes;	/* array of all probes */static int		dtrace_nprobes;		/* number of probes */static dtrace_provider_t *dtrace_provider;	/* provider list */static dtrace_meta_t	*dtrace_meta_pid;	/* user-land meta provider */static int		dtrace_opens;		/* number of opens */static void		*dtrace_softstate;	/* softstate pointer */static dtrace_hash_t	*dtrace_bymod;		/* probes hashed by module */static dtrace_hash_t	*dtrace_byfunc;		/* probes hashed by function */static dtrace_hash_t	*dtrace_byname;		/* probes hashed by name */static dtrace_toxrange_t *dtrace_toxrange;	/* toxic range array */static int		dtrace_toxranges;	/* number of toxic ranges */static int		dtrace_toxranges_max;	/* size of toxic range array */static dtrace_anon_t	dtrace_anon;		/* anonymous enabling */static kmem_cache_t	*dtrace_state_cache;	/* cache for dynamic state */static uint64_t		dtrace_vtime_references; /* number of vtimestamp refs */static kthread_t	*dtrace_panicked;	/* panicking thread */static dtrace_ecb_t	*dtrace_ecb_create_cache; /* cached created ECB */static int		dtrace_double_errors;	/* ERRORs inducing error */static dtrace_state_t	*dtrace_state;		/* temporary variable */static int		dtrace_error;		/* temporary variable *//* * List of helpers that must be processed once a 'pid' meta provider comes * along. This is protected by dtrace_lock. */static dtrace_helpers_t *dtrace_deferred_pid;/* * DTrace Locking * DTrace is protected by three (relatively coarse-grained) locks: * * (1) dtrace_lock is required to manipulate essentially any DTrace state, *     including enabling state, probes, ECBs, consumer state, helper state, *     etc.  Importantly, dtrace_lock is _not_ required when in probe context; *     probe context is lock-free -- synchronization is handled via the *     dtrace_sync() cross call mechanism. * * (2) dtrace_provider_lock is required when manipulating provider state, or *     when provider state must be held constant. * * (3) dtrace_meta_lock is required when manipulating meta provider state, or *     when meta provider state must be held constant. * * The lock ordering between these three locks is dtrace_meta_lock before * dtrace_provider_lock before dtrace_lock.  (In particular, there are * several places where dtrace_provider_lock is held by the framework as it * calls into the providers -- which then call back into the framework, * grabbing dtrace_lock.) * * There are two other locks in the mix:  mod_lock and cpu_lock.  cpu_lock * continues its historical role as a coarse-grained lock; it is acquired * before both dtrace_provider_lock and dtrace_lock.  mod_lock is slightly * stranger:  it must be acquired _between_ dtrace_provider_lock and * dtrace_lock. */static kmutex_t		dtrace_lock;		/* probe state lock */static kmutex_t		dtrace_provider_lock;	/* provider state lock */static kmutex_t		dtrace_meta_lock;	/* meta-provider state lock *//* * DTrace Provider Variables * * These are the variables relating to DTrace as a provider (that is, the * provider of the BEGIN, END, and ERROR probes). */static dtrace_pattr_t	dtrace_provider_attr = {{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },};static voiddtrace_nullop(void){}static dtrace_pops_t	dtrace_provider_ops = {	(void (*)(void *, const dtrace_probedesc_t *))dtrace_nullop,	(void (*)(void *, struct modctl *))dtrace_nullop,	(void (*)(void *, dtrace_id_t, void *))dtrace_nullop,	(void (*)(void *, dtrace_id_t, void *))dtrace_nullop,	(void (*)(void *, dtrace_id_t, void *))dtrace_nullop,	(void (*)(void *, dtrace_id_t, void *))dtrace_nullop,	NULL,	NULL,	NULL,	(void (*)(void *, dtrace_id_t, void *))dtrace_nullop};static dtrace_id_t	dtrace_probeid_begin;	/* special BEGIN probe */static dtrace_id_t	dtrace_probeid_end;	/* special END probe */dtrace_id_t		dtrace_probeid_error;	/* special ERROR probe *//* * DTrace Helper Tracing Variables */uint32_t dtrace_helptrace_next = 0;uint32_t dtrace_helptrace_nlocals;char	*dtrace_helptrace_buffer;int	dtrace_helptrace_bufsize = 512 * 1024;#ifdef DEBUGint	dtrace_helptrace_enabled = 1;#elseint	dtrace_helptrace_enabled = 0;#endif/* * DTrace Error Hashing * * On DEBUG kernels, DTrace will track the errors that has seen in a hash * table.  This is very useful for checking coverage of tests that are * expected to induce DIF or DOF processing errors, and may be useful for * debugging problems in the DIF code generator or in DOF generation .  The * error hash may be examined with the ::dtrace_errhash MDB dcmd. */#ifdef DEBUGstatic dtrace_errhash_t	dtrace_errhash[DTRACE_ERRHASHSZ];static const char *dtrace_errlast;static kthread_t *dtrace_errthread;static kmutex_t dtrace_errlock;#endif/* * DTrace Macros and Constants * * These are various macros that are useful in various spots in the * implementation, along with a few random constants that have no meaning * outside of the implementation.  There is no real structure to this cpp * mishmash -- but is there ever? */#define	DTRACE_HASHSTR(hash, probe)	\	dtrace_hash_str(*((char **)((uintptr_t)(probe) + (hash)->dth_stroffs)))#define	DTRACE_HASHNEXT(hash, probe)	\	(dtrace_probe_t **)((uintptr_t)(probe) + (hash)->dth_nextoffs)#define	DTRACE_HASHPREV(hash, probe)	\	(dtrace_probe_t **)((uintptr_t)(probe) + (hash)->dth_prevoffs)#define	DTRACE_HASHEQ(hash, lhs, rhs)	\	(strcmp(*((char **)((uintptr_t)(lhs) + (hash)->dth_stroffs)), \	    *((char **)((uintptr_t)(rhs) + (hash)->dth_stroffs))) == 0)#define	DTRACE_AGGHASHSIZE_SLEW		17/* * The key for a thread-local variable consists of the lower 61 bits of the * t_did, plus the 3 bits of the highest active interrupt above LOCK_LEVEL. * We add DIF_VARIABLE_MAX to t_did to assure that the thread key is never * equal to a variable identifier.  This is necessary (but not sufficient) to * assure that global associative arrays never collide with thread-local * variables.  To guarantee that they cannot collide, we must also define the * order for keying dynamic variables.  That order is: * *   [ key0 ] ... [ keyn ] [ variable-key ] [ tls-key ] * * Because the variable-key and the tls-key are in orthogonal spaces, there is * no way for a global variable key signature to match a thread-local key * signature. */#define	DTRACE_TLS_THRKEY(where) { \	uint_t intr = 0; \	uint_t actv = CPU->cpu_intr_actv >> (LOCK_LEVEL + 1); \	for (; actv; actv >>= 1) \		intr++; \	ASSERT(intr < (1 << 3)); \	(where) = ((curthread->t_did + DIF_VARIABLE_MAX) & \	    (((uint64_t)1 << 61) - 1)) | ((uint64_t)intr << 61); \}#define	DTRACE_STORE(type, tomax, offset, what) \	*((type *)((uintptr_t)(tomax) + (uintptr_t)offset)) = (type)(what);#ifndef __i386#define	DTRACE_ALIGNCHECK(addr, size, flags)				\	if (addr & (size - 1)) {					\		*flags |= CPU_DTRACE_BADALIGN;				\		cpu_core[CPU->cpu_id].cpuc_dtrace_illval = addr;	\		return (0);						\	}#else#define	DTRACE_ALIGNCHECK(addr, size, flags)#endif#define	DTRACE_LOADFUNC(bits)						\/*CSTYLED*/								\uint##bits##_t								\dtrace_load##bits(uintptr_t addr)					\{									\	size_t size = bits / NBBY;					\	/*CSTYLED*/							\	uint##bits##_t rval;						\	int i;								\	volatile uint16_t *flags = (volatile uint16_t *)		\	    &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;			\									\	DTRACE_ALIGNCHECK(addr, size, flags);				\									\	for (i = 0; i < dtrace_toxranges; i++) {			\		if (addr >= dtrace_toxrange[i].dtt_limit)		\			continue;					\									\		if (addr + size <= dtrace_toxrange[i].dtt_base)		\			continue;					\									\		/*							\		 * This address falls within a toxic region; return 0.	\		 */							\		*flags |= CPU_DTRACE_BADADDR;				\		cpu_core[CPU->cpu_id].cpuc_dtrace_illval = addr;	\		return (0);						\	}								\									\	*flags |= CPU_DTRACE_NOFAULT;					\	/*CSTYLED*/							\	rval = *((volatile uint##bits##_t *)addr);			\	*flags &= ~CPU_DTRACE_NOFAULT;					\									\	return (rval);							\}#ifdef _LP64#define	dtrace_loadptr	dtrace_load64#else#define	dtrace_loadptr	dtrace_load32#endif#define	DTRACE_MATCH_NEXT	0#define	DTRACE_MATCH_DONE	1#define	DTRACE_ANCHORED(probe)	((probe)->dtpr_func[0] != '\0')#define	DTRACE_STATE_ALIGN	64static dtrace_probe_t *dtrace_probe_lookup_id(dtrace_id_t id);static void dtrace_anon_provide(void);static dtrace_state_t *dtrace_anon_grab(void);static void dtrace_anon_match(const char *, dtrace_probespec_t);static uint64_t dtrace_helper(int, dtrace_mstate_t *,    dtrace_state_t *, uint64_t, uint64_t);static dtrace_helpers_t *dtrace_helpers_create(proc_t *);static void dtrace_buffer_drop(dtrace_buffer_t *);static intptr_t dtrace_buffer_reserve(dtrace_buffer_t *, size_t, size_t,    dtrace_state_t *, dtrace_mstate_t *);static int dtrace_state_option(dtrace_state_t *, dtrace_optid_t,    dtrace_optval_t);static int dtrace_ecb_create_enable(dtrace_probe_t *, void *);/* * DTrace Probe Context Functions * * These functions are called from probe context.  Because probe context is * any context in which C may be called, arbitrarily locks may be held, * interrupts may be disabled, we may be in arbitrary dispatched state, etc. * As a result, functions called from probe context may only call other DTrace * support functions -- they may not interact at all with the system at large. * (Note that the ASSERT macro is made probe-context safe by redefining it in * terms of dtrace_assfail(), a probe-context safe function.) If arbitrary * loads are to be performed from probe context, they _must_ be in terms of * the safe dtrace_load*() variants. * * Some functions in this block are not actually called from probe context; * for these functions, there will be a comment above the function reading * "Note:  not called from probe context." */voiddtrace_panic(const char *format, ...){	va_list alist;	va_start(alist, format);	dtrace_vpanic(format, alist);	va_end(alist);}intdtrace_assfail(const char *a, const char *f, int l){	dtrace_panic("assertion failed: %s, file: %s, line: %d", a, f, l);	/*	 * We just need something here that even the most clever compiler	 * cannot optimize away.	 */	return (a[(uintptr_t)f]);}/* * Use the DTRACE_LOADFUNC macro to define functions for each of loading a * uint8_t, a uint16_t, a uint32_t and a uint64_t. */DTRACE_LOADFUNC(8)DTRACE_LOADFUNC(16)DTRACE_LOADFUNC(32)DTRACE_LOADFUNC(64)static intdtrace_inscratch(uintptr_t dest, size_t size, dtrace_mstate_t *mstate){	if (dest < mstate->dtms_scratch_base)		return (0);	if (dest + size < dest)		return (0);	if (dest + size > mstate->dtms_scratch_ptr)		return (0);	return (1);}/* * Check to see if the address is within a memory region to which a store may * be issued.  This includes the DTrace scratch areas, and any DTrace variable * region.  The caller of dtrace_canstore() is responsible for performing any * alignment checks that are needed before stores are actually executed. */static intdtrace_canstore(uint64_t addr, size_t sz, dtrace_mstate_t *mstate,    dtrace_vstate_t *vstate){	uintptr_t a;	size_t s;	int i;	/*

⌨️ 快捷键说明

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