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.c142
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
121static 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
142static char *debuginfo_path; /* Currently dummy */
143
144static 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
154static 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 */
163static 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) {
181error:
182 dwfl_end(*dwflp);
183 *dwflp = NULL;
184 }
185 return dbg;
186}
187
188/* Get a Dwarf from live kernel image */
189static 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 */
1415int find_perf_probe_point(int fd, unsigned long addr, 1513int 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
1493end: 1599end:
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