aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2011-01-13 07:45:58 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-24 07:49:52 -0500
commit4cc9cec636e7f78aba7f17606ac13cac07ea5787 (patch)
treee0c89d4298121257fdd128a1210e9deca86fc4f7 /tools/perf/util/probe-finder.c
parentb0e8572f3b29c0760b66ba5627a6d5426c88c97d (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.c321
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) */
462typedef int (* line_walk_handler_t) (const char *fname, int lineno,
463 Dwarf_Addr addr, void *data);
464
465struct __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 */
472static 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
489static 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 */
504static 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, &param, 0);
573 ret = param.retval;
574 }
575
576 return ret;
577}
578
461struct __find_variable_param { 579struct __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 */ 1171static int probe_point_line_walker(const char *fname, int lineno,
1054static 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. */ 1188static 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
1244static 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 */
1144static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 1267static 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 */ 1726static int line_range_walk_cb(const char *fname, int lineno,
1648static 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
1669static 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, &param, 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 */
1677static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1743static 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);