From 161dad5cda797f8e01cf43923524df63809b3990 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Wed, 27 Jan 2016 21:36:01 -0500 Subject: [PATCH] dtrace: support multiple instances of the same probe in a function Up until now, no function in the kernel (or modules) ever had more than a single instance of the same probe in a single function. Due to compiler optimizations, sparc64 caused duplication of a probe call in kernel code. The existing code was not adequate to deal wih that situation, causing the probe to not get enabled in more than one location, thereby causing it to not fire when expected. This commit adds support to dtrace_sdt.sh to handle multiple instances of the same probe in a single function. It also adds equialent support in the SDT boot-time processing to ensure that probes with multiple locations in a function are linked together so that all locations are enabled and disabled together. (While this was found as an artifact of testing the 4.3 kernel series, it also applies to 4.1 because it is not unlikely that a compiler upgrade may cause the same problem there.) Orabug: 22514493 Signed-off-by: Kris Van Hees Acked-by: Nick Alcock --- kernel/dtrace/dtrace_sdt_core.c | 11 +++++-- scripts/dtrace_sdt.sh | 52 +++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/kernel/dtrace/dtrace_sdt_core.c b/kernel/dtrace/dtrace_sdt_core.c index 5e4f189df1572..0a93aac1e0324 100644 --- a/kernel/dtrace/dtrace_sdt_core.c +++ b/kernel/dtrace/dtrace_sdt_core.c @@ -20,7 +20,8 @@ const char *sdt_prefix = "__dtrace_probe_"; static int sdt_probe_set(sdt_probedesc_t *sdp, char *name, char *func, - uintptr_t addr, asm_instr_t **paddr) + uintptr_t addr, asm_instr_t **paddr,\ + sdt_probedesc_t *prv) { if ((sdp->sdpd_name = kstrdup(name, GFP_KERNEL)) == NULL) { kfree(sdp); @@ -34,9 +35,14 @@ static int sdt_probe_set(sdt_probedesc_t *sdp, char *name, char *func, } sdp->sdpd_offset = addr; + sdp->sdpd_next = NULL; *paddr = (asm_instr_t *)addr; + if (prv && strcmp(prv->sdpd_name, sdp->sdpd_name) == 0 + && strcmp(prv->sdpd_func, sdp->sdpd_func) == 0) + prv->sdpd_next = sdp; + return 0; } @@ -96,7 +102,8 @@ void dtrace_sdt_register(struct module *mp) char *func = pi->name + pi->name_len + 1; if (sdt_probe_set(&sdps[cnt], pi->name, func, pi->addr, - &addrs[cnt])) + &addrs[cnt], + cnt > 0 ? &sdps[cnt - 1] : NULL)) pr_warning("%s: failed to add SDT probe %s\n", __func__, pi->name); else diff --git a/scripts/dtrace_sdt.sh b/scripts/dtrace_sdt.sh index 1fce667026ca0..528121243651d 100755 --- a/scripts/dtrace_sdt.sh +++ b/scripts/dtrace_sdt.sh @@ -197,28 +197,32 @@ fi for (i = 1; i <= NF; i++) { prb = $i; - pn = fun":"prb; - ad = addl(baseaddr, poffst[pn]); - - if (arch == "x86" || arch == "x86_64") - ad = subl(ad, 1); - - if (lfn != "kmod") { - printf "\tPTR\t0x%s\n", ad; - printf "\tPTR\t%d\n", length(prb); - printf "\tPTR\t%d\n", length(fun); - printf "\t.asciz\t\042%s\042\n", prb; - printf "\t.asciz\t\042%s\042\n", fun; - print "\tALGN"; - } else { - if (probec == 0) - print "static sdt_probedesc_t\t_sdt_probes[] = {"; + pn = fun ":" prb; + + for (j = 0; j < pidcnt[pn]; j++) { + pid = pn"-"j; + ad = addl(baseaddr, poffst[pid]); + + if (arch == "x86" || arch == "x86_64") + ad = subl(ad, 1); + + if (lfn != "kmod") { + printf "\tPTR\t0x%s\n", ad; + printf "\tPTR\t%d\n", length(prb); + printf "\tPTR\t%d\n", length(fun); + printf "\t.asciz\t\042%s\042\n", prb; + printf "\t.asciz\t\042%s\042\n", fun; + print "\tALGN"; + } else { + if (probec == 0) + print "static sdt_probedesc_t\t_sdt_probes[] = {"; + + printf " {\042%s\042, \042%s\042, 0x%s },\n", \ + prb, fun, ad; + } - printf " {\042%s\042, \042%s\042, 0x%s },\n", \ - prb, fun, ad; + probec++; } - - probec++; } } @@ -238,8 +242,12 @@ fi sub(/^0+/, "", $2); pn = fun":"$4; - probes[fun] = $4 " " probes[fun]; - poffst[pn] = subl($2, addr); + if (!pidcnt[pn]) + probes[fun] = $4 " " probes[fun]; + + pid = pn"-"int(pidcnt[pn]); + pidcnt[pn]++; + poffst[pid] = subl($2, addr); next; } -- 2.50.1