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.c159
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 */
277static 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 */
277static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 296static 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)
497static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 516static 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
1817found: 1846post:
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 }
1826end: 1872end:
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