(2013/12/21 3:01), Arnaldo Carvalho de Melo wrote:
> 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?
> 

OK, here is the examples from 0/3. :)
Or, should I better put this into the patch description too?

For example)
- Shows the probe-able lines of the given function
----
# ./perf probe -x perf --line map__load
<map__load@/home/fedora/ksrc/linux-2.6/tools/perf/util/map.c:0>
      0  int map__load(struct map *map, symbol_filter_t filter)
      1  {
      2         const char *name = map->dso->long_name;
                int nr;

      5         if (dso__loaded(map->dso, map->type))
      6                 return 0;

      8         nr = dso__load(map->dso, map, filter);
      9         if (nr < 0) {
     10                 if (map->dso->has_build_id) {
----

- Shows the available variables of the given line
----
# ./perf probe -x perf --vars map__load:8
Available variables at map__load:8
        @<map__load+96>
                char*   name
                struct map*     map
                symbol_filter_t filter
        @<map__find_symbol+112>
                char*   name
                symbol_filter_t filter
        @<map__find_symbol_by_name+136>
                char*   name
                symbol_filter_t filter
        @<map_groups__find_symbol_by_name+176>
                char*   name
                struct map*     map
                symbol_filter_t filter
----

- Set a probe with available vars on the given line
----
# ./perf probe -x perf --add 'map__load:8 $vars'

Added new events:
  probe_perf:map__load (on map__load:8 with $vars)
  probe_perf:map__load_1 (on map__load:8 with $vars)
  probe_perf:map__load_2 (on map__load:8 with $vars)
  probe_perf:map__load_3 (on map__load:8 with $vars)

You can now use it in all perf tools, such as:

        perf record -e probe_perf:map__load_3 -aR sleep 1
----

> 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;
>>  }
>>
> 


-- 
Masami HIRAMATSU
IT Management Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu...@hitachi.com


--
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