diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2011-01-13 07:45:58 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-01-24 07:49:52 -0500 |
commit | 4cc9cec636e7f78aba7f17606ac13cac07ea5787 (patch) | |
tree | e0c89d4298121257fdd128a1210e9deca86fc4f7 /tools/perf/util/probe-finder.c | |
parent | b0e8572f3b29c0760b66ba5627a6d5426c88c97d (diff) |
perf probe: Introduce lines walker interface
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>
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | 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 ab83b6ac5d65..508c017f566a 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, | |||
458 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); | 458 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); |
459 | } | 459 | } |
460 | 460 | ||
461 | /* Walker on lines (Note: line number will not be sorted) */ | ||
462 | typedef int (* line_walk_handler_t) (const char *fname, int lineno, | ||
463 | Dwarf_Addr addr, void *data); | ||
464 | |||
465 | struct __line_walk_param { | ||
466 | line_walk_handler_t handler; | ||
467 | void *data; | ||
468 | int retval; | ||
469 | }; | ||
470 | |||
471 | /* Walk on decl lines in given DIE */ | ||
472 | static int __die_walk_funclines(Dwarf_Die *sp_die, | ||
473 | line_walk_handler_t handler, void *data) | ||
474 | { | ||
475 | const char *fname; | ||
476 | Dwarf_Addr addr; | ||
477 | int lineno, ret = 0; | ||
478 | |||
479 | /* Handle function declaration line */ | ||
480 | fname = dwarf_decl_file(sp_die); | ||
481 | if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && | ||
482 | dwarf_entrypc(sp_die, &addr) == 0) { | ||
483 | ret = handler(fname, lineno, addr, data); | ||
484 | } | ||
485 | |||
486 | return ret; | ||
487 | } | ||
488 | |||
489 | static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | ||
490 | { | ||
491 | struct __line_walk_param *lw = data; | ||
492 | |||
493 | lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data); | ||
494 | if (lw->retval != 0) | ||
495 | return DWARF_CB_ABORT; | ||
496 | |||
497 | return DWARF_CB_OK; | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on | ||
502 | * the lines inside the subprogram, otherwise PDIE must be a CU DIE. | ||
503 | */ | ||
504 | static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler, | ||
505 | void *data) | ||
506 | { | ||
507 | Dwarf_Lines *lines; | ||
508 | Dwarf_Line *line; | ||
509 | Dwarf_Addr addr; | ||
510 | const char *fname; | ||
511 | int lineno, ret = 0; | ||
512 | Dwarf_Die die_mem, *cu_die; | ||
513 | size_t nlines, i; | ||
514 | |||
515 | /* Get the CU die */ | ||
516 | if (dwarf_tag(pdie) == DW_TAG_subprogram) | ||
517 | cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL); | ||
518 | else | ||
519 | cu_die = pdie; | ||
520 | if (!cu_die) { | ||
521 | pr_debug2("Failed to get CU from subprogram\n"); | ||
522 | return -EINVAL; | ||
523 | } | ||
524 | |||
525 | /* Get lines list in the CU */ | ||
526 | if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) { | ||
527 | pr_debug2("Failed to get source lines on this CU.\n"); | ||
528 | return -ENOENT; | ||
529 | } | ||
530 | pr_debug2("Get %zd lines from this CU\n", nlines); | ||
531 | |||
532 | /* Walk on the lines on lines list */ | ||
533 | for (i = 0; i < nlines; i++) { | ||
534 | line = dwarf_onesrcline(lines, i); | ||
535 | if (line == NULL || | ||
536 | dwarf_lineno(line, &lineno) != 0 || | ||
537 | dwarf_lineaddr(line, &addr) != 0) { | ||
538 | pr_debug2("Failed to get line info. " | ||
539 | "Possible error in debuginfo.\n"); | ||
540 | continue; | ||
541 | } | ||
542 | /* Filter lines based on address */ | ||
543 | if (pdie != cu_die) | ||
544 | /* | ||
545 | * Address filtering | ||
546 | * The line is included in given function, and | ||
547 | * no inline block includes it. | ||
548 | */ | ||
549 | if (!dwarf_haspc(pdie, addr) || | ||
550 | die_find_inlinefunc(pdie, addr, &die_mem)) | ||
551 | continue; | ||
552 | /* Get source line */ | ||
553 | fname = dwarf_linesrc(line, NULL, NULL); | ||
554 | |||
555 | ret = handler(fname, lineno, addr, data); | ||
556 | if (ret != 0) | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * Dwarf lines doesn't include function declarations and inlined | ||
562 | * subroutines. We have to check functions list or given function. | ||
563 | */ | ||
564 | if (pdie != cu_die) | ||
565 | ret = __die_walk_funclines(pdie, handler, data); | ||
566 | else { | ||
567 | struct __line_walk_param param = { | ||
568 | .handler = handler, | ||
569 | .data = data, | ||
570 | .retval = 0, | ||
571 | }; | ||
572 | dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0); | ||
573 | ret = param.retval; | ||
574 | } | ||
575 | |||
576 | return ret; | ||
577 | } | ||
578 | |||
461 | struct __find_variable_param { | 579 | struct __find_variable_param { |
462 | const char *name; | 580 | const char *name; |
463 | Dwarf_Addr addr; | 581 | Dwarf_Addr addr; |
@@ -1050,43 +1168,26 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1050 | return ret; | 1168 | return ret; |
1051 | } | 1169 | } |
1052 | 1170 | ||
1053 | /* Find probe point from its line number */ | 1171 | static int probe_point_line_walker(const char *fname, int lineno, |
1054 | static int find_probe_point_by_line(struct probe_finder *pf) | 1172 | Dwarf_Addr addr, void *data) |
1055 | { | 1173 | { |
1056 | Dwarf_Lines *lines; | 1174 | struct probe_finder *pf = data; |
1057 | Dwarf_Line *line; | 1175 | int ret; |
1058 | size_t nlines, i; | ||
1059 | Dwarf_Addr addr; | ||
1060 | int lineno; | ||
1061 | int ret = 0; | ||
1062 | 1176 | ||
1063 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { | 1177 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
1064 | pr_warning("No source lines found.\n"); | 1178 | return 0; |
1065 | return -ENOENT; | ||
1066 | } | ||
1067 | 1179 | ||
1068 | for (i = 0; i < nlines && ret == 0; i++) { | 1180 | pf->addr = addr; |
1069 | line = dwarf_onesrcline(lines, i); | 1181 | ret = call_probe_finder(NULL, pf); |
1070 | if (dwarf_lineno(line, &lineno) != 0 || | ||
1071 | lineno != pf->lno) | ||
1072 | continue; | ||
1073 | 1182 | ||
1074 | /* TODO: Get fileno from line, but how? */ | 1183 | /* Continue if no error, because the line will be in inline function */ |
1075 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 1184 | return ret < 0 ?: 0; |
1076 | continue; | 1185 | } |
1077 | |||
1078 | if (dwarf_lineaddr(line, &addr) != 0) { | ||
1079 | pr_warning("Failed to get the address of the line.\n"); | ||
1080 | return -ENOENT; | ||
1081 | } | ||
1082 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", | ||
1083 | (int)i, lineno, (uintmax_t)addr); | ||
1084 | pf->addr = addr; | ||
1085 | 1186 | ||
1086 | ret = call_probe_finder(NULL, pf); | 1187 | /* Find probe point from its line number */ |
1087 | /* Continuing, because target line might be inlined. */ | 1188 | static int find_probe_point_by_line(struct probe_finder *pf) |
1088 | } | 1189 | { |
1089 | return ret; | 1190 | return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); |
1090 | } | 1191 | } |
1091 | 1192 | ||
1092 | /* Find lines which match lazy pattern */ | 1193 | /* Find lines which match lazy pattern */ |
@@ -1140,15 +1241,31 @@ out_close: | |||
1140 | return nlines; | 1241 | return nlines; |
1141 | } | 1242 | } |
1142 | 1243 | ||
1244 | static int probe_point_lazy_walker(const char *fname, int lineno, | ||
1245 | Dwarf_Addr addr, void *data) | ||
1246 | { | ||
1247 | struct probe_finder *pf = data; | ||
1248 | int ret; | ||
1249 | |||
1250 | if (!line_list__has_line(&pf->lcache, lineno) || | ||
1251 | strtailcmp(fname, pf->fname) != 0) | ||
1252 | return 0; | ||
1253 | |||
1254 | pr_debug("Probe line found: line:%d addr:0x%llx\n", | ||
1255 | lineno, (unsigned long long)addr); | ||
1256 | pf->addr = addr; | ||
1257 | ret = call_probe_finder(NULL, pf); | ||
1258 | |||
1259 | /* | ||
1260 | * Continue if no error, because the lazy pattern will match | ||
1261 | * to other lines | ||
1262 | */ | ||
1263 | return ret < 0 ?: 0; | ||
1264 | } | ||
1265 | |||
1143 | /* Find probe points from lazy pattern */ | 1266 | /* Find probe points from lazy pattern */ |
1144 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | 1267 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
1145 | { | 1268 | { |
1146 | Dwarf_Lines *lines; | ||
1147 | Dwarf_Line *line; | ||
1148 | size_t nlines, i; | ||
1149 | Dwarf_Addr addr; | ||
1150 | Dwarf_Die die_mem; | ||
1151 | int lineno; | ||
1152 | int ret = 0; | 1269 | int ret = 0; |
1153 | 1270 | ||
1154 | if (list_empty(&pf->lcache)) { | 1271 | if (list_empty(&pf->lcache)) { |
@@ -1162,45 +1279,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1162 | return ret; | 1279 | return ret; |
1163 | } | 1280 | } |
1164 | 1281 | ||
1165 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { | 1282 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
1166 | pr_warning("No source lines found.\n"); | ||
1167 | return -ENOENT; | ||
1168 | } | ||
1169 | |||
1170 | for (i = 0; i < nlines && ret >= 0; i++) { | ||
1171 | line = dwarf_onesrcline(lines, i); | ||
1172 | |||
1173 | if (dwarf_lineno(line, &lineno) != 0 || | ||
1174 | !line_list__has_line(&pf->lcache, lineno)) | ||
1175 | continue; | ||
1176 | |||
1177 | /* TODO: Get fileno from line, but how? */ | ||
1178 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | ||
1179 | continue; | ||
1180 | |||
1181 | if (dwarf_lineaddr(line, &addr) != 0) { | ||
1182 | pr_debug("Failed to get the address of line %d.\n", | ||
1183 | lineno); | ||
1184 | continue; | ||
1185 | } | ||
1186 | if (sp_die) { | ||
1187 | /* Address filtering 1: does sp_die include addr? */ | ||
1188 | if (!dwarf_haspc(sp_die, addr)) | ||
1189 | continue; | ||
1190 | /* Address filtering 2: No child include addr? */ | ||
1191 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) | ||
1192 | continue; | ||
1193 | } | ||
1194 | |||
1195 | pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n", | ||
1196 | (int)i, lineno, (unsigned long long)addr); | ||
1197 | pf->addr = addr; | ||
1198 | |||
1199 | ret = call_probe_finder(sp_die, pf); | ||
1200 | /* Continuing, because target line might be inlined. */ | ||
1201 | } | ||
1202 | /* TODO: deallocate lines, but how? */ | ||
1203 | return ret; | ||
1204 | } | 1283 | } |
1205 | 1284 | ||
1206 | /* Callback parameter with return value */ | 1285 | /* Callback parameter with return value */ |
@@ -1644,91 +1723,28 @@ static int line_range_add_line(const char *src, unsigned int lineno, | |||
1644 | return line_list__add_line(&lr->line_list, lineno); | 1723 | return line_list__add_line(&lr->line_list, lineno); |
1645 | } | 1724 | } |
1646 | 1725 | ||
1647 | /* Search function declaration lines */ | 1726 | static int line_range_walk_cb(const char *fname, int lineno, |
1648 | static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) | 1727 | Dwarf_Addr addr __used, |
1728 | void *data) | ||
1649 | { | 1729 | { |
1650 | struct dwarf_callback_param *param = data; | 1730 | struct line_finder *lf = data; |
1651 | struct line_finder *lf = param->data; | ||
1652 | const char *src; | ||
1653 | int lineno; | ||
1654 | |||
1655 | src = dwarf_decl_file(sp_die); | ||
1656 | if (src && strtailcmp(src, lf->fname) != 0) | ||
1657 | return DWARF_CB_OK; | ||
1658 | 1731 | ||
1659 | if (dwarf_decl_line(sp_die, &lineno) != 0 || | 1732 | if ((strtailcmp(fname, lf->fname) != 0) || |
1660 | (lf->lno_s > lineno || lf->lno_e < lineno)) | 1733 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
1661 | return DWARF_CB_OK; | 1734 | return 0; |
1662 | 1735 | ||
1663 | param->retval = line_range_add_line(src, lineno, lf->lr); | 1736 | if (line_range_add_line(fname, lineno, lf->lr) < 0) |
1664 | if (param->retval < 0) | 1737 | return -EINVAL; |
1665 | return DWARF_CB_ABORT; | ||
1666 | return DWARF_CB_OK; | ||
1667 | } | ||
1668 | 1738 | ||
1669 | static int find_line_range_func_decl_lines(struct line_finder *lf) | 1739 | return 0; |
1670 | { | ||
1671 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; | ||
1672 | dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, ¶m, 0); | ||
1673 | return param.retval; | ||
1674 | } | 1740 | } |
1675 | 1741 | ||
1676 | /* Find line range from its line number */ | 1742 | /* Find line range from its line number */ |
1677 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 1743 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
1678 | { | 1744 | { |
1679 | Dwarf_Lines *lines; | 1745 | int ret; |
1680 | Dwarf_Line *line; | ||
1681 | size_t nlines, i; | ||
1682 | Dwarf_Addr addr; | ||
1683 | int lineno, ret = 0; | ||
1684 | const char *src; | ||
1685 | Dwarf_Die die_mem; | ||
1686 | |||
1687 | line_list__init(&lf->lr->line_list); | ||
1688 | if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) { | ||
1689 | pr_warning("No source lines found.\n"); | ||
1690 | return -ENOENT; | ||
1691 | } | ||
1692 | |||
1693 | /* Search probable lines on lines list */ | ||
1694 | for (i = 0; i < nlines; i++) { | ||
1695 | line = dwarf_onesrcline(lines, i); | ||
1696 | if (dwarf_lineno(line, &lineno) != 0 || | ||
1697 | (lf->lno_s > lineno || lf->lno_e < lineno)) | ||
1698 | continue; | ||
1699 | |||
1700 | if (sp_die) { | ||
1701 | /* Address filtering 1: does sp_die include addr? */ | ||
1702 | if (dwarf_lineaddr(line, &addr) != 0 || | ||
1703 | !dwarf_haspc(sp_die, addr)) | ||
1704 | continue; | ||
1705 | |||
1706 | /* Address filtering 2: No child include addr? */ | ||
1707 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) | ||
1708 | continue; | ||
1709 | } | ||
1710 | |||
1711 | /* TODO: Get fileno from line, but how? */ | ||
1712 | src = dwarf_linesrc(line, NULL, NULL); | ||
1713 | if (strtailcmp(src, lf->fname) != 0) | ||
1714 | continue; | ||
1715 | |||
1716 | ret = line_range_add_line(src, lineno, lf->lr); | ||
1717 | if (ret < 0) | ||
1718 | return ret; | ||
1719 | } | ||
1720 | 1746 | ||
1721 | /* | 1747 | ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); |
1722 | * Dwarf lines doesn't include function declarations. We have to | ||
1723 | * check functions list or given function. | ||
1724 | */ | ||
1725 | if (sp_die) { | ||
1726 | src = dwarf_decl_file(sp_die); | ||
1727 | if (src && dwarf_decl_line(sp_die, &lineno) == 0 && | ||
1728 | (lf->lno_s <= lineno && lf->lno_e >= lineno)) | ||
1729 | ret = line_range_add_line(src, lineno, lf->lr); | ||
1730 | } else | ||
1731 | ret = find_line_range_func_decl_lines(lf); | ||
1732 | 1748 | ||
1733 | /* Update status */ | 1749 | /* Update status */ |
1734 | if (ret >= 0) | 1750 | if (ret >= 0) |
@@ -1758,9 +1774,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1758 | struct line_finder *lf = param->data; | 1774 | struct line_finder *lf = param->data; |
1759 | struct line_range *lr = lf->lr; | 1775 | struct line_range *lr = lf->lr; |
1760 | 1776 | ||
1761 | pr_debug("find (%llx) %s\n", | ||
1762 | (unsigned long long)dwarf_dieoffset(sp_die), | ||
1763 | dwarf_diename(sp_die)); | ||
1764 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1777 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
1765 | die_compare_name(sp_die, lr->function)) { | 1778 | die_compare_name(sp_die, lr->function)) { |
1766 | lf->fname = dwarf_decl_file(sp_die); | 1779 | lf->fname = dwarf_decl_file(sp_die); |