diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 361 |
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 */ | ||
284 | static 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 */ |
284 | static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | 297 | static 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) */ | ||
475 | typedef int (* line_walk_handler_t) (const char *fname, int lineno, | ||
476 | Dwarf_Addr addr, void *data); | ||
477 | |||
478 | struct __line_walk_param { | ||
479 | const char *fname; | ||
480 | line_walk_handler_t handler; | ||
481 | void *data; | ||
482 | int retval; | ||
483 | }; | ||
484 | |||
485 | static 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 */ | ||
504 | static 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); | ||
525 | done: | ||
526 | return lw.retval; | ||
527 | } | ||
528 | |||
529 | static 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 | */ | ||
544 | static 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, ¶m, 0); | ||
613 | ret = param.retval; | ||
614 | } | ||
615 | |||
616 | return ret; | ||
617 | } | ||
618 | |||
461 | struct __find_variable_param { | 619 | struct __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 */ | 1211 | static int probe_point_line_walker(const char *fname, int lineno, |
1054 | static 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. */ | 1228 | static 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 | ||
1284 | static 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 */ |
1144 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | 1307 | static 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 */ | 1766 | static int line_range_walk_cb(const char *fname, int lineno, |
1648 | static 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 | ||
1669 | static 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, ¶m, 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 */ |
1677 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 1783 | static 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); |