diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 134 |
1 files changed, 81 insertions, 53 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 689ab462a188..b7c85ce466a1 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 | { |
@@ -1704,11 +1723,9 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | |||
1704 | Dwarf_Die cudie, spdie, indie; | 1723 | Dwarf_Die cudie, spdie, indie; |
1705 | Dwarf *dbg = NULL; | 1724 | Dwarf *dbg = NULL; |
1706 | Dwfl *dwfl = NULL; | 1725 | Dwfl *dwfl = NULL; |
1707 | Dwarf_Line *line; | 1726 | Dwarf_Addr _addr, baseaddr, bias = 0; |
1708 | Dwarf_Addr laddr, eaddr, bias = 0; | 1727 | const char *fname = NULL, *func = NULL, *tmp; |
1709 | const char *tmp; | 1728 | int baseline = 0, lineno = 0, ret = 0; |
1710 | int lineno, ret = 0; | ||
1711 | bool found = false; | ||
1712 | 1729 | ||
1713 | /* Open the live linux kernel */ | 1730 | /* Open the live linux kernel */ |
1714 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); | 1731 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); |
@@ -1729,68 +1746,79 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | |||
1729 | goto end; | 1746 | goto end; |
1730 | } | 1747 | } |
1731 | 1748 | ||
1732 | /* Find a corresponding line */ | 1749 | /* Find a corresponding line (filename and lineno) */ |
1733 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); | 1750 | cu_find_lineinfo(&cudie, addr, &fname, &lineno); |
1734 | if (line) { | 1751 | /* Don't care whether it failed or not */ |
1735 | if (dwarf_lineaddr(line, &laddr) == 0 && | ||
1736 | (Dwarf_Addr)addr == laddr && | ||
1737 | dwarf_lineno(line, &lineno) == 0) { | ||
1738 | tmp = dwarf_linesrc(line, NULL, NULL); | ||
1739 | if (tmp) { | ||
1740 | ppt->line = lineno; | ||
1741 | ppt->file = strdup(tmp); | ||
1742 | if (ppt->file == NULL) { | ||
1743 | ret = -ENOMEM; | ||
1744 | goto end; | ||
1745 | } | ||
1746 | found = true; | ||
1747 | } | ||
1748 | } | ||
1749 | } | ||
1750 | 1752 | ||
1751 | /* Find a corresponding function */ | 1753 | /* Find a corresponding function (name, baseline and baseaddr) */ |
1752 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1754 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1755 | /* Get function entry information */ | ||
1753 | tmp = dwarf_diename(&spdie); | 1756 | tmp = dwarf_diename(&spdie); |
1754 | if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) | 1757 | if (!tmp || |
1755 | goto end; | 1758 | dwarf_entrypc(&spdie, &baseaddr) != 0 || |
1756 | 1759 | dwarf_decl_line(&spdie, &baseline) != 0) | |
1757 | if (ppt->line) { | 1760 | goto post; |
1758 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | 1761 | func = tmp; |
1759 | &indie)) { | 1762 | |
1760 | /* addr in an inline function */ | 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 | */ | ||
1761 | tmp = dwarf_diename(&indie); | 1783 | tmp = dwarf_diename(&indie); |
1762 | if (!tmp) | 1784 | if (tmp && |
1763 | goto end; | 1785 | dwarf_decl_line(&spdie, &baseline) == 0) |
1764 | ret = dwarf_decl_line(&indie, &lineno); | 1786 | func = tmp; |
1765 | } else { | ||
1766 | if (eaddr == addr) { /* Function entry */ | ||
1767 | lineno = ppt->line; | ||
1768 | ret = 0; | ||
1769 | } else | ||
1770 | ret = dwarf_decl_line(&spdie, &lineno); | ||
1771 | } | ||
1772 | if (ret == 0) { | ||
1773 | /* Make a relative line number */ | ||
1774 | ppt->line -= lineno; | ||
1775 | goto found; | ||
1776 | } | 1787 | } |
1777 | } | 1788 | } |
1778 | /* We don't have a line number, let's use offset */ | 1789 | } |
1779 | ppt->offset = addr - (unsigned long)eaddr; | 1790 | |
1780 | found: | 1791 | post: |
1781 | ppt->function = strdup(tmp); | 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); | ||
1782 | if (ppt->function == NULL) { | 1801 | if (ppt->function == NULL) { |
1783 | ret = -ENOMEM; | 1802 | ret = -ENOMEM; |
1784 | goto end; | 1803 | goto end; |
1785 | } | 1804 | } |
1786 | found = true; | ||
1787 | } | 1805 | } |
1788 | 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 | } | ||
1789 | end: | 1817 | end: |
1790 | if (dwfl) | 1818 | if (dwfl) |
1791 | dwfl_end(dwfl); | 1819 | dwfl_end(dwfl); |
1792 | if (ret >= 0) | 1820 | if (ret == 0 && (fname || func)) |
1793 | ret = found ? 1 : 0; | 1821 | ret = 1; /* Found a point */ |
1794 | return ret; | 1822 | return ret; |
1795 | } | 1823 | } |
1796 | 1824 | ||