diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 159 |
1 files changed, 105 insertions, 54 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ff416b85f7e8..a7c7145a8d4f 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -273,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die) | |||
273 | return dwarf_formstring(&attr); | 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 | /* Compare diename and tname */ | 295 | /* Compare diename and tname */ |
277 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | 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) | |||
497 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 516 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
498 | Dwarf_Die *die_mem) | 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 | /* Walker on lines (Note: line number will not be sorted) */ | 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) | |||
1395 | !die_compare_name(sp_die, pp->function)) | 1427 | !die_compare_name(sp_die, pp->function)) |
1396 | return DWARF_CB_OK; | 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 | pf->fname = dwarf_decl_file(sp_die); | 1434 | pf->fname = dwarf_decl_file(sp_die); |
1399 | if (pp->line) { /* Function relative line */ | 1435 | if (pp->line) { /* Function relative line */ |
1400 | dwarf_decl_line(sp_die, &pf->lno); | 1436 | dwarf_decl_line(sp_die, &pf->lno); |
@@ -1483,6 +1519,7 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1483 | if (!dbg) { | 1519 | if (!dbg) { |
1484 | pr_warning("No debug information found in the vmlinux - " | 1520 | pr_warning("No debug information found in the vmlinux - " |
1485 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 1521 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
1522 | close(fd); /* Without dwfl_end(), fd isn't closed. */ | ||
1486 | return -EBADF; | 1523 | return -EBADF; |
1487 | } | 1524 | } |
1488 | 1525 | ||
@@ -1741,11 +1778,9 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | |||
1741 | Dwarf_Die cudie, spdie, indie; | 1778 | Dwarf_Die cudie, spdie, indie; |
1742 | Dwarf *dbg = NULL; | 1779 | Dwarf *dbg = NULL; |
1743 | Dwfl *dwfl = NULL; | 1780 | Dwfl *dwfl = NULL; |
1744 | Dwarf_Line *line; | 1781 | Dwarf_Addr _addr, baseaddr, bias = 0; |
1745 | Dwarf_Addr laddr, eaddr, bias = 0; | 1782 | const char *fname = NULL, *func = NULL, *tmp; |
1746 | const char *tmp; | 1783 | int baseline = 0, lineno = 0, ret = 0; |
1747 | int lineno, ret = 0; | ||
1748 | bool found = false; | ||
1749 | 1784 | ||
1750 | /* Open the live linux kernel */ | 1785 | /* Open the live linux kernel */ |
1751 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); | 1786 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); |
@@ -1766,68 +1801,79 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | |||
1766 | goto end; | 1801 | goto end; |
1767 | } | 1802 | } |
1768 | 1803 | ||
1769 | /* Find a corresponding line */ | 1804 | /* Find a corresponding line (filename and lineno) */ |
1770 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); | 1805 | cu_find_lineinfo(&cudie, addr, &fname, &lineno); |
1771 | if (line) { | 1806 | /* Don't care whether it failed or not */ |
1772 | if (dwarf_lineaddr(line, &laddr) == 0 && | ||
1773 | (Dwarf_Addr)addr == laddr && | ||
1774 | dwarf_lineno(line, &lineno) == 0) { | ||
1775 | tmp = dwarf_linesrc(line, NULL, NULL); | ||
1776 | if (tmp) { | ||
1777 | ppt->line = lineno; | ||
1778 | ppt->file = strdup(tmp); | ||
1779 | if (ppt->file == NULL) { | ||
1780 | ret = -ENOMEM; | ||
1781 | goto end; | ||
1782 | } | ||
1783 | found = true; | ||
1784 | } | ||
1785 | } | ||
1786 | } | ||
1787 | 1807 | ||
1788 | /* Find a corresponding function */ | 1808 | /* Find a corresponding function (name, baseline and baseaddr) */ |
1789 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1809 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1810 | /* Get function entry information */ | ||
1790 | tmp = dwarf_diename(&spdie); | 1811 | tmp = dwarf_diename(&spdie); |
1791 | if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) | 1812 | if (!tmp || |
1792 | goto end; | 1813 | dwarf_entrypc(&spdie, &baseaddr) != 0 || |
1793 | 1814 | dwarf_decl_line(&spdie, &baseline) != 0) | |
1794 | if (ppt->line) { | 1815 | goto post; |
1795 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | 1816 | func = tmp; |
1796 | &indie)) { | 1817 | |
1797 | /* addr in an inline function */ | 1818 | if (addr == (unsigned long)baseaddr) |
1819 | /* Function entry - Relative line number is 0 */ | ||
1820 | lineno = baseline; | ||
1821 | else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | ||
1822 | &indie)) { | ||
1823 | if (dwarf_entrypc(&indie, &_addr) == 0 && | ||
1824 | _addr == addr) | ||
1825 | /* | ||
1826 | * addr is at an inline function entry. | ||
1827 | * In this case, lineno should be the call-site | ||
1828 | * line number. | ||
1829 | */ | ||
1830 | lineno = die_get_call_lineno(&indie); | ||
1831 | else { | ||
1832 | /* | ||
1833 | * addr is in an inline function body. | ||
1834 | * Since lineno points one of the lines | ||
1835 | * of the inline function, baseline should | ||
1836 | * be the entry line of the inline function. | ||
1837 | */ | ||
1798 | tmp = dwarf_diename(&indie); | 1838 | tmp = dwarf_diename(&indie); |
1799 | if (!tmp) | 1839 | if (tmp && |
1800 | goto end; | 1840 | dwarf_decl_line(&spdie, &baseline) == 0) |
1801 | ret = dwarf_decl_line(&indie, &lineno); | 1841 | func = tmp; |
1802 | } else { | ||
1803 | if (eaddr == addr) { /* Function entry */ | ||
1804 | lineno = ppt->line; | ||
1805 | ret = 0; | ||
1806 | } else | ||
1807 | ret = dwarf_decl_line(&spdie, &lineno); | ||
1808 | } | ||
1809 | if (ret == 0) { | ||
1810 | /* Make a relative line number */ | ||
1811 | ppt->line -= lineno; | ||
1812 | goto found; | ||
1813 | } | 1842 | } |
1814 | } | 1843 | } |
1815 | /* We don't have a line number, let's use offset */ | 1844 | } |
1816 | ppt->offset = addr - (unsigned long)eaddr; | 1845 | |
1817 | found: | 1846 | post: |
1818 | ppt->function = strdup(tmp); | 1847 | /* Make a relative line number or an offset */ |
1848 | if (lineno) | ||
1849 | ppt->line = lineno - baseline; | ||
1850 | else if (func) | ||
1851 | ppt->offset = addr - (unsigned long)baseaddr; | ||
1852 | |||
1853 | /* Duplicate strings */ | ||
1854 | if (func) { | ||
1855 | ppt->function = strdup(func); | ||
1819 | if (ppt->function == NULL) { | 1856 | if (ppt->function == NULL) { |
1820 | ret = -ENOMEM; | 1857 | ret = -ENOMEM; |
1821 | goto end; | 1858 | goto end; |
1822 | } | 1859 | } |
1823 | found = true; | ||
1824 | } | 1860 | } |
1825 | 1861 | if (fname) { | |
1862 | ppt->file = strdup(fname); | ||
1863 | if (ppt->file == NULL) { | ||
1864 | if (ppt->function) { | ||
1865 | free(ppt->function); | ||
1866 | ppt->function = NULL; | ||
1867 | } | ||
1868 | ret = -ENOMEM; | ||
1869 | goto end; | ||
1870 | } | ||
1871 | } | ||
1826 | end: | 1872 | end: |
1827 | if (dwfl) | 1873 | if (dwfl) |
1828 | dwfl_end(dwfl); | 1874 | dwfl_end(dwfl); |
1829 | if (ret >= 0) | 1875 | if (ret == 0 && (fname || func)) |
1830 | ret = found ? 1 : 0; | 1876 | ret = 1; /* Found a point */ |
1831 | return ret; | 1877 | return ret; |
1832 | } | 1878 | } |
1833 | 1879 | ||
@@ -1895,6 +1941,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1895 | struct line_finder *lf = param->data; | 1941 | struct line_finder *lf = param->data; |
1896 | struct line_range *lr = lf->lr; | 1942 | struct line_range *lr = lf->lr; |
1897 | 1943 | ||
1944 | /* Check declared file */ | ||
1945 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) | ||
1946 | return DWARF_CB_OK; | ||
1947 | |||
1898 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1948 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
1899 | die_compare_name(sp_die, lr->function)) { | 1949 | die_compare_name(sp_die, lr->function)) { |
1900 | lf->fname = dwarf_decl_file(sp_die); | 1950 | lf->fname = dwarf_decl_file(sp_die); |
@@ -1947,6 +1997,7 @@ int find_line_range(int fd, struct line_range *lr) | |||
1947 | if (!dbg) { | 1997 | if (!dbg) { |
1948 | pr_warning("No debug information found in the vmlinux - " | 1998 | pr_warning("No debug information found in the vmlinux - " |
1949 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 1999 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
2000 | close(fd); /* Without dwfl_end(), fd isn't closed. */ | ||
1950 | return -EBADF; | 2001 | return -EBADF; |
1951 | } | 2002 | } |
1952 | 2003 | ||