dtrace_load.c revision 262038
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: stable/9/sys/cddl/dev/dtrace/dtrace_load.c 262038 2014-02-17 12:42:57Z avg $
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
59255763Smarkj	/* Register callbacks for linker file load and unload events. */
60255763Smarkj	dtrace_kld_load_tag = EVENTHANDLER_REGISTER(kld_load,
61255763Smarkj	    dtrace_kld_load, NULL, EVENTHANDLER_PRI_ANY);
62262038Savg	dtrace_kld_unload_try_tag = EVENTHANDLER_REGISTER(kld_unload_try,
63262038Savg	    dtrace_kld_unload_try, NULL, EVENTHANDLER_PRI_ANY);
64255763Smarkj
65179237Sjb	/*
66179237Sjb	 * XXX This is a short term hack to avoid having to comment
67179237Sjb	 * out lots and lots of lock/unlock calls.
68179237Sjb	 */
69179237Sjb	mutex_init(&mod_lock,"XXX mod_lock hack", MUTEX_DEFAULT, NULL);
70179237Sjb
71179237Sjb	/*
72179237Sjb	 * Initialise the mutexes without 'witness' because the dtrace
73179237Sjb	 * code is mostly written to wait for memory. To have the
74179237Sjb	 * witness code change a malloc() from M_WAITOK to M_NOWAIT
75179237Sjb	 * because a lock is held would surely create a panic in a
76179237Sjb	 * low memory situation. And that low memory situation might be
77179237Sjb	 * the very problem we are trying to trace.
78179237Sjb	 */
79179237Sjb	mutex_init(&dtrace_lock,"dtrace probe state", MUTEX_DEFAULT, NULL);
80179237Sjb	mutex_init(&dtrace_provider_lock,"dtrace provider state", MUTEX_DEFAULT, NULL);
81179237Sjb	mutex_init(&dtrace_meta_lock,"dtrace meta-provider state", MUTEX_DEFAULT, NULL);
82254704Savg#ifdef DEBUG
83179237Sjb	mutex_init(&dtrace_errlock,"dtrace error lock", MUTEX_DEFAULT, NULL);
84254704Savg#endif
85179237Sjb
86179237Sjb	mutex_enter(&dtrace_provider_lock);
87179237Sjb	mutex_enter(&dtrace_lock);
88179237Sjb	mutex_enter(&cpu_lock);
89179237Sjb
90179237Sjb	ASSERT(MUTEX_HELD(&cpu_lock));
91179237Sjb
92179237Sjb	dtrace_arena = new_unrhdr(1, INT_MAX, &dtrace_unr_mtx);
93179237Sjb
94179237Sjb	dtrace_state_cache = kmem_cache_create("dtrace_state_cache",
95179237Sjb	    sizeof (dtrace_dstate_percpu_t) * NCPU, DTRACE_STATE_ALIGN,
96179237Sjb	    NULL, NULL, NULL, NULL, NULL, 0);
97179237Sjb
98179237Sjb	ASSERT(MUTEX_HELD(&cpu_lock));
99179237Sjb	dtrace_bymod = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_mod),
100179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextmod),
101179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevmod));
102179237Sjb
103179237Sjb	dtrace_byfunc = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_func),
104179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextfunc),
105179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevfunc));
106179237Sjb
107179237Sjb	dtrace_byname = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_name),
108179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextname),
109179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevname));
110179237Sjb
111179237Sjb	if (dtrace_retain_max < 1) {
112179237Sjb		cmn_err(CE_WARN, "illegal value (%lu) for dtrace_retain_max; "
113179237Sjb		    "setting to 1", dtrace_retain_max);
114179237Sjb		dtrace_retain_max = 1;
115179237Sjb	}
116179237Sjb
117179237Sjb	/*
118179237Sjb	 * Now discover our toxic ranges.
119179237Sjb	 */
120179237Sjb	dtrace_toxic_ranges(dtrace_toxrange_add);
121179237Sjb
122179237Sjb	/*
123179237Sjb	 * Before we register ourselves as a provider to our own framework,
124179237Sjb	 * we would like to assert that dtrace_provider is NULL -- but that's
125179237Sjb	 * not true if we were loaded as a dependency of a DTrace provider.
126179237Sjb	 * Once we've registered, we can assert that dtrace_provider is our
127179237Sjb	 * pseudo provider.
128179237Sjb	 */
129179237Sjb	(void) dtrace_register("dtrace", &dtrace_provider_attr,
130179237Sjb	    DTRACE_PRIV_NONE, 0, &dtrace_provider_ops, NULL, &id);
131179237Sjb
132179237Sjb	ASSERT(dtrace_provider != NULL);
133179237Sjb	ASSERT((dtrace_provider_id_t)dtrace_provider == id);
134179237Sjb
135179237Sjb	dtrace_probeid_begin = dtrace_probe_create((dtrace_provider_id_t)
136179237Sjb	    dtrace_provider, NULL, NULL, "BEGIN", 0, NULL);
137179237Sjb	dtrace_probeid_end = dtrace_probe_create((dtrace_provider_id_t)
138179237Sjb	    dtrace_provider, NULL, NULL, "END", 0, NULL);
139179237Sjb	dtrace_probeid_error = dtrace_probe_create((dtrace_provider_id_t)
140179237Sjb	    dtrace_provider, NULL, NULL, "ERROR", 1, NULL);
141179237Sjb
142179237Sjb	mutex_exit(&cpu_lock);
143179237Sjb
144179237Sjb	/*
145179237Sjb	 * If DTrace helper tracing is enabled, we need to allocate the
146179237Sjb	 * trace buffer and initialize the values.
147179237Sjb	 */
148179237Sjb	if (dtrace_helptrace_enabled) {
149179237Sjb		ASSERT(dtrace_helptrace_buffer == NULL);
150179237Sjb		dtrace_helptrace_buffer =
151179237Sjb		    kmem_zalloc(dtrace_helptrace_bufsize, KM_SLEEP);
152179237Sjb		dtrace_helptrace_next = 0;
153179237Sjb	}
154179237Sjb
155179237Sjb	mutex_exit(&dtrace_lock);
156179237Sjb	mutex_exit(&dtrace_provider_lock);
157179237Sjb
158179237Sjb	mutex_enter(&cpu_lock);
159179237Sjb
160179237Sjb	/* Setup the boot CPU */
161179237Sjb	(void) dtrace_cpu_setup(CPU_CONFIG, 0);
162179237Sjb
163179237Sjb	mutex_exit(&cpu_lock);
164179237Sjb
165184698Srodrigc#if __FreeBSD_version < 800039
166179237Sjb	/* Enable device cloning. */
167179237Sjb	clone_setup(&dtrace_clones);
168179237Sjb
169179237Sjb	/* Setup device cloning events. */
170179237Sjb	eh_tag = EVENTHANDLER_REGISTER(dev_clone, dtrace_clone, 0, 1000);
171184698Srodrigc#else
172211608Srpaulo	dtrace_dev = make_dev(&dtrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
173211608Srpaulo	    "dtrace/dtrace");
174212093Srpaulo	helper_dev = make_dev(&helper_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660,
175211608Srpaulo	    "dtrace/helper");
176184698Srodrigc#endif
177179237Sjb
178179237Sjb	return;
179179237Sjb}
180