Skip to content

Commit 270bde1

Browse files
hkshaw1990acmel
authored andcommitted
perf probe: Search both .eh_frame and .debug_frame sections for probe location
'perf probe' through debuginfo__find_probes() in util/probe-finder.c checks for the functions' frame descriptions in either .eh_frame section of an ELF or the .debug_frame. The check is based on whether either one of these sections is present. Depending on distro, toolchain defaults, architetcutre, build flags, etc., CFI might be found in either .eh_frame and/or .debug_frame. Sometimes, it may happen that, .eh_frame, even if present, may not be complete and may miss some descriptions. Therefore, to be sure, to find the CFI covering an address we will always have to investigate both if available. For e.g., in powerpc, this may happen: $ gcc -g bin.c -o bin $ objdump --dwarf ./bin <1><145>: Abbrev Number: 7 (DW_TAG_subprogram) <146> DW_AT_external : 1 <146> DW_AT_name : (indirect string, offset: 0x9e): main <14a> DW_AT_decl_file : 1 <14b> DW_AT_decl_line : 39 <14c> DW_AT_prototyped : 1 <14c> DW_AT_type : <0x57> <150> DW_AT_low_pc : 0x100007b8 If the .eh_frame and .debug_frame are checked for the same binary, we will find that, .eh_frame (although present) doesn't contain a description for "main" function. But, .debug_frame has a description: 000000d8 00000024 00000000 FDE cie=00000000 pc=100007b8..10000838 DW_CFA_advance_loc: 16 to 100007c8 DW_CFA_def_cfa_offset: 144 DW_CFA_offset_extended_sf: r65 at cfa+16 ... Due to this (since, perf checks whether .eh_frame is present and goes on searching for that address inside that frame), perf is unable to process the probes: # perf probe -x ./bin main Failed to get call frame on 0x100007b8 Error: Failed to add events. To avoid this issue, we need to check both the sections (.eh_frame and .debug_frame), which is done in this patch. Note that, we can always force everything into both .eh_frame and .debug_frame by: $ gcc bin.c -fasynchronous-unwind-tables -fno-dwarf2-cfi-asm -g -o bin Signed-off-by: Hemant Kumar <hemant@linux.vnet.ibm.com> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: linuxppc-dev@lists.ozlabs.org Cc: Mark Wielaard <mjw@redhat.com> Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Link: http://lkml.kernel.org/r/1454426806-13974-1-git-send-email-hemant@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 3a4acda commit 270bde1

File tree

2 files changed

+41
-26
lines changed

2 files changed

+41
-26
lines changed

tools/perf/util/probe-finder.c

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -686,8 +686,9 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
686686
pf->fb_ops = NULL;
687687
#if _ELFUTILS_PREREQ(0, 142)
688688
} else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
689-
pf->cfi != NULL) {
690-
if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
689+
(pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
690+
if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 &&
691+
(dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) ||
691692
dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
692693
pr_warning("Failed to get call frame on 0x%jx\n",
693694
(uintmax_t)pf->addr);
@@ -1015,8 +1016,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
10151016
return DWARF_CB_OK;
10161017
}
10171018

1018-
/* Find probe points from debuginfo */
1019-
static int debuginfo__find_probes(struct debuginfo *dbg,
1019+
static int debuginfo__find_probe_location(struct debuginfo *dbg,
10201020
struct probe_finder *pf)
10211021
{
10221022
struct perf_probe_point *pp = &pf->pev->point;
@@ -1025,27 +1025,6 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
10251025
Dwarf_Die *diep;
10261026
int ret = 0;
10271027

1028-
#if _ELFUTILS_PREREQ(0, 142)
1029-
Elf *elf;
1030-
GElf_Ehdr ehdr;
1031-
GElf_Shdr shdr;
1032-
1033-
/* Get the call frame information from this dwarf */
1034-
elf = dwarf_getelf(dbg->dbg);
1035-
if (elf == NULL)
1036-
return -EINVAL;
1037-
1038-
if (gelf_getehdr(elf, &ehdr) == NULL)
1039-
return -EINVAL;
1040-
1041-
if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
1042-
shdr.sh_type == SHT_PROGBITS) {
1043-
pf->cfi = dwarf_getcfi_elf(elf);
1044-
} else {
1045-
pf->cfi = dwarf_getcfi(dbg->dbg);
1046-
}
1047-
#endif
1048-
10491028
off = 0;
10501029
pf->lcache = intlist__new(NULL);
10511030
if (!pf->lcache)
@@ -1108,6 +1087,39 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
11081087
return ret;
11091088
}
11101089

1090+
/* Find probe points from debuginfo */
1091+
static int debuginfo__find_probes(struct debuginfo *dbg,
1092+
struct probe_finder *pf)
1093+
{
1094+
int ret = 0;
1095+
1096+
#if _ELFUTILS_PREREQ(0, 142)
1097+
Elf *elf;
1098+
GElf_Ehdr ehdr;
1099+
GElf_Shdr shdr;
1100+
1101+
if (pf->cfi_eh || pf->cfi_dbg)
1102+
return debuginfo__find_probe_location(dbg, pf);
1103+
1104+
/* Get the call frame information from this dwarf */
1105+
elf = dwarf_getelf(dbg->dbg);
1106+
if (elf == NULL)
1107+
return -EINVAL;
1108+
1109+
if (gelf_getehdr(elf, &ehdr) == NULL)
1110+
return -EINVAL;
1111+
1112+
if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
1113+
shdr.sh_type == SHT_PROGBITS)
1114+
pf->cfi_eh = dwarf_getcfi_elf(elf);
1115+
1116+
pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
1117+
#endif
1118+
1119+
ret = debuginfo__find_probe_location(dbg, pf);
1120+
return ret;
1121+
}
1122+
11111123
struct local_vars_finder {
11121124
struct probe_finder *pf;
11131125
struct perf_probe_arg *args;

tools/perf/util/probe-finder.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ struct probe_finder {
7676

7777
/* For variable searching */
7878
#if _ELFUTILS_PREREQ(0, 142)
79-
Dwarf_CFI *cfi; /* Call Frame Information */
79+
/* Call Frame Information from .eh_frame */
80+
Dwarf_CFI *cfi_eh;
81+
/* Call Frame Information from .debug_frame */
82+
Dwarf_CFI *cfi_dbg;
8083
#endif
8184
Dwarf_Op *fb_ops; /* Frame base attribute */
8285
struct perf_probe_arg *pvar; /* Current target variable */

0 commit comments

Comments
 (0)