| @@ -273,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die) · 272 unmodified lines |
| 273 | 273 | return dwarf_formstring(&attr); |
| 274 | 274 | } |
| 275 | 275 | |
| 276 | +/* Get a line number and file name for given address */ |
| 277 | +static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, |
| 278 | + const char **fname, int *lineno) |
| 279 | +{ |
| 280 | + Dwarf_Line *line; |
| 281 | + Dwarf_Addr laddr; |
| 282 | + |
| 283 | + line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr); |
| 284 | + if (line && dwarf_lineaddr(line, &laddr) == 0 && |
| 285 | + addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) { |
| 286 | + *fname = dwarf_linesrc(line, NULL, NULL); |
| 287 | + if (!*fname) |
| 288 | + /* line number is useless without filename */ |
| 289 | + *lineno = 0; |
| 290 | + } |
| 291 | + |
| 292 | + return *lineno ?: -ENOENT; |
| 293 | +} |
| 294 | + |
| 276 | 295 | /* Compare diename and tname */ |
| 277 | 296 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) |
| 278 | 297 | { |
| @@ -497,7 +516,20 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) · 218 unmodified lines |
| 497 | 516 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
| 498 | 517 | Dwarf_Die *die_mem) |
| 499 | 518 | { |
| 500 | | − return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); |
| 519 | + Dwarf_Die tmp_die; |
| 520 | + |
| 521 | + sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die); |
| 522 | + if (!sp_die) |
| 523 | + return NULL; |
| 524 | + |
| 525 | + /* Inlined function could be recursive. Trace it until fail */ |
| 526 | + while (sp_die) { |
| 527 | + memcpy(die_mem, sp_die, sizeof(Dwarf_Die)); |
| 528 | + sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, |
| 529 | + &tmp_die); |
| 530 | + } |
| 531 | + |
| 532 | + return die_mem; |
| 501 | 533 | } |
| 502 | 534 | |
| 503 | 535 | /* Walker on lines (Note: line number will not be sorted) */ |
| @@ -1395,6 +1427,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) · 891 unmodified lines |
| 1395 | 1427 | !die_compare_name(sp_die, pp->function)) |
| 1396 | 1428 | return DWARF_CB_OK; |
| 1397 | 1429 | |
| 1430 | + /* Check declared file */ |
| 1431 | + if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) |
| 1432 | + return DWARF_CB_OK; |
| 1433 | + |
| 1398 | 1434 | pf->fname = dwarf_decl_file(sp_die); |
| 1399 | 1435 | if (pp->line) { /* Function relative line */ |
| 1400 | 1436 | dwarf_decl_line(sp_die, &pf->lno); |
| @@ -1451,6 +1487,7 @@ static int find_probes(int fd, struct probe_finder *pf) · 50 unmodified lines |
| 1451 | 1487 | if (!dbg) { |
| 1452 | 1488 | pr_warning("No debug information found in the vmlinux - " |
| 1453 | 1489 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
| 1490 | + close(fd); /* Without dwfl_end(), fd isn't closed. */ |
| 1454 | 1491 | return -EBADF; |
| 1455 | 1492 | } |
| 1456 | 1493 | |
| @@ -1686,11 +1723,9 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) · 229 unmodified lines |
| 1686 | 1723 | Dwarf_Die cudie, spdie, indie; |
| 1687 | 1724 | Dwarf *dbg = NULL; |
| 1688 | 1725 | Dwfl *dwfl = NULL; |
| 1689 | | − Dwarf_Line *line; |
| 1690 | | − Dwarf_Addr laddr, eaddr, bias = 0; |
| 1691 | | − const char *tmp; |
| 1692 | | − int lineno, ret = 0; |
| 1693 | | − bool found = false; |
| 1726 | + Dwarf_Addr _addr, baseaddr, bias = 0; |
| 1727 | + const char *fname = NULL, *func = NULL, *tmp; |
| 1728 | + int baseline = 0, lineno = 0, ret = 0; |
| 1694 | 1729 | |
| 1695 | 1730 | /* Open the live linux kernel */ |
| 1696 | 1731 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); |
| @@ -1711,68 +1746,79 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) · 14 unmodified lines |
| 1711 | 1746 | goto end; |
| 1712 | 1747 | } |
| 1713 | 1748 | |
| 1714 | | − /* Find a corresponding line */ |
| 1715 | | − line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); |
| 1716 | | − if (line) { |
| 1717 | | − if (dwarf_lineaddr(line, &laddr) == 0 && |
| 1718 | | − (Dwarf_Addr)addr == laddr && |
| 1719 | | − dwarf_lineno(line, &lineno) == 0) { |
| 1720 | | − tmp = dwarf_linesrc(line, NULL, NULL); |
| 1721 | | − if (tmp) { |
| 1722 | | − ppt->line = lineno; |
| 1723 | | − ppt->file = strdup(tmp); |
| 1724 | | − if (ppt->file == NULL) { |
| 1725 | | − ret = -ENOMEM; |
| 1726 | | − goto end; |
| 1727 | | − } |
| 1728 | | − found = true; |
| 1729 | | − } |
| 1730 | | − } |
| 1731 | | − } |
| 1749 | + /* Find a corresponding line (filename and lineno) */ |
| 1750 | + cu_find_lineinfo(&cudie, addr, &fname, &lineno); |
| 1751 | + /* Don't care whether it failed or not */ |
| 1732 | 1752 | |
| 1733 | | − /* Find a corresponding function */ |
| 1753 | + /* Find a corresponding function (name, baseline and baseaddr) */ |
| 1734 | 1754 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { |
| 1755 | + /* Get function entry information */ |
| 1735 | 1756 | tmp = dwarf_diename(&spdie); |
| 1736 | | − if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) |
| 1737 | | − goto end; |
| 1738 | | − |
| 1739 | | − if (ppt->line) { |
| 1740 | | − if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, |
| 1741 | | − &indie)) { |
| 1742 | | − /* addr in an inline function */ |
| 1757 | + if (!tmp || |
| 1758 | + dwarf_entrypc(&spdie, &baseaddr) != 0 || |
| 1759 | + dwarf_decl_line(&spdie, &baseline) != 0) |
| 1760 | + goto post; |
| 1761 | + func = tmp; |
| 1762 | + |
| 1763 | + if (addr == (unsigned long)baseaddr) |
| 1764 | + /* Function entry - Relative line number is 0 */ |
| 1765 | + lineno = baseline; |
| 1766 | + else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, |
| 1767 | + &indie)) { |
| 1768 | + if (dwarf_entrypc(&indie, &_addr) == 0 && |
| 1769 | + _addr == addr) |
| 1770 | + /* |
| 1771 | + * addr is at an inline function entry. |
| 1772 | + * In this case, lineno should be the call-site |
| 1773 | + * line number. |
| 1774 | + */ |
| 1775 | + lineno = die_get_call_lineno(&indie); |
| 1776 | + else { |
| 1777 | + /* |
| 1778 | + * addr is in an inline function body. |
| 1779 | + * Since lineno points one of the lines |
| 1780 | + * of the inline function, baseline should |
| 1781 | + * be the entry line of the inline function. |
| 1782 | + */ |
| 1743 | 1783 | tmp = dwarf_diename(&indie); |
| 1744 | | − if (!tmp) |
| 1745 | | − goto end; |
| 1746 | | − ret = dwarf_decl_line(&indie, &lineno); |
| 1747 | | − } else { |
| 1748 | | − if (eaddr == addr) { /* Function entry */ |
| 1749 | | − lineno = ppt->line; |
| 1750 | | − ret = 0; |
| 1751 | | − } else |
| 1752 | | − ret = dwarf_decl_line(&spdie, &lineno); |
| 1753 | | − } |
| 1754 | | − if (ret == 0) { |
| 1755 | | − /* Make a relative line number */ |
| 1756 | | − ppt->line -= lineno; |
| 1757 | | − goto found; |
| 1784 | + if (tmp && |
| 1785 | + dwarf_decl_line(&spdie, &baseline) == 0) |
| 1786 | + func = tmp; |
| 1758 | 1787 | } |
| 1759 | 1788 | } |
| 1760 | | − /* We don't have a line number, let's use offset */ |
| 1761 | | − ppt->offset = addr - (unsigned long)eaddr; |
| 1762 | | −found: |
| 1763 | | − ppt->function = strdup(tmp); |
| 1789 | + } |
| 1790 | + |
| 1791 | +post: |
| 1792 | + /* Make a relative line number or an offset */ |
| 1793 | + if (lineno) |
| 1794 | + ppt->line = lineno - baseline; |
| 1795 | + else if (func) |
| 1796 | + ppt->offset = addr - (unsigned long)baseaddr; |
| 1797 | + |
| 1798 | + /* Duplicate strings */ |
| 1799 | + if (func) { |
| 1800 | + ppt->function = strdup(func); |
| 1764 | 1801 | if (ppt->function == NULL) { |
| 1765 | 1802 | ret = -ENOMEM; |
| 1766 | 1803 | goto end; |
| 1767 | 1804 | } |
| 1768 | | − found = true; |
| 1769 | 1805 | } |
| 1770 | | − |
| 1806 | + if (fname) { |
| 1807 | + ppt->file = strdup(fname); |
| 1808 | + if (ppt->file == NULL) { |
| 1809 | + if (ppt->function) { |
| 1810 | + free(ppt->function); |
| 1811 | + ppt->function = NULL; |
| 1812 | + } |
| 1813 | + ret = -ENOMEM; |
| 1814 | + goto end; |
| 1815 | + } |
| 1816 | + } |
| 1771 | 1817 | end: |
| 1772 | 1818 | if (dwfl) |
| 1773 | 1819 | dwfl_end(dwfl); |
| 1774 | | − if (ret >= 0) |
| 1775 | | − ret = found ? 1 : 0; |
| 1820 | + if (ret == 0 && (fname || func)) |
| 1821 | + ret = 1; /* Found a point */ |
| 1776 | 1822 | return ret; |
| 1777 | 1823 | } |
| 1778 | 1824 | |
| @@ -1840,6 +1886,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) · 61 unmodified lines |
| 1840 | 1886 | struct line_finder *lf = param->data; |
| 1841 | 1887 | struct line_range *lr = lf->lr; |
| 1842 | 1888 | |
| 1889 | + /* Check declared file */ |
| 1890 | + if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) |
| 1891 | + return DWARF_CB_OK; |
| 1892 | + |
| 1843 | 1893 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
| 1844 | 1894 | die_compare_name(sp_die, lr->function)) { |
| 1845 | 1895 | lf->fname = dwarf_decl_file(sp_die); |
| @@ -1892,6 +1942,7 @@ int find_line_range(int fd, struct line_range *lr) · 46 unmodified lines |
| 1892 | 1942 | if (!dbg) { |
| 1893 | 1943 | pr_warning("No debug information found in the vmlinux - " |
| 1894 | 1944 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
| 1945 | + close(fd); /* Without dwfl_end(), fd isn't closed. */ |
| 1895 | 1946 | return -EBADF; |
| 1896 | 1947 | } |
| 1897 | 1948 | |