From owner-p4-projects@FreeBSD.ORG Thu Apr 20 01:22:10 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id A1F4816A409; Thu, 20 Apr 2006 01:22:10 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4C53516A402 for ; Thu, 20 Apr 2006 01:22:10 +0000 (UTC) (envelope-from jb@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id C6C2A43D46 for ; Thu, 20 Apr 2006 01:22:09 +0000 (GMT) (envelope-from jb@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id k3K1M9jC093396 for ; Thu, 20 Apr 2006 01:22:09 GMT (envelope-from jb@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id k3K1M9TL093388 for perforce@freebsd.org; Thu, 20 Apr 2006 01:22:09 GMT (envelope-from jb@freebsd.org) Date: Thu, 20 Apr 2006 01:22:09 GMT Message-Id: <200604200122.k3K1M9TL093388@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jb@freebsd.org using -f From: John Birrell To: Perforce Change Reviews Cc: Subject: PERFORCE change 95649 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 Apr 2006 01:22:10 -0000 http://perforce.freebsd.org/chv.cgi?CH=95649 Change 95649 by jb@jb_freebsd2 on 2006/04/20 01:21:25 Work-in-progress update. Suck in the bulk of the Solaris dtrace device definitions, leaving things commented out that would cause compiler errors/warnings. Affected files ... .. //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace.c#5 edit Differences ... ==== //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace.c#5 (text+ko) ==== @@ -22,6 +22,50 @@ * */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * 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 header file. The + * internal architecture of DTrace is described in the block comments in the + * 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 #include #include @@ -41,15 +85,20 @@ #include #include #include +#include -#include -#include +#include -#include -#include +/* For compatibility with Solaris code. */ +typedef struct mtx kmutex_t; +#define mutex_enter(_a) mtx_lock(_a) +#define mutex_exit(_a) mtx_unlock(_a) #define DTRACE_MINOR 0 +MALLOC_DECLARE(M_DTRACE); +MALLOC_DEFINE(M_DTRACE, "dtrace", "Dynamic Trace"); + static d_close_t dtrace_close; static d_ioctl_t dtrace_ioctl; static d_open_t dtrace_open; @@ -57,23 +106,380 @@ static int dtrace_unload(void); static struct cdevsw dtrace_cdevsw = { - .d_version = D_VERSION, - .d_close = dtrace_close, - .d_ioctl = dtrace_ioctl, - .d_open = dtrace_open, - .d_name = "dtrace", + .d_version = D_VERSION, + .d_close = dtrace_close, + .d_ioctl = dtrace_ioctl, + .d_open = dtrace_open, + .d_name = "dtrace", }; /* For use with make_dev(9)/destroy_dev(9). */ -static struct cdev *dtrace_dev; +static struct cdev *dtrace_dev; + +/* + * 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. + * When tuning these variables, avoid pathological values; while some attempt + * is made to verify the integrity of these variables, they are not considered + * part of the supported interface to DTrace, and they are therefore not + * checked comprehensively. Further, these variables should not be tuned + * dynamically via "mdb -kw" or other means; they should only be tuned via + * /etc/system. + */ +#ifdef DOODAD +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); +size_t dtrace_retain_max = 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; +#endif + +/* + * 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. + */ +#ifdef DOODAD +const char dtrace_zero[256] = { 0 }; /* zero-filled memory */ +#endif + +/* + * DTrace Internal Variables + */ +#ifdef DOODAD +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 */ +#endif +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 */ +#ifdef DOODAD +static dtrace_meta_t *dtrace_meta_pid; /* user-land meta provider */ +#endif +static int dtrace_opens; /* number of opens */ +static int dtrace_helpers; /* number of helpers */ +#ifdef DOODAD +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 */ +#endif +static dtrace_anon_t dtrace_anon; /* anonymous enabling */ +#ifdef DOODAD +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 dtrace_genid_t dtrace_probegen; /* current probe generation */ +static dtrace_helpers_t *dtrace_deferred_pid; /* deferred helper list */ +static dtrace_enabling_t *dtrace_retained; /* list of retained enablings */ +static dtrace_dynvar_t dtrace_dynhash_sink; /* end of dynamic hash chains */ +#endif + +/* + * 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. With respect + * to dtrace_provider_lock and dtrace_lock, cpu_lock continues its historical + * role as a coarse-grained lock; it is acquired before both of these locks. + * With respect to dtrace_meta_lock, its behavior is stranger: cpu_lock must + * be acquired _between_ dtrace_meta_lock and any other DTrace locks. + * mod_lock is similar with respect to dtrace_provider_lock in that 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 void +dtrace_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 +}; + +#ifdef DOODAD +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 DEBUG +int dtrace_helptrace_enabled = 1; +#else +int 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 DEBUG +static 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_DYNHASH_FREE 0 +#define DTRACE_DYNHASH_SINK 1 +#define DTRACE_DYNHASH_VALID 2 + +#define DTRACE_MATCH_NEXT 0 +#define DTRACE_MATCH_DONE 1 +#define DTRACE_ANCHORED(probe) ((probe)->dtpr_func[0] != '\0') +#define DTRACE_STATE_ALIGN 64 + +#define DTRACE_FLAGS2FLT(flags) \ + (((flags) & CPU_DTRACE_BADADDR) ? DTRACEFLT_BADADDR : \ + ((flags) & CPU_DTRACE_ILLOP) ? DTRACEFLT_ILLOP : \ + ((flags) & CPU_DTRACE_DIVZERO) ? DTRACEFLT_DIVZERO : \ + ((flags) & CPU_DTRACE_KPRIV) ? DTRACEFLT_KPRIV : \ + ((flags) & CPU_DTRACE_UPRIV) ? DTRACEFLT_UPRIV : \ + ((flags) & CPU_DTRACE_TUPOFLOW) ? DTRACEFLT_TUPOFLOW : \ + ((flags) & CPU_DTRACE_BADALIGN) ? DTRACEFLT_BADALIGN : \ + ((flags) & CPU_DTRACE_NOSCRATCH) ? DTRACEFLT_NOSCRATCH : \ + DTRACEFLT_UNKNOWN) + +#define DTRACEACT_ISSTRING(act) \ + ((act)->dta_kind == DTRACEACT_DIFEXPR && \ + (act)->dta_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING) + +static dtrace_probe_t *dtrace_probe_lookup_id(dtrace_id_t id); +static void dtrace_enabling_provide(dtrace_provider_t *); +static int dtrace_enabling_match(dtrace_enabling_t *, int *); +static void dtrace_enabling_matchall(void); +static dtrace_state_t *dtrace_anon_grab(void); +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 *); +#endif +#include +#include +#include #include #include #include #include #include +#include #include #include +#include DEV_MODULE(dtrace, dtrace_modevent, NULL); MODULE_VERSION(dtrace, 1);