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 <masami.hiramatsu...@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;
>  }
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to