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.c134
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 */
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{
@@ -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
1780found: 1791post:
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 }
1789end: 1817end:
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