dtrace_load.c revision 184698
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 184698 2008-11-05 19:39:11Z rodrigc $
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. */
33179237Sjb	for (i = 1; i <= mp_maxid; i++) {
34179237Sjb		if (pcpu_find(i) == NULL)
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
59179237Sjb	/*
60179237Sjb	 * XXX This is a short term hack to avoid having to comment
61179237Sjb	 * out lots and lots of lock/unlock calls.
62179237Sjb	 */
63179237Sjb	mutex_init(&mod_lock,"XXX mod_lock hack", MUTEX_DEFAULT, NULL);
64179237Sjb
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);
76179237Sjb	mutex_init(&dtrace_errlock,"dtrace error lock", MUTEX_DEFAULT, NULL);
77179237Sjb
78179237Sjb	mutex_enter(&dtrace_provider_lock);
79179237Sjb	mutex_enter(&dtrace_lock);
80179237Sjb	mutex_enter(&cpu_lock);
81179237Sjb
82179237Sjb	ASSERT(MUTEX_HELD(&cpu_lock));
83179237Sjb
84179237Sjb	dtrace_arena = new_unrhdr(1, INT_MAX, &dtrace_unr_mtx);
85179237Sjb
86179237Sjb	dtrace_state_cache = kmem_cache_create("dtrace_state_cache",
87179237Sjb	    sizeof (dtrace_dstate_percpu_t) * NCPU, DTRACE_STATE_ALIGN,
88179237Sjb	    NULL, NULL, NULL, NULL, NULL, 0);
89179237Sjb
90179237Sjb	ASSERT(MUTEX_HELD(&cpu_lock));
91179237Sjb	dtrace_bymod = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_mod),
92179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextmod),
93179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevmod));
94179237Sjb
95179237Sjb	dtrace_byfunc = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_func),
96179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextfunc),
97179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevfunc));
98179237Sjb
99179237Sjb	dtrace_byname = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_name),
100179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextname),
101179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevname));
102179237Sjb
103179237Sjb	if (dtrace_retain_max < 1) {
104179237Sjb		cmn_err(CE_WARN, "illegal value (%lu) for dtrace_retain_max; "
105179237Sjb		    "setting to 1", dtrace_retain_max);
106179237Sjb		dtrace_retain_max = 1;
107179237Sjb	}
108179237Sjb
109179237Sjb	/*
110179237Sjb	 * Now discover our toxic ranges.
111179237Sjb	 */
112179237Sjb	dtrace_toxic_ranges(dtrace_toxrange_add);
113179237Sjb
114179237Sjb	/*
115179237Sjb	 * Before we register ourselves as a provider to our own framework,
116179237Sjb	 * we would like to assert that dtrace_provider is NULL -- but that's
117179237Sjb	 * not true if we were loaded as a dependency of a DTrace provider.
118179237Sjb	 * Once we've registered, we can assert that dtrace_provider is our
119179237Sjb	 * pseudo provider.
120179237Sjb	 */
121179237Sjb	(void) dtrace_register("dtrace", &dtrace_provider_attr,
122179237Sjb	    DTRACE_PRIV_NONE, 0, &dtrace_provider_ops, NULL, &id);
123179237Sjb
124179237Sjb	ASSERT(dtrace_provider != NULL);
125179237Sjb	ASSERT((dtrace_provider_id_t)dtrace_provider == id);
126179237Sjb
127179237Sjb	dtrace_probeid_begin = dtrace_probe_create((dtrace_provider_id_t)
128179237Sjb	    dtrace_provider, NULL, NULL, "BEGIN", 0, NULL);
129179237Sjb	dtrace_probeid_end = dtrace_probe_create((dtrace_provider_id_t)
130179237Sjb	    dtrace_provider, NULL, NULL, "END", 0, NULL);
131179237Sjb	dtrace_probeid_error = dtrace_probe_create((dtrace_provider_id_t)
132179237Sjb	    dtrace_provider, NULL, NULL, "ERROR", 1, NULL);
133179237Sjb
134179237Sjb	mutex_exit(&cpu_lock);
135179237Sjb
136179237Sjb	/*
137179237Sjb	 * If DTrace helper tracing is enabled, we need to allocate the
138179237Sjb	 * trace buffer and initialize the values.
139179237Sjb	 */
140179237Sjb	if (dtrace_helptrace_enabled) {
141179237Sjb		ASSERT(dtrace_helptrace_buffer == NULL);
142179237Sjb		dtrace_helptrace_buffer =
143179237Sjb		    kmem_zalloc(dtrace_helptrace_bufsize, KM_SLEEP);
144179237Sjb		dtrace_helptrace_next = 0;
145179237Sjb	}
146179237Sjb
147179237Sjb	mutex_exit(&dtrace_lock);
148179237Sjb	mutex_exit(&dtrace_provider_lock);
149179237Sjb
150179237Sjb	mutex_enter(&cpu_lock);
151179237Sjb
152179237Sjb	/* Setup the boot CPU */
153179237Sjb	(void) dtrace_cpu_setup(CPU_CONFIG, 0);
154179237Sjb
155179237Sjb	mutex_exit(&cpu_lock);
156179237Sjb
157184698Srodrigc#if __FreeBSD_version < 800039
158179237Sjb	/* Enable device cloning. */
159179237Sjb	clone_setup(&dtrace_clones);
160179237Sjb
161179237Sjb	/* Setup device cloning events. */
162179237Sjb	eh_tag = EVENTHANDLER_REGISTER(dev_clone, dtrace_clone, 0, 1000);
163184698Srodrigc#else
164184698Srodrigc	dtrace_dev = make_dev(&dtrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "dtrace/dtrace");
165184698Srodrigc#endif
166179237Sjb
167179237Sjb	return;
168179237Sjb}
169