diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 142 |
1 files changed, 126 insertions, 16 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index a274fd0c143e..c20bd52833aa 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -116,6 +116,101 @@ static void line_list__free(struct list_head *head) | |||
116 | } | 116 | } |
117 | } | 117 | } |
118 | 118 | ||
119 | /* Dwarf FL wrappers */ | ||
120 | |||
121 | static int __linux_kernel_find_elf(Dwfl_Module *mod, | ||
122 | void **userdata, | ||
123 | const char *module_name, | ||
124 | Dwarf_Addr base, | ||
125 | char **file_name, Elf **elfp) | ||
126 | { | ||
127 | int fd; | ||
128 | const char *path = kernel_get_module_path(module_name); | ||
129 | |||
130 | if (path) { | ||
131 | fd = open(path, O_RDONLY); | ||
132 | if (fd >= 0) { | ||
133 | *file_name = strdup(path); | ||
134 | return fd; | ||
135 | } | ||
136 | } | ||
137 | /* If failed, try to call standard method */ | ||
138 | return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, | ||
139 | file_name, elfp); | ||
140 | } | ||
141 | |||
142 | static char *debuginfo_path; /* Currently dummy */ | ||
143 | |||
144 | static const Dwfl_Callbacks offline_callbacks = { | ||
145 | .find_debuginfo = dwfl_standard_find_debuginfo, | ||
146 | .debuginfo_path = &debuginfo_path, | ||
147 | |||
148 | .section_address = dwfl_offline_section_address, | ||
149 | |||
150 | /* We use this table for core files too. */ | ||
151 | .find_elf = dwfl_build_id_find_elf, | ||
152 | }; | ||
153 | |||
154 | static const Dwfl_Callbacks kernel_callbacks = { | ||
155 | .find_debuginfo = dwfl_standard_find_debuginfo, | ||
156 | .debuginfo_path = &debuginfo_path, | ||
157 | |||
158 | .find_elf = __linux_kernel_find_elf, | ||
159 | .section_address = dwfl_linux_kernel_module_section_address, | ||
160 | }; | ||
161 | |||
162 | /* Get a Dwarf from offline image */ | ||
163 | static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) | ||
164 | { | ||
165 | Dwfl_Module *mod; | ||
166 | Dwarf *dbg = NULL; | ||
167 | |||
168 | if (!dwflp) | ||
169 | return NULL; | ||
170 | |||
171 | *dwflp = dwfl_begin(&offline_callbacks); | ||
172 | if (!*dwflp) | ||
173 | return NULL; | ||
174 | |||
175 | mod = dwfl_report_offline(*dwflp, "", "", fd); | ||
176 | if (!mod) | ||
177 | goto error; | ||
178 | |||
179 | dbg = dwfl_module_getdwarf(mod, bias); | ||
180 | if (!dbg) { | ||
181 | error: | ||
182 | dwfl_end(*dwflp); | ||
183 | *dwflp = NULL; | ||
184 | } | ||
185 | return dbg; | ||
186 | } | ||
187 | |||
188 | /* Get a Dwarf from live kernel image */ | ||
189 | static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, | ||
190 | Dwarf_Addr *bias) | ||
191 | { | ||
192 | Dwarf *dbg; | ||
193 | |||
194 | if (!dwflp) | ||
195 | return NULL; | ||
196 | |||
197 | *dwflp = dwfl_begin(&kernel_callbacks); | ||
198 | if (!*dwflp) | ||
199 | return NULL; | ||
200 | |||
201 | /* Load the kernel dwarves: Don't care the result here */ | ||
202 | dwfl_linux_kernel_report_kernel(*dwflp); | ||
203 | dwfl_linux_kernel_report_modules(*dwflp); | ||
204 | |||
205 | dbg = dwfl_addrdwarf(*dwflp, addr, bias); | ||
206 | /* Here, check whether we could get a real dwarf */ | ||
207 | if (!dbg) { | ||
208 | dwfl_end(*dwflp); | ||
209 | *dwflp = NULL; | ||
210 | } | ||
211 | return dbg; | ||
212 | } | ||
213 | |||
119 | /* Dwarf wrappers */ | 214 | /* Dwarf wrappers */ |
120 | 215 | ||
121 | /* Find the realpath of the target file. */ | 216 | /* Find the realpath of the target file. */ |
@@ -1177,10 +1272,12 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1177 | Dwarf_Off off, noff; | 1272 | Dwarf_Off off, noff; |
1178 | size_t cuhl; | 1273 | size_t cuhl; |
1179 | Dwarf_Die *diep; | 1274 | Dwarf_Die *diep; |
1180 | Dwarf *dbg; | 1275 | Dwarf *dbg = NULL; |
1276 | Dwfl *dwfl; | ||
1277 | Dwarf_Addr bias; /* Currently ignored */ | ||
1181 | int ret = 0; | 1278 | int ret = 0; |
1182 | 1279 | ||
1183 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1280 | dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); |
1184 | if (!dbg) { | 1281 | if (!dbg) { |
1185 | pr_warning("No dwarf info found in the vmlinux - " | 1282 | pr_warning("No dwarf info found in the vmlinux - " |
1186 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 1283 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
@@ -1221,7 +1318,8 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1221 | off = noff; | 1318 | off = noff; |
1222 | } | 1319 | } |
1223 | line_list__free(&pf->lcache); | 1320 | line_list__free(&pf->lcache); |
1224 | dwarf_end(dbg); | 1321 | if (dwfl) |
1322 | dwfl_end(dwfl); | ||
1225 | 1323 | ||
1226 | return ret; | 1324 | return ret; |
1227 | } | 1325 | } |
@@ -1412,23 +1510,31 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev, | |||
1412 | } | 1510 | } |
1413 | 1511 | ||
1414 | /* Reverse search */ | 1512 | /* Reverse search */ |
1415 | int find_perf_probe_point(int fd, unsigned long addr, | 1513 | int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) |
1416 | struct perf_probe_point *ppt) | ||
1417 | { | 1514 | { |
1418 | Dwarf_Die cudie, spdie, indie; | 1515 | Dwarf_Die cudie, spdie, indie; |
1419 | Dwarf *dbg; | 1516 | Dwarf *dbg = NULL; |
1517 | Dwfl *dwfl = NULL; | ||
1420 | Dwarf_Line *line; | 1518 | Dwarf_Line *line; |
1421 | Dwarf_Addr laddr, eaddr; | 1519 | Dwarf_Addr laddr, eaddr, bias = 0; |
1422 | const char *tmp; | 1520 | const char *tmp; |
1423 | int lineno, ret = 0; | 1521 | int lineno, ret = 0; |
1424 | bool found = false; | 1522 | bool found = false; |
1425 | 1523 | ||
1426 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1524 | /* Open the live linux kernel */ |
1427 | if (!dbg) | 1525 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); |
1428 | return -EBADF; | 1526 | if (!dbg) { |
1527 | pr_warning("No dwarf info found in the vmlinux - " | ||
1528 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1529 | ret = -EINVAL; | ||
1530 | goto end; | ||
1531 | } | ||
1429 | 1532 | ||
1533 | /* Adjust address with bias */ | ||
1534 | addr += bias; | ||
1430 | /* Find cu die */ | 1535 | /* Find cu die */ |
1431 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { | 1536 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { |
1537 | pr_warning("No CU DIE is found at %lx\n", addr); | ||
1432 | ret = -EINVAL; | 1538 | ret = -EINVAL; |
1433 | goto end; | 1539 | goto end; |
1434 | } | 1540 | } |
@@ -1491,7 +1597,8 @@ found: | |||
1491 | } | 1597 | } |
1492 | 1598 | ||
1493 | end: | 1599 | end: |
1494 | dwarf_end(dbg); | 1600 | if (dwfl) |
1601 | dwfl_end(dwfl); | ||
1495 | if (ret >= 0) | 1602 | if (ret >= 0) |
1496 | ret = found ? 1 : 0; | 1603 | ret = found ? 1 : 0; |
1497 | return ret; | 1604 | return ret; |
@@ -1624,6 +1731,8 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1624 | struct line_finder *lf = param->data; | 1731 | struct line_finder *lf = param->data; |
1625 | struct line_range *lr = lf->lr; | 1732 | struct line_range *lr = lf->lr; |
1626 | 1733 | ||
1734 | pr_debug("find (%lx) %s\n", dwarf_dieoffset(sp_die), | ||
1735 | dwarf_diename(sp_die)); | ||
1627 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1736 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
1628 | die_compare_name(sp_die, lr->function)) { | 1737 | die_compare_name(sp_die, lr->function)) { |
1629 | lf->fname = dwarf_decl_file(sp_die); | 1738 | lf->fname = dwarf_decl_file(sp_die); |
@@ -1667,10 +1776,12 @@ int find_line_range(int fd, struct line_range *lr) | |||
1667 | Dwarf_Off off = 0, noff; | 1776 | Dwarf_Off off = 0, noff; |
1668 | size_t cuhl; | 1777 | size_t cuhl; |
1669 | Dwarf_Die *diep; | 1778 | Dwarf_Die *diep; |
1670 | Dwarf *dbg; | 1779 | Dwarf *dbg = NULL; |
1780 | Dwfl *dwfl; | ||
1781 | Dwarf_Addr bias; /* Currently ignored */ | ||
1671 | const char *comp_dir; | 1782 | const char *comp_dir; |
1672 | 1783 | ||
1673 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1784 | dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); |
1674 | if (!dbg) { | 1785 | if (!dbg) { |
1675 | pr_warning("No dwarf info found in the vmlinux - " | 1786 | pr_warning("No dwarf info found in the vmlinux - " |
1676 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 1787 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
@@ -1716,8 +1827,7 @@ int find_line_range(int fd, struct line_range *lr) | |||
1716 | } | 1827 | } |
1717 | 1828 | ||
1718 | pr_debug("path: %s\n", lr->path); | 1829 | pr_debug("path: %s\n", lr->path); |
1719 | dwarf_end(dbg); | 1830 | dwfl_end(dwfl); |
1720 | |||
1721 | return (ret < 0) ? ret : lf.found; | 1831 | return (ret < 0) ? ret : lf.found; |
1722 | } | 1832 | } |
1723 | 1833 | ||