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