https://sourceware.org/bugzilla/show_bug.cgi?id=33658

            Bug ID: 33658
           Summary: eh_frame_hdr is not used if it comes after eh_frame
           Product: elfutils
           Version: unspecified
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: libdw
          Assignee: unassigned at sourceware dot org
          Reporter: shimin.guo at skydio dot com
                CC: elfutils-devel at sourceware dot org
  Target Milestone: ---

In the function getcfi_shdr in libdw/dwarf_getcfi_elf.c, the code calls
getcfi_scn_eh_frame immediately after seeing the .eh_frame section. If by that
time, it hasn't yet seen the .eh_frame_hdr, the search table in .eh_frame_hdr
will not be used, resulting in large performance penalty for large binaries.

We encountered the issue because we have a large binary created with the gold
linker with hundreds of thousands of FDEs, where .eh_frame_hdr comes after
.eh_frame. When using "perf script" on data the contains about 50k samples, the
current version takes more than an hour, whereas with a fix like the following
(not meant to be an actual patch, for illustration purposes only,) it takes
only seconds.

diff --git a/libdw/dwarf_getcfi_elf.c b/libdw/dwarf_getcfi_elf.c
index adcaea0..7625b69 100644
--- a/libdw/dwarf_getcfi_elf.c
+++ b/libdw/dwarf_getcfi_elf.c
@@ -282,6 +282,10 @@ getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
       Elf_Scn *hdr_scn = NULL;
       GElf_Addr hdr_vaddr = 0;
       Elf_Scn *scn = NULL;
+      Elf_Scn *eh_frame_scn = NULL;
+      bool has_eh_frame_hdr = false;
+      bool has_eh_frame = false;
+      GElf_Shdr eh_frame_shdr_mem;
       while ((scn = elf_nextscn (elf, scn)) != NULL)
        {
          GElf_Shdr shdr_mem;
@@ -293,20 +297,39 @@ getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
            continue;
          if (!strcmp (name, ".eh_frame_hdr"))
            {
+        has_eh_frame_hdr = true;
              hdr_scn = scn;
              hdr_vaddr = shdr->sh_addr;
+        if (has_eh_frame)
+        {
+          return getcfi_scn_eh_frame (elf, ehdr, eh_frame_scn,
&eh_frame_shdr_mem,
+                                      hdr_scn, hdr_vaddr);
+        }
            }
          else if (!strcmp (name, ".eh_frame"))
            {
+        has_eh_frame = true;
              if (shdr->sh_type != SHT_NOBITS)
-               return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
+        {
+          if (has_eh_frame_hdr)
+          {
+            return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
                                            hdr_scn, hdr_vaddr);
+          }
+          else
+          {
+            eh_frame_scn = scn;
+            eh_frame_shdr_mem = *shdr;
+          }
+        }
              else
                return NULL;
            }
-       }
     }
-
+  if (eh_frame_scn != NULL)
+    return getcfi_scn_eh_frame (elf, ehdr, eh_frame_scn, &eh_frame_shdr_mem,
+                                hdr_scn, hdr_vaddr);
+    }
   return (void *) -1l;
 }

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to