From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3847 invoked by alias); 20 Dec 2013 18:02:04 -0000 Mailing-List: contact systemtap-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: systemtap-owner@sourceware.org Received: (qmail 3838 invoked by uid 89); 20 Dec 2013 18:02:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=BAYES_00,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-qc0-f178.google.com Received: from mail-qc0-f178.google.com (HELO mail-qc0-f178.google.com) (209.85.216.178) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 20 Dec 2013 18:02:03 +0000 Received: by mail-qc0-f178.google.com with SMTP id i17so2493648qcy.37 for ; Fri, 20 Dec 2013 10:02:00 -0800 (PST) X-Received: by 10.224.156.77 with SMTP id v13mr16560809qaw.80.1387562520824; Fri, 20 Dec 2013 10:02:00 -0800 (PST) Received: from zoo.ghostprotocols.net ([177.159.12.241]) by mx.google.com with ESMTPSA id o5sm18107243qeg.2.2013.12.20.10.01.57 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Dec 2013 10:01:59 -0800 (PST) Received: by zoo.ghostprotocols.net (Postfix, from userid 1000) id 52A0E1E1791; Fri, 20 Dec 2013 15:01:54 -0300 (BRT) Date: Fri, 20 Dec 2013 18:02:00 -0000 From: Arnaldo Carvalho de Melo To: Masami Hiramatsu Cc: Ingo Molnar , Srikar Dronamraju , David Ahern , lkml , "Steven Rostedt (Red Hat)" , Oleg Nesterov , "David A. Long" , systemtap@sourceware.org, yrl.pp-manager.tt@hitachi.com, Namhyung Kim Subject: Re: [PATCH -tip 2/3] perf-probe: Support dwarf on uprobe events Message-ID: <20131220180154.GB28878@ghostprotocols.net> References: <20131220100255.7169.19384.stgit@kbuild-fedora.novalocal> <20131220100259.7169.57512.stgit@kbuild-fedora.novalocal> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20131220100259.7169.57512.stgit@kbuild-fedora.novalocal> X-Url: http://acmel.wordpress.com User-Agent: Mutt/1.5.21 (2010-09-15) X-SW-Source: 2013-q4/txt/msg00469.txt.bz2 Em Fri, Dec 20, 2013 at 10:02:59AM +0000, Masami Hiramatsu escreveu: > Support dwarf(debuginfo) based operations for uprobe events. > With this change, perf probe can analyze debuginfo of user > application binary to set up new uprobe event. > This allows perf-probe --add/--line works with -x option. > (Actually, --vars has already accepted -x option) Can you provide an example? Showing output from commands when new features are implemented can speed up the process of having it used :-) - Arnaldo > Signed-off-by: Masami Hiramatsu > --- > tools/perf/builtin-probe.c | 2 > tools/perf/util/probe-event.c | 230 +++++++++++++++++++++++++++-------------- > 2 files changed, 155 insertions(+), 77 deletions(-) > > diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c > index b40d064..7fc566a 100644 > --- a/tools/perf/builtin-probe.c > +++ b/tools/perf/builtin-probe.c > @@ -420,7 +420,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) > } > > #ifdef HAVE_DWARF_SUPPORT > - if (params.show_lines && !params.uprobes) { > + if (params.show_lines) { > if (params.mod_events) { > pr_err(" Error: Don't use --line with" > " --add/--del.\n"); > diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c > index 05be5de..e27cecb 100644 > --- a/tools/perf/util/probe-event.c > +++ b/tools/perf/util/probe-event.c > @@ -186,6 +186,90 @@ static int init_user_exec(void) > return ret; > } > > +static const char *__target_symbol; > +static struct symbol *__result_sym; > + > +static int filter_target_symbol(struct map *map __maybe_unused, > + struct symbol *sym) > +{ > + if (strcmp(__target_symbol, sym->name) == 0) { > + __result_sym = sym; > + return 0; > + } > + return 1; > +} > + > +/* Find the offset of the symbol in the executable binary */ > +static int find_symbol_offset(const char *exec, const char *function, > + unsigned long *offs) > +{ > + struct symbol *sym; > + struct map *map = NULL; > + int ret = -EINVAL; > + > + if (!offs) > + return -EINVAL; > + > + map = dso__new_map(exec); > + if (!map) { > + pr_warning("Cannot find appropriate DSO for %s.\n", exec); > + goto out; > + } > + pr_debug("Search %s in %s\n", function, exec); > + __target_symbol = function; > + __result_sym = NULL; > + if (map__load(map, filter_target_symbol)) { > + pr_err("Failed to find %s in %s.\n", function, exec); > + goto out; > + } > + sym = __result_sym; > + if (!sym) { > + pr_warning("Cannot find %s in DSO %s\n", function, exec); > + goto out; > + } > + > + *offs = (map->start > sym->start) ? map->start : 0; > + *offs += sym->start + map->pgoff; > + ret = 0; > +out: > + if (map) { > + dso__delete(map->dso); > + map__delete(map); > + } > + return ret; > +} > + > +static int convert_exec_to_group(const char *exec, char **result) > +{ > + char *ptr1, *ptr2, *exec_copy; > + char buf[64]; > + int ret; > + > + exec_copy = strdup(exec); > + if (!exec_copy) > + return -ENOMEM; > + > + ptr1 = basename(exec_copy); > + if (!ptr1) { > + ret = -EINVAL; > + goto out; > + } > + > + ptr2 = strpbrk(ptr1, "-._"); > + if (ptr2) > + *ptr2 = '\0'; > + ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); > + if (ret < 0) > + goto out; > + > + *result = strdup(buf); > + ret = *result ? 0 : -ENOMEM; > + > +out: > + free(exec_copy); > + return ret; > +} > + > static int convert_to_perf_probe_point(struct probe_trace_point *tp, > struct perf_probe_point *pp) > { > @@ -261,6 +345,45 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, > return 0; > } > > +static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, > + int ntevs, const char *exec, > + const char *group) > +{ > + int i, ret = 0; > + unsigned long offset; > + char buf[32]; > + > + if (!exec) > + return 0; > + > + for (i = 0; i < ntevs && ret >= 0; i++) { > + /* Get proper offset */ > + ret = find_symbol_offset(exec, tevs[i].point.symbol, &offset); > + if (ret < 0) > + break; > + offset += tevs[i].point.offset; > + tevs[i].point.offset = 0; > + free(tevs[i].point.symbol); > + ret = e_snprintf(buf, 32, "0x%lx", offset); > + if (ret < 0) > + break; > + tevs[i].point.module = strdup(exec); > + tevs[i].point.symbol = strdup(buf); > + if (!tevs[i].point.symbol || !tevs[i].point.module) { > + ret = -ENOMEM; > + break; > + } > + /* Replace group name if not given */ > + if (!group) { > + free(tevs[i].group); > + ret = convert_exec_to_group(exec, &tevs[i].group); > + } > + tevs[i].uprobes = true; > + } > + > + return ret; > +} > + > static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, > int ntevs, const char *module) > { > @@ -305,15 +428,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, > struct debuginfo *dinfo; > int ntevs, ret = 0; > > - if (pev->uprobes) { > - if (need_dwarf) { > - pr_warning("Debuginfo-analysis is not yet supported" > - " with -x/--exec option.\n"); > - return -ENOSYS; > - } > - return convert_name_to_addr(pev, target); > - } > - > dinfo = open_debuginfo(target); > > if (!dinfo) { > @@ -332,9 +446,14 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, > > if (ntevs > 0) { /* Succeeded to find trace events */ > pr_debug("find %d probe_trace_events.\n", ntevs); > - if (target) > - ret = add_module_to_probe_trace_events(*tevs, ntevs, > - target); > + if (target) { > + if (pev->uprobes) > + ret = add_exec_to_probe_trace_events(*tevs, > + ntevs, target, pev->group); > + else > + ret = add_module_to_probe_trace_events(*tevs, > + ntevs, target); > + } > return ret < 0 ? ret : ntevs; > } > > @@ -654,9 +773,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, > return -ENOSYS; > } > > - if (pev->uprobes) > - return convert_name_to_addr(pev, target); > - > return 0; > } > > @@ -1916,11 +2032,26 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, > int ret = 0, i; > struct probe_trace_event *tev; > > + if (pev->uprobes) > + if (!pev->group) { > + ret = convert_exec_to_group(target, &pev->group); > + if (ret != 0) { > + pr_warning("Failed to make group name.\n"); > + return ret; > + } > + } > + > /* Convert perf_probe_event with debuginfo */ > ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); > if (ret != 0) > return ret; /* Found in debuginfo or got an error */ > > + if (pev->uprobes) { > + ret = convert_name_to_addr(pev, target); > + if (ret < 0) > + return ret; > + } > + > /* Allocate trace event buffer */ > tev = *tevs = zalloc(sizeof(struct probe_trace_event)); > if (tev == NULL) > @@ -2279,88 +2410,35 @@ int show_available_funcs(const char *target, struct strfilter *_filter, > static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) > { > struct perf_probe_point *pp = &pev->point; > - struct symbol *sym; > - struct map *map = NULL; > - char *function = NULL; > int ret = -EINVAL; > - unsigned long long vaddr = 0; > + unsigned long vaddr = 0; > > if (!pp->function) { > pr_warning("No function specified for uprobes"); > goto out; > } > > - function = strdup(pp->function); > - if (!function) { > - pr_warning("Failed to allocate memory by strdup.\n"); > - ret = -ENOMEM; > - goto out; > - } > - > - map = dso__new_map(exec); > - if (!map) { > - pr_warning("Cannot find appropriate DSO for %s.\n", exec); > - goto out; > - } > - available_func_filter = strfilter__new(function, NULL); > - if (map__load(map, filter_available_functions)) { > - pr_err("Failed to load map.\n"); > - goto out; > - } > - > - sym = map__find_symbol_by_name(map, function, NULL); > - if (!sym) { > - pr_warning("Cannot find %s in DSO %s\n", function, exec); > + ret = find_symbol_offset(exec, pp->function, &vaddr); > + if (ret < 0) > goto out; > - } > > - if (map->start > sym->start) > - vaddr = map->start; > - vaddr += sym->start + pp->offset + map->pgoff; > + vaddr += pp->offset; > pp->offset = 0; > > if (!pev->event) { > - pev->event = function; > - function = NULL; > - } > - if (!pev->group) { > - char *ptr1, *ptr2, *exec_copy; > - > - pev->group = zalloc(sizeof(char *) * 64); > - exec_copy = strdup(exec); > - if (!exec_copy) { > - ret = -ENOMEM; > - pr_warning("Failed to copy exec string.\n"); > - goto out; > - } > + pev->event = pp->function; > + } else > + free(pp->function); > > - ptr1 = strdup(basename(exec_copy)); > - if (ptr1) { > - ptr2 = strpbrk(ptr1, "-._"); > - if (ptr2) > - *ptr2 = '\0'; > - e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP, > - ptr1); > - free(ptr1); > - } > - free(exec_copy); > - } > - free(pp->function); > pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS); > if (!pp->function) { > ret = -ENOMEM; > pr_warning("Failed to allocate memory by zalloc.\n"); > goto out; > } > - e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr); > + e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%lx", vaddr); > ret = 0; > > out: > - if (map) { > - dso__delete(map->dso); > - map__delete(map); > - } > - if (function) > - free(function); > return ret; > } >