lkml.org 
[lkml]   [2013]   [Dec]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[PATCH -tip 2/3] perf-probe: Support dwarf on uprobe events
From
Date
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)

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
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;
}



\
 
 \ /
  Last update: 2013-12-20 20:41    [W:0.142 / U:0.144 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site