lkml.org 
[lkml]   [2015]   [May]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH] perf probe: Fix segfault when glob matching function without debuginfo
    Date
    Commit 4c859351226c920b227fec040a3b447f0d482af3 ("perf probe: Support
    glob wildcards for function name") introduces segfault problems when
    debuginfo is not available:

    # perf probe 'sys_w*'
    Added new events:
    Segmentation fault

    The first problem resides in find_probe_trace_events_from_map(). In
    that function, find_probe_functions() is called to match each symbol
    against glob to find the number of matching functions, but still use
    map__for_each_symbol_by_name() to find 'struct symbol' for matching
    functions. Unfortunately, map__for_each_symbol_by_name() does
    exact matching by searching in an rbtree. It doesn't know glob
    matching, and not easy for it to support it because it use rbtree based
    binary search, but we are unable to ensure all names matched by the
    glob (any glob passed by user) reside in one subtree.

    This patch drops map__for_each_symbol_by_name(). Since there is no
    rbtree again, re-matching all symbols costs a lot. This patch avoid it
    by saving all matching results into an array (syms).

    The second problem is the lost of tp->realname. In
    __add_probe_trace_events(), if pev->point.function is glob, the event
    name should be set to tev->point.realname. This patch ensures its
    existence by strdup sym->name instead of leaving a NULL pointer there.

    After this patch:

    # perf probe 'sys_w*'
    Added new events:
    probe:sys_waitid (on sys_w*)
    probe:sys_wait4 (on sys_w*)
    probe:sys_waitpid (on sys_w*)
    probe:sys_write (on sys_w*)
    probe:sys_writev (on sys_w*)

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

    perf record -e probe:sys_writev -aR sleep 1

    Signed-off-by: Wang Nan <wangnan0@huawei.com>
    ---
    tools/perf/util/probe-event.c | 26 +++++++++++++++++++++-----
    1 file changed, 21 insertions(+), 5 deletions(-)

    diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
    index 9052e7b..4f1bc78 100644
    --- a/tools/perf/util/probe-event.c
    +++ b/tools/perf/util/probe-event.c
    @@ -2493,7 +2493,8 @@ close_out:
    return ret;
    }

    -static int find_probe_functions(struct map *map, char *name)
    +static int find_probe_functions(struct map *map, char *name,
    + struct symbol **syms)
    {
    int found = 0;
    struct symbol *sym;
    @@ -2503,8 +2504,11 @@ static int find_probe_functions(struct map *map, char *name)
    return 0;

    map__for_each_symbol(map, sym, tmp) {
    - if (strglobmatch(sym->name, name))
    + if (strglobmatch(sym->name, name)) {
    found++;
    + if (syms && found < probe_conf.max_probes)
    + syms[found - 1] = sym;
    + }
    }

    return found;
    @@ -2527,11 +2531,12 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
    struct map *map = NULL;
    struct ref_reloc_sym *reloc_sym = NULL;
    struct symbol *sym;
    + struct symbol **syms = NULL;
    struct probe_trace_event *tev;
    struct perf_probe_point *pp = &pev->point;
    struct probe_trace_point *tp;
    int num_matched_functions;
    - int ret, i;
    + int ret, i, j;

    map = get_target_map(pev->target, pev->uprobes);
    if (!map) {
    @@ -2539,11 +2544,17 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
    goto out;
    }

    + syms = malloc(sizeof(struct symbol *) * probe_conf.max_probes);
    + if (!syms) {
    + ret = -ENOMEM;
    + goto out;
    + }
    +
    /*
    * Load matched symbols: Since the different local symbols may have
    * same name but different addresses, this lists all the symbols.
    */
    - num_matched_functions = find_probe_functions(map, pp->function);
    + num_matched_functions = find_probe_functions(map, pp->function, syms);
    if (num_matched_functions == 0) {
    pr_err("Failed to find symbol %s in %s\n", pp->function,
    pev->target ? : "kernel");
    @@ -2574,7 +2585,9 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,

    ret = 0;

    - map__for_each_symbol_by_name(map, pp->function, sym) {
    + for (j = 0; j < num_matched_functions; j++) {
    + sym = syms[j];
    +
    tev = (*tevs) + ret;
    tp = &tev->point;
    if (ret == num_matched_functions) {
    @@ -2598,6 +2611,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
    tp->symbol = strdup_or_goto(sym->name, nomem_out);
    tp->offset = pp->offset;
    }
    + tp->realname = strdup_or_goto(sym->name, nomem_out);
    +
    tp->retprobe = pp->retprobe;
    if (pev->target)
    tev->point.module = strdup_or_goto(pev->target,
    @@ -2628,6 +2643,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,

    out:
    put_target_map(map, pev->uprobes);
    + free(syms);
    return ret;

    nomem_out:
    --
    1.8.3.4


    \
     
     \ /
      Last update: 2015-05-29 12:21    [W:3.055 / U:0.104 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site