aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r--tools/perf/util/probe-finder.c361
1 files changed, 207 insertions, 154 deletions
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)
280 return name ? (strcmp(tname, name) == 0) : false; 280 return name ? (strcmp(tname, name) == 0) : false;
281} 281}
282 282
283/* Get callsite line number of inline-function instance */
284static int die_get_call_lineno(Dwarf_Die *in_die)
285{
286 Dwarf_Attribute attr;
287 Dwarf_Word ret;
288
289 if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
290 return -ENOENT;
291
292 dwarf_formudata(&attr, &ret);
293 return (int)ret;
294}
295
283/* Get type die */ 296/* Get type die */
284static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 297static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
285{ 298{
@@ -458,6 +471,151 @@ 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); 471 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
459} 472}
460 473
474/* Walker on lines (Note: line number will not be sorted) */
475typedef int (* line_walk_handler_t) (const char *fname, int lineno,
476 Dwarf_Addr addr, void *data);
477
478struct __line_walk_param {
479 const char *fname;
480 line_walk_handler_t handler;
481 void *data;
482 int retval;
483};
484
485static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
486{
487 struct __line_walk_param *lw = data;
488 Dwarf_Addr addr;
489 int lineno;
490
491 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
492 lineno = die_get_call_lineno(in_die);
493 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
494 lw->retval = lw->handler(lw->fname, lineno, addr,
495 lw->data);
496 if (lw->retval != 0)
497 return DIE_FIND_CB_FOUND;
498 }
499 }
500 return DIE_FIND_CB_SIBLING;
501}
502
503/* Walk on lines of blocks included in given DIE */
504static int __die_walk_funclines(Dwarf_Die *sp_die,
505 line_walk_handler_t handler, void *data)
506{
507 struct __line_walk_param lw = {
508 .handler = handler,
509 .data = data,
510 .retval = 0,
511 };
512 Dwarf_Die die_mem;
513 Dwarf_Addr addr;
514 int lineno;
515
516 /* Handle function declaration line */
517 lw.fname = dwarf_decl_file(sp_die);
518 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
519 dwarf_entrypc(sp_die, &addr) == 0) {
520 lw.retval = handler(lw.fname, lineno, addr, data);
521 if (lw.retval != 0)
522 goto done;
523 }
524 die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
525done:
526 return lw.retval;
527}
528
529static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
530{
531 struct __line_walk_param *lw = data;
532
533 lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
534 if (lw->retval != 0)
535 return DWARF_CB_ABORT;
536
537 return DWARF_CB_OK;
538}
539
540/*
541 * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
542 * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
543 */
544static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
545 void *data)
546{
547 Dwarf_Lines *lines;
548 Dwarf_Line *line;
549 Dwarf_Addr addr;
550 const char *fname;
551 int lineno, ret = 0;
552 Dwarf_Die die_mem, *cu_die;
553 size_t nlines, i;
554
555 /* Get the CU die */
556 if (dwarf_tag(pdie) == DW_TAG_subprogram)
557 cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
558 else
559 cu_die = pdie;
560 if (!cu_die) {
561 pr_debug2("Failed to get CU from subprogram\n");
562 return -EINVAL;
563 }
564
565 /* Get lines list in the CU */
566 if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
567 pr_debug2("Failed to get source lines on this CU.\n");
568 return -ENOENT;
569 }
570 pr_debug2("Get %zd lines from this CU\n", nlines);
571
572 /* Walk on the lines on lines list */
573 for (i = 0; i < nlines; i++) {
574 line = dwarf_onesrcline(lines, i);
575 if (line == NULL ||
576 dwarf_lineno(line, &lineno) != 0 ||
577 dwarf_lineaddr(line, &addr) != 0) {
578 pr_debug2("Failed to get line info. "
579 "Possible error in debuginfo.\n");
580 continue;
581 }
582 /* Filter lines based on address */
583 if (pdie != cu_die)
584 /*
585 * Address filtering
586 * The line is included in given function, and
587 * no inline block includes it.
588 */
589 if (!dwarf_haspc(pdie, addr) ||
590 die_find_inlinefunc(pdie, addr, &die_mem))
591 continue;
592 /* Get source line */
593 fname = dwarf_linesrc(line, NULL, NULL);
594
595 ret = handler(fname, lineno, addr, data);
596 if (ret != 0)
597 return ret;
598 }
599
600 /*
601 * Dwarf lines doesn't include function declarations and inlined
602 * subroutines. We have to check functions list or given function.
603 */
604 if (pdie != cu_die)
605 ret = __die_walk_funclines(pdie, handler, data);
606 else {
607 struct __line_walk_param param = {
608 .handler = handler,
609 .data = data,
610 .retval = 0,
611 };
612 dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
613 ret = param.retval;
614 }
615
616 return ret;
617}
618
461struct __find_variable_param { 619struct __find_variable_param {
462 const char *name; 620 const char *name;
463 Dwarf_Addr addr; 621 Dwarf_Addr addr;
@@ -1050,43 +1208,26 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1050 return ret; 1208 return ret;
1051} 1209}
1052 1210
1053/* Find probe point from its line number */ 1211static int probe_point_line_walker(const char *fname, int lineno,
1054static int find_probe_point_by_line(struct probe_finder *pf) 1212 Dwarf_Addr addr, void *data)
1055{ 1213{
1056 Dwarf_Lines *lines; 1214 struct probe_finder *pf = data;
1057 Dwarf_Line *line; 1215 int ret;
1058 size_t nlines, i;
1059 Dwarf_Addr addr;
1060 int lineno;
1061 int ret = 0;
1062
1063 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
1064 pr_warning("No source lines found.\n");
1065 return -ENOENT;
1066 }
1067 1216
1068 for (i = 0; i < nlines && ret == 0; i++) { 1217 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
1069 line = dwarf_onesrcline(lines, i); 1218 return 0;
1070 if (dwarf_lineno(line, &lineno) != 0 ||
1071 lineno != pf->lno)
1072 continue;
1073 1219
1074 /* TODO: Get fileno from line, but how? */ 1220 pf->addr = addr;
1075 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) 1221 ret = call_probe_finder(NULL, pf);
1076 continue;
1077 1222
1078 if (dwarf_lineaddr(line, &addr) != 0) { 1223 /* Continue if no error, because the line will be in inline function */
1079 pr_warning("Failed to get the address of the line.\n"); 1224 return ret < 0 ?: 0;
1080 return -ENOENT; 1225}
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 1226
1086 ret = call_probe_finder(NULL, pf); 1227/* Find probe point from its line number */
1087 /* Continuing, because target line might be inlined. */ 1228static int find_probe_point_by_line(struct probe_finder *pf)
1088 } 1229{
1089 return ret; 1230 return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
1090} 1231}
1091 1232
1092/* Find lines which match lazy pattern */ 1233/* Find lines which match lazy pattern */
@@ -1140,15 +1281,31 @@ out_close:
1140 return nlines; 1281 return nlines;
1141} 1282}
1142 1283
1284static int probe_point_lazy_walker(const char *fname, int lineno,
1285 Dwarf_Addr addr, void *data)
1286{
1287 struct probe_finder *pf = data;
1288 int ret;
1289
1290 if (!line_list__has_line(&pf->lcache, lineno) ||
1291 strtailcmp(fname, pf->fname) != 0)
1292 return 0;
1293
1294 pr_debug("Probe line found: line:%d addr:0x%llx\n",
1295 lineno, (unsigned long long)addr);
1296 pf->addr = addr;
1297 ret = call_probe_finder(NULL, pf);
1298
1299 /*
1300 * Continue if no error, because the lazy pattern will match
1301 * to other lines
1302 */
1303 return ret < 0 ?: 0;
1304}
1305
1143/* Find probe points from lazy pattern */ 1306/* Find probe points from lazy pattern */
1144static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 1307static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1145{ 1308{
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; 1309 int ret = 0;
1153 1310
1154 if (list_empty(&pf->lcache)) { 1311 if (list_empty(&pf->lcache)) {
@@ -1162,45 +1319,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1162 return ret; 1319 return ret;
1163 } 1320 }
1164 1321
1165 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { 1322 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} 1323}
1205 1324
1206/* Callback parameter with return value */ 1325/* Callback parameter with return value */
@@ -1644,91 +1763,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1644 return line_list__add_line(&lr->line_list, lineno); 1763 return line_list__add_line(&lr->line_list, lineno);
1645} 1764}
1646 1765
1647/* Search function declaration lines */ 1766static int line_range_walk_cb(const char *fname, int lineno,
1648static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) 1767 Dwarf_Addr addr __used,
1768 void *data)
1649{ 1769{
1650 struct dwarf_callback_param *param = data; 1770 struct line_finder *lf = data;
1651 struct line_finder *lf = param->data;
1652 const char *src;
1653 int lineno;
1654 1771
1655 src = dwarf_decl_file(sp_die); 1772 if ((strtailcmp(fname, lf->fname) != 0) ||
1656 if (src && strtailcmp(src, lf->fname) != 0)
1657 return DWARF_CB_OK;
1658
1659 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1660 (lf->lno_s > lineno || lf->lno_e < lineno)) 1773 (lf->lno_s > lineno || lf->lno_e < lineno))
1661 return DWARF_CB_OK; 1774 return 0;
1662 1775
1663 param->retval = line_range_add_line(src, lineno, lf->lr); 1776 if (line_range_add_line(fname, lineno, lf->lr) < 0)
1664 if (param->retval < 0) 1777 return -EINVAL;
1665 return DWARF_CB_ABORT;
1666 return DWARF_CB_OK;
1667}
1668 1778
1669static int find_line_range_func_decl_lines(struct line_finder *lf) 1779 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} 1780}
1675 1781
1676/* Find line range from its line number */ 1782/* Find line range from its line number */
1677static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 1783static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1678{ 1784{
1679 Dwarf_Lines *lines; 1785 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 1786
1721 /* 1787 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 1788
1733 /* Update status */ 1789 /* Update status */
1734 if (ret >= 0) 1790 if (ret >= 0)
@@ -1758,9 +1814,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1758 struct line_finder *lf = param->data; 1814 struct line_finder *lf = param->data;
1759 struct line_range *lr = lf->lr; 1815 struct line_range *lr = lf->lr;
1760 1816
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 && 1817 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1765 die_compare_name(sp_die, lr->function)) { 1818 die_compare_name(sp_die, lr->function)) {
1766 lf->fname = dwarf_decl_file(sp_die); 1819 lf->fname = dwarf_decl_file(sp_die);