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.c138
1 files changed, 79 insertions, 59 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index be0329394d56..f0692737ebf1 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -118,7 +118,6 @@ static const Dwfl_Callbacks offline_callbacks = {
118static int debuginfo__init_offline_dwarf(struct debuginfo *self, 118static int debuginfo__init_offline_dwarf(struct debuginfo *self,
119 const char *path) 119 const char *path)
120{ 120{
121 Dwfl_Module *mod;
122 int fd; 121 int fd;
123 122
124 fd = open(path, O_RDONLY); 123 fd = open(path, O_RDONLY);
@@ -129,11 +128,11 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *self,
129 if (!self->dwfl) 128 if (!self->dwfl)
130 goto error; 129 goto error;
131 130
132 mod = dwfl_report_offline(self->dwfl, "", "", fd); 131 self->mod = dwfl_report_offline(self->dwfl, "", "", fd);
133 if (!mod) 132 if (!self->mod)
134 goto error; 133 goto error;
135 134
136 self->dbg = dwfl_module_getdwarf(mod, &self->bias); 135 self->dbg = dwfl_module_getdwarf(self->mod, &self->bias);
137 if (!self->dbg) 136 if (!self->dbg)
138 goto error; 137 goto error;
139 138
@@ -676,37 +675,42 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
676} 675}
677 676
678/* Convert subprogram DIE to trace point */ 677/* Convert subprogram DIE to trace point */
679static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 678static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
680 bool retprobe, struct probe_trace_point *tp) 679 Dwarf_Addr paddr, bool retprobe,
680 struct probe_trace_point *tp)
681{ 681{
682 Dwarf_Addr eaddr, highaddr; 682 Dwarf_Addr eaddr, highaddr;
683 const char *name; 683 GElf_Sym sym;
684 684 const char *symbol;
685 /* Copy the name of probe point */ 685
686 name = dwarf_diename(sp_die); 686 /* Verify the address is correct */
687 if (name) { 687 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
688 if (dwarf_entrypc(sp_die, &eaddr) != 0) { 688 pr_warning("Failed to get entry address of %s\n",
689 pr_warning("Failed to get entry address of %s\n", 689 dwarf_diename(sp_die));
690 dwarf_diename(sp_die)); 690 return -ENOENT;
691 return -ENOENT; 691 }
692 } 692 if (dwarf_highpc(sp_die, &highaddr) != 0) {
693 if (dwarf_highpc(sp_die, &highaddr) != 0) { 693 pr_warning("Failed to get end address of %s\n",
694 pr_warning("Failed to get end address of %s\n", 694 dwarf_diename(sp_die));
695 dwarf_diename(sp_die)); 695 return -ENOENT;
696 return -ENOENT; 696 }
697 } 697 if (paddr > highaddr) {
698 if (paddr > highaddr) { 698 pr_warning("Offset specified is greater than size of %s\n",
699 pr_warning("Offset specified is greater than size of %s\n", 699 dwarf_diename(sp_die));
700 dwarf_diename(sp_die)); 700 return -EINVAL;
701 return -EINVAL; 701 }
702 } 702
703 tp->symbol = strdup(name); 703 /* Get an appropriate symbol from symtab */
704 if (tp->symbol == NULL) 704 symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
705 return -ENOMEM; 705 if (!symbol) {
706 tp->offset = (unsigned long)(paddr - eaddr); 706 pr_warning("Failed to find symbol at 0x%lx\n",
707 } else 707 (unsigned long)paddr);
708 /* This function has no name. */ 708 return -ENOENT;
709 tp->offset = (unsigned long)paddr; 709 }
710 tp->offset = (unsigned long)(paddr - sym.st_value);
711 tp->symbol = strdup(symbol);
712 if (!tp->symbol)
713 return -ENOMEM;
710 714
711 /* Return probe must be on the head of a subprogram */ 715 /* Return probe must be on the head of a subprogram */
712 if (retprobe) { 716 if (retprobe) {
@@ -734,7 +738,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
734 } 738 }
735 739
736 /* If not a real subprogram, find a real one */ 740 /* If not a real subprogram, find a real one */
737 if (dwarf_tag(sc_die) != DW_TAG_subprogram) { 741 if (!die_is_func_def(sc_die)) {
738 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { 742 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
739 pr_warning("Failed to find probe point in any " 743 pr_warning("Failed to find probe point in any "
740 "functions.\n"); 744 "functions.\n");
@@ -980,12 +984,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
980 struct dwarf_callback_param *param = data; 984 struct dwarf_callback_param *param = data;
981 struct probe_finder *pf = param->data; 985 struct probe_finder *pf = param->data;
982 struct perf_probe_point *pp = &pf->pev->point; 986 struct perf_probe_point *pp = &pf->pev->point;
983 Dwarf_Attribute attr;
984 987
985 /* Check tag and diename */ 988 /* Check tag and diename */
986 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 989 if (!die_is_func_def(sp_die) ||
987 !die_compare_name(sp_die, pp->function) || 990 !die_compare_name(sp_die, pp->function))
988 dwarf_attr(sp_die, DW_AT_declaration, &attr))
989 return DWARF_CB_OK; 991 return DWARF_CB_OK;
990 992
991 /* Check declared file */ 993 /* Check declared file */
@@ -1151,7 +1153,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1151 tev = &tf->tevs[tf->ntevs++]; 1153 tev = &tf->tevs[tf->ntevs++];
1152 1154
1153 /* Trace point should be converted from subprogram DIE */ 1155 /* Trace point should be converted from subprogram DIE */
1154 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1156 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
1155 pf->pev->point.retprobe, &tev->point); 1157 pf->pev->point.retprobe, &tev->point);
1156 if (ret < 0) 1158 if (ret < 0)
1157 return ret; 1159 return ret;
@@ -1183,7 +1185,7 @@ int debuginfo__find_trace_events(struct debuginfo *self,
1183{ 1185{
1184 struct trace_event_finder tf = { 1186 struct trace_event_finder tf = {
1185 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1187 .pf = {.pev = pev, .callback = add_probe_trace_event},
1186 .max_tevs = max_tevs}; 1188 .mod = self->mod, .max_tevs = max_tevs};
1187 int ret; 1189 int ret;
1188 1190
1189 /* Allocate result tevs array */ 1191 /* Allocate result tevs array */
@@ -1252,7 +1254,7 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
1252 vl = &af->vls[af->nvls++]; 1254 vl = &af->vls[af->nvls++];
1253 1255
1254 /* Trace point should be converted from subprogram DIE */ 1256 /* Trace point should be converted from subprogram DIE */
1255 ret = convert_to_trace_point(&pf->sp_die, pf->addr, 1257 ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr,
1256 pf->pev->point.retprobe, &vl->point); 1258 pf->pev->point.retprobe, &vl->point);
1257 if (ret < 0) 1259 if (ret < 0)
1258 return ret; 1260 return ret;
@@ -1291,6 +1293,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self,
1291{ 1293{
1292 struct available_var_finder af = { 1294 struct available_var_finder af = {
1293 .pf = {.pev = pev, .callback = add_available_vars}, 1295 .pf = {.pev = pev, .callback = add_available_vars},
1296 .mod = self->mod,
1294 .max_vls = max_vls, .externs = externs}; 1297 .max_vls = max_vls, .externs = externs};
1295 int ret; 1298 int ret;
1296 1299
@@ -1324,8 +1327,8 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1324 struct perf_probe_point *ppt) 1327 struct perf_probe_point *ppt)
1325{ 1328{
1326 Dwarf_Die cudie, spdie, indie; 1329 Dwarf_Die cudie, spdie, indie;
1327 Dwarf_Addr _addr, baseaddr; 1330 Dwarf_Addr _addr = 0, baseaddr = 0;
1328 const char *fname = NULL, *func = NULL, *tmp; 1331 const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp;
1329 int baseline = 0, lineno = 0, ret = 0; 1332 int baseline = 0, lineno = 0, ret = 0;
1330 1333
1331 /* Adjust address with bias */ 1334 /* Adjust address with bias */
@@ -1346,27 +1349,36 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1346 /* Find a corresponding function (name, baseline and baseaddr) */ 1349 /* Find a corresponding function (name, baseline and baseaddr) */
1347 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { 1350 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
1348 /* Get function entry information */ 1351 /* Get function entry information */
1349 tmp = dwarf_diename(&spdie); 1352 func = basefunc = dwarf_diename(&spdie);
1350 if (!tmp || 1353 if (!func ||
1351 dwarf_entrypc(&spdie, &baseaddr) != 0 || 1354 dwarf_entrypc(&spdie, &baseaddr) != 0 ||
1352 dwarf_decl_line(&spdie, &baseline) != 0) 1355 dwarf_decl_line(&spdie, &baseline) != 0) {
1356 lineno = 0;
1353 goto post; 1357 goto post;
1354 func = tmp; 1358 }
1355 1359
1356 if (addr == (unsigned long)baseaddr) 1360 fname = dwarf_decl_file(&spdie);
1361 if (addr == (unsigned long)baseaddr) {
1357 /* Function entry - Relative line number is 0 */ 1362 /* Function entry - Relative line number is 0 */
1358 lineno = baseline; 1363 lineno = baseline;
1359 else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, 1364 goto post;
1360 &indie)) { 1365 }
1366
1367 /* Track down the inline functions step by step */
1368 while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr,
1369 &indie)) {
1370 /* There is an inline function */
1361 if (dwarf_entrypc(&indie, &_addr) == 0 && 1371 if (dwarf_entrypc(&indie, &_addr) == 0 &&
1362 _addr == addr) 1372 _addr == addr) {
1363 /* 1373 /*
1364 * addr is at an inline function entry. 1374 * addr is at an inline function entry.
1365 * In this case, lineno should be the call-site 1375 * In this case, lineno should be the call-site
1366 * line number. 1376 * line number. (overwrite lineinfo)
1367 */ 1377 */
1368 lineno = die_get_call_lineno(&indie); 1378 lineno = die_get_call_lineno(&indie);
1369 else { 1379 fname = die_get_call_file(&indie);
1380 break;
1381 } else {
1370 /* 1382 /*
1371 * addr is in an inline function body. 1383 * addr is in an inline function body.
1372 * Since lineno points one of the lines 1384 * Since lineno points one of the lines
@@ -1374,19 +1386,27 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1374 * be the entry line of the inline function. 1386 * be the entry line of the inline function.
1375 */ 1387 */
1376 tmp = dwarf_diename(&indie); 1388 tmp = dwarf_diename(&indie);
1377 if (tmp && 1389 if (!tmp ||
1378 dwarf_decl_line(&spdie, &baseline) == 0) 1390 dwarf_decl_line(&indie, &baseline) != 0)
1379 func = tmp; 1391 break;
1392 func = tmp;
1393 spdie = indie;
1380 } 1394 }
1381 } 1395 }
1396 /* Verify the lineno and baseline are in a same file */
1397 tmp = dwarf_decl_file(&spdie);
1398 if (!tmp || strcmp(tmp, fname) != 0)
1399 lineno = 0;
1382 } 1400 }
1383 1401
1384post: 1402post:
1385 /* Make a relative line number or an offset */ 1403 /* Make a relative line number or an offset */
1386 if (lineno) 1404 if (lineno)
1387 ppt->line = lineno - baseline; 1405 ppt->line = lineno - baseline;
1388 else if (func) 1406 else if (basefunc) {
1389 ppt->offset = addr - (unsigned long)baseaddr; 1407 ppt->offset = addr - (unsigned long)baseaddr;
1408 func = basefunc;
1409 }
1390 1410
1391 /* Duplicate strings */ 1411 /* Duplicate strings */
1392 if (func) { 1412 if (func) {
@@ -1474,7 +1494,7 @@ static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1474 return 0; 1494 return 0;
1475} 1495}
1476 1496
1477/* Search function from function name */ 1497/* Search function definition from function name */
1478static int line_range_search_cb(Dwarf_Die *sp_die, void *data) 1498static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1479{ 1499{
1480 struct dwarf_callback_param *param = data; 1500 struct dwarf_callback_param *param = data;
@@ -1485,7 +1505,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1485 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) 1505 if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
1486 return DWARF_CB_OK; 1506 return DWARF_CB_OK;
1487 1507
1488 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1508 if (die_is_func_def(sp_die) &&
1489 die_compare_name(sp_die, lr->function)) { 1509 die_compare_name(sp_die, lr->function)) {
1490 lf->fname = dwarf_decl_file(sp_die); 1510 lf->fname = dwarf_decl_file(sp_die);
1491 dwarf_decl_line(sp_die, &lr->offset); 1511 dwarf_decl_line(sp_die, &lr->offset);