X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=tools%2Fperf%2Futil%2Fprobe-finder.c;h=69215bff17e91354e81bf1267cf15c085bdb5079;hb=5069ed86be3c2f28bcdf7fae1374ec0c325aafba;hp=ab83b6ac5d657c80af1e67790c1ace15d7592578;hpb=2c0076d8c7eb1dafa03d0a792444862080b34106;p=pandora-kernel.git diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ab83b6ac5d65..69215bff17e9 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -280,6 +280,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) return name ? (strcmp(tname, name) == 0) : false; } +/* Get callsite line number of inline-function instance */ +static int die_get_call_lineno(Dwarf_Die *in_die) +{ + Dwarf_Attribute attr; + Dwarf_Word ret; + + if (!dwarf_attr(in_die, DW_AT_call_line, &attr)) + return -ENOENT; + + dwarf_formudata(&attr, &ret); + return (int)ret; +} + /* Get type die */ static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) { @@ -458,6 +471,151 @@ 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 { + const char *fname; + line_walk_handler_t handler; + void *data; + int retval; +}; + +static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) +{ + struct __line_walk_param *lw = data; + Dwarf_Addr addr; + int lineno; + + if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { + lineno = die_get_call_lineno(in_die); + if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { + lw->retval = lw->handler(lw->fname, lineno, addr, + lw->data); + if (lw->retval != 0) + return DIE_FIND_CB_FOUND; + } + } + return DIE_FIND_CB_SIBLING; +} + +/* Walk on lines of blocks included in given DIE */ +static int __die_walk_funclines(Dwarf_Die *sp_die, + line_walk_handler_t handler, void *data) +{ + struct __line_walk_param lw = { + .handler = handler, + .data = data, + .retval = 0, + }; + Dwarf_Die die_mem; + Dwarf_Addr addr; + int lineno; + + /* Handle function declaration line */ + lw.fname = dwarf_decl_file(sp_die); + if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && + dwarf_entrypc(sp_die, &addr) == 0) { + lw.retval = handler(lw.fname, lineno, addr, data); + if (lw.retval != 0) + goto done; + } + die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem); +done: + return lw.retval; +} + +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, ¶m, 0); + ret = param.retval; + } + + return ret; +} + struct __find_variable_param { const char *name; Dwarf_Addr addr; @@ -1050,43 +1208,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; - - if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { - pr_warning("No source lines found.\n"); - return -ENOENT; - } + struct probe_finder *pf = data; + int ret; - for (i = 0; i < nlines && ret == 0; i++) { - line = dwarf_onesrcline(lines, i); - if (dwarf_lineno(line, &lineno) != 0 || - lineno != pf->lno) - continue; + if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) + return 0; - /* TODO: Get fileno from line, but how? */ - if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) - continue; + pf->addr = addr; + ret = call_probe_finder(NULL, pf); - 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 +1281,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 +1319,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 +1763,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; + struct line_finder *lf = data; - src = dwarf_decl_file(sp_die); - if (src && strtailcmp(src, lf->fname) != 0) - return DWARF_CB_OK; - - 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, ¶m, 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 +1814,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);