From: Kris Van Hees Date: Tue, 10 Feb 2015 17:12:27 +0000 (-0500) Subject: dtrace: add support for DTrace on sparc64 X-Git-Tag: v4.1.12-111.0.20170907_2225~3^2~3^2~83 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=fb3238e92c2cafd1cff73e181202bdc94b7625f3;p=users%2Fjedix%2Flinux-maple.git dtrace: add support for DTrace on sparc64 This commit adds support for sparc64 to the DTrace modules. It also includes some changes to the arch-independent code, to account for some extra support pieces that are necessary for sparc64 without needing to unnecessarily increase the portion of arch-dependent code. - Add sparc64 implementations for arch-specific portions of DTrace. - Add support for a provider API function (dtps_cleanup_module) to be called for modules when a provider module is being unloaded. When defined, this function can take care of any final cleanup that may be necessary. This facility is used by the SDT code on sparc64 to clean up the trampolines for the SDT probes. - Add support for the pdata member in the module struct. This member (generic pointer) can be populated with a pointer to a structure that holds implementation specific DTrace data for the module. Each arch must define dtrace_module_t (in include//dtrace/mod_arch.h), containing at a minimum: size_t sdt_probe_cnt int sdt_enabled size_t fbt_probe_cnt For sparc64 there is also a sdt_instr_t *sdt_tab member that will hold a memory block for SDT trampolines. The dtrace_module_t structs are allocated from a kmem cache. For modules that exist before dtrace is loaded, the pdata member is populated during the loading of dtrace. Modules loaded after dtrace get it populated from a module notifier. When modules are unloaded, the module notifier cleans up the pdata member. When dtrace itself is unloaded, all remaining modules have their pdata member cleaned up. - Provide a generic method for calling a function on every loaded module in the absence of a kernel facility to allow modules access to the actual list of loaded modules. This adds an exported function void dtrace_for_each_module(for_each_module_fn *fn, void *arg) to be used from module code to call fn(arg, modile) for every module that is loaded. Orabug: 19005048 Signed-off-by: Kris Van Hees Acked-by: Nick Alcock --- diff --git a/dtrace/dt_perf_mod.c b/dtrace/dt_perf_mod.c index 1fd67d812f4c8..9cc1b96ee6904 100644 --- a/dtrace/dt_perf_mod.c +++ b/dtrace/dt_perf_mod.c @@ -49,6 +49,7 @@ DT_PROVIDER_POPS(dt_perf) static dtrace_pops_t dt_perf_pops = { dt_perf_provide, NULL, + NULL, dt_perf_enable, dt_perf_disable, NULL, diff --git a/dtrace/dt_test_mod.c b/dtrace/dt_test_mod.c index b7e059bd57ead..143519ab8be9f 100644 --- a/dtrace/dt_test_mod.c +++ b/dtrace/dt_test_mod.c @@ -49,6 +49,7 @@ DT_PROVIDER_POPS(dt_test) static dtrace_pops_t dt_test_pops = { dt_test_provide, NULL, + NULL, dt_test_enable, dt_test_disable, NULL, diff --git a/dtrace/dtrace_asm_sparc64.S b/dtrace/dtrace_asm_sparc64.S new file mode 100644 index 0000000000000..dcea85cb07bb3 --- /dev/null +++ b/dtrace/dtrace_asm_sparc64.S @@ -0,0 +1,293 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2010-2014 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include + +#define CPU_DTRACE_BADADDR 0x0004 /* DTrace fault: bad address */ +#define ASI_USER ASI_AIUS +#define nwin_minus_one 0x7 + + ENTRY(dtrace_getfp) + retl + mov %fp, %o0 + ENDPROC(dtrace_getfp) + + ENTRY(dtrace_cas32) + cas [%o0], %o1, %o2 + retl + mov %o2, %o0 + ENDPROC(dtrace_cas32) + + ENTRY(dtrace_casptr) + casn [%o0], %o1, %o2 + retl + mov %o2, %o0 + ENDPROC(dtrace_casptr) + + ENTRY(dtrace_fish) + rd %pc, %g5 + ba 0f + add %g5, 12, %g5 + mov %l0, %g4 + mov %l1, %g4 + mov %l2, %g4 + mov %l3, %g4 + mov %l4, %g4 + mov %l5, %g4 + mov %l6, %g4 + mov %l7, %g4 + mov %i0, %g4 + mov %i1, %g4 + mov %i2, %g4 + mov %i3, %g4 + mov %i4, %g4 + mov %i5, %g4 + mov %i6, %g4 + mov %i7, %g4 +0: + sub %o1, 16, %o1 ! Can only retrieve %l's and %i's + sll %o1, 2, %o1 ! Multiply by instruction size + add %g5, %o1, %g5 ! %g5 now contains the instr. to pick + + mov nwin_minus_one, %g4 + + ! + ! First we need to see if the frame that we're fishing in is still + ! contained in the register windows. + ! + rdpr %canrestore, %g2 + cmp %g2, %o0 + bl %icc, 2f + rdpr %cwp, %g1 + sub %g1, %o0, %g3 + brgez,a,pt %g3, 0f + wrpr %g3, %cwp + + ! + ! CWP minus the number of frames is negative; we must perform the + ! arithmetic modulo MAXWIN. + ! + add %g4, %g3, %g3 + inc %g3 + wrpr %g3, %cwp +0: + jmp %g5 + ba 1f +1: + wrpr %g1, %cwp + stn %g4, [%o2] + retl + clr %o0 ! Success; return 0. +2: + ! + ! The frame that we're looking for has been flushed to the stack; the + ! caller will be forced to retrieve regiters from there. + ! + retl + add %g2, 1, %o0 ! Failure; return deepest frame + 1 + ENDPROC(dtrace_fish) + +/* FIXME */ + ENTRY(dtrace_caller) + mov nwin_minus_one, %g4 + rdpr %canrestore, %g2 + cmp %g2, %o0 + bl %icc, 1f + rdpr %cwp, %g1 + sub %g1, %o0, %g3 + brgez,a,pt %g3, 0f + wrpr %g3, %cwp + ! + ! CWP minus the number of frames is negative; we must perform the + ! arithmetic modulo MAXWIN. + ! + add %g4, %g3, %g3 + inc %g3 + wrpr %g3, %cwp +0: + mov %i7, %g4 + wrpr %g1, %cwp + retl + mov %g4, %o0 +1: + ! + ! The caller has been flushed to the stack. This is unlikely + ! (interrupts are disabled in dtrace_probe()), but possible (the + ! interrupt inducing the spill may have been taken before the + ! call to dtrace_probe()). + ! + retl + mov -1, %o0 + ENDPROC(dtrace_caller) + + ENTRY(dtrace_copyin) + tst %o2 + bz 2f + clr %g1 + lduba [%o0 + %g1]ASI_USER, %g2 +0: + ! check for an error if the count is 4k-aligned + andcc %g1, 0xfff, %g0 + bnz,pt %icc, 1f + stub %g2, [%o1 + %g1] + lduh [%o3], %g3 + andcc %g3, CPU_DTRACE_BADADDR, %g0 + bnz,pn %icc, 2f + nop +1: + inc %g1 + cmp %g1, %o2 + bl,a 0b + lduba [%o0 + %g1]ASI_USER, %g2 +2: + retl + nop + ENDPROC(dtrace_copyin) + + ENTRY(dtrace_copyinstr) + tst %o2 + bz 2f + clr %g1 + lduba [%o0 + %g1]ASI_USER, %g2 +0: + stub %g2, [%o1 + %g1] + ! check for an error if the count is 4k-aligned + andcc %g1, 0xfff, %g0 + bnz,pt %icc, 1f + inc %g1 + lduh [%o3], %g3 + andcc %g3, CPU_DTRACE_BADADDR, %g0 + bnz,pn %icc, 2f + nop +1: + cmp %g2, 0 + be 2f + cmp %g1, %o2 + bl,a 0b + lduba [%o0 + %g1]ASI_USER, %g2 +2: + retl + nop + ENDPROC(dtrace_copyinstr) + + ENTRY(dtrace_copyout) + tst %o2 + bz 2f + clr %g1 + ldub [%o0 + %g1], %g2 +0: + ! check for an error if the count is 4k-aligned + andcc %g1, 0xfff, %g0 + bnz,pt %icc, 1f + stuba %g2, [%o1 + %g1]ASI_USER + lduh [%o3], %g3 + andcc %g3, CPU_DTRACE_BADADDR, %g0 + bnz,pn %icc, 2f + nop +1: + inc %g1 + cmp %g1, %o2 + bl,a 0b + ldub [%o0 + %g1], %g2 +2: + retl + nop + ENDPROC(dtrace_copyout) + + ENTRY(dtrace_copyoutstr) + tst %o2 + bz 2f + clr %g1 + ldub [%o0 + %g1], %g2 +0: + stuba %g2, [%o1 + %g1]ASI_USER + ! check for an error if the count is 4k-aligned + andcc %g1, 0xfff, %g0 + bnz,pt %icc, 1f + inc %g1 + lduh [%o3], %g3 + andcc %g3, CPU_DTRACE_BADADDR, %g0 + bnz,pn %icc, 2f + nop +1: + cmp %g2, 0 + be 2f + cmp %g1, %o2 + bl,a 0b + ldub [%o0 + %g1], %g2 +2: + retl + nop + ENDPROC(dtrace_copyoutstr) + + ENTRY(dtrace_fulword) + clr %o1 + ldna [%o0]ASI_USER, %o1 + retl + mov %o1, %o0 + ENDPROC(dtrace_fulword) + + ENTRY(dtrace_fuword8) + clr %o1 + lduba [%o0]ASI_AIUS, %o1 + retl + mov %o1, %o0 + ENDPROC(dtrace_fuword8) + + ENTRY(dtrace_fuword16) + clr %o1 + lduha [%o0]ASI_AIUS, %o1 + retl + mov %o1, %o0 + ENDPROC(dtrace_fuword16) + + ENTRY(dtrace_fuword32) + clr %o1 + lda [%o0]ASI_AIUS, %o1 + retl + mov %o1, %o0 + ENDPROC(dtrace_fuword32) + + ENTRY(dtrace_fuword64) + clr %o1 + ldxa [%o0]ASI_AIUS, %o1 + retl + mov %o1, %o0 + ENDPROC(dtrace_fuword64) + + ENTRY(dtrace_probe_error) + save %sp, -192, %sp + sethi %hi(dtrace_probeid_error), %l0 + ld [%l0 + %lo(dtrace_probeid_error)], %o0 + mov %i0, %o1 + mov %i1, %o2 + mov %i2, %o3 + mov %i3, %o4 + call dtrace_probe + mov %i4, %o5 + ret + restore + ENDPROC(dtrace_probe_error) diff --git a/dtrace/dtrace_dev.c b/dtrace/dtrace_dev.c index 039d0a1e8b2c4..b41abc23287ff 100644 --- a/dtrace/dtrace_dev.c +++ b/dtrace/dtrace_dev.c @@ -58,6 +58,7 @@ int dtrace_err_verbose; dtrace_pops_t dtrace_provider_ops = { (void (*)(void *, const dtrace_probedesc_t *))dtrace_nullop, (void (*)(void *, struct module *))dtrace_nullop, + (void (*)(void *, struct module *))dtrace_nullop, (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop, (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, @@ -75,6 +76,7 @@ int dtrace_toxranges; static int dtrace_toxranges_max; struct kmem_cache *dtrace_state_cachep; +struct kmem_cache *dtrace_pdata_cachep; static dtrace_pattr_t dtrace_provider_attr = { { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, @@ -1123,7 +1125,33 @@ static struct miscdevice helper_dev = { .fops = &helper_fops, }; -static void dtrace_module_loaded(struct module *mod) +static void module_add_pdata(void *dmy, struct module *mp) +{ + if (mp->pdata) { + pr_warn_once("%s: pdata already assigned for %s\n", + __func__, mp->name); + return; + } + + mp->pdata = kmem_cache_alloc(dtrace_pdata_cachep, + GFP_KERNEL | __GFP_ZERO); +} + +static void module_del_pdata(void *dmy, struct module *mp) +{ + if (!mp->pdata) + return; + + kmem_cache_free(dtrace_pdata_cachep, mp->pdata); + mp->pdata = NULL; +} + +static void dtrace_module_loading(struct module *mp) +{ + module_add_pdata(NULL, mp); +} + +static void dtrace_module_loaded(struct module *mp) { dtrace_provider_t *prv; @@ -1133,7 +1161,7 @@ static void dtrace_module_loaded(struct module *mod) * Give all providers a chance to register probes for this module. */ for (prv = dtrace_provider; prv != NULL; prv = prv->dtpv_next) - prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, mod); + prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, mp); mutex_unlock(&dtrace_provider_lock); @@ -1151,12 +1179,12 @@ static void dtrace_module_loaded(struct module *mod) dtrace_enabling_matchall(); } -static void dtrace_module_unloaded(struct module *mod) +static void dtrace_module_unloaded(struct module *mp) { dtrace_probe_t template, *probe, *first, *next; - dtrace_provider_t *prov; + dtrace_provider_t *prv; - template.dtpr_mod = mod->name; + template.dtpr_mod = mp->name; mutex_lock(&dtrace_provider_lock); mutex_lock(&dtrace_lock); @@ -1189,7 +1217,7 @@ static void dtrace_module_unloaded(struct module *mod) */ if (dtrace_err_verbose) { pr_warning("unloaded module '%s' had " - "enabled probes", mod->name); + "enabled probes", mp->name); } return; @@ -1224,8 +1252,8 @@ static void dtrace_module_unloaded(struct module *mod) for (probe = first; probe != NULL; probe = first) { first = probe->dtpr_nextmod; - prov = probe->dtpr_provider; - prov->dtpv_pops.dtps_destroy(prov->dtpv_arg, probe->dtpr_id, + prv = probe->dtpr_provider; + prv->dtpv_pops.dtps_destroy(prv->dtpv_arg, probe->dtpr_id, probe->dtpr_arg); kfree(probe->dtpr_mod); kfree(probe->dtpr_func); @@ -1233,8 +1261,19 @@ static void dtrace_module_unloaded(struct module *mod) kfree(probe); } + + /* + * Give all providers a chance to do cleanup for this module. + */ + for (prv = dtrace_provider; prv != NULL; prv = prv->dtpv_next) { + if (prv->dtpv_pops.dtps_cleanup_module) + prv->dtpv_pops.dtps_cleanup_module(prv->dtpv_arg, mp); + } + mutex_unlock(&dtrace_lock); mutex_unlock(&dtrace_provider_lock); + + module_del_pdata(NULL, mp); } /* @@ -1312,18 +1351,22 @@ int dtrace_istoxic(uintptr_t kaddr, size_t size) static int dtrace_mod_notifier(struct notifier_block *nb, unsigned long val, void *args) { - struct module *mod = args; + struct module *mp = args; - if (!mod) + if (!mp) return NOTIFY_DONE; switch (val) { + case MODULE_STATE_COMING: + dtrace_module_loading(mp); + break; + case MODULE_STATE_LIVE: - dtrace_module_loaded(mod); + dtrace_module_loaded(mp); break; case MODULE_STATE_GOING: - dtrace_module_unloaded(mod); + dtrace_module_unloaded(mp); break; } @@ -1383,8 +1426,6 @@ int dtrace_dev_init(void) return rc; } - register_module_notifier(&dtrace_modmgmt); - #if defined(CONFIG_DT_FASTTRAP) || defined(CONFIG_DT_FASTTRAP_MODULE) dtrace_helpers_cleanup = dtrace_helpers_destroy; dtrace_helpers_fork = dtrace_helpers_duplicate; @@ -1408,6 +1449,22 @@ int dtrace_dev_init(void) sizeof(dtrace_dstate_percpu_t) * NR_CPUS, 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL); + dtrace_pdata_cachep = kmem_cache_create("dtrace_pdata_cache", + sizeof(dtrace_module_t), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, + NULL); + + /* + * Yes, this is scary... But we know that DTrace is the consumer for + * the pdata object, and all other DTrace modules (and tracing) cannot + * have started yet. Therefore, there isn't any code yet that would + * use the pdata object... + * + * We loop through the list of all loaded modules to populate each with + * a pdata object. Modules loaded after this one will get their pdata + * object assigned using the module notifier hook. + */ + dtrace_for_each_module(module_add_pdata, NULL); /* * Create the probe hashtables. @@ -1491,6 +1548,9 @@ int dtrace_dev_init(void) * the first provider causing the core to be loaded. */ #endif + + register_module_notifier(&dtrace_modmgmt); + mutex_unlock(&dtrace_lock); mutex_unlock(&dtrace_provider_lock); mutex_unlock(&cpu_lock); @@ -1534,7 +1594,21 @@ void dtrace_dev_exit(void) dtrace_byfunc = NULL; dtrace_byname = NULL; + /* + * Yes, this is scary... But we know that DTrace is the consumer for + * the pdata object, and all other DTrace modules (and tracing) must + * be gone by now. Therefore, there isn't any code left that would + * use the pdata object... + * + * We loop through the list of all loaded modules to remove the pdata + * object from each one. Modules that were unloaded prior to this + * point had their pdata object cleaned up using the module notifier + * hook. + */ + dtrace_for_each_module(module_del_pdata, NULL); + kmem_cache_destroy(dtrace_state_cachep); + kmem_cache_destroy(dtrace_pdata_cachep); mutex_unlock(&dtrace_lock); mutex_unlock(&dtrace_provider_lock); diff --git a/dtrace/dtrace_isa_sparc64.c b/dtrace/dtrace_isa_sparc64.c new file mode 100644 index 0000000000000..9176c417efa37 --- /dev/null +++ b/dtrace/dtrace_isa_sparc64.c @@ -0,0 +1,211 @@ +/* + * FILE: dtrace_isa_sparc64.c + * DESCRIPTION: Dynamic Tracing: sparc64 arch-specific support functions + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2010-2014 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include +#include + +#include "dtrace.h" + +/* Register indices */ +#define REG_G0 0 +#define REG_G1 (REG_G0 + 1) +#define REG_G2 (REG_G0 + 2) +#define REG_G3 (REG_G0 + 3) +#define REG_G4 (REG_G0 + 4) +#define REG_G5 (REG_G0 + 5) +#define REG_G6 (REG_G0 + 6) +#define REG_G7 (REG_G0 + 7) + +#define REG_O0 (REG_G7 + 1) /* 8 */ +#define REG_O1 (REG_O0 + 1) +#define REG_O2 (REG_O0 + 2) +#define REG_O3 (REG_O0 + 3) +#define REG_O4 (REG_O0 + 4) +#define REG_O5 (REG_O0 + 5) +#define REG_O6 (REG_O0 + 6) +#define REG_O7 (REG_O0 + 7) + +#define REG_L0 (REG_O7 + 1) /* 16 */ +#define REG_L1 (REG_L0 + 1) +#define REG_L2 (REG_L0 + 2) +#define REG_L3 (REG_L0 + 3) +#define REG_L4 (REG_L0 + 4) +#define REG_L5 (REG_L0 + 5) +#define REG_L6 (REG_L0 + 6) +#define REG_L7 (REG_L0 + 7) + +#define REG_I0 (REG_L7 + 1) /* 24 */ +#define REG_I1 (REG_I0 + 1) +#define REG_I2 (REG_I0 + 2) +#define REG_I3 (REG_I0 + 3) +#define REG_I4 (REG_I0 + 4) +#define REG_I5 (REG_I0 + 5) +#define REG_I6 (REG_I0 + 6) +#define REG_I7 (REG_I0 + 7) + +#define REG_CCR (REG_I7 + 1) /* 32 */ + +#define REG_PC (REG_CCR + 1) /* 33 */ +#define REG_nPC (REG_PC + 1) /* 34 */ +#define REG_Y (REG_nPC + 1) /* 35 */ + +#define REG_ASI (REG_Y + 1) /* 36 */ +#define REG_FPRS (REG_ASI + 1) /* 37 */ + +/* + * Our own personal SPARC V9 stack layout structure, because the one in + * /arch/sparc/include/uapi/asm/ptrace.h is wrong. + */ +struct sparc_v9_frame { + unsigned long locals[8]; + unsigned long ins[6]; + struct sparc_v9_frame *fp; + unsigned long callers_pc; + unsigned long xargs[6]; + unsigned long xxargs[1]; +}; + +uint64_t dtrace_getarg(int argno, int aframes) +{ + uintptr_t val; + struct sparc_v9_frame *fp; + uint64_t rval; + int lvl; + + /* + * Account for the fact that dtrace_getarg() consumes an additional + * stack frame. + */ + aframes++; + +#ifdef FIXME + if (argno < 6) { + if ((lvl = dtrace_fish(aframes, REG_I0 + argno, &val)) == 0) + return val; + } else { + if ((lvl = dtrace_fish(aframes, REG_I6, &val)) == 0) { + /* + * We have a stack pointer; grab the argument. + */ + fp = (struct sparc_v9_frame *)(val + STACK_BIAS); + + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + rval = fp->ins[argno - 6]; + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); + + return rval; + } + } +#endif + /* + * This is the slow way to get to function arguments. We force a full + * register windows flush, and then walk the chain of frames until we + * get to the one we need. The flush is expensive, so we should try to + * avoid this whenever possible. + */ + fp = (struct sparc_v9_frame *)((uintptr_t)dtrace_getfp() + STACK_BIAS); + flushw_all(); + + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + + for (aframes -= 1; aframes; aframes--) + fp = (struct sparc_v9_frame *)((uintptr_t)fp->fp + STACK_BIAS); + + if (argno < 6) { + rval = fp->ins[argno]; + } else { + fp = (struct sparc_v9_frame *)((uintptr_t)fp->fp + STACK_BIAS); + rval = fp->xxargs[argno - 6]; + } + + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); + + return rval; +} + +ulong_t dtrace_getreg(struct task_struct *task, uint_t reg) +{ + struct pt_regs *rp = task_pt_regs(task); + + if (reg <= REG_O7) /* G[0-7], O[0-7] */ + return rp->u_regs[reg]; /* 0 .. 15 */ + + if (reg <= REG_I7) { /* L[0-7], I[0-7] */ + if (rp->tstate & TSTATE_PRIV) { + struct reg_window *rw; + + rw = (struct reg_window *)(rp->u_regs[14] + STACK_BIAS); + + if (reg <= REG_L7) + return rw->locals[reg - REG_L0]; + else + return rw->ins[reg - REG_I0]; + } else { + mm_segment_t old_fs; + struct reg_window __user *rw; + ulong_t val; + + rw = (struct reg_window __user *) + (rp->u_regs[14] + STACK_BIAS); + + old_fs = get_fs(); + set_fs(USER_DS); + + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + + if (reg < REG_L7) + val = dtrace_fulword(&rw->locals[reg - REG_L0]); + else + val = dtrace_fulword(&rw->locals[reg - REG_I0]); + + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); + + set_fs(old_fs); + + return val; + } + } + + switch (reg) { + case REG_CCR: + return (rp->tstate & TSTATE_CCR) >> TSTATE_CCR_SHIFT; + case REG_PC: + return rp->tpc; + case REG_nPC: + return rp->tnpc; + case REG_Y: + return rp->y; + case REG_ASI: + return (rp->tstate & TSTATE_ASI) >> TSTATE_ASI_SHIFT; + case REG_FPRS: + return 0; /* FIXME */ + default: + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return 0; + } +} diff --git a/dtrace/dtrace_probe.c b/dtrace/dtrace_probe.c index e042e82fe4a8d..0437ba21810c2 100644 --- a/dtrace/dtrace_probe.c +++ b/dtrace/dtrace_probe.c @@ -196,11 +196,7 @@ void dtrace_probe_provide(dtrace_probedesc_t *desc, dtrace_provider_t *prv) */ prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, THIS_MODULE); -#ifdef FIXME - mutex_lock(&module_mutex); -#else rcu_read_lock(); -#endif list_for_each_entry(mod, &(THIS_MODULE->list), list) { /* @@ -224,11 +220,7 @@ void dtrace_probe_provide(dtrace_probedesc_t *desc, dtrace_provider_t *prv) prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, mod); } -#ifdef FIXME - mutex_unlock(&module_mutex); -#else rcu_read_unlock(); -#endif } while (all && (prv = prv->dtpv_next) != NULL); } diff --git a/dtrace/dtrace_util.c b/dtrace/dtrace_util.c index 8063f01608f5c..40cdc2c769cf3 100644 --- a/dtrace/dtrace_util.c +++ b/dtrace/dtrace_util.c @@ -26,6 +26,7 @@ */ #include +#include #include #include @@ -175,3 +176,43 @@ void dtrace_cred2priv(const cred_t *cr, uint32_t *privp, uid_t *uidp) } #endif } + +void dtrace_for_each_module(for_each_module_fn *fn, void *arg) +{ + struct module *mp; + + /* + * The Linux kernel does not export the modules list explicitly, nor + * is there an API to do so. However, when operating on a module + * that is in the modules list, we can traverse the entire list anyway. + * That's what we're doing here. + * + * The current module is the anchor and sentinel for the loop, so we + * need to call the worker function explicitly for that module. We + * must also identify and skip the list header because that is not a + * valid module at all. + */ + fn(arg, THIS_MODULE); + + rcu_read_lock(); + + list_for_each_entry_rcu(mp, &(THIS_MODULE->list), list) { +#ifdef MODULES_VADDR + if ((uintptr_t)mp < MODULES_VADDR || + (uintptr_t)mp >= MODULES_END) + continue; +#else + if ((uintptr_t)mp < VMALLOC_START || + (uintptr_t)mp >= VMALLOC_END) + continue; +#endif + + if (mp->state != MODULE_STATE_LIVE) + continue; + + fn(arg, mp); + } + + rcu_read_unlock(); +} +EXPORT_SYMBOL(dtrace_for_each_module); diff --git a/dtrace/fasttrap_dev.c b/dtrace/fasttrap_dev.c index 8325f08ed6911..2b3bef83fafc1 100644 --- a/dtrace/fasttrap_dev.c +++ b/dtrace/fasttrap_dev.c @@ -790,6 +790,7 @@ static dtrace_pops_t pid_pops = { #ifdef FIXME fasttrap_pid_provide, NULL, + NULL, fasttrap_pid_enable, fasttrap_pid_disable, NULL, @@ -804,6 +805,7 @@ static dtrace_pops_t pid_pops = { static dtrace_pops_t usdt_pops = { fasttrap_pid_provide, NULL, + NULL, fasttrap_pid_enable, fasttrap_pid_disable, NULL, diff --git a/dtrace/include/dtrace/dtrace_impl.h b/dtrace/include/dtrace/dtrace_impl.h index 01482893b14e7..23f5d446caead 100644 --- a/dtrace/include/dtrace/dtrace_impl.h +++ b/dtrace/include/dtrace/dtrace_impl.h @@ -852,6 +852,9 @@ extern int dtrace_badattr(const dtrace_attribute_t *); extern int dtrace_badname(const char *); extern void dtrace_cred2priv(const cred_t *, uint32_t *, uid_t *); +typedef void for_each_module_fn(void *, struct module *); +extern void dtrace_for_each_module(for_each_module_fn *fn, void *arg); + extern void ctf_forceload(void); #define dtrace_membar_producer() smp_wmb() diff --git a/dtrace/include/dtrace/dtrace_impl_defines.h b/dtrace/include/dtrace/dtrace_impl_defines.h index c18586ac84fe0..e17f185ff340e 100644 --- a/dtrace/include/dtrace/dtrace_impl_defines.h +++ b/dtrace/include/dtrace/dtrace_impl_defines.h @@ -36,6 +36,8 @@ #include #include +#include + typedef typeof(instruction_pointer((struct pt_regs *)0)) pc_t; typedef enum dtrace_activity { @@ -207,4 +209,6 @@ typedef enum dtrace_speculation_state { # define dtrace_preempt_on() preempt_enable_no_resched() #endif +#define PDATA(mp) ((dtrace_module_t *)mp->pdata) + #endif /* _LINUX_DTRACE_IMPL_DEFINES_H */ diff --git a/dtrace/include/dtrace/provider.h b/dtrace/include/dtrace/provider.h index c5a3a4f252d62..1811658a279e8 100644 --- a/dtrace/include/dtrace/provider.h +++ b/dtrace/include/dtrace/provider.h @@ -707,6 +707,7 @@ typedef struct dtrace_pops { void (*dtps_provide)(void *, const struct dtrace_probedesc *); void (*dtps_provide_module)(void *, struct module *); + void (*dtps_cleanup_module)(void *, struct module *); int (*dtps_enable)(void *, dtrace_id_t, void *); void (*dtps_disable)(void *, dtrace_id_t, void *); void (*dtps_suspend)(void *, dtrace_id_t, void *); diff --git a/dtrace/include/sparc64/dtrace/mod_arch.h b/dtrace/include/sparc64/dtrace/mod_arch.h new file mode 100644 index 0000000000000..7254ae84c420a --- /dev/null +++ b/dtrace/include/sparc64/dtrace/mod_arch.h @@ -0,0 +1,45 @@ +#ifndef _SPARC64_MOD_ARCH_H +#define _SPARC64_MOD_ARCH_H + +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2009-2014 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include + +/* + * Structure to hold DTrace specific information about modules (including the + * core kernel module). Note that each module (and the main kernel) already + * has three fields that relate to probing: + * - sdt_probes: description of SDT probes in the module + * - sdt_probec: number of SDT probes in the module + * - pdata: pointer to a dtrace_module struct (for DTrace) + */ +typedef struct dtrace_module { + size_t sdt_probe_cnt; + int sdt_enabled; + sdt_instr_t *sdt_tab; + size_t fbt_probe_cnt; +} dtrace_module_t; + +#endif /* _SPARC64_MOD_ARCH_H */ diff --git a/dtrace/include/sparc64/dtrace/sdt_arch.h b/dtrace/include/sparc64/dtrace/sdt_arch.h new file mode 100644 index 0000000000000..c21ef6126fe93 --- /dev/null +++ b/dtrace/include/sparc64/dtrace/sdt_arch.h @@ -0,0 +1,38 @@ +#ifndef _SPARC64_SDT_ARCH_H +#define _SPARC64_SDT_ARCH_H + +/* + * Statically Defined Tracing Implementation defines + * + * Note: The contents of this file are private to the implementation of the + * DTrace subsystem and are subject to change at any time without notice. + */ + +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2009-2014 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#define SDT_AFRAMES 1 + +#endif /* _SPARC64_SDT_ARCH_H */ diff --git a/dtrace/include/x86_64/dtrace/mod_arch.h b/dtrace/include/x86_64/dtrace/mod_arch.h new file mode 100644 index 0000000000000..5db59861d2b27 --- /dev/null +++ b/dtrace/include/x86_64/dtrace/mod_arch.h @@ -0,0 +1,42 @@ +#ifndef _X86_64_MOD_ARCH_H +#define _X86_64_MOD_ARCH_H + +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2009-2014 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Structure to hold DTrace specific information about modules (including the + * core kernel module). Note that each module (and the main kernel) already + * has three fields that relate to probing: + * - sdt_probes: description of SDT probes in the module + * - sdt_probec: number of SDT probes in the module + * - pdata: pointer to a dtrace_module struct (for DTrace) + */ +typedef struct dtrace_module { + size_t sdt_probe_cnt; + int sdt_enabled; + size_t fbt_probe_cnt; +} dtrace_module_t; + +#endif /* _X86_64_MOD_ARCH_H */ diff --git a/dtrace/profile_mod.c b/dtrace/profile_mod.c index e3cc2b16b449f..17ea344054244 100644 --- a/dtrace/profile_mod.c +++ b/dtrace/profile_mod.c @@ -49,6 +49,7 @@ DT_PROVIDER_POPS(profile) static dtrace_pops_t profile_pops = { profile_provide, NULL, + NULL, profile_enable, profile_disable, NULL, diff --git a/dtrace/sdt_dev.c b/dtrace/sdt_dev.c index c0bc989f59853..4f5acc7f1df35 100644 --- a/dtrace/sdt_dev.c +++ b/dtrace/sdt_dev.c @@ -113,13 +113,13 @@ void sdt_provide_module(void *arg, struct module *mp) /* * Nothing to do if the module SDT probes were already created. */ - if (mp->sdt_nprobes != 0) + if (PDATA(mp)->sdt_probe_cnt != 0) return; /* * Nothing to do if there are no SDT probes. */ - if (mp->num_dtrace_probes == 0) + if (mp->sdt_probec == 0) return; /* @@ -134,7 +134,7 @@ void sdt_provide_module(void *arg, struct module *mp) if (!sdt_provide_module_arch(arg, mp)) return; - for (idx = 0, sdpd = mp->sdt_probes; idx < mp->num_dtrace_probes; + for (idx = 0, sdpd = mp->sdt_probes; idx < mp->sdt_probec; idx++, sdpd++) { char *name = sdpd->sdpd_name, *nname; int i, j; @@ -196,7 +196,7 @@ void sdt_provide_module(void *arg, struct module *mp) sdpd->sdpd_func, nname, SDT_AFRAMES, sdp); - mp->sdt_nprobes++; + PDATA(mp)->sdt_probe_cnt++; } sdp->sdp_hashnext = sdt_probetab[ @@ -224,8 +224,8 @@ int _sdt_enable(void *arg, dtrace_id_t id, void *parg) * reference we took above, because we only need one to prevent the * module from being unloaded. */ - sdp->sdp_module->mod_nenabled++; - if (sdp->sdp_module->mod_nenabled > 1) + PDATA(sdp->sdp_module)->sdt_enabled++; + if (PDATA(sdp->sdp_module)->sdt_enabled > 1) module_put(sdp->sdp_module); while (sdp != NULL) { @@ -246,8 +246,8 @@ void _sdt_disable(void *arg, dtrace_id_t id, void *parg) * being unloaded. If we disable the last probe on the module, we can * drop the reference. */ - sdp->sdp_module->mod_nenabled--; - if (sdp->sdp_module->mod_nenabled == 0) + PDATA(sdp->sdp_module)->sdt_enabled--; + if (PDATA(sdp->sdp_module)->sdt_enabled == 0) module_put(sdp->sdp_module); while (sdp != NULL) { @@ -296,7 +296,7 @@ void sdt_destroy(void *arg, dtrace_id_t id, void *parg) { sdt_probe_t *sdp = parg; - sdp->sdp_module->sdt_nprobes--; + PDATA(sdp->sdp_module)->sdt_probe_cnt--; while (sdp != NULL) { sdt_probe_t *old = sdp, *last, *hash; diff --git a/dtrace/sdt_impl.h b/dtrace/sdt_impl.h index bcfe2533968f6..f60ca25120456 100644 --- a/dtrace/sdt_impl.h +++ b/dtrace/sdt_impl.h @@ -45,6 +45,7 @@ extern void sdt_enable_arch(sdt_probe_t *, dtrace_id_t, void *); extern void sdt_disable_arch(sdt_probe_t *, dtrace_id_t, void *); extern void sdt_provide_module(void *, struct module *); +extern void sdt_cleanup_module(void *, struct module *); extern int _sdt_enable(void *, dtrace_id_t, void *); extern void _sdt_disable(void *, dtrace_id_t, void *); extern void sdt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); diff --git a/dtrace/sdt_mod.c b/dtrace/sdt_mod.c index f189edca980ea..c946cf8e5951f 100644 --- a/dtrace/sdt_mod.c +++ b/dtrace/sdt_mod.c @@ -114,6 +114,11 @@ DT_PROVIDER_POPS(sdt) static dtrace_pops_t sdt_pops = { NULL, sdt_provide_module, +#ifdef CONFIG_SPARC64 + sdt_cleanup_module, +#else + NULL, +#endif sdt_enable, sdt_disable, NULL, diff --git a/dtrace/sdt_sparc64.c b/dtrace/sdt_sparc64.c new file mode 100644 index 0000000000000..915a7874cb209 --- /dev/null +++ b/dtrace/sdt_sparc64.c @@ -0,0 +1,209 @@ +/* + * FILE: sdt_sparc64.c + * DESCRIPTION: Statically Defined Tracing: arch support (sparc64) + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2010, 2011, 2012 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include +#include +#include +#include + +#include "dtrace.h" +#include "dtrace_dev.h" +#include "sdt_impl.h" + +/* + * The trampoline follows the instruction sequence (if sdp_id > 0xfff): + * save + * sethi %hi(sdp->sdp_id), %o0 + * or %o0, %lo(sdp->sdp_id), %o0 + * mov %i0, %o1 + * mov %i1, %o2 + * mov %i2, %o3 + * mov %i3, %o4 + * call 0xfff> + * mov %i4, %o5 + * ret + * restore + * + * otherwise it follows: + * save + * or %g0, sdp->sdp_id, %o0 + * mov %i0, %o1 + * mov %i1, %o2 + * mov %i2, %o3 + * mov %i3, %o4 + * call + * mov %i4, %o5 + * ret + * restore + */ +#define SDT_TRAMP_SIZE 11 + +#define SA(x) ((long)ALIGN((x), 4)) +#define MINFRAME STACKFRAME_SZ + +#define SDT_REG_G0 0 +#define SDT_REG_O0 8 +#define SDT_REG_O1 (SDT_REG_O0 + 1) +#define SDT_REG_O2 (SDT_REG_O1 + 1) +#define SDT_REG_O3 (SDT_REG_O2 + 1) +#define SDT_REG_O4 (SDT_REG_O3 + 1) +#define SDT_REG_O5 (SDT_REG_O4 + 1) +#define SDT_REG_I0 24 +#define SDT_REG_I1 (SDT_REG_I0 + 1) +#define SDT_REG_I2 (SDT_REG_I1 + 1) +#define SDT_REG_I3 (SDT_REG_I2 + 1) +#define SDT_REG_I4 (SDT_REG_I3 + 1) +#define SDT_REG_I5 (SDT_REG_I4 + 1) + +#define SDT_OP_SETHI 0x1000000 +#define SDT_OP_OR 0x80100000 + +#define SDT_FMT2_RD_SHIFT 25 +#define SDT_IMM22_SHIFT 10 +#define SDT_IMM22_MASK 0x3fffff +#define SDT_IMM10_MASK 0x3ff + +#define SDT_FMT3_RD_SHIFT 25 +#define SDT_FMT3_RS1_SHIFT 14 +#define SDT_FMT3_RS2_SHIFT 0 +#define SDT_FMT3_IMM (1 << 13) + +#define SDT_SIMM13_MASK 0x1fff +#define SDT_SIMM13_MAX ((int32_t)0xfff) + +#define SDT_SAVE (0x9de3a000 | \ + ((-SA(MINFRAME)) & SDT_SIMM13_MASK)) +#define SDT_SETHI(v, rd) (SDT_OP_SETHI | (rd << SDT_FMT2_RD_SHIFT) | \ + ((v >> SDT_IMM22_SHIFT) & SDT_IMM22_MASK)) +#define SDT_ORLO(rs, v, rd) (SDT_OP_OR | ((rs) << SDT_FMT3_RS1_SHIFT) | \ + ((rd) << SDT_FMT3_RD_SHIFT) | SDT_FMT3_IMM | \ + ((v) & SDT_IMM10_MASK)) +#define SDT_ORSIMM13(rs, v, rd) (SDT_OP_OR | ((rs) << SDT_FMT3_RS1_SHIFT) | \ + ((rd) << SDT_FMT3_RD_SHIFT) | SDT_FMT3_IMM | \ + ((v) & SDT_SIMM13_MASK)) +#define SDT_MOV(rs, rd) (SDT_OP_OR | \ + (SDT_REG_G0 << SDT_FMT3_RS1_SHIFT) | \ + ((rs) << SDT_FMT3_RS2_SHIFT) | \ + ((rd) << SDT_FMT3_RD_SHIFT)) +#define SDT_CALL(s, d) (((uint32_t)1 << 30) | \ + ((((uintptr_t)(d) - (uintptr_t)(s)) >> 2) & \ + 0x3fffffff)) +#define SDT_RET 0x81c7e008 +#define SDT_RESTORE 0x81e80000 + +void sdt_provide_probe_arch(sdt_probe_t *sdp, struct module *mp, int idx) +{ + sdt_instr_t *trampoline = &(PDATA(mp)->sdt_tab[idx * + SDT_TRAMP_SIZE]); + sdt_instr_t *instr = trampoline; + + *instr++ = SDT_SAVE; + + if (sdp->sdp_id > (uint32_t)SDT_SIMM13_MAX) { + *instr++ = SDT_SETHI(sdp->sdp_id, SDT_REG_O0); + *instr++ = SDT_ORLO(SDT_REG_O0, sdp->sdp_id, SDT_REG_O0); + } else { + *instr++ = SDT_ORSIMM13(SDT_REG_G0, sdp->sdp_id, SDT_REG_O0); + } + + *instr++ = SDT_MOV(SDT_REG_I0, SDT_REG_O1); + *instr++ = SDT_MOV(SDT_REG_I1, SDT_REG_O2); + *instr++ = SDT_MOV(SDT_REG_I2, SDT_REG_O3); + *instr++ = SDT_MOV(SDT_REG_I3, SDT_REG_O4); + *instr = SDT_CALL(instr, dtrace_probe); + instr++; + *instr++ = SDT_MOV(SDT_REG_I4, SDT_REG_O5); + + *instr++ = SDT_RET; + *instr++ = SDT_RESTORE; + + sdp->sdp_patchval = SDT_CALL(sdp->sdp_patchpoint, trampoline); + sdp->sdp_savedval = *sdp->sdp_patchpoint; +} + +int sdt_provide_module_arch(void *arg, struct module *mp) +{ + /* + * The vmlinux pseudo-module (core Linux kernel) is a special case... + */ + if (mp == dtrace_kmod && PDATA(mp)->sdt_tab == NULL) { + PDATA(mp)->sdt_tab = (sdt_instr_t *)ALIGN( + (uintptr_t)PDATA(mp) + sizeof(dtrace_module_t), 8); + return 1; + } + + if (PDATA(mp)->sdt_tab == NULL) { + PDATA(mp)->sdt_tab = __vmalloc(mp->sdt_probec * + SDT_TRAMP_SIZE * sizeof(sdt_instr_t), + GFP_DMA32, PAGE_KERNEL); + + if (PDATA(mp)->sdt_tab == NULL) { + pr_info("%s(): cannot allocate trampolines for %s\n", + __func__, mp->name); + return 0; + } + } + + return 1; +} + +void sdt_cleanup_module(void *dmy, struct module *mp) +{ + if (PDATA(mp)->sdt_tab) { + vfree(PDATA(mp)->sdt_tab); + PDATA(mp)->sdt_tab = NULL; + } +} + +void sdt_enable_arch(sdt_probe_t *sdp, dtrace_id_t id, void *arg) +{ + *sdp->sdp_patchpoint = sdp->sdp_patchval; +} + +void sdt_disable_arch(sdt_probe_t *sdp, dtrace_id_t id, void *arg) +{ + *sdp->sdp_patchpoint = sdp->sdp_savedval; +} + +int sdt_dev_init_arch(void) +{ + return 0; +} + +static void module_del_sdt_tab(void *dmy, struct module *mp) +{ + if (PDATA(mp)->sdt_tab) { + vfree(PDATA(mp)->sdt_tab); + PDATA(mp)->sdt_tab = NULL; + } +} + +void sdt_dev_exit_arch(void) +{ + dtrace_for_each_module(module_del_sdt_tab, NULL); +} diff --git a/dtrace/systrace_mod.c b/dtrace/systrace_mod.c index 3f89f8ea2f59b..87b7fe037b813 100644 --- a/dtrace/systrace_mod.c +++ b/dtrace/systrace_mod.c @@ -49,6 +49,7 @@ DT_PROVIDER_POPS(systrace) static dtrace_pops_t syscall_pops = { systrace_provide, NULL, + NULL, systrace_enable, systrace_disable, NULL,