From: Hemant Kumar [mailto:hem...@linux.vnet.ibm.com]
>
>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 <hem...@linux.vnet.ibm.com>

Looks good to me:)

Acked-by: Masami Hiramatsu <masami.hiramatsu...@hitachi.com>

Thanks!

>---
>Changes since v2:
>- Fixed an issue related to filling up both the CFIs (Suggested by Masami).
>
>Changes since v1:
>- pf->cfi is now cached as pf->cfi_eh and pf->cfi_dbg depending on the source 
>of CFI
>  (Suggested by Mark Wielard).
>
> tools/perf/util/probe-finder.c | 62 +++++++++++++++++++++++++-----------------
> tools/perf/util/probe-finder.h |  5 +++-
> 2 files changed, 41 insertions(+), 26 deletions(-)
>
>diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
>index 05012bb..e4d0498 100644
>--- a/tools/perf/util/probe-finder.c
>+++ b/tools/perf/util/probe-finder.c
>@@ -685,9 +685,10 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct 
>probe_finder *pf)
>               pf->fb_ops = NULL;
> #if _ELFUTILS_PREREQ(0, 142)
>       } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
>-                 pf->cfi != NULL) {
>+                 (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
>               Dwarf_Frame *frame;
>-              if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
>+              if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 &&
>+                   (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) 
>||
>                   dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
>                       pr_warning("Failed to get call frame on 0x%jx\n",
>                                  (uintmax_t)pf->addr);
>@@ -1013,8 +1014,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global 
>*gl, void *data)
>       return DWARF_CB_OK;
> }
>
>-/* Find probe points from debuginfo */
>-static int debuginfo__find_probes(struct debuginfo *dbg,
>+static int debuginfo__find_probe_location(struct debuginfo *dbg,
>                                 struct probe_finder *pf)
> {
>       struct perf_probe_point *pp = &pf->pev->point;
>@@ -1023,27 +1023,6 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
>       Dwarf_Die *diep;
>       int ret = 0;
>
>-#if _ELFUTILS_PREREQ(0, 142)
>-      Elf *elf;
>-      GElf_Ehdr ehdr;
>-      GElf_Shdr shdr;
>-
>-      /* Get the call frame information from this dwarf */
>-      elf = dwarf_getelf(dbg->dbg);
>-      if (elf == NULL)
>-              return -EINVAL;
>-
>-      if (gelf_getehdr(elf, &ehdr) == NULL)
>-              return -EINVAL;
>-
>-      if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
>-          shdr.sh_type == SHT_PROGBITS) {
>-              pf->cfi = dwarf_getcfi_elf(elf);
>-      } else {
>-              pf->cfi = dwarf_getcfi(dbg->dbg);
>-      }
>-#endif
>-
>       off = 0;
>       pf->lcache = intlist__new(NULL);
>       if (!pf->lcache)
>@@ -1106,6 +1085,39 @@ found:
>       return ret;
> }
>
>+/* Find probe points from debuginfo */
>+static int debuginfo__find_probes(struct debuginfo *dbg,
>+                                struct probe_finder *pf)
>+{
>+      int ret = 0;
>+
>+#if _ELFUTILS_PREREQ(0, 142)
>+      Elf *elf;
>+      GElf_Ehdr ehdr;
>+      GElf_Shdr shdr;
>+
>+      if (pf->cfi_eh || pf->cfi_dbg)
>+              return debuginfo__find_probe_location(dbg, pf);
>+
>+      /* Get the call frame information from this dwarf */
>+      elf = dwarf_getelf(dbg->dbg);
>+      if (elf == NULL)
>+              return -EINVAL;
>+
>+      if (gelf_getehdr(elf, &ehdr) == NULL)
>+              return -EINVAL;
>+
>+      if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
>+          shdr.sh_type == SHT_PROGBITS)
>+              pf->cfi_eh = dwarf_getcfi_elf(elf);
>+
>+      pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
>+#endif
>+
>+      ret = debuginfo__find_probe_location(dbg, pf);
>+      return ret;
>+}
>+
> struct local_vars_finder {
>       struct probe_finder *pf;
>       struct perf_probe_arg *args;
>diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
>index bed8271..0aec770 100644
>--- a/tools/perf/util/probe-finder.h
>+++ b/tools/perf/util/probe-finder.h
>@@ -76,7 +76,10 @@ struct probe_finder {
>
>       /* For variable searching */
> #if _ELFUTILS_PREREQ(0, 142)
>-      Dwarf_CFI               *cfi;           /* Call Frame Information */
>+      /* Call Frame Information from .eh_frame */
>+      Dwarf_CFI               *cfi_eh;
>+      /* Call Frame Information from .debug_frame */
>+      Dwarf_CFI               *cfi_dbg;
> #endif
>       Dwarf_Op                *fb_ops;        /* Frame base attribute */
>       struct perf_probe_arg   *pvar;          /* Current target variable */
>--
>1.9.3

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to