15572901bSJohn Birrell /*- 25572901bSJohn Birrell * Copyright 2006-2008 John Birrell <jb@FreeBSD.org> 35572901bSJohn Birrell * 45572901bSJohn Birrell * Redistribution and use in source and binary forms, with or without 55572901bSJohn Birrell * modification, are permitted provided that the following conditions 65572901bSJohn Birrell * are met: 75572901bSJohn Birrell * 1. Redistributions of source code must retain the above copyright 85572901bSJohn Birrell * notice, this list of conditions and the following disclaimer. 95572901bSJohn Birrell * 2. Redistributions in binary form must reproduce the above copyright 105572901bSJohn Birrell * notice, this list of conditions and the following disclaimer in the 115572901bSJohn Birrell * documentation and/or other materials provided with the distribution. 125572901bSJohn Birrell * 135572901bSJohn Birrell * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 145572901bSJohn Birrell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 155572901bSJohn Birrell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 165572901bSJohn Birrell * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 175572901bSJohn Birrell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 185572901bSJohn Birrell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 195572901bSJohn Birrell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 205572901bSJohn Birrell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 215572901bSJohn Birrell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 225572901bSJohn Birrell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 235572901bSJohn Birrell * SUCH DAMAGE. 245572901bSJohn Birrell * 255572901bSJohn Birrell * $FreeBSD$ 265572901bSJohn Birrell * 275572901bSJohn Birrell * Backend for the Statically Defined Tracing (SDT) kernel support. This is 285572901bSJohn Birrell * required to allow a module to load even though DTrace kernel support may 295572901bSJohn Birrell * not be present. A module may be built with SDT probes in it which are 305572901bSJohn Birrell * registered and deregistered via SYSINIT/SYSUNINIT. 315572901bSJohn Birrell * 325572901bSJohn Birrell */ 335572901bSJohn Birrell 345572901bSJohn Birrell #include "opt_kdtrace.h" 355572901bSJohn Birrell 365572901bSJohn Birrell #include <sys/cdefs.h> 375572901bSJohn Birrell #include <sys/param.h> 385572901bSJohn Birrell #include <sys/systm.h> 395572901bSJohn Birrell #include <sys/kernel.h> 405572901bSJohn Birrell #include <sys/linker.h> 415572901bSJohn Birrell #include <sys/lock.h> 425572901bSJohn Birrell #include <sys/proc.h> 435572901bSJohn Birrell #include <sys/sx.h> 445572901bSJohn Birrell #include <sys/sdt.h> 455572901bSJohn Birrell 465572901bSJohn Birrell /* 475572901bSJohn Birrell * This is the list of statically defined tracing providers. 485572901bSJohn Birrell */ 495572901bSJohn Birrell static TAILQ_HEAD(sdt_provider_list_head, sdt_provider) sdt_provider_list; 505572901bSJohn Birrell 515572901bSJohn Birrell /* 525572901bSJohn Birrell * Mutex to serialise access to the SDT provider list. 535572901bSJohn Birrell */ 545572901bSJohn Birrell static struct sx sdt_sx; 555572901bSJohn Birrell 565572901bSJohn Birrell /* 575572901bSJohn Birrell * Hook for the DTrace probe function. The 'sdt' provider will set this 585572901bSJohn Birrell * to dtrace_probe when it loads. 595572901bSJohn Birrell */ 605572901bSJohn Birrell sdt_probe_func_t sdt_probe_func = sdt_probe_stub; 615572901bSJohn Birrell 625572901bSJohn Birrell /* 635572901bSJohn Birrell * This is a stub for probe calls in case kernel DTrace support isn't 645572901bSJohn Birrell * compiled in. It should never get called because there is no DTrace 655572901bSJohn Birrell * support to enable it. 665572901bSJohn Birrell */ 675572901bSJohn Birrell void 685572901bSJohn Birrell sdt_probe_stub(u_int32_t id, uintptr_t arg0, uintptr_t arg1, 695572901bSJohn Birrell uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) 705572901bSJohn Birrell { 715572901bSJohn Birrell printf("sdt_probe_stub: Why did this get called?\n"); 725572901bSJohn Birrell } 735572901bSJohn Birrell 745572901bSJohn Birrell /* 755572901bSJohn Birrell * Called from SYSINIT to register a provider. 765572901bSJohn Birrell */ 775572901bSJohn Birrell void 785572901bSJohn Birrell sdt_provider_register(void *arg) 795572901bSJohn Birrell { 805572901bSJohn Birrell struct sdt_provider *prov = arg; 815572901bSJohn Birrell 825572901bSJohn Birrell sx_xlock(&sdt_sx); 835572901bSJohn Birrell 845572901bSJohn Birrell TAILQ_INSERT_TAIL(&sdt_provider_list, prov, prov_entry); 855572901bSJohn Birrell 865572901bSJohn Birrell TAILQ_INIT(&prov->probe_list); 875572901bSJohn Birrell 885572901bSJohn Birrell sx_xunlock(&sdt_sx); 895572901bSJohn Birrell } 905572901bSJohn Birrell 915572901bSJohn Birrell /* 925572901bSJohn Birrell * Called from SYSUNINIT to de-register a provider. 935572901bSJohn Birrell */ 945572901bSJohn Birrell void 955572901bSJohn Birrell sdt_provider_deregister(void *arg) 965572901bSJohn Birrell { 975572901bSJohn Birrell struct sdt_provider *prov = arg; 985572901bSJohn Birrell 995572901bSJohn Birrell sx_xlock(&sdt_sx); 1005572901bSJohn Birrell 1015572901bSJohn Birrell TAILQ_REMOVE(&sdt_provider_list, prov, prov_entry); 1025572901bSJohn Birrell 1035572901bSJohn Birrell sx_xunlock(&sdt_sx); 1045572901bSJohn Birrell } 1055572901bSJohn Birrell 1065572901bSJohn Birrell /* 1075572901bSJohn Birrell * Called from SYSINIT to register a statically defined trace probe. 1085572901bSJohn Birrell */ 1095572901bSJohn Birrell void 1105572901bSJohn Birrell sdt_probe_register(void *arg) 1115572901bSJohn Birrell { 1125572901bSJohn Birrell struct sdt_probe *probe = arg; 1135572901bSJohn Birrell 1145572901bSJohn Birrell /* 1155572901bSJohn Birrell * Check the reference structure version. Only version 1 is 1165572901bSJohn Birrell * supported at the moment. 1175572901bSJohn Birrell */ 1185572901bSJohn Birrell if (probe->version != sizeof(struct sdt_probe)) { 1195572901bSJohn Birrell printf("%s:%s:%s has version %d when %d required\n", probe->mod, probe->func, probe->name, probe->version, (int) sizeof(struct sdt_probe)); 1205572901bSJohn Birrell return; 1215572901bSJohn Birrell } 1225572901bSJohn Birrell 1235572901bSJohn Birrell sx_xlock(&sdt_sx); 1245572901bSJohn Birrell 1255572901bSJohn Birrell TAILQ_INSERT_TAIL(&probe->prov->probe_list, probe, probe_entry); 1265572901bSJohn Birrell 1275572901bSJohn Birrell TAILQ_INIT(&probe->argtype_list); 1285572901bSJohn Birrell 1295572901bSJohn Birrell probe->state = SDT_INIT; 1305572901bSJohn Birrell 1315572901bSJohn Birrell sx_xunlock(&sdt_sx); 1325572901bSJohn Birrell } 1335572901bSJohn Birrell 1345572901bSJohn Birrell /* 1355572901bSJohn Birrell * Called from SYSUNINIT to de-register a statically defined trace probe. 1365572901bSJohn Birrell */ 1375572901bSJohn Birrell void 1385572901bSJohn Birrell sdt_probe_deregister(void *arg) 1395572901bSJohn Birrell { 1405572901bSJohn Birrell struct sdt_probe *probe = arg; 1415572901bSJohn Birrell 1425572901bSJohn Birrell sx_xlock(&sdt_sx); 1435572901bSJohn Birrell 1445572901bSJohn Birrell if (probe->state == SDT_INIT) { 1455572901bSJohn Birrell TAILQ_REMOVE(&probe->prov->probe_list, probe, probe_entry); 1465572901bSJohn Birrell probe->state = SDT_UNINIT; 1475572901bSJohn Birrell } 1485572901bSJohn Birrell 1495572901bSJohn Birrell sx_xunlock(&sdt_sx); 1505572901bSJohn Birrell } 1515572901bSJohn Birrell 1525572901bSJohn Birrell /* 1535572901bSJohn Birrell * Called from SYSINIT to register a statically defined trace probe argument. 1545572901bSJohn Birrell */ 1555572901bSJohn Birrell void 1565572901bSJohn Birrell sdt_argtype_register(void *arg) 1575572901bSJohn Birrell { 1585572901bSJohn Birrell struct sdt_argtype *argtype = arg; 1595572901bSJohn Birrell 1605572901bSJohn Birrell sx_xlock(&sdt_sx); 1615572901bSJohn Birrell 1625572901bSJohn Birrell TAILQ_INSERT_TAIL(&argtype->probe->argtype_list, argtype, argtype_entry); 1635572901bSJohn Birrell 1645572901bSJohn Birrell argtype->probe->n_args++; 1655572901bSJohn Birrell 1665572901bSJohn Birrell sx_xunlock(&sdt_sx); 1675572901bSJohn Birrell } 1685572901bSJohn Birrell 1695572901bSJohn Birrell /* 1705572901bSJohn Birrell * Called from SYSUNINIT to de-register a statically defined trace probe argument. 1715572901bSJohn Birrell */ 1725572901bSJohn Birrell void 1735572901bSJohn Birrell sdt_argtype_deregister(void *arg) 1745572901bSJohn Birrell { 1755572901bSJohn Birrell struct sdt_argtype *argtype = arg; 1765572901bSJohn Birrell 1775572901bSJohn Birrell sx_xlock(&sdt_sx); 1785572901bSJohn Birrell 1795572901bSJohn Birrell TAILQ_REMOVE(&argtype->probe->argtype_list, argtype, argtype_entry); 1805572901bSJohn Birrell 1815572901bSJohn Birrell sx_xunlock(&sdt_sx); 1825572901bSJohn Birrell } 1835572901bSJohn Birrell 1845572901bSJohn Birrell static void 1855572901bSJohn Birrell sdt_init(void *arg) 1865572901bSJohn Birrell { 1875572901bSJohn Birrell sx_init_flags(&sdt_sx, "Statically Defined Tracing", SX_NOWITNESS); 1885572901bSJohn Birrell 1895572901bSJohn Birrell TAILQ_INIT(&sdt_provider_list); 1905572901bSJohn Birrell } 1915572901bSJohn Birrell 1925572901bSJohn Birrell SYSINIT(sdt, SI_SUB_KDTRACE, SI_ORDER_FIRST, sdt_init, NULL); 1935572901bSJohn Birrell 1945572901bSJohn Birrell static void 1955572901bSJohn Birrell sdt_uninit(void *arg) 1965572901bSJohn Birrell { 1975572901bSJohn Birrell sx_destroy(&sdt_sx); 1985572901bSJohn Birrell } 1995572901bSJohn Birrell 2005572901bSJohn Birrell SYSUNINIT(sdt, SI_SUB_KDTRACE, SI_ORDER_FIRST, sdt_uninit, NULL); 2015572901bSJohn Birrell 2025572901bSJohn Birrell /* 2035572901bSJohn Birrell * List statically defined tracing providers. 2045572901bSJohn Birrell */ 2055572901bSJohn Birrell int 2065572901bSJohn Birrell sdt_provider_listall(sdt_provider_listall_func_t callback_func,void *arg) 2075572901bSJohn Birrell { 2085572901bSJohn Birrell int error = 0; 2095572901bSJohn Birrell struct sdt_provider *prov; 2105572901bSJohn Birrell 2115572901bSJohn Birrell sx_xlock(&sdt_sx); 2125572901bSJohn Birrell 2135572901bSJohn Birrell TAILQ_FOREACH(prov, &sdt_provider_list, prov_entry) { 2145572901bSJohn Birrell if ((error = callback_func(prov, arg)) != 0) 2155572901bSJohn Birrell break; 2165572901bSJohn Birrell } 2175572901bSJohn Birrell 2185572901bSJohn Birrell sx_xunlock(&sdt_sx); 2195572901bSJohn Birrell 2205572901bSJohn Birrell return (error); 2215572901bSJohn Birrell } 2225572901bSJohn Birrell 2235572901bSJohn Birrell /* 2245572901bSJohn Birrell * List statically defined tracing probes. 2255572901bSJohn Birrell */ 2265572901bSJohn Birrell int 2275572901bSJohn Birrell sdt_probe_listall(struct sdt_provider *prov, 2285572901bSJohn Birrell sdt_probe_listall_func_t callback_func,void *arg) 2295572901bSJohn Birrell { 2305572901bSJohn Birrell int error = 0; 2315572901bSJohn Birrell int locked; 2325572901bSJohn Birrell struct sdt_probe *probe; 2335572901bSJohn Birrell 2345572901bSJohn Birrell locked = sx_xlocked(&sdt_sx); 2355572901bSJohn Birrell if (!locked) 2365572901bSJohn Birrell sx_xlock(&sdt_sx); 2375572901bSJohn Birrell 2385572901bSJohn Birrell TAILQ_FOREACH(probe, &prov->probe_list, probe_entry) { 2395572901bSJohn Birrell if ((error = callback_func(probe, arg)) != 0) 2405572901bSJohn Birrell break; 2415572901bSJohn Birrell } 2425572901bSJohn Birrell 2435572901bSJohn Birrell if (!locked) 2445572901bSJohn Birrell sx_xunlock(&sdt_sx); 2455572901bSJohn Birrell 2465572901bSJohn Birrell return (error); 2475572901bSJohn Birrell } 2485572901bSJohn Birrell 2495572901bSJohn Birrell /* 2505572901bSJohn Birrell * List statically defined tracing probe arguments. 2515572901bSJohn Birrell */ 2525572901bSJohn Birrell int 2535572901bSJohn Birrell sdt_argtype_listall(struct sdt_probe *probe, 2545572901bSJohn Birrell sdt_argtype_listall_func_t callback_func,void *arg) 2555572901bSJohn Birrell { 2565572901bSJohn Birrell int error = 0; 2575572901bSJohn Birrell int locked; 2585572901bSJohn Birrell struct sdt_argtype *argtype; 2595572901bSJohn Birrell 2605572901bSJohn Birrell locked = sx_xlocked(&sdt_sx); 2615572901bSJohn Birrell if (!locked) 2625572901bSJohn Birrell sx_xlock(&sdt_sx); 2635572901bSJohn Birrell 2645572901bSJohn Birrell TAILQ_FOREACH(argtype, &probe->argtype_list, argtype_entry) { 2655572901bSJohn Birrell if ((error = callback_func(argtype, arg)) != 0) 2665572901bSJohn Birrell break; 2675572901bSJohn Birrell } 2685572901bSJohn Birrell 2695572901bSJohn Birrell if (!locked) 2705572901bSJohn Birrell sx_xunlock(&sdt_sx); 2715572901bSJohn Birrell 2725572901bSJohn Birrell return (error); 2735572901bSJohn Birrell } 274