dtrace_load.c revision 254268
1179237Sjb/*
2179237Sjb * CDDL HEADER START
3179237Sjb *
4179237Sjb * The contents of this file are subject to the terms of the
5179237Sjb * Common Development and Distribution License (the "License").
6179237Sjb * You may not use this file except in compliance with the License.
7179237Sjb *
8179237Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9179237Sjb * or http://www.opensolaris.org/os/licensing.
10179237Sjb * See the License for the specific language governing permissions
11179237Sjb * and limitations under the License.
12179237Sjb *
13179237Sjb * When distributing Covered Code, include this CDDL HEADER in each
14179237Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15179237Sjb * If applicable, add the following below this CDDL HEADER, with the
16179237Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17179237Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18179237Sjb *
19179237Sjb * CDDL HEADER END
20179237Sjb *
21179237Sjb * $FreeBSD: head/sys/cddl/dev/dtrace/dtrace_load.c 254268 2013-08-13 03:10:39Z markj $
22179237Sjb *
23179237Sjb */
24179237Sjb
25179237Sjbstatic void
26179237Sjbdtrace_ap_start(void *dummy)
27179237Sjb{
28179237Sjb	int i;
29179237Sjb
30179237Sjb	mutex_enter(&cpu_lock);
31179237Sjb
32179237Sjb	/* Setup the rest of the CPUs. */
33209059Sjhb	CPU_FOREACH(i) {
34209059Sjhb		if (i == 0)
35179237Sjb			continue;
36179237Sjb
37179237Sjb		(void) dtrace_cpu_setup(CPU_CONFIG, i);
38179237Sjb	}
39179237Sjb
40179237Sjb	mutex_exit(&cpu_lock);
41179237Sjb}
42179237Sjb
43179237SjbSYSINIT(dtrace_ap_start, SI_SUB_SMP, SI_ORDER_ANY, dtrace_ap_start, NULL);
44179237Sjb
45179237Sjbstatic void
46179237Sjbdtrace_load(void *dummy)
47179237Sjb{
48179237Sjb	dtrace_provider_id_t id;
49179237Sjb
50179237Sjb	/* Hook into the trap handler. */
51179237Sjb	dtrace_trap_func = dtrace_trap;
52179237Sjb
53179237Sjb	/* Hang our hook for thread switches. */
54179237Sjb	dtrace_vtime_switch_func = dtrace_vtime_switch;
55179237Sjb
56179237Sjb	/* Hang our hook for exceptions. */
57179237Sjb	dtrace_invop_init();
58179237Sjb
59254268Smarkj	/* Register callbacks for module load and unload events. */
60254268Smarkj	dtrace_modload_tag = EVENTHANDLER_REGISTER(mod_load,
61254268Smarkj	    dtrace_mod_load, NULL, EVENTHANDLER_PRI_ANY);
62254268Smarkj	dtrace_modunload_tag = EVENTHANDLER_REGISTER(mod_unload,
63254268Smarkj	    dtrace_mod_unload, NULL, EVENTHANDLER_PRI_ANY);
64254268Smarkj
65179237Sjb	/*
66179237Sjb	 * Initialise the mutexes without 'witness' because the dtrace
67179237Sjb	 * code is mostly written to wait for memory. To have the
68179237Sjb	 * witness code change a malloc() from M_WAITOK to M_NOWAIT
69179237Sjb	 * because a lock is held would surely create a panic in a
70179237Sjb	 * low memory situation. And that low memory situation might be
71179237Sjb	 * the very problem we are trying to trace.
72179237Sjb	 */
73179237Sjb	mutex_init(&dtrace_lock,"dtrace probe state", MUTEX_DEFAULT, NULL);
74179237Sjb	mutex_init(&dtrace_provider_lock,"dtrace provider state", MUTEX_DEFAULT, NULL);
75179237Sjb	mutex_init(&dtrace_meta_lock,"dtrace meta-provider state", MUTEX_DEFAULT, NULL);
76253996Savg#ifdef DEBUG
77179237Sjb	mutex_init(&dtrace_errlock,"dtrace error lock", MUTEX_DEFAULT, NULL);
78253996Savg#endif
79179237Sjb
80179237Sjb	mutex_enter(&dtrace_provider_lock);
81179237Sjb	mutex_enter(&dtrace_lock);
82179237Sjb	mutex_enter(&cpu_lock);
83179237Sjb
84179237Sjb	ASSERT(MUTEX_HELD(&cpu_lock));
85179237Sjb
86179237Sjb	dtrace_arena = new_unrhdr(1, INT_MAX, &dtrace_unr_mtx);
87179237Sjb
88179237Sjb	dtrace_state_cache = kmem_cache_create("dtrace_state_cache",
89179237Sjb	    sizeof (dtrace_dstate_percpu_t) * NCPU, DTRACE_STATE_ALIGN,
90179237Sjb	    NULL, NULL, NULL, NULL, NULL, 0);
91179237Sjb
92179237Sjb	ASSERT(MUTEX_HELD(&cpu_lock));
93179237Sjb	dtrace_bymod = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_mod),
94179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextmod),
95179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevmod));
96179237Sjb
97179237Sjb	dtrace_byfunc = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_func),
98179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextfunc),
99179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevfunc));
100179237Sjb
101179237Sjb	dtrace_byname = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_name),
102179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextname),
103179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevname));
104179237Sjb
105179237Sjb	if (dtrace_retain_max < 1) {
106179237Sjb		cmn_err(CE_WARN, "illegal value (%lu) for dtrace_retain_max; "
107179237Sjb		    "setting to 1", dtrace_retain_max);
108179237Sjb		dtrace_retain_max = 1;
109179237Sjb	}
110179237Sjb
111179237Sjb	/*
112179237Sjb	 * Now discover our toxic ranges.
113179237Sjb	 */
114179237Sjb	dtrace_toxic_ranges(dtrace_toxrange_add);
115179237Sjb
116179237Sjb	/*
117179237Sjb	 * Before we register ourselves as a provider to our own framework,
118179237Sjb	 * we would like to assert that dtrace_provider is NULL -- but that's
119179237Sjb	 * not true if we were loaded as a dependency of a DTrace provider.
120179237Sjb	 * Once we've registered, we can assert that dtrace_provider is our
121179237Sjb	 * pseudo provider.
122179237Sjb	 */
123179237Sjb	(void) dtrace_register("dtrace", &dtrace_provider_attr,
124179237Sjb	    DTRACE_PRIV_NONE, 0, &dtrace_provider_ops, NULL, &id);
125179237Sjb
126179237Sjb	ASSERT(dtrace_provider != NULL);
127179237Sjb	ASSERT((dtrace_provider_id_t)dtrace_provider == id);
128179237Sjb
129179237Sjb	dtrace_probeid_begin = dtrace_probe_create((dtrace_provider_id_t)
130179237Sjb	    dtrace_provider, NULL, NULL, "BEGIN", 0, NULL);
131179237Sjb	dtrace_probeid_end = dtrace_probe_create((dtrace_provider_id_t)
132179237Sjb	    dtrace_provider, NULL, NULL, "END", 0, NULL);
133179237Sjb	dtrace_probeid_error = dtrace_probe_create((dtrace_provider_id_t)
134179237Sjb	    dtrace_provider, NULL, NULL, "ERROR", 1, NULL);
135179237Sjb
136179237Sjb	mutex_exit(&cpu_lock);
137179237Sjb
138179237Sjb	/*
139179237Sjb	 * If DTrace helper tracing is enabled, we need to allocate the
140179237Sjb	 * trace buffer and initialize the values.
141179237Sjb	 */
142179237Sjb	if (dtrace_helptrace_enabled) {
143179237Sjb		ASSERT(dtrace_helptrace_buffer == NULL);
144179237Sjb		dtrace_helptrace_buffer =
145179237Sjb		    kmem_zalloc(dtrace_helptrace_bufsize, KM_SLEEP);
146179237Sjb		dtrace_helptrace_next = 0;
147179237Sjb	}
148179237Sjb
149179237Sjb	mutex_exit(&dtrace_lock);
150179237Sjb	mutex_exit(&dtrace_provider_lock);
151179237Sjb
152179237Sjb	mutex_enter(&cpu_lock);
153179237Sjb
154179237Sjb	/* Setup the boot CPU */
155179237Sjb	(void) dtrace_cpu_setup(CPU_CONFIG, 0);
156179237Sjb
157179237Sjb	mutex_exit(&cpu_lock);
158179237Sjb
159184698Srodrigc#if __FreeBSD_version < 800039
160179237Sjb	/* Enable device cloning. */
161179237Sjb	clone_setup(&dtrace_clones);
162179237Sjb
163179237Sjb	/* Setup device cloning events. */
164179237Sjb	eh_tag = EVENTHANDLER_REGISTER(dev_clone, dtrace_clone, 0, 1000);
165184698Srodrigc#else
166211608Srpaulo	dtrace_dev = make_dev(&dtrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
167211608Srpaulo	    "dtrace/dtrace");
168212093Srpaulo	helper_dev = make_dev(&helper_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660,
169211608Srpaulo	    "dtrace/helper");
170184698Srodrigc#endif
171179237Sjb
172179237Sjb	return;
173179237Sjb}
174