xref: /freebsd/sys/kern/kern_sdt.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
1 /*-
2  * Copyright 2006-2008 John Birrell <jb@FreeBSD.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  *
27  * Backend for the Statically Defined Tracing (SDT) kernel support. This is
28  * required to allow a module to load even though DTrace kernel support may
29  * not be present. A module may be built with SDT probes in it which are
30  * registered and deregistered via SYSINIT/SYSUNINIT.
31  *
32  */
33 
34 #include "opt_kdtrace.h"
35 
36 #include <sys/cdefs.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/linker.h>
41 #include <sys/lock.h>
42 #include <sys/proc.h>
43 #include <sys/sx.h>
44 #include <sys/sdt.h>
45 
46 /*
47  * This is the list of statically defined tracing providers.
48  */
49 static TAILQ_HEAD(sdt_provider_list_head, sdt_provider) sdt_provider_list;
50 
51 /*
52  * Mutex to serialise access to the SDT provider list.
53  */
54 static struct sx sdt_sx;
55 
56 /*
57  * Hook for the DTrace probe function. The 'sdt' provider will set this
58  * to dtrace_probe when it loads.
59  */
60 sdt_probe_func_t sdt_probe_func = sdt_probe_stub;
61 
62 /*
63  * This is a stub for probe calls in case kernel DTrace support isn't
64  * compiled in. It should never get called because there is no DTrace
65  * support to enable it.
66  */
67 void
68 sdt_probe_stub(uint32_t id, uintptr_t arg0, uintptr_t arg1,
69     uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
70 {
71 	printf("sdt_probe_stub: Why did this get called?\n");
72 }
73 
74 /*
75  * Called from SYSINIT to register a provider.
76  */
77 void
78 sdt_provider_register(void *arg)
79 {
80 	struct sdt_provider *prov = arg;
81 
82 	sx_xlock(&sdt_sx);
83 
84 	TAILQ_INSERT_TAIL(&sdt_provider_list, prov, prov_entry);
85 
86 	TAILQ_INIT(&prov->probe_list);
87 
88 	sx_xunlock(&sdt_sx);
89 }
90 
91 /*
92  * Called from SYSUNINIT to de-register a provider.
93  */
94 void
95 sdt_provider_deregister(void *arg)
96 {
97 	struct sdt_provider *prov = arg;
98 
99 	sx_xlock(&sdt_sx);
100 
101 	TAILQ_REMOVE(&sdt_provider_list, prov, prov_entry);
102 
103 	sx_xunlock(&sdt_sx);
104 }
105 
106 /*
107  * Called from SYSINIT to register a statically defined trace probe.
108  */
109 void
110 sdt_probe_register(void *arg)
111 {
112 	struct sdt_probe *probe = arg;
113 
114 	/*
115 	 * Check the reference structure version. Only version 1 is
116 	 * supported at the moment.
117 	 */
118 	if (probe->version != sizeof(struct sdt_probe)) {
119 		printf("%s:%s:%s has version %d when %d required\n", probe->mod, probe->func, probe->name, probe->version, (int) sizeof(struct sdt_probe));
120 		return;
121 	}
122 
123 	sx_xlock(&sdt_sx);
124 
125 	TAILQ_INSERT_TAIL(&probe->prov->probe_list, probe, probe_entry);
126 
127 	TAILQ_INIT(&probe->argtype_list);
128 
129 	probe->state = SDT_INIT;
130 
131 	sx_xunlock(&sdt_sx);
132 }
133 
134 /*
135  * Called from SYSUNINIT to de-register a statically defined trace probe.
136  */
137 void
138 sdt_probe_deregister(void *arg)
139 {
140 	struct sdt_probe *probe = arg;
141 
142 	sx_xlock(&sdt_sx);
143 
144 	if (probe->state == SDT_INIT) {
145 		TAILQ_REMOVE(&probe->prov->probe_list, probe, probe_entry);
146 		probe->state = SDT_UNINIT;
147 	}
148 
149 	sx_xunlock(&sdt_sx);
150 }
151 
152 /*
153  * Called from SYSINIT to register a statically defined trace probe argument.
154  */
155 void
156 sdt_argtype_register(void *arg)
157 {
158 	struct sdt_argtype *argtype = arg;
159 
160 	sx_xlock(&sdt_sx);
161 
162 	TAILQ_INSERT_TAIL(&argtype->probe->argtype_list, argtype, argtype_entry);
163 
164 	argtype->probe->n_args++;
165 
166 	sx_xunlock(&sdt_sx);
167 }
168 
169 /*
170  * Called from SYSUNINIT to de-register a statically defined trace probe argument.
171  */
172 void
173 sdt_argtype_deregister(void *arg)
174 {
175 	struct sdt_argtype *argtype = arg;
176 
177 	sx_xlock(&sdt_sx);
178 
179 	TAILQ_REMOVE(&argtype->probe->argtype_list, argtype, argtype_entry);
180 
181 	sx_xunlock(&sdt_sx);
182 }
183 
184 static void
185 sdt_init(void *arg)
186 {
187 	sx_init_flags(&sdt_sx, "Statically Defined Tracing", SX_NOWITNESS);
188 
189 	TAILQ_INIT(&sdt_provider_list);
190 }
191 
192 SYSINIT(sdt, SI_SUB_KDTRACE, SI_ORDER_FIRST, sdt_init, NULL);
193 
194 static void
195 sdt_uninit(void *arg)
196 {
197 	sx_destroy(&sdt_sx);
198 }
199 
200 SYSUNINIT(sdt, SI_SUB_KDTRACE, SI_ORDER_FIRST, sdt_uninit, NULL);
201 
202 /*
203  * List statically defined tracing providers.
204  */
205 int
206 sdt_provider_listall(sdt_provider_listall_func_t callback_func,void *arg)
207 {
208 	int error = 0;
209 	struct sdt_provider *prov;
210 
211 	sx_xlock(&sdt_sx);
212 
213 	TAILQ_FOREACH(prov, &sdt_provider_list, prov_entry) {
214 		if ((error = callback_func(prov, arg)) != 0)
215 			break;
216 	}
217 
218 	sx_xunlock(&sdt_sx);
219 
220 	return (error);
221 }
222 
223 /*
224  * List statically defined tracing probes.
225  */
226 int
227 sdt_probe_listall(struct sdt_provider *prov,
228     sdt_probe_listall_func_t callback_func,void *arg)
229 {
230 	int error = 0;
231 	int locked;
232 	struct sdt_probe *probe;
233 
234 	locked = sx_xlocked(&sdt_sx);
235 	if (!locked)
236 		sx_xlock(&sdt_sx);
237 
238 	TAILQ_FOREACH(probe, &prov->probe_list, probe_entry) {
239 		if ((error = callback_func(probe, arg)) != 0)
240 			break;
241 	}
242 
243 	if (!locked)
244 		sx_xunlock(&sdt_sx);
245 
246 	return (error);
247 }
248 
249 /*
250  * List statically defined tracing probe arguments.
251  */
252 int
253 sdt_argtype_listall(struct sdt_probe *probe,
254     sdt_argtype_listall_func_t callback_func,void *arg)
255 {
256 	int error = 0;
257 	int locked;
258 	struct sdt_argtype *argtype;
259 
260 	locked = sx_xlocked(&sdt_sx);
261 	if (!locked)
262 		sx_xlock(&sdt_sx);
263 
264 	TAILQ_FOREACH(argtype, &probe->argtype_list, argtype_entry) {
265 		if ((error = callback_func(argtype, arg)) != 0)
266 			break;
267 	}
268 
269 	if (!locked)
270 		sx_xunlock(&sdt_sx);
271 
272 	return (error);
273 }
274