From: Kris Van Hees Date: Tue, 17 Dec 2013 23:06:57 +0000 (-0500) Subject: dtrace: implement SDT in kernel modules X-Git-Tag: v4.1.12-92~313^2~50 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=1587572cac3ccab5ce1403004d531d9de4a7cd0f;p=users%2Fjedix%2Flinux-maple.git dtrace: implement SDT in kernel modules Full implementation of SDT probes in kernel modules. The dtrace_sdt.sh script has been modified to handle both the creation of the SDT stubs and the SDT info. It's syntax has therefore changed: dtrace_sdt.sh sdtstub * or dtrace_sdt.sh sdtinfo vmlinux.o or dtrace_sdt.sh sdtinfo vmlinux.o .tmp_vmlinux1 or dtrace_sdt.sh sdtinfo .o kmod The first form generates a stub file in assembler to ensure that the (fake) functions that are called from SDT probe points will not longer be reported as undefined symbols, and to ensure that when SDT is not enabled, the probes become calls to a function that simply returns. The second form creates the initial (dummy) SDT info file for the kernel linking process, mainly to ensure that its size is known. The third form then creates the true SDT info file for the kernel, based on the kernel object file and the first stage linked kernel image. The fourth and final form generates SDT info for a kernel module, based on its initial linked object. This commit also enables the test probes in the dt_test module. Orabug: 17851716 Reviewed-by: Jamie Iles Signed-off-by: Kris Van Hees Conflicts: Makefile scripts/Makefile.build --- diff --git a/Makefile b/Makefile index 468d99cca309..44b764208235 100644 --- a/Makefile +++ b/Makefile @@ -1452,8 +1452,8 @@ clean: $(clean-dirs) $(call cmd,rmfiles) @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ - -o -name '*.ko.*' \ - -o -name '*.dwo' \ + -o -name '*.ko.*' -o -name '*.dwo' \ + -o -name '*.sdtinfo.c' -o -name '*.sdtstub.S' \ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ -o -name '*.symtypes' -o -name 'modules.order' \ -o -name 'modules.builtin' -o -name 'objects.builtin' \ diff --git a/include/linux/sdt.h b/include/linux/sdt.h index affca435065b..57dcb93c4652 100644 --- a/include/linux/sdt.h +++ b/include/linux/sdt.h @@ -134,7 +134,9 @@ typedef struct dtrace_sdt_probeinfo { char name[0]; } __aligned(sizeof(unsigned long)) dtrace_sdt_probeinfo_t; +void dtrace_sdt_init(void); void dtrace_sdt_register(struct module *); +void dtrace_sdt_exit(void); #endif /* __KERNEL__ */ @@ -434,7 +436,7 @@ typedef struct sdt_probedesc { struct sdt_probedesc *sdpd_next; /* next static probe */ } sdt_probedesc_t; -extern void dtrace_register_builtins(void); +/* extern void dtrace_register_builtins(void); */ #ifdef __cplusplus } diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index 8f46d9617449..4a371c867302 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -58,6 +58,7 @@ void dtrace_os_init(void) SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL); + dtrace_sdt_init(); dtrace_sdt_register(dtrace_kmod); } EXPORT_SYMBOL(dtrace_os_init); diff --git a/kernel/dtrace/dtrace_sdt.c b/kernel/dtrace/dtrace_sdt.c index 0844941de070..3b6d2b6f5636 100644 --- a/kernel/dtrace/dtrace_sdt.c +++ b/kernel/dtrace/dtrace_sdt.c @@ -19,6 +19,7 @@ #define SDT_NOP_SIZE 5 const char *sdt_prefix = "__dtrace_probe_"; +uint8_t nops[SDT_NOP_SIZE]; /* This code is based on apply_alternatives and text_poke_early. It needs to * run before SMP is initialized in order to avoid SMP problems with patching @@ -44,15 +45,10 @@ static void __init_or_module text_poke_batch(struct text_poke_param *reqs, restart_nmi(); } -static int sdt_probe_add(struct module *mp, char *name, char *func, - uintptr_t addr, struct text_poke_param *tpp, - void *nops) +static int sdt_probe_set(sdt_probedesc_t *sdp, char *name, char *func, + uintptr_t addr, struct text_poke_param *tpp) { - sdt_probedesc_t *sdp; - uint8_t *instr; - - if ((sdp = kmalloc(sizeof(sdt_probedesc_t), GFP_KERNEL)) == NULL) - return 1; + uint8_t *instr; if ((sdp->sdpd_name = kstrdup(name, GFP_KERNEL)) == NULL) { kfree(sdp); @@ -68,10 +64,7 @@ static int sdt_probe_add(struct module *mp, char *name, char *func, /* adjust relocation address to beginning of call instruction */ instr = (uint8_t *)(addr - 1); - /* TBD: use a kernel list? */ sdp->sdpd_offset = (uintptr_t)instr; - sdp->sdpd_next = mp->sdt_probes; - mp->sdt_probes = sdp; tpp->addr = instr; tpp->opcode = nops; @@ -80,13 +73,17 @@ static int sdt_probe_add(struct module *mp, char *name, char *func, return 0; } +/* + * Register the SDT probes for the core kernel, i.e. SDT probes that reside in + * vmlinux. For SDT probes in kernel modules, we use dtrace_mod_notifier(). + */ void dtrace_sdt_register(struct module *mod) { int i, cnt; dtrace_sdt_probeinfo_t *pi = (dtrace_sdt_probeinfo_t *)&dtrace_sdt_probes; void *nextpi; - uint8_t nops[SDT_NOP_SIZE]; + sdt_probedesc_t *sdps; struct text_poke_param *reqs; if (mod == NULL) { @@ -95,19 +92,25 @@ void dtrace_sdt_register(struct module *mod) return; } + /* + * Just in case we run into failures further on... + */ + mod->sdt_probes = NULL; + mod->num_dtrace_probes = 0; + if (dtrace_sdt_nprobes == 0) return; /* - * A little unusual, but potentially necessary. While we could use a - * single NOP sequence of length SDT_NOP_SIZE, we need to consider the - * fact that when a SDT probe point is enabled, a single invalid opcode - * is written on the first byte of this NOP sequence. By using a - * sequence of a 1-byte NOP, followed by a (SDT_NOP_SIZE - 1) byte NOP - * sequence, we play it pretty safe. + * Allocate the array of SDT probe descriptions to be registered in the + * vmlinux pseudo-module. */ - add_nops(nops, 1); - add_nops(nops + 1, SDT_NOP_SIZE - 1); + sdps = (sdt_probedesc_t *)vmalloc(dtrace_sdt_nprobes * + sizeof(sdt_probedesc_t)); + if (sdps == NULL) { + pr_warning("%s: cannot allocate SDT probe array\n", __func__); + return; + } /* * Set up a batch of text_poke requests that will handle replacing all @@ -118,16 +121,17 @@ void dtrace_sdt_register(struct module *mod) vmalloc(dtrace_sdt_nprobes * sizeof(struct text_poke_param)); if (reqs == NULL) { - pr_warning("%s: failed to allocate text_poke_param array\n", + pr_warning("%s: cannot allocate text_poke_param array\n", __func__); + vfree(sdps); return; } for (i = cnt = 0; cnt < dtrace_sdt_nprobes; i++) { char *func = pi->name + pi->name_len + 1; - if (sdt_probe_add(dtrace_kmod, pi->name, func, pi->addr, - &reqs[cnt], nops)) + if (sdt_probe_set(&sdps[cnt], pi->name, func, pi->addr, + &reqs[cnt])) pr_warning("%s: failed to add SDT probe %s\n", __func__, pi->name); else @@ -139,7 +143,12 @@ void dtrace_sdt_register(struct module *mod) pi = nextpi; } + mod->sdt_probes = sdps; + mod->num_dtrace_probes = cnt; + text_poke_batch(reqs, cnt); + + vfree(reqs); } static int __init nosdt(char *str) @@ -151,6 +160,90 @@ static int __init nosdt(char *str) early_param("nosdt", nosdt); +static int dtrace_mod_notifier(struct notifier_block *nb, unsigned long val, + void *args) +{ + struct module *mod = args; + struct text_poke_param *reqs, *req; + int idx, cnt; + sdt_probedesc_t *sdp; + + /* + * We only need to capture modules in the COMING state, we need a valid + * module structure as argument, and the module needs to actually have + * SDT probes. If not, ignore... + */ + if (val != MODULE_STATE_COMING) + return NOTIFY_DONE; + if (!mod) + return NOTIFY_DONE; + if (mod->num_dtrace_probes == 0 || mod->sdt_probes == NULL) + return NOTIFY_DONE; + + /* + * Set up a batch of text_poke requests that will handle replacing all + * calls at SDT probe locations with the NOP sequence. Allocate the + * requests array, and then fill it in. + */ + reqs = (struct text_poke_param *) + vmalloc(dtrace_sdt_nprobes * + sizeof(struct text_poke_param)); + if (reqs == NULL) { + pr_warning("%s: cannot allocate text_poke_param array (%s)\n", + __func__, mod->name); + return NOTIFY_DONE; + } + + for (idx = cnt = 0, req = reqs, sdp = mod->sdt_probes; + idx < mod->num_dtrace_probes; idx++, sdp++) { + /* + * Fix-up the offset to reflect the relocated address of the + * probe. We subtract 1 to put us at the beginning of the call + * instruction. We verify that the offset won't put us beyond + * the module core, just to be safe. + */ + sdp->sdpd_offset += (uintptr_t)mod->module_core - 1; + if (!within_module_core(sdp->sdpd_offset, mod)) { + pr_warning("%s: SDT probe outside module core %s\n", + __func__, mod->name); + continue; + } + + req->addr = (uint8_t *)sdp->sdpd_offset; + req->opcode = nops; + req->len = SDT_NOP_SIZE; + + cnt++; + req++; + } + + text_poke_batch(reqs, cnt); + + vfree(reqs); + + return NOTIFY_DONE; +} + +static struct notifier_block dtrace_modfix = { + .notifier_call = dtrace_mod_notifier, +}; + +void dtrace_sdt_init(void) +{ + /* + * A little unusual, but potentially necessary. While we could use a + * single NOP sequence of length SDT_NOP_SIZE, we need to consider the + * fact that when a SDT probe point is enabled, a single invalid opcode + * is written on the first byte of this NOP sequence. By using a + * sequence of a 1-byte NOP, followed by a (SDT_NOP_SIZE - 1) byte NOP + * sequence, we play it pretty safe. + */ + add_nops(nops, 1); + add_nops(nops + 1, SDT_NOP_SIZE - 1); + + register_module_notifier(&dtrace_modfix); +} + #if defined(CONFIG_DT_DT_PERF) || defined(CONFIG_DT_DT_PERF_MODULE) void dtrace_sdt_perf(void) { diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 01df30af4d4a..81ec4f729d5c 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -380,9 +380,38 @@ $($(subst $(obj)/,,$(@:.o=-y)))), $^) quiet_cmd_link_multi-y = LD $@ cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) +ifdef CONFIG_DTRACE + +# We need secondary expansion for the %.sdtstub.S creation rule +.SECONDEXPANSION: + +sdtgen = scripts/dtrace_sdt.sh + +quiet_cmd_sdtstub = SDTSTB $@ + cmd_sdtstub = $(sdtgen) sdtstub $@ \ + $(filter $(addprefix $(obj)/, \ + $($(subst $(obj)/,,$(@:.sdtstub.S=-objs))) \ + $($(subst $(obj)/,,$(@:.sdtstub.S=-y)))), \ + $(multi-objs-m)) + +$(multi-used-m:.o=.sdtstub.S) : %.sdtstub.S: $(multi-objs-m) + $(call if_changed,sdtstub) + +$(multi-used-m:.o=.sdtstub.o) : %.sdtstub.o: %.sdtstub.S + $(call if_changed,as_o_S) + +$(multi-used-m) : %.o: %.sdtstub.o + +quiet_cmd_link_multi-m = LD [M] $@ +cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $*.sdtstub.o $(cmd_secanalysis) + +else + quiet_cmd_link_multi-m = LD [M] $@ cmd_link_multi-m = $(cmd_link_multi-y) +endif + $(multi-used-y): FORCE $(call if_changed,link_multi-y) $(call multi_depend, $(multi-used-y), .o, -objs -y) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index ebeef7c89269..4cf971c3cc70 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -105,18 +105,34 @@ vmlinux.o: FORCE $(symverfile): __modpost ; $(modules:.ko=.mod.c): __modpost ; -# Step 5), compile all *.mod.c files +# Step 5), compile all *.mod.c files (includes the generation of SDT data) # modname is set to make c_flags define KBUILD_MODNAME modname = $(notdir $(@:.mod.o=)) quiet_cmd_cc_o_c = CC $@ cmd_cc_o_c = $(CC) $(c_flags) $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE) \ - -c -o $@ $< + -I$(dir $@) -c -o $@ $< + +ifdef CONFIG_DTRACE + +sdtgen = scripts/dtrace_sdt.sh + +quiet_cmd_sdtinfo = SDTINF $@ + cmd_sdtinfo = $(sdtgen) sdtinfo $@ $< kmod + +$(modules:.ko=.sdtinfo.c): %.sdtinfo.c: %.o + $(call cmd,sdtinfo) + +$(modules:.ko=.mod.o): %.mod.o: %.mod.c %.sdtinfo.c FORCE + $(call if_changed_dep,cc_o_c) +else $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE $(call if_changed_dep,cc_o_c) +endif + targets += $(modules:.ko=.mod.o) # Step 6), generate CTF for the entire kernel, or for the module alone if this diff --git a/scripts/dtrace_sdt.sh b/scripts/dtrace_sdt.sh index 73a0d11814f6..27979b8ed418 100755 --- a/scripts/dtrace_sdt.sh +++ b/scripts/dtrace_sdt.sh @@ -2,12 +2,54 @@ LANG=C +opr="$1" +shift +if [ -z "$opr" ]; then + echo "ERROR: Missing operation" > /dev/stderr + exit 1 +fi + +tfn="$1" +shift +if [ -z "$tfn" ]; then + echo "ERROR: Missing target filename" > /dev/stderr + exit 1 +fi + ofn="$1" lfn="$2" +if [ -z "$ofn" ]; then + echo "ERROR: Missing object file argument" > /dev/stderr + exit 1 +fi + +if [ "$opr" = "sdtstub" ]; then + ${NM} -u $* | \ + grep __dtrace_probe_ | sort | uniq | \ + ${AWK} '{ + printf("\t.globl %s\n\t.type %s,@function\n%s:\n", + $2, $2, $2); + count++; + } + + END { + if (count) + print "\tret"; + else + exit(1); + }' > $tfn + exit 0 +fi + +if [ "$opr" != "sdtinfo" ]; then + echo "ERROR: Invalid operation, should be sdtstub or sdtinfo" > /dev/stderr + exit 1 +fi + ( objdump -htr "$ofn" | \ - awk -v lfn=${lfn} \ + awk -v lfn="${lfn}" \ '/^Sections:/ { getline; getline; @@ -27,7 +69,7 @@ lfn="$2" $3 == "F" { printf "%16s %s F %s\n", $4, $1, $6; - if (!lfn) + if (!lfn || lfn == "kmod") printf "%s t %s\n", $1, $6; next; @@ -47,9 +89,10 @@ lfn="$2" next; }' | \ sort - [ "x${lfn}" != "x" ] && nm ${lfn} + [ "x${lfn}" != "x" -a "x${lfn}" != "xkmod" ] && nm ${lfn} ) | \ - awk 'function addl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { + awk -v lfn="${lfn}" \ + 'function addl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { tmp = $0; if (length(v0) > 8) { d = length(v0); @@ -111,21 +154,27 @@ lfn="$2" } BEGIN { - print "#include "; - print "#if BITS_PER_LONG == 64"; - print "# define PTR .quad"; - print "# define ALGN .align 8"; - print "#else"; - print "# define PTR .long"; - print "# define ALGN .align 4"; - print "#endif"; - - print "\t.section .rodata, \042a\042"; - print ""; - - print ".globl dtrace_sdt_probes"; - print "\tALGN"; - print "dtrace_sdt_probes:"; + if (lfn != "kmod") { + print "#include "; + print "#if BITS_PER_LONG == 64"; + print "# define PTR .quad"; + print "# define ALGN .align 8"; + print "#else"; + print "# define PTR .long"; + print "# define ALGN .align 4"; + print "#endif"; + + print "\t.section .rodata, \042a\042"; + print ""; + + print ".globl dtrace_sdt_probes"; + print "\tALGN"; + print "dtrace_sdt_probes:"; + } else { + print "#include "; + } + + probec = 0; } $2 ~ /^[tT]$/ { @@ -140,13 +189,21 @@ lfn="$2" for (i = 1; i <= NF; i++) { prb = $i; pn = fun":"prb; + ad = addl(baseaddr, poffst[pn]); + + if (lfn != "kmod") { + print "\tPTR\t0x" ad; + print "\tPTR\t" length(prb); + print "\tPTR\t" length(fun); + print "\t.asciz\t\042" prb "\042"; + print "\t.asciz\t\042" fun "\042"; + print "\tALGN"; + } else { + if (probec == 0) + print "static sdt_probedesc_t\t_sdt_probes[] = {"; - print "\tPTR\t0x" addl(baseaddr, poffst[pn]); - print "\tPTR\t" length(prb); - print "\tPTR\t" length(fun); - print "\t.asciz\t\042" prb "\042"; - print "\t.asciz\t\042" fun "\042"; - print "\tALGN"; + print " {\042" prb "\042, \042"fun"\042, 0x" ad " },"; + } probec++; } @@ -175,14 +232,25 @@ lfn="$2" } END { - print ""; - print ".globl dtrace_sdt_nprobes"; - print "\tALGN"; - print "dtrace_sdt_nprobes:"; - print "\tPTR\t" probec; + if (lfn != "kmod") { + print ""; + print ".globl dtrace_sdt_nprobes"; + print "\tALGN"; + print "dtrace_sdt_nprobes:"; + print "\tPTR\t" probec; + } else { + if (probec > 0) + print "};"; + else + print "#define _sdt_probes\tNULL"; + + print "#define _sdt_probec\t" probec; + } if (errc > 0) { print errc " errors generating SDT probe data." > /dev/stderr; exit 1; } - }' + }' > $tfn + +exit 0 diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index c61eca2494ae..bd9e6c288bf6 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -39,30 +39,25 @@ info() # Generate the SDT probe point stubs object file # ${1} output file -sdtstubs() +sdtstub() { - info MKSTUBS ${1} - ${NM} -u ${KBUILD_VMLINUX_INIT} ${KBUILD_VMLINUX_MAIN} | \ - grep __dtrace_probe_ | sort | uniq | \ - ${AWK} '{ - printf("\t.globl %s\n\t.type %s,@function\n%s:\n", - $2, $2, $2); - }' > .tmp_sdtstubs.S - echo " ret" >> .tmp_sdtstubs.S + info SDTSTB ${1} + ${srctree}/scripts/dtrace_sdt.sh sdtstub .tmp_sdtstub.S \ + ${KBUILD_VMLINUX_INIT} ${KBUILD_VMLINUX_MAIN} local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" - ${CC} ${aflags} -c -o ${1} .tmp_sdtstubs.S + ${CC} ${aflags} -c -o ${1} .tmp_sdtstub.S } # Generate the SDT probe info for object file ${1} and kernel image ${2} # ${3} output file sdtinfo() { - info DT-SDT ${3} + info SDTINF ${3} - ${srctree}/scripts/dtrace_sdt.sh ${1} ${2} > .tmp_sdtinfo.S + ${srctree}/scripts/dtrace_sdt.sh sdtinfo .tmp_sdtinfo.S ${1} ${2} local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" @@ -150,7 +145,7 @@ cleanup() rm -f .old_version rm -f .tmp_System.map rm -f .tmp_kallsyms* - rm -f .tmp_sdtstubs.* + rm -f .tmp_sdtstub.* rm -f .tmp_sdtinfo.* rm -f .tmp_version rm -f .tmp_vmlinux* @@ -183,12 +178,12 @@ case "${KCONFIG_CONFIG}" in . "./${KCONFIG_CONFIG}" esac -sdtstubso="" +sdtstubo="" sdtinfoo="" if [ -n "${CONFIG_DTRACE}" ]; then - sdtstubso=.tmp_sdtstubs.o + sdtstubo=.tmp_sdtstub.o sdtinfoo=.tmp_sdtinfo.o - sdtstubs ${sdtstubso} + sdtstub ${sdtstubo} fi #link vmlinux.o @@ -242,7 +237,7 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then fi # step 1 - vmlinux_link "${sdtstubso} ${sdtinfoo}" .tmp_vmlinux1 + vmlinux_link "${sdtstubo} ${sdtinfoo}" .tmp_vmlinux1 kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o if [ -n "${CONFIG_DTRACE}" ]; then @@ -250,7 +245,7 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then fi # step 2 - vmlinux_link "${sdtstubso} .tmp_kallsyms1.o ${sdtinfoo}" .tmp_vmlinux2 + vmlinux_link "${sdtstubo} .tmp_kallsyms1.o ${sdtinfoo}" .tmp_vmlinux2 kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o # step 2a @@ -258,14 +253,14 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then kallsymso=.tmp_kallsyms3.o kallsyms_vmlinux=.tmp_vmlinux3 - vmlinux_link "${sdtstubso} .tmp_kallsyms2.o ${sdtinfoo}" .tmp_vmlinux3 + vmlinux_link "${sdtstubo} .tmp_kallsyms2.o ${sdtinfoo}" .tmp_vmlinux3 kallsyms .tmp_vmlinux3 .tmp_kallsyms3.o fi fi info LD vmlinux -vmlinux_link "${sdtstubso} ${kallsymso} ${sdtinfoo}" vmlinux +vmlinux_link "${sdtstubo} ${kallsymso} ${sdtinfoo}" vmlinux if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then info SORTEX vmlinux diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 91ee1b2e0f9a..b5bd379634de 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2099,10 +2099,21 @@ static void check_exports(struct module *mod) **/ static void add_header(struct buffer *b, struct module *mod) { + const char *modname; + + if ((modname = strrchr(mod->name, '/')) != NULL) + modname++; + else + modname = mod->name; + buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "\n"); + buf_printf(b, "#ifdef CONFIG_DTRACE\n"); + buf_printf(b, "# include \"%s.sdtinfo.c\"\n", modname); + buf_printf(b, "#endif\n"); + buf_printf(b, "\n"); buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); buf_printf(b, "\n"); buf_printf(b, "__visible struct module __this_module\n"); @@ -2115,6 +2126,10 @@ static void add_header(struct buffer *b, struct module *mod) "\t.exit = cleanup_module,\n" "#endif\n"); buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); + buf_printf(b, "#ifdef CONFIG_DTRACE\n"); + buf_printf(b, "\t.sdt_probes = _sdt_probes,\n"); + buf_printf(b, "\t.num_dtrace_probes = _sdt_probec,\n"); + buf_printf(b, "#endif\n"); buf_printf(b, "};\n"); }