lkml.org 
[lkml]   [2011]   [Jan]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 22/29] perf probe: Introduce lines walker interface
    Date
    From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

    Introduce die_walk_lines() for walking on the line list of given die, and use
    it in line_range finder and probe point finder.

    Cc: 2nddept-manager@sdl.hitachi.co.jp
    Cc: Franck Bui-Huu <fbuihuu@gmail.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
    Cc: Steven Rostedt <rostedt@goodmis.org>
    LKML-Reference: <20110113124558.22426.48170.stgit@ltc236.sdl.hitachi.co.jp>
    Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
    [ committer note: s/%ld/%zd/ for a size_t nlines var that broke f14 x86 build]
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    ---
    tools/perf/util/probe-finder.c | 321 +++++++++++++++++++++-------------------
    1 files changed, 167 insertions(+), 154 deletions(-)

    diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
    index ab83b6a..508c017 100644
    --- a/tools/perf/util/probe-finder.c
    +++ b/tools/perf/util/probe-finder.c
    @@ -458,6 +458,124 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
    return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
    }

    +/* Walker on lines (Note: line number will not be sorted) */
    +typedef int (* line_walk_handler_t) (const char *fname, int lineno,
    + Dwarf_Addr addr, void *data);
    +
    +struct __line_walk_param {
    + line_walk_handler_t handler;
    + void *data;
    + int retval;
    +};
    +
    +/* Walk on decl lines in given DIE */
    +static int __die_walk_funclines(Dwarf_Die *sp_die,
    + line_walk_handler_t handler, void *data)
    +{
    + const char *fname;
    + Dwarf_Addr addr;
    + int lineno, ret = 0;
    +
    + /* Handle function declaration line */
    + fname = dwarf_decl_file(sp_die);
    + if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
    + dwarf_entrypc(sp_die, &addr) == 0) {
    + ret = handler(fname, lineno, addr, data);
    + }
    +
    + return ret;
    +}
    +
    +static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
    +{
    + struct __line_walk_param *lw = data;
    +
    + lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
    + if (lw->retval != 0)
    + return DWARF_CB_ABORT;
    +
    + return DWARF_CB_OK;
    +}
    +
    +/*
    + * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
    + * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
    + */
    +static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
    + void *data)
    +{
    + Dwarf_Lines *lines;
    + Dwarf_Line *line;
    + Dwarf_Addr addr;
    + const char *fname;
    + int lineno, ret = 0;
    + Dwarf_Die die_mem, *cu_die;
    + size_t nlines, i;
    +
    + /* Get the CU die */
    + if (dwarf_tag(pdie) == DW_TAG_subprogram)
    + cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
    + else
    + cu_die = pdie;
    + if (!cu_die) {
    + pr_debug2("Failed to get CU from subprogram\n");
    + return -EINVAL;
    + }
    +
    + /* Get lines list in the CU */
    + if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
    + pr_debug2("Failed to get source lines on this CU.\n");
    + return -ENOENT;
    + }
    + pr_debug2("Get %zd lines from this CU\n", nlines);
    +
    + /* Walk on the lines on lines list */
    + for (i = 0; i < nlines; i++) {
    + line = dwarf_onesrcline(lines, i);
    + if (line == NULL ||
    + dwarf_lineno(line, &lineno) != 0 ||
    + dwarf_lineaddr(line, &addr) != 0) {
    + pr_debug2("Failed to get line info. "
    + "Possible error in debuginfo.\n");
    + continue;
    + }
    + /* Filter lines based on address */
    + if (pdie != cu_die)
    + /*
    + * Address filtering
    + * The line is included in given function, and
    + * no inline block includes it.
    + */
    + if (!dwarf_haspc(pdie, addr) ||
    + die_find_inlinefunc(pdie, addr, &die_mem))
    + continue;
    + /* Get source line */
    + fname = dwarf_linesrc(line, NULL, NULL);
    +
    + ret = handler(fname, lineno, addr, data);
    + if (ret != 0)
    + return ret;
    + }
    +
    + /*
    + * Dwarf lines doesn't include function declarations and inlined
    + * subroutines. We have to check functions list or given function.
    + */
    + if (pdie != cu_die)
    + ret = __die_walk_funclines(pdie, handler, data);
    + else {
    + struct __line_walk_param param = {
    + .handler = handler,
    + .data = data,
    + .retval = 0,
    + };
    + dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
    + ret = param.retval;
    + }
    +
    + return ret;
    +}
    +
    struct __find_variable_param {
    const char *name;
    Dwarf_Addr addr;
    @@ -1050,43 +1168,26 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
    return ret;
    }

    -/* Find probe point from its line number */
    -static int find_probe_point_by_line(struct probe_finder *pf)
    +static int probe_point_line_walker(const char *fname, int lineno,
    + Dwarf_Addr addr, void *data)
    {
    - Dwarf_Lines *lines;
    - Dwarf_Line *line;
    - size_t nlines, i;
    - Dwarf_Addr addr;
    - int lineno;
    - int ret = 0;
    + struct probe_finder *pf = data;
    + int ret;

    - if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
    - pr_warning("No source lines found.\n");
    - return -ENOENT;
    - }
    + if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
    + return 0;

    - for (i = 0; i < nlines && ret == 0; i++) {
    - line = dwarf_onesrcline(lines, i);
    - if (dwarf_lineno(line, &lineno) != 0 ||
    - lineno != pf->lno)
    - continue;
    + pf->addr = addr;
    + ret = call_probe_finder(NULL, pf);

    - /* TODO: Get fileno from line, but how? */
    - if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
    - continue;
    -
    - if (dwarf_lineaddr(line, &addr) != 0) {
    - pr_warning("Failed to get the address of the line.\n");
    - return -ENOENT;
    - }
    - pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
    - (int)i, lineno, (uintmax_t)addr);
    - pf->addr = addr;
    + /* Continue if no error, because the line will be in inline function */
    + return ret < 0 ?: 0;
    +}

    - ret = call_probe_finder(NULL, pf);
    - /* Continuing, because target line might be inlined. */
    - }
    - return ret;
    +/* Find probe point from its line number */
    +static int find_probe_point_by_line(struct probe_finder *pf)
    +{
    + return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
    }

    /* Find lines which match lazy pattern */
    @@ -1140,15 +1241,31 @@ out_close:
    return nlines;
    }

    +static int probe_point_lazy_walker(const char *fname, int lineno,
    + Dwarf_Addr addr, void *data)
    +{
    + struct probe_finder *pf = data;
    + int ret;
    +
    + if (!line_list__has_line(&pf->lcache, lineno) ||
    + strtailcmp(fname, pf->fname) != 0)
    + return 0;
    +
    + pr_debug("Probe line found: line:%d addr:0x%llx\n",
    + lineno, (unsigned long long)addr);
    + pf->addr = addr;
    + ret = call_probe_finder(NULL, pf);
    +
    + /*
    + * Continue if no error, because the lazy pattern will match
    + * to other lines
    + */
    + return ret < 0 ?: 0;
    +}
    +
    /* Find probe points from lazy pattern */
    static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
    {
    - Dwarf_Lines *lines;
    - Dwarf_Line *line;
    - size_t nlines, i;
    - Dwarf_Addr addr;
    - Dwarf_Die die_mem;
    - int lineno;
    int ret = 0;

    if (list_empty(&pf->lcache)) {
    @@ -1162,45 +1279,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
    return ret;
    }

    - if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
    - pr_warning("No source lines found.\n");
    - return -ENOENT;
    - }
    -
    - for (i = 0; i < nlines && ret >= 0; i++) {
    - line = dwarf_onesrcline(lines, i);
    -
    - if (dwarf_lineno(line, &lineno) != 0 ||
    - !line_list__has_line(&pf->lcache, lineno))
    - continue;
    -
    - /* TODO: Get fileno from line, but how? */
    - if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
    - continue;
    -
    - if (dwarf_lineaddr(line, &addr) != 0) {
    - pr_debug("Failed to get the address of line %d.\n",
    - lineno);
    - continue;
    - }
    - if (sp_die) {
    - /* Address filtering 1: does sp_die include addr? */
    - if (!dwarf_haspc(sp_die, addr))
    - continue;
    - /* Address filtering 2: No child include addr? */
    - if (die_find_inlinefunc(sp_die, addr, &die_mem))
    - continue;
    - }
    -
    - pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
    - (int)i, lineno, (unsigned long long)addr);
    - pf->addr = addr;
    -
    - ret = call_probe_finder(sp_die, pf);
    - /* Continuing, because target line might be inlined. */
    - }
    - /* TODO: deallocate lines, but how? */
    - return ret;
    + return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
    }

    /* Callback parameter with return value */
    @@ -1644,91 +1723,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
    return line_list__add_line(&lr->line_list, lineno);
    }

    -/* Search function declaration lines */
    -static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
    +static int line_range_walk_cb(const char *fname, int lineno,
    + Dwarf_Addr addr __used,
    + void *data)
    {
    - struct dwarf_callback_param *param = data;
    - struct line_finder *lf = param->data;
    - const char *src;
    - int lineno;
    -
    - src = dwarf_decl_file(sp_die);
    - if (src && strtailcmp(src, lf->fname) != 0)
    - return DWARF_CB_OK;
    + struct line_finder *lf = data;

    - if (dwarf_decl_line(sp_die, &lineno) != 0 ||
    + if ((strtailcmp(fname, lf->fname) != 0) ||
    (lf->lno_s > lineno || lf->lno_e < lineno))
    - return DWARF_CB_OK;
    + return 0;

    - param->retval = line_range_add_line(src, lineno, lf->lr);
    - if (param->retval < 0)
    - return DWARF_CB_ABORT;
    - return DWARF_CB_OK;
    -}
    + if (line_range_add_line(fname, lineno, lf->lr) < 0)
    + return -EINVAL;

    -static int find_line_range_func_decl_lines(struct line_finder *lf)
    -{
    - struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
    - dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
    - return param.retval;
    + return 0;
    }

    /* Find line range from its line number */
    static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
    {
    - Dwarf_Lines *lines;
    - Dwarf_Line *line;
    - size_t nlines, i;
    - Dwarf_Addr addr;
    - int lineno, ret = 0;
    - const char *src;
    - Dwarf_Die die_mem;
    -
    - line_list__init(&lf->lr->line_list);
    - if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
    - pr_warning("No source lines found.\n");
    - return -ENOENT;
    - }
    -
    - /* Search probable lines on lines list */
    - for (i = 0; i < nlines; i++) {
    - line = dwarf_onesrcline(lines, i);
    - if (dwarf_lineno(line, &lineno) != 0 ||
    - (lf->lno_s > lineno || lf->lno_e < lineno))
    - continue;
    -
    - if (sp_die) {
    - /* Address filtering 1: does sp_die include addr? */
    - if (dwarf_lineaddr(line, &addr) != 0 ||
    - !dwarf_haspc(sp_die, addr))
    - continue;
    -
    - /* Address filtering 2: No child include addr? */
    - if (die_find_inlinefunc(sp_die, addr, &die_mem))
    - continue;
    - }
    -
    - /* TODO: Get fileno from line, but how? */
    - src = dwarf_linesrc(line, NULL, NULL);
    - if (strtailcmp(src, lf->fname) != 0)
    - continue;
    -
    - ret = line_range_add_line(src, lineno, lf->lr);
    - if (ret < 0)
    - return ret;
    - }
    + int ret;

    - /*
    - * Dwarf lines doesn't include function declarations. We have to
    - * check functions list or given function.
    - */
    - if (sp_die) {
    - src = dwarf_decl_file(sp_die);
    - if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
    - (lf->lno_s <= lineno && lf->lno_e >= lineno))
    - ret = line_range_add_line(src, lineno, lf->lr);
    - } else
    - ret = find_line_range_func_decl_lines(lf);
    + ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);

    /* Update status */
    if (ret >= 0)
    @@ -1758,9 +1774,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
    struct line_finder *lf = param->data;
    struct line_range *lr = lf->lr;

    - pr_debug("find (%llx) %s\n",
    - (unsigned long long)dwarf_dieoffset(sp_die),
    - dwarf_diename(sp_die));
    if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
    die_compare_name(sp_die, lr->function)) {
    lf->fname = dwarf_decl_file(sp_die);
    --
    1.6.2.5


    \
     
     \ /
      Last update: 2011-01-25 18:29    [W:0.040 / U:30.980 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site