]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/kern/kern_sdt.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / kern / kern_sdt.c
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(u_int32_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 }