]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Dump com.redhat.elfutils.pmachata.sharing from monotone. pmachata/sharing
authorPetr Machata <pmachata@redhat.com>
Mon, 15 Dec 2008 13:17:39 +0000 (14:17 +0100)
committerPetr Machata <pmachata@redhat.com>
Mon, 15 Dec 2008 13:17:39 +0000 (14:17 +0100)
37 files changed:
libdwfl/ChangeLog
libdwfl/Makefile.am
libdwfl/core-file.c
libdwfl/cu.c
libdwfl/derelocate.c
libdwfl/dwfl_build_id_find_debuginfo.c
libdwfl/dwfl_build_id_find_elf.c
libdwfl/dwfl_file.c [new file with mode: 0644]
libdwfl/dwfl_lineinfo.c
libdwfl/dwfl_module.c
libdwfl/dwfl_module_addrsym.c
libdwfl/dwfl_module_build_id.c
libdwfl/dwfl_module_getdwarf.c
libdwfl/dwfl_module_getsrc_file.c
libdwfl/dwfl_module_getsym.c
libdwfl/dwfl_module_info.c
libdwfl/dwfl_module_register_names.c
libdwfl/dwfl_module_report_build_id.c
libdwfl/dwfl_module_return_value_location.c
libdwfl/dwfl_nextcu.c
libdwfl/dwfl_report_elf.c
libdwfl/dwfl_segment_report_module.c
libdwfl/dwfl_symtab.c [new file with mode: 0644]
libdwfl/find-debuginfo.c
libdwfl/libdwflP.h
libdwfl/link_map.c
libdwfl/linux-kernel-modules.c
libdwfl/offline.c
libdwfl/relocate.c
libelf/elf_getarhdr.c
tests/ChangeLog
tests/Makefile.am
tests/debuginfo.c [new file with mode: 0644]
tests/relocate.c [new file with mode: 0644]
tests/run-debuginfo.sh [new file with mode: 0755]
tests/run-relocate.sh [new file with mode: 0755]
tests/sharing1.c [new file with mode: 0644]

index 4f03855f5c6b88394a7934c3ab918c390a16f4c3..1b4a046305e9495e808298735c8cde91c48d066a 100644 (file)
        * linux-kernel-modules.c (check_module_notes): Use FTS_LOGICAL so
        we accept symlinks.
 
+2008-04-30  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_module_getdwarf.c
+       (find_debuginfo): Use mod->debug.cberr to record failure.
+
 2008-04-27  Roland McGrath  <roland@redhat.com>
 
        * linux-kernel-modules.c (report_kernel): Fix crash when
        dwfl_report_elf fails.
 
+2008-04-22  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h: Move Module.ebl to dwfl_shared_file.
+       * dwfl_module_getdwarf.c: Adjust to change above.  Module.main's
+       ebl is always used.
+       * dwfl_module_register_names.c: Likewise.
+       * dwfl_module_return_value_location.c: Likewise.
+       * relocate.c: Likewise.
+       * dwfl_module.c: Move ebl_closebackend...
+       * dwfl_file.c: ... here.
+
+2008-04-22  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h: Add dwerr to dwfl_shared_file.  Module.dwerr was
+       retained to record errors in establishing shared debug file.
+       * dwfl_nextcu.c: Adjust to above change.
+       * dwfl_module_getdwarf.c: Likewise.
+       (find_dw): Now returns Dwfl_Error.
+
+2008-04-22  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h: Move Module.dw to struct dwfl_shared_file
+       * cu.c: Adjust to above change.
+       * derelocate.c: Likewise.
+       * dwfl_module_getdwarf.c: Likewise.
+       * dwfl_module_getsrc_file.c: Likewise.
+       * dwfl_nextcu.c: Likewise.
+       * dwfl_module.c: Move dwarf_ending of dw...
+       * dwfl_file.c: ... here.
+
+2008-04-17  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_file.c (__libdwfl_open_file): Handle synthetic
+       ELF (non-null ELF handle, but fd==-1).  Key it with all zeroes.
+
+2008-04-16  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_build_id_find_elf.c (open_and_check): New function, opens a
+       file and checks its build ID.
+       (__libdwfl_open_by_build_id): Change prototype.
+       (dwfl_build_id_find_elf): Only call __libdwfl_open_by_build_id.
+       * dwfl_module_build_id.c (__libdwfl_find_build_id): Pass build_id
+       pointer instead of dwfl Module argument.
+       (dwfl_module_build_id): Adjust to above: pass NULL instead of true.
+       * libdwflP.h: Adjust to changes above.
+       * dwfl_build_id_find_debuginfo.c
+       (dwfl_build_id_find_debuginfo): Call __libdwfl_open_file_build_id
+       to open file and check build ID.
+       * dwfl_module_getdwarf.c (find_file): Only open file if callback
+       didn't open it via __libdwfl_open_file_build_id already.
+       (find_debuginfo): Likewise.
+
+2008-04-14  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_build_id_find_elf.c (dwfl_build_id_find_elf):
+       Cache build_id if it is found to be valid.
+
+2008-04-11  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_module_build_id.c (found_build_id): Renamed to
+       __libdwfl_found_build_id, exported.
+       Now allocates struct build_id on the heap.
+       * libdwflP.h: Export above.
+       (BUILD_ID_NOT_FOUND): New macro holds value of cached
+       build-id-not-found pointer.
+       (BUILD_ID_PTR): Predicate of validity of build ID pointer.
+       (struct dwfl_shared_file, struct Dwfl_Module): Make struct
+       dwfl_build_id heap-allocated.
+       * dwfl_module_build_id.c (dwfl_module_report_build_id): Call
+       __libdwfl_found_build_id instead of duplicating the work.
+       Adjust to above changes.
+       * dwfl_build_id_find_elf.c, dwfl_file.c, dwfl_module.c,
+       dwfl_module_getdwarf.c, find-debuginfo.c, linux-kernel-modules.c:
+       Adjust to above changes.
+
 2008-04-05  Roland McGrath  <roland@redhat.com>
 
        * linux-proc-maps.c (proc_maps_report): Don't leak LAST_FILE.
        prototype to avoid older compiler's complaint about reuse of the name.
        (__libdwfl_canon_error): Likewise.
 
+2008-03-14  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h (Dwfl_Module.symerr): Delete field.
+       * dwfl_module_getdwarf.c: Adjust to above.
+       * relocate.c: Likewise.
+
+2008-03-14  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h (Dwfl_Module.elferr): Delete field.
+       (dwfl_file.cberr): New field.
+       * dwfl_module_getdwarf.c: Adjust to above.
+
+2008-03-13  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h (dwfl_shared_file.elferr): New field.
+       * dwfl_file.c: When reading of the Elf file failed, keep the cache
+       entry around to cache the failure.
+       * derelocate.c: Adjust to above.
+       * dwfl_module_getdwarf.c: Likewise.
+       * dwfl_module_info.c: Likewise.
+       * offline.c: Likewise.
+
+2008-03-07  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h
+       (struct dwfl_build_id): New structure.
+       (dwfl_shared_file.valid): Dropped.
+       (dwfl_shared_file.build_id): New field.
+       (Dwfl_Module.build_id_*): Dropped.
+       (Dwfl_Module.build_id): New field.
+       * dwfl_file.c
+       (__libdwfl_close_file): Always free filename.  Also free build id.
+       * dwfl_module_report_build_id.c: Adjust to above.
+       * linux-kernel-modules.c: Likewise.
+       * dwfl_build_id_find_debuginfo.c: Drop validation.
+       * dwfl_build_id_find_elf.c: Adjust to above, drop validation.
+       * dwfl_module_build_id.c
+       (found_build_id): Take dwfl_build_id arg instead of Dwfl_Module.
+       (check_notes): Likewise.
+       (__libdwfl_find_build_id): Use appropriate build_id cache
+       Adjust the rest to above changes.
+       (dwfl_module_build_id): Likewise.
+       * find-debuginfo.c: Adjust to above.
+       (validate): Drop ELF backdooring for now.
+
+2008-03-07  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_file.c (__libdwfl_open_file): Call elf_cntl ELF_C_FDREAD if
+       possible, and consume fd right away.
+       * dwfl_module_getdwarf.c (load_dw): Remove ELF_C_FDREAD hack.
+       * offline.c (process_elf): Likewise.
+       * dwfl_report_elf.c (__libdwfl_report_elf): Return error instead
+       of asserting.
+
+2008-03-05  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h
+       (dwfl_shared_file): Renamed from dwfl_file.
+       (dwfl_file): New structure.
+       (DWBIAS, SYMBIAS): Adjust code to above change.
+       * delrelocate.c: Likewise.
+       * dwfl_build_id_find_debuginfo.c: Likewise.
+       * dwfl_build_id_find_elf.c: Likewise.
+       * dwfl_module.c: Likewise.
+       * dwfl_module_addrsym.c: Likewise.
+       * dwfl_module_build_id.c: Likewise.
+       * dwfl_module_getdwarf.c: Likewise.
+       * dwfl_module_getsym.c: Likewise.
+       * dwfl_module_info.c: Likewise.
+       * dwfl_module_report_build_id.c: Likewise.
+       * dwfl_report_elf.c: Likewise.
+       * dwfl_symtab.c: Likewise.
+       * find-debuginfo.c: Likewise.
+       * offline.c: Likewise.
+       * relocate.c: Likewise.
+       * dwfl_file.c: Likewise.
+       (__libdwfl_open_file): Consume passed-in Elf on cache hit.
+
 2008-02-19  Roland McGrath  <roland@redhat.com>
 
        * relocate.c (relocate_section): Check for an unhandled relocation
        * dwfl_build_id_find_elf.c (__libdwfl_open_by_build_id): Don't clear
        incoming *FILE_NAME at the start.
 
+2008-01-23  Petr Machata  <pmachata@redhat.com>
+
+       * relocate.c (find_relocation_symfile): New function.
+       (relocate_section): Take additional argument SYMFILE.
+       (__libdwfl_relocate, __libdwfl_relocate_section): Use above.
+
+2008-01-22  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_module_getdwarf.c (load_dw): Remove useless call to
+       find_symfile.
+
+2008-01-18  Petr Machata  <pmachata@redhat.com>
+
+       * relocate.c:
+       (struct reloc_symtab_cache): Drop.
+       (#define RELOC_SYMTAB_CACHE): Drop.
+       (relocate_getsym): Drop most of the code, inline the rest.
+       (resolve_symbol): Drop loading of symstrdata, that's already done
+       in __libdwfl_find_symtab.
+       (relocate_section): Inlined the rest of relocate_getsym.
+       (__libdwfl_relocate): Take dwfl_file instead of Elf.
+       (__libdwfl_relocate_section): Likewise.
+       * derelocate.c: Adjust to above.
+       * dwfl_module_getdwarf.c: Likewise.
+       * libdwflP.h (__libdwfl_relocate): Adjust prototype.
+       (__libdwfl_relocate_section): Likewise.
+
+2008-01-18  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_symtab.c: New file.
+       (__libdwfl_find_symtab): New function.
+       * Makefile.am: Add dwfl_symtab.c to the build process.
+       * dwfl_module_getdwarf.c
+       (load_symtab, find_offsets, find_dynsym): Move to dwfl_symtab.c
+       * libdwflP.h (struct dwfl_file.is_symtab): New field.
+       (struct dwfl_file.symerr): Likekwise.
+
+2008-01-14  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_file.c (__libdwfl_open_file): close the file descriptor
+       when reusing the node, and even when it was passed in by the caller.
+       (__libdwfl_close_file): Unconditionally close fd and call elf_end.
+       * dwfl_module_build_id.c: Formatting change.
+       * dwfl_module_getdwarf.c
+       (find_file): Return Dwfl_Error instead of void; adjust to changes
+       in __libdwfl_open_file.
+       (find_symtab): Take advantage from find_file returning Dwfl_Error.
+       (__libdwfl_module_getebl, find_dw, dwfl_module_getelf): Likewise.
+
 2008-01-08  Roland McGrath  <roland@redhat.com>
 
        * Makefile.am (euinclude): Variable removed.
        (pkginclude_HEADERS): Set this instead of euinclude_HEADERS.
 
+2007-12-11  Petr Machata  <pmachata@redhat.com>
+
+       * libdwflP.h
+       (struct dwfl_file.bias): Moved to struct Dwfl_Module.
+       (struct dwfl_file.align): New field.
+       (struct dwfl_file.start): New field.
+       (#define DWBIAS): New macro.
+       (#define SYMBIAS): New macro.
+       * cu.c: Use SYMBIAS/DWBIAS instead of main/debug->bias.
+       * derelocate.c: Likewise.
+       * dwfl_lineinfo.c: Likewise.
+       * dwfl_module_addrsym.c: Likewise.
+       * dwfl_module_build_id.c: Likewise.
+       * dwfl_module_getsym.c: Likewise.
+       * dwfl_module_info.c: Likewise.
+       * dwfl_nextcu.c: Likewise.
+       * dwfl_report_elf.c: Likewise.
+       * dwfl_module_getdwarf.c: Likewise.
+
+2007-12-10  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_file.c: Use likely/unlikely where possible.
+       * libdwflP.h (struct Dwfl_Module): Move symdata, syments,
+       symstrdata, symxndxdata, to struct dwfl_file.
+       * dwfl_module_getdwarf.c: Adjust to above changes.
+       (load_symtab): Drop the parameter `syments'.
+       (find_symtab): Use module->main or module->debug to initialize
+       module->symfile when possible.
+       * dwfl_module_getsym.c: Adjust to above changes.
+       * dwfl_report_elf.c: Likewise.
+       * relocate.c: Likewise.
+
+2007-12-05  Petr Machata  <pmachata@redhat.com>
+
+       * dwfl_file.c: New file.
+       * Makefile.am (libdwfl_a_SOURCES): Add dwfl_file.c.
+       * libdwflP.h
+       (__libdwfl_open_file): New internal function.
+       (__libdwfl_close_file): New internal function.
+       * cu.c: Adjust to the above change.
+       * derelocate.c: Likewise.
+       * dwfl_build_id_find_debuginfo.c: Likewise.
+       * dwfl_build_id_find_elf.c: Likewise.
+       * dwfl_lineinfo.c: Likewise.
+       * dwfl_module.c: Likewise.
+       * dwfl_module_build_id.c: Likewise.
+       * dwfl_module_getdwarf.c: Likewise.
+       * dwfl_module_info.c: Likewise.
+       * dwfl_module_report_build_id.c: Likewise.
+       * dwfl_nextcu.c: Likewise.
+       * dwfl_report_elf.c: Likewise.
+       * find-debuginfo.c: Likewise.
+       * offline.c: Likewise.
+
+       * dwfl_module.c (free_file): Code moved to dwfl_file.c.
+       (__libdwfl_module_free): Call __libdwfl_release_file.
+       * dwfl_module_getdwarf.c (open_elf): Code moved to dwfl_file.c.
+       (find_file): Call __libdwfl_open_file.
+       (find_debuginfo): Likewise.
+       (find_dw): Call __libdwfl_retain_file instead of copying members.
+       * dwfl_report_elf.c (__libdwfl_report_elf): Call __libdwfl_open_file.
+
 2007-10-23  Roland McGrath  <roland@redhat.com>
 
        * linux-kernel-modules.c (report_kernel_archive): Reorder the kernel
index db14db2a380f2a36b5c90746502de9604e492b77..a7d6b2b1424827247412a699d4ad0bc3d7f53b55 100644 (file)
@@ -73,7 +73,8 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
                    dwfl_module_return_value_location.c \
                    dwfl_module_register_names.c \
                    dwfl_segment_report_module.c \
-                   link_map.c core-file.c
+                   link_map.c core-file.c \
+                   dwfl_file.c dwfl_symtab.c
 
 
 if MUDFLAP
index bc881eb90623686c19448f8347c1bc5334bdf7ba..d34fe0ed9a10ba287a2416fb29652fd9447c0a78 100644 (file)
@@ -240,7 +240,8 @@ core_file_read_eagerly (Dwfl_Module *mod,
     requires find_elf hook re-doing the magic to fall back if no file found
   */
 
-  if (mod->build_id_len > 0)
+  if (mod->build_id != NULL
+      || (mod->main.shared != NULL && mod->main.shared->build_id != NULL))
     /* There is a build ID that could help us find the whole file,
        which might be more useful than what we have.
        We'll just rely on that.  */
index 8f01ea6bd2d0cb086d999aaac0e2c6be23d50573..fe6ef1a6cdcdb9889559052e3794534ea815a9b2 100644 (file)
@@ -56,7 +56,7 @@
 static inline Dwarf_Arange *
 dwar (Dwfl_Module *mod, unsigned int idx)
 {
-  return &mod->dw->aranges->info[mod->aranges[idx].arange];
+  return &mod->debug.shared->dw->aranges->info[mod->aranges[idx].arange];
 }
 
 
@@ -68,7 +68,7 @@ addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
       struct dwfl_arange *aranges = NULL;
       Dwarf_Aranges *dwaranges = NULL;
       size_t naranges;
-      if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
+      if (INTUSE(dwarf_getaranges) (mod->debug.shared->dw, &dwaranges, &naranges) != 0)
        return DWFL_E_LIBDW;
 
       /* If the module has no aranges (when no code is included) we
@@ -106,7 +106,7 @@ addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
     }
 
   /* The address must be inside the module to begin with.  */
-  addr -= mod->debug.bias;
+  addr -= DWBIAS (mod);
 
   /* The ranges are sorted by address, so we can use binary search.  */
   size_t l = 0, u = mod->naranges;
@@ -132,8 +132,9 @@ addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
          else
            {
              /* It might be in the last range.  */
+             Dwarf *dw = mod->debug.shared->dw;
              const Dwarf_Arange *last
-               = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
+               = &dw->aranges->info[dw->aranges->naranges - 1];
              if (addr > last->addr + last->length)
                break;
            }
@@ -196,7 +197,8 @@ intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
 
   if (*found == &key || *found == NULL)
     {
-      if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
+      Dwarf * dw = mod->debug.shared->dw;
+      if (unlikely (cuoff + 4 >= dw->sectiondata[IDX_debug_info]->d_size))
        {
          /* This is the EOF marker.  Now we have interned all the CUs.
             One increment in MOD->lazycu counts not having hit EOF yet.  */
@@ -218,7 +220,7 @@ intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
          cu->lines = NULL;
 
          /* XXX use non-searching lookup */
-         Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cu->die);
+         Dwarf_Die *die = INTUSE(dwarf_offdie) (dw, cuoff, &cu->die);
          if (die == NULL)
            return DWFL_E_LIBDW;
          assert (die == &cu->die);
@@ -272,8 +274,9 @@ __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
     {
       size_t cuhdrsz;
       Dwarf_Off nextoff;
-      int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
-                                       NULL, NULL, NULL);
+      int end = INTUSE(dwarf_nextcu) (mod->debug.shared->dw, cuoff,
+                                     &nextoff, &cuhdrsz,
+                                     NULL, NULL, NULL);
       if (end < 0)
        return DWFL_E_LIBDW;
       if (end > 0)
@@ -302,7 +305,8 @@ arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
 {
   if (arange->cu == NULL)
     {
-      const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
+      Dwarf *dw = mod->debug.shared->dw;
+      const Dwarf_Arange *dwarange = &dw->aranges->info[arange->arange];
       Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
       if (result != DWFL_E_NOERROR)
        return result;
index 402bc06f76caafca1ec64bba4652a0af5de84ec9..2e62f6afc115b1be992594db87056c34bcb3c033 100644 (file)
@@ -93,8 +93,12 @@ cache_sections (Dwfl_Module *mod)
   struct secref *refs = NULL;
   size_t nrefs = 0;
 
+  assert (mod->main.shared != NULL
+         && mod->main.shared->elf != NULL);
+  Elf *main_elf = mod->main.shared->elf;
+
   size_t shstrndx;
-  if (unlikely (elf_getshstrndx (mod->main.elf, &shstrndx) < 0))
+  if (unlikely (elf_getshstrndx (main_elf, &shstrndx) < 0))
     {
     elf_error:
       __libdwfl_seterrno (DWFL_E_LIBELF);
@@ -103,7 +107,7 @@ cache_sections (Dwfl_Module *mod)
 
   bool check_reloc_sections = false;
   Elf_Scn *scn = NULL;
-  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+  while ((scn = elf_nextscn (main_elf, scn)) != NULL)
     {
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
@@ -113,7 +117,7 @@ cache_sections (Dwfl_Module *mod)
       if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0)
        {
          /* This section might not yet have been looked at.  */
-         if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
+         if (__libdwfl_relocate_value (mod, main_elf, &shstrndx,
                                        elf_ndxscn (scn),
                                        &shdr->sh_addr) != DWFL_E_NOERROR)
            continue;
@@ -124,7 +128,7 @@ cache_sections (Dwfl_Module *mod)
 
       if (shdr->sh_flags & SHF_ALLOC)
        {
-         const char *name = elf_strptr (mod->main.elf, shstrndx,
+         const char *name = elf_strptr (main_elf, shstrndx,
                                         shdr->sh_name);
          if (unlikely (name == NULL))
            goto elf_error;
@@ -133,7 +137,7 @@ cache_sections (Dwfl_Module *mod)
          newref->scn = scn;
          newref->relocs = NULL;
          newref->name = name;
-         newref->start = shdr->sh_addr + mod->main.bias;
+         newref->start = shdr->sh_addr + mod->bias;
          newref->end = newref->start + shdr->sh_size;
          newref->next = refs;
          refs = newref;
@@ -148,7 +152,7 @@ cache_sections (Dwfl_Module *mod)
          if (shdr->sh_info < elf_ndxscn (scn))
            {
              /* We've already looked at the section these relocs apply to.  */
-             Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
+             Elf_Scn *tscn = elf_getscn (main_elf, shdr->sh_info);
              if (likely (tscn != NULL))
                for (struct secref *sec = refs; sec != NULL; sec = sec->next)
                  if (sec->scn == tscn)
@@ -194,7 +198,7 @@ cache_sections (Dwfl_Module *mod)
         possible target sections we care about.  */
 
       scn = NULL;
-      while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+      while ((scn = elf_nextscn (main_elf, scn)) != NULL)
        {
          GElf_Shdr shdr_mem;
          GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
@@ -204,7 +208,7 @@ cache_sections (Dwfl_Module *mod)
          if (shdr->sh_size != 0
              && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
            {
-             Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
+             Elf_Scn *tscn = elf_getscn (main_elf, shdr->sh_info);
              if (likely (tscn != NULL))
                for (size_t i = 0; i < nrefs; ++i)
                  if (mod->reloc_info->refs[i].scn == tscn)
@@ -238,7 +242,9 @@ dwfl_module_relocations (Dwfl_Module *mod)
       return 1;
 
     case ET_EXEC:
-      assert (mod->debug.bias == 0);
+      assert (mod->debug.shared != NULL
+             && mod->debug.shared->elf != NULL);
+      assert (DWBIAS (mod) == 0);
       break;
     }
 
@@ -296,7 +302,8 @@ check_module (Dwfl_Module *mod)
        }
     }
 
-  if (mod->dw == NULL)
+  if (mod->debug.shared == NULL
+      || mod->debug.shared->dw == NULL)
     {
       Dwarf_Addr bias;
       if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
@@ -358,7 +365,7 @@ dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
 
   if (mod->e_type != ET_REL)
     {
-      *addr -= mod->debug.bias;
+      *addr -= DWBIAS (mod);
       return 0;
     }
 
@@ -383,7 +390,7 @@ dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
 
       Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
       Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
-      Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
+      Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.shared,
                                                      relocscn, tscn, true);
       if (likely (result == DWFL_E_NOERROR))
        mod->reloc_info->refs[idx].relocs = NULL;
@@ -394,7 +401,7 @@ dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
        }
     }
 
-  *bias = mod->main.bias;
+  *bias = mod->bias;
   return mod->reloc_info->refs[idx].scn;
 }
 INTDEF (dwfl_module_address_section)
index 97def07279a847ea7d59e812fb753aa07e7ee1ea..e7096723e26900f11c55b38a65a9d6870295a32a 100644 (file)
@@ -61,32 +61,15 @@ dwfl_build_id_find_debuginfo (Dwfl_Module *mod,
                              GElf_Word crc __attribute__ ((unused)),
                              char **debuginfo_file_name)
 {
-  int fd = -1;
   const unsigned char *bits;
   GElf_Addr vaddr;
-  if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
-    fd = __libdwfl_open_by_build_id (mod, true, debuginfo_file_name);
-  if (fd >= 0)
-    {
-      /* We need to open an Elf handle on the file so we can check its
-        build ID note for validation.  Backdoor the handle into the
-        module data structure since we had to open it early anyway.  */
-      mod->debug.elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
-      if (likely (__libdwfl_find_build_id (mod, false, mod->debug.elf) == 2))
-       /* Also backdoor the gratuitous flag.  */
-       mod->debug.valid = true;
-      else
-       {
-         /* A mismatch!  */
-         elf_end (mod->debug.elf);
-         mod->debug.elf = NULL;
-         close (fd);
-         fd = -1;
-         free (*debuginfo_file_name);
-         *debuginfo_file_name = NULL;
-         errno = 0;
-       }
-    }
-  return fd;
+
+  if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0
+      && !__libdwfl_open_by_build_id (mod->dwfl->callbacks,
+                                     &mod->debug, mod->main.shared->build_id,
+                                     mod->bias, true, debuginfo_file_name))
+    errno = 0;
+
+  return -1;
 }
 INTDEF (dwfl_build_id_find_debuginfo)
index 1a226dfd0ec92ef267c154a955536937666d44f5..381203d86a8f8f69c15254dbab3338ca511de0f5 100644 (file)
 #include <unistd.h>
 
 
-int
+static bool
+open_and_check (struct dwfl_file *file,
+               const struct dwfl_build_id *build_id,
+               GElf_Addr bias,
+               char *file_name, int fd)
+{
+  if (__libdwfl_open_file (file, file_name,
+                          fd, NULL) != DWFL_E_NOERROR)
+    return false;
+
+  /* For the "check" (set==false) call, we can safely cast away const
+     and take stack pointer. */
+  if (__libdwfl_find_build_id ((struct dwfl_build_id **)&build_id,
+                              bias, false, file->shared->elf) != 2)
+    {
+      __libdwfl_close_file (file);
+      return false;
+    }
+
+  return true;
+}
+
+bool
 internal_function
-__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
+__libdwfl_open_by_build_id (const Dwfl_Callbacks *const cb,
+                           struct dwfl_file *file,
+                           const struct dwfl_build_id *build_id,
+                           GElf_Addr bias,
+                           bool debug, char **file_name)
 {
   /* If *FILE_NAME was primed into the module, leave it there
      as the fallback when we have nothing to offer.  */
   errno = 0;
-  if (mod->build_id_len <= 0)
+  if (!BUILD_ID_PTR (build_id))
     return -1;
 
-  const size_t id_len = mod->build_id_len;
-  const uint8_t *id = mod->build_id_bits;
+  const size_t id_len = build_id->len;
+  const uint8_t *id = build_id->bits;
 
   /* Search debuginfo_path directories' .build-id/ subdirectories.  */
 
@@ -83,7 +109,6 @@ __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
     strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2],
            ".debug");
 
-  const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
   char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
                        ?: DEFAULT_DEBUGINFO_PATH);
 
@@ -126,7 +151,17 @@ __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
   if (fd < 0 && errno == ENOENT)
     errno = 0;
 
-  return fd;
+  if (fd >= 0)
+    {
+      char *fn = *file_name;
+      *file_name = open_and_check (file, build_id, bias, fn, fd)
+       ? file->name : NULL;
+
+      if (fn != *file_name)
+       free (fn); /* Failure, or strdup in __libdwfl_open_file. */
+    }
+
+  return *file_name != NULL;
 }
 
 int
@@ -137,24 +172,17 @@ dwfl_build_id_find_elf (Dwfl_Module *mod,
                        char **file_name, Elf **elfp)
 {
   *elfp = NULL;
-  int fd = __libdwfl_open_by_build_id (mod, false, file_name);
-  if (fd >= 0)
+  if (__libdwfl_open_by_build_id (mod->dwfl->callbacks,
+                                 &mod->main, mod->build_id,
+                                 mod->bias, false, file_name)
+      && mod->main.shared->build_id == NULL)
     {
-      *elfp = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
-      if (__libdwfl_find_build_id (mod, false, *elfp) == 2)
-       /* This is a backdoor signal to short-circuit the ID refresh.  */
-       mod->main.valid = true;
-      else
-       {
-         /* This file does not contain the ID it should!  */
-         elf_end (*elfp);
-         *elfp = NULL;
-         close (fd);
-         fd = -1;
-         free (*file_name);
-         *file_name = NULL;
-       }
+      /* Move build ID bits into the cache. */
+      mod->build_id->vaddr -= mod->bias;
+      mod->main.shared->build_id = mod->build_id;
+      mod->build_id = NULL;
     }
-  return fd;
+
+  return -1;
 }
 INTDEF (dwfl_build_id_find_elf)
diff --git a/libdwfl/dwfl_file.c b/libdwfl/dwfl_file.c
new file mode 100644 (file)
index 0000000..c7927d0
--- /dev/null
@@ -0,0 +1,281 @@
+/* Find debugging and symbol information for a module in libdwfl.
+   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include <config.h>
+#include "../libelf/libelfP.h"  /* For elf->map_address. */
+#undef _
+
+#include "libdwflP.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+struct cache_key
+{
+  dev_t dev;
+  ino64_t ino;
+  struct timespec ctim;
+  size_t refcount;
+};
+
+struct cache_entry
+{
+  struct dwfl_shared_file shared;
+  struct cache_key key;
+
+  struct cache_entry *next;
+};
+
+static struct cache_entry *cache = NULL;
+
+static struct cache_entry *
+lookup_entry (struct stat64 *s)
+{
+  for (struct cache_entry *entry = cache; entry != NULL; entry = entry->next)
+    if (entry->key.dev == s->st_dev
+       && entry->key.ino == s->st_ino
+       && entry->key.ctim.tv_nsec == s->st_ctim.tv_nsec
+       && entry->key.ctim.tv_sec == s->st_ctim.tv_sec)
+      return entry;
+  return NULL;
+}
+
+Dwfl_Error
+internal_function
+__libdwfl_open_file (struct dwfl_file *tgt,
+                    const char *file_name,
+                    int fd, Elf *elf)
+{
+  if (tgt->shared != NULL)
+    return tgt->shared->elferr;
+
+  Dwfl_Error error;
+  if (fd < 0
+      && elf == NULL
+      && unlikely ((fd = open64 (file_name, O_RDONLY)) < 0))
+    {
+      tgt->shared = NULL;
+      return DWFL_E (ERRNO, errno);
+    }
+
+  struct cache_entry *entry = NULL;
+  bool synthetic = false;
+  struct stat64 s;
+
+  /* If we get there and fd < 0, it's ELF without file backing. */
+  if (fd >= 0)
+    {
+      if (unlikely (fstat64 (fd, &s) < 0))
+       {
+         tgt->shared = NULL;
+         return DWFL_E (ERRNO, errno);
+       }
+
+      /* Reuse cache entry if possible. */
+      entry = lookup_entry (&s);
+      if (entry != NULL)
+       {
+         /* Consume elf. */
+         if (elf != NULL)
+           elf_end (elf);
+
+         /* Consume the fd.  We don't need it when reusing. */
+         if (fd >= 0 && unlikely (close (fd) < 0))
+           {
+             tgt->shared = NULL;
+             return DWFL_E (ERRNO, errno);
+           }
+
+         ++entry->key.refcount;
+         tgt->shared = &entry->shared;
+         return entry->shared.elferr;
+       }
+    }
+  else
+    synthetic = true;
+
+  /* Failing that, enlist a new entry. */
+  entry = calloc (1, sizeof *entry);
+  if (unlikely (entry == NULL))
+    {
+      error = DWFL_E_NOMEM;
+      goto fail;
+    }
+
+  entry->next = cache;
+  cache = entry;
+
+  /* For synthetic files, the key is left initialized to zero. */
+  if (!synthetic)
+    {
+      entry->key.dev = s.st_dev;
+      entry->key.ino = s.st_ino;
+      entry->key.ctim = s.st_ctim;
+    }
+  entry->key.refcount = 1;
+
+  tgt->shared = &entry->shared;
+  tgt->name = file_name ? strdup (file_name) : NULL;
+
+  if (elf == NULL)
+    {
+      elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+      if (unlikely (elf == NULL))
+       {
+         error = DWFL_E_LIBELF;
+         goto fail;
+       }
+    }
+  if (!synthetic
+      && elf->map_address != NULL
+      && elf_cntl (elf, ELF_C_FDREAD) == 0)
+    {
+      close (fd);
+      fd = -1;
+    }
+  entry->shared.elf = elf;
+  entry->shared.fd = fd;
+
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr *ehdr = gelf_getehdr (entry->shared.elf, &ehdr_mem);
+  if (unlikely (ehdr == NULL))
+    {
+      error = DWFL_E_LIBELF;
+      goto fail;
+    }
+
+  for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+    {
+      GElf_Phdr ph_mem;
+      GElf_Phdr *ph = gelf_getphdr (entry->shared.elf, i, &ph_mem);
+      if (ph == NULL)
+       {
+         error = DWFL_E_LIBELF;
+         goto fail;
+       }
+      if (ph->p_type == PT_LOAD)
+       {
+         entry->shared.start = ph->p_vaddr;
+         entry->shared.align = ph->p_align;
+         break;
+       }
+    }
+
+  return entry->shared.elferr = DWFL_E_NOERROR;
+
+
+  /* Upon failure, keep the shared file open, but cache error. */
+ fail:
+  if (fd != -1)
+    {
+      /* Consume the FD, even if the caller opened it.  We don't check
+        for success, because if it failed, which error should we pass up? */
+      close (fd);
+      entry->shared.fd = -1;
+    }
+
+  if (elf != NULL)
+    {
+      elf_end (elf);
+      entry->shared.elf = NULL;
+    }
+
+  error = __libdwfl_canon_error (error);
+  if (entry != NULL)
+    entry->shared.elferr = error;
+  return error;
+}
+
+void
+internal_function
+__libdwfl_close_file (struct dwfl_file *tgt)
+{
+  if (likely (tgt->shared != NULL))
+    {
+      /* Look up the file in cache.  With singly linked list, we can't
+        simply cast file to entry, we need the prev pointer. */
+      struct cache_entry *entry;
+      struct cache_entry **prevp = &cache;
+      for (entry = cache; entry != NULL;
+          entry = *(prevp = &entry->next))
+       if (&entry->shared == tgt->shared)
+         break;
+      assert (entry != NULL);
+
+      if (--entry->key.refcount == 0)
+       {
+         if (entry->shared.elf != NULL)
+           elf_end (entry->shared.elf);
+         if (entry->shared.fd != -1)
+           close (entry->shared.fd);
+
+         if (tgt->shared->dw != NULL)
+           INTUSE(dwarf_end) (tgt->shared->dw);
+
+         if (tgt->shared->ebl != NULL)
+           ebl_closebackend (tgt->shared->ebl);
+
+         *prevp = entry->next;
+         free (entry);
+
+         if (BUILD_ID_PTR (entry->shared.build_id))
+           free (entry->shared.build_id);
+       }
+
+      tgt->shared = NULL;
+    }
+
+  if (tgt->name != NULL)
+    {
+      free (tgt->name);
+      tgt->name = NULL;
+    }
+}
index 0d8a6887ee40f0e5c7d10a44f64afb07527d0709..86bae1380db0ead428a408663c846f6995dccf16 100644 (file)
@@ -61,7 +61,7 @@ dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr, int *linep, int *colp,
   const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx];
 
   if (addr != NULL)
-    *addr = info->addr + cu->mod->debug.bias;
+    *addr = info->addr + DWBIAS (cu->mod);
   if (linep != NULL)
     *linep = info->line;
   if (colp != NULL)
index d7e5413862274de2ac02632749d1114c91a894fd..908982a536959790a4b4f1974be1f14c576dd9c6 100644 (file)
@@ -64,16 +64,6 @@ nofree (void *arg __attribute__ ((unused)))
 {
 }
 
-static void
-free_file (struct dwfl_file *file)
-{
-  free (file->name);
-
-  /* Close the fd only on the last reference.  */
-  if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
-    close (file->fd);
-}
-
 void
 internal_function
 __libdwfl_module_free (Dwfl_Module *mod)
@@ -91,18 +81,15 @@ __libdwfl_module_free (Dwfl_Module *mod)
       free (mod->cu);
     }
 
-  if (mod->dw != NULL)
-    INTUSE(dwarf_end) (mod->dw);
-
-  if (mod->ebl != NULL)
-    ebl_closebackend (mod->ebl);
+  if (mod->debug.shared != NULL && mod->debug.shared != mod->main.shared)
+    __libdwfl_close_file (&mod->debug);
+  mod->debug.name = NULL;
 
-  if (mod->debug.elf != mod->main.elf)
-    free_file (&mod->debug);
-  free_file (&mod->main);
+  __libdwfl_close_file (&mod->main);
+  mod->main.name = NULL;
 
-  if (mod->build_id_bits != NULL)
-    free (mod->build_id_bits);
+  if (BUILD_ID_PTR (mod->build_id))
+    free (mod->build_id);
 
   free (mod->name);
   free (mod);
index 72280d118c8418fe1ad029b3bcfff20183ef6f74..6607b274f418754ceadd5faf3d4fa8dc5d314745 100644 (file)
@@ -71,10 +71,10 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
       /* Figure out what section ADDR lies in.  */
       if (addr_shndx == SHN_UNDEF)
        {
-         GElf_Addr mod_addr = addr - mod->symfile->bias;
+         GElf_Addr mod_addr = addr - SYMBIAS (mod);
          Elf_Scn *scn = NULL;
          addr_shndx = SHN_ABS;
-         while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
+         while ((scn = elf_nextscn (mod->symfile->shared->elf, scn)) != NULL)
            {
              GElf_Shdr shdr_mem;
              GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
index 8725afbccf20167255c503c1a2d73e46637aaee9..d02c89f2020767f1dcb989b351f63759ab14c7ec 100644 (file)
 
 #include "libdwflP.h"
 
-static int
-found_build_id (Dwfl_Module *mod, bool set,
-               const void *bits, int len, GElf_Addr vaddr)
+int
+internal_function
+__libdwfl_found_build_id (struct dwfl_build_id **build_idp, bool set,
+                         const void *bits, int len, GElf_Addr vaddr)
 {
+  struct dwfl_build_id *build_id = *build_idp;
+
   if (!set)
     /* When checking bits, we do not compare VADDR because the
        address found in a debuginfo file may not match the main
        file as modified by prelink.  */
-    return 1 + (mod->build_id_len == len
-               && !memcmp (bits, mod->build_id_bits, len));
+    return 1 + (build_id != NULL
+               && build_id->len == len
+               && !memcmp (bits, build_id->bits, len));
 
-  void *copy = malloc (len);
-  if (unlikely (copy == NULL))
+  build_id = malloc (offsetof (struct dwfl_build_id, bits[len]));
+  if (unlikely (build_id == NULL))
     {
       __libdwfl_seterrno (DWFL_E_NOMEM);
       return -1;
     }
 
-  mod->build_id_bits = memcpy (copy, bits, len);
-  mod->build_id_vaddr = vaddr;
-  mod->build_id_len = len;
+  memcpy (build_id->bits, bits, len);
+  build_id->vaddr = vaddr;
+  build_id->len = len;
+
+  *build_idp = build_id;
   return len;
 }
 
 #define NO_VADDR       ((GElf_Addr) -1l)
 
 static int
-check_notes (Dwfl_Module *mod, bool set, Elf_Data *data, GElf_Addr data_vaddr)
+check_notes (struct dwfl_build_id **build_idp, bool set,
+            Elf_Data *data, GElf_Addr data_vaddr)
 {
   size_t pos = 0;
   GElf_Nhdr nhdr;
@@ -84,21 +91,25 @@ check_notes (Dwfl_Module *mod, bool set, Elf_Data *data, GElf_Addr data_vaddr)
   size_t desc_pos;
   while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0)
     if (nhdr.n_type == NT_GNU_BUILD_ID
-       && nhdr.n_namesz == sizeof "GNU" && !memcmp (data->d_buf + name_pos,
-                                                    "GNU", sizeof "GNU"))
-      return found_build_id (mod, set,
-                            data->d_buf + desc_pos, nhdr.n_descsz,
-                            data_vaddr == NO_VADDR ? 0
-                            : data_vaddr + desc_pos);
+       && nhdr.n_namesz == sizeof "GNU"
+       && !memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU"))
+      return __libdwfl_found_build_id (build_idp, set,
+                                      data->d_buf + desc_pos,
+                                      nhdr.n_descsz,
+                                      data_vaddr == NO_VADDR
+                                        ? 0 : data_vaddr + desc_pos);
   return 0;
 }
 
 int
 internal_function
-__libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
+__libdwfl_find_build_id (struct dwfl_build_id **build_idp, GElf_Addr bias,
+                        bool set, Elf *elf)
 {
-  int result = 0;
+  if (*build_idp == BUILD_ID_NOT_FOUND) /* Cached failure. */
+    return -1;
 
+  int result = 0;
   Elf_Scn *scn = elf_nextscn (elf, NULL);
 
   if (scn == NULL)
@@ -116,12 +127,12 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
          GElf_Phdr phdr_mem;
          GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
          if (likely (phdr != NULL) && phdr->p_type == PT_NOTE)
-           result = check_notes (mod, set,
+           result = check_notes (build_idp, set,
                                  elf_getdata_rawchunk (elf,
                                                        phdr->p_offset,
                                                        phdr->p_filesz,
                                                        ELF_T_NHDR),
-                                 phdr->p_vaddr + mod->main.bias);
+                                 phdr->p_vaddr + bias);
        }
     }
   else
@@ -130,12 +141,17 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
        GElf_Shdr shdr_mem;
        GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
        if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
-         result = check_notes (mod, set, elf_getdata (scn, NULL),
+         result = check_notes (build_idp, set,
+                               elf_getdata (scn, NULL),
                                (shdr->sh_flags & SHF_ALLOC)
-                               ? shdr->sh_addr + mod->main.bias : NO_VADDR);
+                               ? shdr->sh_addr + bias : NO_VADDR);
       }
     while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
 
+  /* Cache negative result. */
+  if (result <= 0)
+    *build_idp = BUILD_ID_NOT_FOUND;
+
   return result;
 }
 
@@ -146,22 +162,28 @@ dwfl_module_build_id (Dwfl_Module *mod,
   if (mod == NULL)
     return -1;
 
-  if (mod->build_id_len == 0 && mod->main.elf != NULL)
+  struct dwfl_build_id *build_id;
+  if (mod->main.shared == NULL)
+    build_id = mod->build_id;
+  else if (mod->main.shared->build_id != NULL)
+    build_id = mod->main.shared->build_id;
+  else if (mod->main.shared->elf != NULL)
     {
       /* We have the file, but have not examined it yet.  */
-      int result = __libdwfl_find_build_id (mod, true, mod->main.elf);
-      if (result <= 0)
-       {
-         mod->build_id_len = -1;       /* Cache negative result.  */
-         return result;
-       }
+      __libdwfl_find_build_id (&mod->main.shared->build_id, mod->bias,
+                              true, mod->main.shared->elf);
+      build_id = mod->main.shared->build_id;
     }
+  else
+    return -1;
 
-  if (mod->build_id_len <= 0)
+  if (build_id == NULL)
     return 0;
+  else if (build_id == BUILD_ID_NOT_FOUND)
+    return -1;
 
-  *bits = mod->build_id_bits;
-  *vaddr = mod->build_id_vaddr;
-  return mod->build_id_len;
+  *bits = build_id->bits;
+  *vaddr = build_id->vaddr;
+  return build_id->len;
 }
 INTDEF (dwfl_module_build_id)
index 652383bed5cd3c013ab93b605c3ee24cc935e0f9..d8313663377032b7a7837090ae73d3c62d4e96fc 100644 (file)
 #include <unistd.h>
 #include "../libdw/libdwP.h"   /* DWARF_E_* values are here.  */
 
-
-/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
-   When we return success, FILE->elf and FILE->bias are set up.  */
-static inline Dwfl_Error
-open_elf (Dwfl_Module *mod, struct dwfl_file *file)
+/* Find the main ELF file for this module and open libelf on it.
+   When we return success, MOD->main is set up.  MOD->elferr is
+   set up in any case. */
+static Dwfl_Error
+find_file (Dwfl_Module *mod)
 {
-  if (file->elf == NULL)
+  if (mod->main.cberr != DWFL_E_NOERROR)
+    return mod->main.cberr;
+  if (mod->main.shared != NULL)        /* Already done.  */
+    return mod->main.shared->elferr;
+
+  Elf *elf = NULL;
+  mod->main.name = NULL;
+  int fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
+                                             &mod->main.name,
+                                             &elf);
+
+  Dwfl_Error err = DWFL_E_NOERROR;
+
+  /* If the callback didn't open the dwfl_file for us, but gave us at
+     least indices, we will do it ourselves. */
+  if (mod->main.shared == NULL)
     {
-      /* If there was a pre-primed file name left that the callback left
-        behind, try to open that file name.  */
-      if (file->fd < 0 && file->name != NULL)
-       file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY));
-
-      if (file->fd < 0)
-       return CBFAIL;
+      if (unlikely (fd < 0 && mod->main.name == NULL && elf == NULL))
+       /* The callback didn't give us anything... */
+       return mod->main.cberr = DWFL_E_CB;
 
-      file->elf = elf_begin (file->fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+      err = __libdwfl_open_file (&mod->main, mod->main.name, fd, elf);
     }
 
-  if (unlikely (elf_kind (file->elf) != ELF_K_ELF))
-    {
-      close (file->fd);
-      file->fd = -1;
-      return DWFL_E_BADELF;
-    }
-
-  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
-  if (ehdr == NULL)
+  if (likely (err == DWFL_E_NOERROR))
     {
-    elf_error:
-      close (file->fd);
-      file->fd = -1;
-      return DWFL_E (LIBELF, elf_errno ());
-    }
-
-  /* The addresses in an ET_EXEC file are absolute.  The lowest p_vaddr of
-     the main file can differ from that of the debug file due to prelink.
-     But that doesn't not change addresses that symbols, debuginfo, or
-     sh_addr of any program sections refer to.  */
-  file->bias = 0;
-  if (mod->e_type != ET_EXEC)
-    for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
-      {
-       GElf_Phdr ph_mem;
-       GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
-       if (ph == NULL)
-         goto elf_error;
-       if (ph->p_type == PT_LOAD)
-         {
-           file->bias = ((mod->low_addr & -ph->p_align)
-                         - (ph->p_vaddr & -ph->p_align));
-           break;
-         }
-      }
-
-  mod->e_type = ehdr->e_type;
+      if (unlikely (elf_kind (mod->main.shared->elf) != ELF_K_ELF))
+       {
+         err = DWFL_E_BADELF;
+       elf_error:
+         __libdwfl_close_file (&mod->main);
+         mod->main.name = NULL;
+         return err;
+       }
 
-  /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN.  */
-  if (mod->e_type == ET_EXEC && file->bias != 0)
-    mod->e_type = ET_DYN;
+      /* Clear any explicitly reported build ID, just in case it was
+        wrong.  We'll fetch it from the file when asked. */
+      free (mod->build_id);
+      mod->build_id = NULL;
 
-  return DWFL_E_NOERROR;
-}
+      /* The following code duplicate to dwfl_report_elf.c. */
+      mod->bias = ((mod->low_addr & -mod->main.shared->align)
+                  - (mod->main.shared->start & -mod->main.shared->align));
 
-/* Find the main ELF file for this module and open libelf on it.
-   When we return success, MOD->main.elf and MOD->main.bias are set up.  */
-static void
-find_file (Dwfl_Module *mod)
-{
-  if (mod->main.elf != NULL    /* Already done.  */
-      || mod->elferr != DWFL_E_NOERROR)        /* Cached failure.  */
-    return;
+      GElf_Ehdr ehdr_mem;
+      GElf_Ehdr *ehdr = gelf_getehdr (mod->main.shared->elf, &ehdr_mem);
+      if (ehdr == NULL)
+       {
+         /* XXX This shouldn't happen, we already got ehdr in
+            __libdwfl_open_file.  Maybe put the the ehdr in shared
+            struct, since we extract it anyway?  */
+         err = DWFL_E (LIBELF, elf_errno ());
+         goto elf_error;
+       }
 
-  mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
-                                                   &mod->main.name,
-                                                   &mod->main.elf);
-  mod->elferr = open_elf (mod, &mod->main);
+      mod->e_type = ehdr->e_type;
 
-  if (mod->elferr == DWFL_E_NOERROR && !mod->main.valid)
-    {
-      /* Clear any explicitly reported build ID, just in case it was wrong.
-        We'll fetch it from the file when asked.  */
-      free (mod->build_id_bits);
-      mod->build_id_bits = NULL;
-      mod->build_id_len = 0;
+      /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN.  */
+      if (mod->e_type == ET_EXEC
+         && mod->bias != 0)
+       mod->e_type = ET_DYN;
     }
+
+  return mod->main.cberr = err;
 }
 
 /* Search an ELF file for a ".gnu_debuglink" section.  */
@@ -207,405 +191,91 @@ find_debuglink (Elf *elf, GElf_Word *crc)
 static Dwfl_Error
 find_debuginfo (Dwfl_Module *mod)
 {
-  if (mod->debug.elf != NULL)
-    return DWFL_E_NOERROR;
+  if (mod->debug.cberr != DWFL_E_NOERROR)
+    return mod->debug.cberr;
+  if (mod->debug.shared != NULL)        /* Already done.  */
+    return mod->debug.shared->elferr;
 
   GElf_Word debuglink_crc = 0;
-  const char *debuglink_file = find_debuglink (mod->main.elf, &debuglink_crc);
-
-  mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
-                                                          mod->main.name,
-                                                          debuglink_file,
-                                                          debuglink_crc,
-                                                          &mod->debug.name);
-  return open_elf (mod, &mod->debug);
-}
-
-
-/* Try to find a symbol table in FILE.
-   Returns DWFL_E_NOERROR if a proper one is found.
-   Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM.  */
-static Dwfl_Error
-load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
-            Elf_Scn **symscn, Elf_Scn **xndxscn,
-            size_t *syments, GElf_Word *strshndx)
-{
-  bool symtab = false;
-  Elf_Scn *scn = NULL;
-  while ((scn = elf_nextscn (file->elf, scn)) != NULL)
-    {
-      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
-      if (shdr != NULL)
-       switch (shdr->sh_type)
-         {
-         case SHT_SYMTAB:
-           symtab = true;
-           *symscn = scn;
-           *symfile = file;
-           *strshndx = shdr->sh_link;
-           *syments = shdr->sh_size / shdr->sh_entsize;
-           if (*xndxscn != NULL)
-             return DWFL_E_NOERROR;
-           break;
-
-         case SHT_DYNSYM:
-           if (symtab)
-             break;
-           /* Use this if need be, but keep looking for SHT_SYMTAB.  */
-           *symscn = scn;
-           *symfile = file;
-           *strshndx = shdr->sh_link;
-           *syments = shdr->sh_size / shdr->sh_entsize;
-           break;
-
-         case SHT_SYMTAB_SHNDX:
-           *xndxscn = scn;
-           if (symtab)
-             return DWFL_E_NOERROR;
-           break;
-
-         default:
-           break;
-         }
-    }
-
-  if (symtab)
-    /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
+  const char *debuglink_file = find_debuglink (mod->main.shared->elf, &debuglink_crc);
+
+  int fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
+                                                   mod->main.name,
+                                                   debuglink_file,
+                                                   debuglink_crc,
+                                                   &mod->debug.name);
+  if (mod->debug.shared != NULL)
     return DWFL_E_NOERROR;
 
-  /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
-     We might have found an SHT_DYNSYM and set *SYMSCN et al though.  */
-  *xndxscn = NULL;
-  return DWFL_E_NO_SYMTAB;
-}
+  if (fd < 0)
+    return mod->debug.cberr = DWFL_E_CB;
 
-
-/* Translate addresses into file offsets.
-   OFFS[*] start out zero and remain zero if unresolved.  */
-static void
-find_offsets (Elf *elf, const GElf_Ehdr *ehdr, size_t n,
-             GElf_Addr addrs[n], GElf_Off offs[n])
-{
-  size_t unsolved = n;
-  for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
-    {
-      GElf_Phdr phdr_mem;
-      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
-      if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
-       for (size_t j = 0; j < n; ++j)
-         if (offs[j] == 0
-             && addrs[j] >= phdr->p_vaddr
-             && addrs[j] - phdr->p_vaddr < phdr->p_filesz)
-           {
-             offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset;
-             if (--unsolved == 0)
-               break;
-           }
-    }
+  return mod->debug.cberr = __libdwfl_open_file (&mod->debug, mod->debug.name,
+                                                fd, NULL);
 }
 
-/* Try to find a dynamic symbol table via phdrs.  */
-static void
-find_dynsym (Dwfl_Module *mod)
-{
-  GElf_Ehdr ehdr_mem;
-  GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);
 
-  for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+/* Try to open a libebl backend for MOD.  */
+Dwfl_Error
+internal_function
+__libdwfl_module_getebl (Dwfl_Module *mod)
+{
+  if (mod->main.shared == NULL
+      || mod->main.shared->ebl == NULL)
     {
-      GElf_Phdr phdr_mem;
-      GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
-      if (phdr == NULL)
-       break;
+      if (find_file (mod) != DWFL_E_NOERROR)
+       return mod->main.cberr;
 
-      if (phdr->p_type == PT_DYNAMIC)
-       {
-         /* Examine the dynamic section for the pointers we need.  */
-
-         Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
-                                                phdr->p_offset, phdr->p_filesz,
-                                                ELF_T_DYN);
-         if (data == NULL)
-           continue;
-
-         enum
-           {
-             i_symtab,
-             i_strtab,
-             i_hash,
-             i_gnu_hash,
-             i_max
-           };
-         GElf_Addr addrs[i_max] = { 0, };
-         GElf_Xword strsz = 0;
-         size_t n = data->d_size / gelf_fsize (mod->main.elf,
-                                               ELF_T_DYN, 1, EV_CURRENT);
-         for (size_t j = 0; j < n; ++j)
-           {
-             GElf_Dyn dyn_mem;
-             GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
-             if (dyn != NULL)
-               switch (dyn->d_tag)
-                 {
-                 case DT_SYMTAB:
-                   addrs[i_symtab] = dyn->d_un.d_ptr;
-                   continue;
-
-                 case DT_HASH:
-                   addrs[i_hash] = dyn->d_un.d_ptr;
-                   continue;
-
-                 case DT_GNU_HASH:
-                   addrs[i_gnu_hash] = dyn->d_un.d_ptr;
-                   continue;
-
-                 case DT_STRTAB:
-                   addrs[i_strtab] = dyn->d_un.d_ptr;
-                   continue;
-
-                 case DT_STRSZ:
-                   strsz = dyn->d_un.d_val;
-                   continue;
-
-                 default:
-                   continue;
-
-                 case DT_NULL:
-                   break;
-                 }
-             break;
-           }
-
-         /* Translate pointers into file offsets.  */
-         GElf_Off offs[i_max] = { 0, };
-         find_offsets (mod->main.elf, ehdr, i_max, addrs, offs);
-
-         /* Figure out the size of the symbol table.  */
-         if (offs[i_hash] != 0)
-           {
-             /* In the original format, .hash says the size of .dynsym.  */
-
-             size_t entsz = SH_ENTSIZE_HASH (ehdr);
-             data = elf_getdata_rawchunk (mod->main.elf,
-                                          offs[i_hash] + entsz, entsz,
-                                          entsz == 4 ? ELF_T_WORD
-                                          : ELF_T_XWORD);
-             if (data != NULL)
-               mod->syments = (entsz == 4
-                               ? *(const GElf_Word *) data->d_buf
-                               : *(const GElf_Xword *) data->d_buf);
-           }
-         if (offs[i_gnu_hash] != 0 && mod->syments == 0)
-           {
-             /* In the new format, we can derive it with some work.  */
-
-             const struct
-             {
-               Elf32_Word nbuckets;
-               Elf32_Word symndx;
-               Elf32_Word maskwords;
-               Elf32_Word shift2;
-             } *header;
-
-             data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
-                                          sizeof *header, ELF_T_WORD);
-             if (data != NULL)
-               {
-                 header = data->d_buf;
-                 Elf32_Word nbuckets = header->nbuckets;
-                 Elf32_Word symndx = header->symndx;
-                 GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
-                                        + (gelf_getclass (mod->main.elf)
-                                           * sizeof (Elf32_Word)
-                                           * header->maskwords));
-
-                 data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
-                                              nbuckets * sizeof (Elf32_Word),
-                                              ELF_T_WORD);
-                 if (data != NULL && symndx < nbuckets)
-                   {
-                     const Elf32_Word *const buckets = data->d_buf;
-                     Elf32_Word maxndx = symndx;
-                     for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
-                       if (buckets[bucket] > maxndx)
-                         maxndx = buckets[bucket];
-
-                     GElf_Off hasharr_at = (buckets_at
-                                            + nbuckets * sizeof (Elf32_Word));
-                     hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
-                     do
-                       {
-                         data = elf_getdata_rawchunk (mod->main.elf,
-                                                      hasharr_at,
-                                                      sizeof (Elf32_Word),
-                                                      ELF_T_WORD);
-                         if (data != NULL
-                             && (*(const Elf32_Word *) data->d_buf & 1u))
-                           {
-                             mod->syments = maxndx + 1;
-                             break;
-                           }
-                         ++maxndx;
-                         hasharr_at += sizeof (Elf32_Word);
-                       } while (data != NULL);
-                   }
-               }
-           }
-         if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
-           mod->syments = ((offs[i_strtab] - offs[i_symtab])
-                           / gelf_fsize (mod->main.elf,
-                                         ELF_T_SYM, 1, EV_CURRENT));
-
-         if (mod->syments > 0)
-           {
-             mod->symdata = elf_getdata_rawchunk (mod->main.elf,
-                                                  offs[i_symtab],
-                                                  gelf_fsize (mod->main.elf,
-                                                              ELF_T_SYM,
-                                                              mod->syments,
-                                                              EV_CURRENT),
-                                                  ELF_T_SYM);
-             if (mod->symdata != NULL)
-               {
-                 mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
-                                                         offs[i_strtab],
-                                                         strsz,
-                                                         ELF_T_BYTE);
-                 if (mod->symstrdata == NULL)
-                   mod->symdata = NULL;
-               }
-             if (mod->symdata == NULL)
-               mod->symerr = DWFL_E (LIBELF, elf_errno ());
-             else
-               {
-                 mod->symfile = &mod->main;
-                 mod->symerr = DWFL_E_NOERROR;
-               }
-             return;
-           }
-       }
+      mod->main.shared->ebl = ebl_openbackend (mod->main.shared->elf);
+      if (mod->main.shared->ebl == NULL)
+       return DWFL_E_LIBEBL;
     }
+  return DWFL_E_NOERROR;
 }
 
-/* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf.  */
-static void
-find_symtab (Dwfl_Module *mod)
+static Dwfl_Error
+find_symfile (Dwfl_Module *mod)
 {
-  if (mod->symdata != NULL     /* Already done.  */
-      || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure.  */
-    return;
+  if (mod->symfile != NULL)
+    return DWFL_E_NOERROR;
 
-  find_file (mod);
-  mod->symerr = mod->elferr;
-  if (mod->symerr != DWFL_E_NOERROR)
-    return;
+  Dwfl_Error error = find_file (mod);
+  if (error != DWFL_E_NOERROR)
+    return error;
 
-  /* First see if the main ELF file has the debugging information.  */
-  Elf_Scn *symscn = NULL, *xndxscn = NULL;
-  GElf_Word strshndx;
-  mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
-                            &xndxscn, &mod->syments, &strshndx);
-  switch (mod->symerr)
+  error = __libdwfl_find_symtab (mod->main.shared);
+  if (error == DWFL_E_NO_SYMTAB
+      || (error == DWFL_E_NOERROR && !mod->main.shared->is_symtab))
     {
-    default:
-      return;
-
-    case DWFL_E_NOERROR:
-      break;
-
-    case DWFL_E_NO_SYMTAB:
-      /* Now we have to look for a separate debuginfo file.  */
-      mod->symerr = find_debuginfo (mod);
-      switch (mod->symerr)
+      error = find_debuginfo (mod);
+      if (error == DWFL_E_NOERROR)
        {
-       default:
-         return;
-
-       case DWFL_E_NOERROR:
-         mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
-                                    &xndxscn, &mod->syments, &strshndx);
-         break;
-
-       case DWFL_E_CB:         /* The find_debuginfo hook failed.  */
-         mod->symerr = DWFL_E_NO_SYMTAB;
-         break;
-       }
-
-      switch (mod->symerr)
-       {
-       default:
-         return;
-
-       case DWFL_E_NOERROR:
-         break;
-
-       case DWFL_E_NO_SYMTAB:
-         if (symscn != NULL)
+         error = __libdwfl_find_symtab (mod->debug.shared);
+         if (error == DWFL_E_NOERROR)
            {
-             /* We still have the dynamic symbol table.  */
-             mod->symerr = DWFL_E_NOERROR;
-             break;
+             /* .dynsym in debuginfo makes no sense, so if there is a
+                symtab, it's the proper one. */
+             mod->symfile = &mod->debug;
+             return error;
            }
-
-         /* Last ditch, look for dynamic symbols without section headers.  */
-         find_dynsym (mod);
-         return;
        }
-      break;
-    }
-
-  /* This does some sanity checks on the string table section.  */
-  if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL)
-    {
-    elferr:
-      mod->symerr = DWFL_E (LIBELF, elf_errno ());
-      return;
-    }
-
-  /* Cache the data; MOD->syments was set above.  */
-
-  mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx),
-                                NULL);
-  if (mod->symstrdata == NULL)
-    goto elferr;
-
-  if (xndxscn == NULL)
-    mod->symxndxdata = NULL;
-  else
-    {
-      mod->symxndxdata = elf_getdata (xndxscn, NULL);
-      if (mod->symxndxdata == NULL)
-       goto elferr;
-    }
-
-  mod->symdata = elf_getdata (symscn, NULL);
-  if (mod->symdata == NULL)
-    goto elferr;
-}
-
-
-/* Try to open a libebl backend for MOD.  */
-Dwfl_Error
-internal_function
-__libdwfl_module_getebl (Dwfl_Module *mod)
-{
-  if (mod->ebl == NULL)
-    {
-      find_file (mod);
-      if (mod->elferr != DWFL_E_NOERROR)
-       return mod->elferr;
-
-      mod->ebl = ebl_openbackend (mod->main.elf);
-      if (mod->ebl == NULL)
-       return DWFL_E_LIBEBL;
+      else if (mod->main.shared->symerr != DWFL_E_NOERROR)
+       /* No .dynsym in main, so report failure to find debuginfo.  */
+       return error;
     }
-  return DWFL_E_NOERROR;
+  if (error == DWFL_E_NOERROR)
+    mod->symfile = &mod->main;
+  return error;
 }
 
 /* Try to start up libdw on DEBUGFILE.  */
 static Dwfl_Error
-load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
+load_dw (Dwfl_Module *mod, struct dwfl_shared_file *debugfile)
 {
+  if (debugfile->dw != NULL                    /* Already done. */
+      || debugfile->dwerr != DWFL_E_NOERROR)   /* Cached previous failure. */
+    return debugfile->dwerr;
+
   if (mod->e_type == ET_REL && !debugfile->relocated)
     {
       const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
@@ -618,28 +288,13 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
       if (error != DWFL_E_NOERROR)
        return error;
 
-      find_symtab (mod);
-      Dwfl_Error result = mod->symerr;
-      if (result == DWFL_E_NOERROR)
-       result = __libdwfl_relocate (mod, debugfile->elf, true);
-      if (result != DWFL_E_NOERROR)
-       return result;
-
-      /* Don't keep the file descriptors around.  */
-      if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
-       {
-         close (mod->main.fd);
-         mod->main.fd = -1;
-       }
-      if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
-       {
-         close (debugfile->fd);
-         debugfile->fd = -1;
-       }
+      error = __libdwfl_relocate (mod, debugfile, true);
+      if (error != DWFL_E_NOERROR)
+       return error;
     }
 
-  mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
-  if (mod->dw == NULL)
+  debugfile->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
+  if (debugfile->dw == NULL)
     {
       int err = INTUSE(dwarf_errno) ();
       return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
@@ -652,32 +307,35 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
 }
 
 /* Try to start up libdw on either the main file or the debuginfo file.  */
-static void
+static Dwfl_Error
 find_dw (Dwfl_Module *mod)
 {
-  if (mod->dw != NULL          /* Already done.  */
-      || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure.  */
-    return;
+  if (mod->dwerr != DWFL_E_NOERROR) /* Cached failure to setup debug file. */
+    return mod->dwerr;
 
-  find_file (mod);
-  mod->dwerr = mod->elferr;
+  if (mod->debug.shared != NULL
+      && (mod->debug.shared->dw != NULL /* Already done.  */
+         || mod->debug.shared->dwerr != DWFL_E_NOERROR)) /* Cached failure. */
+    return mod->debug.shared->dwerr;
+
+  mod->dwerr = find_file (mod);
   if (mod->dwerr != DWFL_E_NOERROR)
-    return;
+    return mod->dwerr;
 
   /* First see if the main ELF file has the debugging information.  */
-  mod->dwerr = load_dw (mod, &mod->main);
-  switch (mod->dwerr)
+  mod->main.shared->dwerr = load_dw (mod, mod->main.shared);
+  switch (mod->main.shared->dwerr)
     {
     case DWFL_E_NOERROR:
-      mod->debug.elf = mod->main.elf;
-      mod->debug.bias = mod->main.bias;
-      return;
+      mod->debug.shared = mod->main.shared;
+      return DWFL_E_NOERROR;
 
     case DWFL_E_NO_DWARF:
       break;
 
     default:
-      goto canonicalize;
+      return (mod->main.shared->dwerr
+             = __libdwfl_canon_error (mod->main.shared->dwerr));
     }
 
   /* Now we have to look for a separate debuginfo file.  */
@@ -685,19 +343,15 @@ find_dw (Dwfl_Module *mod)
   switch (mod->dwerr)
     {
     case DWFL_E_NOERROR:
-      mod->dwerr = load_dw (mod, &mod->debug);
-      break;
+      return (mod->debug.shared->dwerr
+             = __libdwfl_canon_error (load_dw (mod, mod->debug.shared)));
 
     case DWFL_E_CB:            /* The find_debuginfo hook failed.  */
-      mod->dwerr = DWFL_E_NO_DWARF;
-      return;
+      return mod->dwerr = DWFL_E_NO_DWARF;
 
     default:
-      break;
+      return mod->dwerr = __libdwfl_canon_error (mod->dwerr);
     }
-
- canonicalize:
-  mod->dwerr = __libdwfl_canon_error (mod->dwerr);
 }
 
 
@@ -707,34 +361,33 @@ dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase)
   if (mod == NULL)
     return NULL;
 
-  find_file (mod);
-  if (mod->elferr == DWFL_E_NOERROR)
+  if (find_file (mod) == DWFL_E_NOERROR)
     {
-      if (mod->e_type == ET_REL && ! mod->main.relocated)
+      if (mod->e_type == ET_REL && ! mod->main.shared->relocated)
        {
          /* Before letting them get at the Elf handle,
             apply all the relocations we know how to.  */
 
-         mod->main.relocated = true;
+         mod->main.shared->relocated = true;
          if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR))
            {
-             (void) __libdwfl_relocate (mod, mod->main.elf, false);
+             (void) __libdwfl_relocate (mod, mod->main.shared, false);
 
-             if (mod->debug.elf == mod->main.elf)
-               mod->debug.relocated = true;
-             else if (mod->debug.elf != NULL && ! mod->debug.relocated)
+             if (mod->debug.shared == mod->main.shared)
+               mod->debug.shared->relocated = true;
+             else if (mod->debug.shared != NULL && ! mod->debug.shared->relocated)
                {
-                 mod->debug.relocated = true;
-                 (void) __libdwfl_relocate (mod, mod->debug.elf, false);
+                 mod->debug.shared->relocated = true;
+                 (void) __libdwfl_relocate (mod, mod->debug.shared, false);
                }
            }
        }
 
-      *loadbase = mod->main.bias;
-      return mod->main.elf;
+      *loadbase = mod->bias;
+      return mod->main.shared->elf;
     }
 
-  __libdwfl_seterrno (mod->elferr);
+  __libdwfl_seterrno (mod->main.cberr);
   return NULL;
 }
 INTDEF (dwfl_module_getelf)
@@ -746,24 +399,24 @@ dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
   if (mod == NULL)
     return NULL;
 
-  find_dw (mod);
-  if (mod->dwerr == DWFL_E_NOERROR)
+  Dwfl_Error err = find_dw (mod);
+  if (err == DWFL_E_NOERROR)
     {
       /* If dwfl_module_getelf was used previously, then partial apply
         relocation to miscellaneous sections in the debug file too.  */
       if (mod->e_type == ET_REL
-         && mod->main.relocated && ! mod->debug.relocated)
+         && mod->main.shared->relocated && ! mod->debug.shared->relocated)
        {
-         mod->debug.relocated = true;
-         if (mod->debug.elf != mod->main.elf)
-           (void) __libdwfl_relocate (mod, mod->debug.elf, false);
+         mod->debug.shared->relocated = true;
+         if (mod->debug.shared->elf != mod->main.shared->elf)
+           (void) __libdwfl_relocate (mod, mod->debug.shared, false);
        }
 
-      *bias = mod->debug.bias;
-      return mod->dw;
+      *bias = DWBIAS (mod);
+      return mod->debug.shared->dw;
     }
 
-  __libdwfl_seterrno (mod->dwerr);
+  __libdwfl_seterrno (err);
   return NULL;
 }
 INTDEF (dwfl_module_getdwarf)
@@ -771,14 +424,18 @@ INTDEF (dwfl_module_getdwarf)
 int
 dwfl_module_getsymtab (Dwfl_Module *mod)
 {
-  if (mod == NULL)
+  if (mod == NULL
+      || mod->main.cberr != DWFL_E_NOERROR)
+    /* Don't mind error in debug.cberr, symtab may be in main. */
     return -1;
 
-  find_symtab (mod);
-  if (mod->symerr == DWFL_E_NOERROR)
-    return mod->syments;
+  Dwfl_Error err = find_symfile(mod);
+  if (mod->symfile == NULL)
+    {
+      __libdwfl_seterrno (err);
+      return -1;
+    }
 
-  __libdwfl_seterrno (mod->symerr);
-  return -1;
+  return mod->symfile->shared->syments;
 }
 INTDEF (dwfl_module_getsymtab)
index 9d0c786b9a2872cfc375c49287f34e58c667ff56..6b0dae6f8c28eb96506cd953aa7ef58e308e0ce9 100644 (file)
@@ -59,7 +59,7 @@ dwfl_module_getsrc_file (Dwfl_Module *mod,
   if (mod == NULL)
     return -1;
 
-  if (mod->dw == NULL)
+  if (mod->debug.shared->dw == NULL)
     {
       Dwarf_Addr bias;
       if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
index 5f289ccb1372716a95f8593e178a71664d2a4af4..f81f555fc7cedb4cfccb169a0104faa26d2c0c49 100644 (file)
@@ -56,7 +56,7 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
   if (unlikely (mod == NULL))
     return NULL;
 
-  if (unlikely (mod->symdata == NULL))
+  if (unlikely (mod->symfile == NULL))
     {
       int result = INTUSE(dwfl_module_getsymtab) (mod);
       if (result < 0)
@@ -64,7 +64,9 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
     }
 
   GElf_Word shndx;
-  sym = gelf_getsymshndx (mod->symdata, mod->symxndxdata, ndx, sym, &shndx);
+  sym = gelf_getsymshndx (mod->symfile->shared->symdata,
+                         mod->symfile->shared->symxndxdata,
+                         ndx, sym, &shndx);
   if (unlikely (sym == NULL))
     {
       __libdwfl_seterrno (DWFL_E_LIBELF);
@@ -90,9 +92,9 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
          /* In an ET_REL file, the symbol table values are relative
             to the section, not to the module's load base.  */
          size_t symshstrndx = SHN_UNDEF;
-         Dwfl_Error result = __libdwfl_relocate_value (mod, mod->symfile->elf,
-                                                       &symshstrndx,
-                                                       shndx, &sym->st_value);
+         Dwfl_Error result
+           = __libdwfl_relocate_value (mod, mod->symfile->shared->elf,
+                                       &symshstrndx, shndx, &sym->st_value);
          if (unlikely (result != DWFL_E_NOERROR))
            {
              __libdwfl_seterrno (result);
@@ -100,15 +102,15 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
            }
        }
       /* Apply the bias to the symbol value.  */
-      sym->st_value += mod->symfile->bias;
+      sym->st_value += SYMBIAS (mod);
       break;
     }
 
-  if (unlikely (sym->st_name >= mod->symstrdata->d_size))
+  if (unlikely (sym->st_name >= mod->symfile->shared->symstrdata->d_size))
     {
       __libdwfl_seterrno (DWFL_E_BADSTROFF);
       return NULL;
     }
-  return (const char *) mod->symstrdata->d_buf + sym->st_name;
+  return (const char *) mod->symfile->shared->symstrdata->d_buf + sym->st_name;
 }
 INTDEF (dwfl_module_getsym)
index 759cb6216e9271c4c2cc93f689922917ea59077e..f2cf38482e026e29f01797622ddd671eaa608595 100644 (file)
@@ -66,9 +66,12 @@ dwfl_module_info (Dwfl_Module *mod, void ***userdata,
     *end = mod->high_addr;
 
   if (dwbias)
-    *dwbias = mod->debug.elf == NULL ? (Dwarf_Addr) -1 : mod->debug.bias;
+    *dwbias = (mod->debug.shared == NULL
+              || mod->debug.shared->elf == NULL)
+      ? (Dwarf_Addr) -1 : DWBIAS (mod);
+
   if (symbias)
-    *symbias = mod->symfile == NULL ? (Dwarf_Addr) -1 : mod->symfile->bias;
+    *symbias = mod->symfile == NULL ? (Dwarf_Addr) -1 : SYMBIAS (mod);
 
   if (mainfile)
     *mainfile = mod->main.name;
index 79a874a8cf88a0588325a4b52b1b1f461828c95a..b9a2d8f3c2486f69899e1ed4d2e7014e766a0f4e 100644 (file)
@@ -61,7 +61,8 @@ dwfl_module_register_names (mod, func, arg)
   if (unlikely (mod == NULL))
     return -1;
 
-  if (unlikely (mod->ebl == NULL))
+  if (unlikely (mod->main.shared == NULL
+               || mod->main.shared->ebl == NULL))
     {
       Dwfl_Error error = __libdwfl_module_getebl (mod);
       if (error != DWFL_E_NOERROR)
@@ -71,7 +72,8 @@ dwfl_module_register_names (mod, func, arg)
        }
     }
 
-  int nregs = ebl_register_info (mod->ebl, -1, NULL, 0,
+  int nregs = ebl_register_info (mod->main.shared->ebl, -1,
+                                NULL, 0,
                                 NULL, NULL, NULL, NULL);
   int result = 0;
   for (int regno = 0; regno < nregs && likely (result == 0); ++regno)
@@ -81,7 +83,8 @@ dwfl_module_register_names (mod, func, arg)
       const char *prefix = NULL;
       int bits = -1;
       int type = -1;
-      ssize_t len = ebl_register_info (mod->ebl, regno, name, sizeof name,
+      ssize_t len = ebl_register_info (mod->main.shared->ebl, regno,
+                                      name, sizeof name,
                                       &prefix, &setname, &bits, &type);
       if (unlikely (len < 0))
        {
index 9a1b14f792b34ba63432852598000322299ba13c..beec9f8b9b1e610d25838439a459253b5f9642b4 100644 (file)
@@ -58,14 +58,16 @@ dwfl_module_report_build_id (Dwfl_Module *mod,
   if (mod == NULL)
     return -1;
 
-  if (mod->main.elf != NULL)
+  if (mod->main.shared != NULL)
     {
       /* Once we know about a file, we won't take any lies about
         its contents.  The only permissible call is a no-op.  */
 
-      if ((size_t) mod->build_id_len == len
-         && (mod->build_id_vaddr == vaddr || vaddr == 0)
-         && !memcmp (bits, mod->build_id_bits, len))
+      struct dwfl_build_id *build_id = mod->main.shared->build_id;
+      if (BUILD_ID_PTR (build_id)
+         && (size_t) build_id->len == len
+         && (build_id->vaddr == vaddr || vaddr == 0)
+         && !memcmp (bits, build_id->bits, len))
        return 0;
 
       __libdwfl_seterrno (DWFL_E_ALREADY_ELF);
@@ -78,24 +80,12 @@ dwfl_module_report_build_id (Dwfl_Module *mod,
       return -1;
     }
 
-  void *copy = NULL;
-  if (len > 0)
-    {
-      copy = malloc (len);
-      if (unlikely (copy == NULL))
-       {
-         __libdwfl_seterrno (DWFL_E_NOMEM);
-         return -1;
-       }
-      memcpy (copy, bits, len);
-    }
+  struct dwfl_build_id *orig_build_id = mod->build_id;
 
-  free (mod->build_id_bits);
-
-  mod->build_id_bits = copy;
-  mod->build_id_len = len;
-  mod->build_id_vaddr = vaddr;
+  if (__libdwfl_found_build_id (&mod->build_id, true, bits, len, vaddr) < 0)
+    return -1;
 
+  free (orig_build_id);
   return 0;
 }
 INTDEF (dwfl_module_report_build_id)
index 3d5154e21499bb969b1dc48af399c580a2e87a62..35612d6da28c610eb0caff35cb0a617c4abf2aca 100644 (file)
@@ -59,7 +59,8 @@ dwfl_module_return_value_location (mod, functypedie, locops)
   if (mod == NULL)
     return -1;
 
-  if (mod->ebl == NULL)
+  if (mod->main.shared == NULL
+      || mod->main.shared->ebl == NULL)
     {
       Dwfl_Error error = __libdwfl_module_getebl (mod);
       if (error != DWFL_E_NOERROR)
@@ -69,7 +70,8 @@ dwfl_module_return_value_location (mod, functypedie, locops)
        }
     }
 
-  int nops = ebl_return_value_location (mod->ebl, functypedie, locops);
+  int nops = ebl_return_value_location (mod->main.shared->ebl,
+                                       functypedie, locops);
   if (unlikely (nops < 0))
     {
       if (nops == -1)
index 6db3e0f14cd687dd9cd123812e101a0a75fdfb6f..db7ec121ca3a96f2ace08f8ec6d7085f239bb4d9 100644 (file)
@@ -75,7 +75,7 @@ dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias)
 
       if (cu != NULL)
        {
-         *bias = mod->debug.bias;
+         *bias = DWBIAS (mod);
          return &cu->die;
        }
 
@@ -88,12 +88,12 @@ dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias)
            return NULL;
 
          if (mod->dwerr == DWFL_E_NOERROR
-             && (mod->dw != NULL
+             && ((mod->debug.shared != NULL && mod->debug.shared->dw != NULL)
                  || INTUSE(dwfl_module_getdwarf) (mod, bias) != NULL))
            break;
        }
       while (mod->dwerr == DWFL_E_NO_DWARF);
-      error = mod->dwerr;
+      error = mod->dwerr ?: mod->debug.shared->dwerr;
     }
   while (error == DWFL_E_NOERROR);
 
index 0e5d09bcb2eee50f3cc7dbd050554f96456d8b53..9711ba7a9c0445c809dce5d283eaa991795b23c5 100644 (file)
@@ -226,34 +226,43 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
   Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end);
   if (m != NULL)
     {
-      if (m->main.name == NULL)
+      if (m->main.shared == NULL)
        {
-         m->main.name = strdup (file_name);
-         m->main.fd = fd;
-       }
-      else if ((fd >= 0 && m->main.fd != fd)
+         Dwfl_Error err = __libdwfl_open_file (&m->main, file_name, fd, elf);
+
+         /* Some code here duplicate to dwfl_module_getdwarf.c. */
+         m->bias = ((m->low_addr & -m->main.shared->align)
+                    - (m->main.shared->start & -m->main.shared->align));
+
+         m->e_type = ehdr->e_type;
+
+         if (m->e_type == ET_EXEC
+             && m->bias != 0)
+           m->e_type = ET_DYN;
+
+
+         if (unlikely (err != DWFL_E_NOERROR))
+           {
+             __libdwfl_seterrno (err);
+             return NULL;
+           }
+         else if (bias != m->bias)
+           {
+             __libdwfl_seterrno (DWFL_E_OVERLAP);
+             m = NULL;
+           }
+       }
+      else if (m->bias != base
+              || (fd >= 0 && m->main.shared->fd >= 0 && m->main.shared->fd != fd)
               || strcmp (m->main.name, file_name))
+       /* This module has already been reported before, but with
+          different bias/fd/name. */
        {
          elf_end (elf);
-       overlap:
          m->gc = true;
          __libdwfl_seterrno (DWFL_E_OVERLAP);
          m = NULL;
        }
-
-      /* Preinstall the open ELF handle for the module.  */
-      if (m->main.elf == NULL)
-       {
-         m->main.elf = elf;
-         m->main.bias = bias;
-         m->e_type = ehdr->e_type;
-       }
-      else
-       {
-         elf_end (elf);
-         if (m->main.bias != base)
-           goto overlap;
-       }
     }
   return m;
 }
index 50ed140ef65f0cf0d86af87a5d2ae864bf3dc633..53e59926a18eb5fa8f31408aa89328af6bb3484c 100644 (file)
@@ -638,8 +638,14 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
   if (elf != NULL)
     {
       /* Install the file in the module.  */
-      mod->main.elf = elf;
-      mod->main.bias = bias;
+      if (__libdwfl_open_file (&mod->main, NULL, -1, elf))
+       {
+         ndx = -1;
+         return finish ();
+       }
+      mod->main.shared->start = start;
+      mod->bias = ((mod->low_addr & -mod->main.shared->align)
+                  - (mod->main.shared->start & -mod->main.shared->align));
     }
 
   return finish ();
diff --git a/libdwfl/dwfl_symtab.c b/libdwfl/dwfl_symtab.c
new file mode 100644 (file)
index 0000000..dd60eb3
--- /dev/null
@@ -0,0 +1,370 @@
+/* Find debugging and symbol information for a module in libdwfl.
+   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include "libdwflP.h"
+
+/* This function is called when load_symtab finds necessary sections
+   in ELF image.  It sets up FILE data apropriately, signalling error
+   when one of the calls fails. */
+static Dwfl_Error
+load_symtab_sections (struct dwfl_shared_file *file, Elf_Scn *symscn,
+                     Elf_Scn *xndxscn, GElf_Word strshndx)
+{
+  /* This does some sanity checks on the string table section.  */
+  if (elf_strptr (file->elf, strshndx, 0) == NULL)
+    goto elferr;
+
+  if (xndxscn == NULL)
+    file->symxndxdata = NULL;
+  else
+    {
+      file->symxndxdata = elf_getdata (xndxscn, NULL);
+      if (file->symxndxdata == NULL)
+        goto elferr;
+    }
+
+  file->symdata = elf_getdata (symscn, NULL);
+  if (file->symdata != NULL)
+    return DWFL_E_NOERROR;
+
+ elferr:
+  return file->symerr = DWFL_E (LIBELF, elf_errno ());
+}
+
+/* Try to find a symbol table in FILE.
+   Returns DWFL_E_NOERROR if a proper one is found.
+   Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM.  */
+static Dwfl_Error
+find_symtab (struct dwfl_shared_file *file, GElf_Word *strshndx)
+{
+  bool symtab = false;
+  Elf_Scn *symscn = NULL, *xndxscn = NULL;
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (file->elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
+      if (shdr != NULL)
+       switch (shdr->sh_type)
+         {
+         case SHT_SYMTAB:
+           symtab = true;
+           symscn = scn;
+           *strshndx = shdr->sh_link;
+           file->syments = shdr->sh_size / shdr->sh_entsize;
+           if (xndxscn != NULL)
+             return load_symtab_sections (file, symscn, xndxscn, *strshndx);
+           break;
+
+         case SHT_DYNSYM:
+           if (symtab)
+             break;
+           symscn = scn;
+           *strshndx = shdr->sh_link;
+           file->syments = shdr->sh_size / shdr->sh_entsize;
+           break;
+
+         case SHT_SYMTAB_SHNDX:
+           xndxscn = scn;
+           if (symtab)
+             return load_symtab_sections (file, symscn, xndxscn, *strshndx);
+           break;
+
+         default:
+           break;
+         }
+    }
+
+  if (symtab)
+    /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
+    return load_symtab_sections (file, symscn, xndxscn, *strshndx);
+
+ /* We found no SHT_SYMTAB.  */
+  return DWFL_E_NO_SYMTAB;
+}
+
+/* Translate addresses into file offsets.
+   OFFS[*] start out zero and remain zero if unresolved.  */
+static void
+find_offsets (Elf *elf, const GElf_Ehdr *ehdr, size_t n,
+             GElf_Addr addrs[n], GElf_Off offs[n])
+{
+  size_t unsolved = n;
+  for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+    {
+      GElf_Phdr phdr_mem;
+      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
+      if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
+       for (size_t j = 0; j < n; ++j)
+         if (offs[j] == 0
+             && addrs[j] >= phdr->p_vaddr
+             && addrs[j] - phdr->p_vaddr < phdr->p_filesz)
+           {
+             offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset;
+             if (--unsolved == 0)
+               break;
+           }
+    }
+}
+
+/* Try to find a dynamic symbol table via phdrs.  */
+static Dwfl_Error
+find_dynsym (struct dwfl_shared_file *file)
+{
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
+
+  for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+    {
+      GElf_Phdr phdr_mem;
+      GElf_Phdr *phdr = gelf_getphdr (file->elf, i, &phdr_mem);
+      if (phdr == NULL)
+       break;
+
+      if (phdr->p_type == PT_DYNAMIC)
+       {
+         /* Examine the dynamic section for the pointers we need.  */
+
+         Elf_Data *data = elf_getdata_rawchunk (file->elf,
+                                                phdr->p_offset, phdr->p_filesz,
+                                                ELF_T_DYN);
+         if (data == NULL)
+           continue;
+
+         enum
+           {
+             i_symtab,
+             i_strtab,
+             i_hash,
+             i_gnu_hash,
+             i_max
+           };
+         GElf_Addr addrs[i_max] = { 0, };
+         GElf_Xword strsz = 0;
+         size_t n = data->d_size / gelf_fsize (file->elf,
+                                               ELF_T_DYN, 1, EV_CURRENT);
+         for (size_t j = 0; j < n; ++j)
+           {
+             GElf_Dyn dyn_mem;
+             GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
+             if (dyn != NULL)
+               switch (dyn->d_tag)
+                 {
+                 case DT_SYMTAB:
+                   addrs[i_symtab] = dyn->d_un.d_ptr;
+                   continue;
+
+                 case DT_HASH:
+                   addrs[i_hash] = dyn->d_un.d_ptr;
+                   continue;
+
+                 case DT_GNU_HASH:
+                   addrs[i_gnu_hash] = dyn->d_un.d_ptr;
+                   continue;
+
+                 case DT_STRTAB:
+                   addrs[i_strtab] = dyn->d_un.d_ptr;
+                   continue;
+
+                 case DT_STRSZ:
+                   strsz = dyn->d_un.d_val;
+                   continue;
+
+                 default:
+                   continue;
+
+                 case DT_NULL:
+                   break;
+                 }
+             break;
+           }
+
+         /* Translate pointers into file offsets.  */
+         GElf_Off offs[i_max] = { 0, };
+         find_offsets (file->elf, ehdr, i_max, addrs, offs);
+
+         /* Figure out the size of the symbol table.  */
+         if (offs[i_hash] != 0)
+           {
+             /* In the original format, .hash says the size of .dynsym.  */
+
+             size_t entsz = SH_ENTSIZE_HASH (ehdr);
+             data = elf_getdata_rawchunk (file->elf,
+                                          offs[i_hash] + entsz, entsz,
+                                          entsz == 4 ? ELF_T_WORD
+                                          : ELF_T_XWORD);
+             if (data != NULL)
+               file->syments = (entsz == 4
+                                ? *(const GElf_Word *) data->d_buf
+                                : *(const GElf_Xword *) data->d_buf);
+           }
+         if (offs[i_gnu_hash] != 0 && file->syments == 0)
+           {
+             /* In the new format, we can derive it with some work.  */
+
+             const struct
+             {
+               Elf32_Word nbuckets;
+               Elf32_Word symndx;
+               Elf32_Word maskwords;
+               Elf32_Word shift2;
+             } *header;
+
+             data = elf_getdata_rawchunk (file->elf, offs[i_gnu_hash],
+                                          sizeof *header, ELF_T_WORD);
+             if (data != NULL)
+               {
+                 header = data->d_buf;
+                 Elf32_Word nbuckets = header->nbuckets;
+                 Elf32_Word symndx = header->symndx;
+                 GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
+                                        + (gelf_getclass (file->elf)
+                                           * sizeof (Elf32_Word)
+                                           * header->maskwords));
+
+                 data = elf_getdata_rawchunk (file->elf, buckets_at,
+                                              nbuckets * sizeof (Elf32_Word),
+                                              ELF_T_WORD);
+                 if (data != NULL && symndx < nbuckets)
+                   {
+                     const Elf32_Word *const buckets = data->d_buf;
+                     Elf32_Word maxndx = symndx;
+                     for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
+                       if (buckets[bucket] > maxndx)
+                         maxndx = buckets[bucket];
+
+                     GElf_Off hasharr_at = (buckets_at
+                                            + nbuckets * sizeof (Elf32_Word));
+                     hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
+                     do
+                       {
+                         data = elf_getdata_rawchunk (file->elf,
+                                                      hasharr_at,
+                                                      sizeof (Elf32_Word),
+                                                      ELF_T_WORD);
+                         if (data != NULL
+                             && (*(const Elf32_Word *) data->d_buf & 1u))
+                           {
+                             file->syments = maxndx + 1;
+                             break;
+                           }
+                         ++maxndx;
+                         hasharr_at += sizeof (Elf32_Word);
+                       } while (data != NULL);
+                   }
+               }
+           }
+         if (offs[i_strtab] > offs[i_symtab] && file->syments == 0)
+           file->syments = ((offs[i_strtab] - offs[i_symtab])
+                                    / gelf_fsize (file->elf,
+                                                  ELF_T_SYM, 1, EV_CURRENT));
+
+         if (file->syments > 0)
+           {
+             file->symdata
+               = elf_getdata_rawchunk (file->elf,
+                                       offs[i_symtab],
+                                       gelf_fsize (file->elf,
+                                                   ELF_T_SYM,
+                                                   file->syments,
+                                                   EV_CURRENT),
+                                       ELF_T_SYM);
+             if (file->symdata != NULL)
+               {
+                 file->symstrdata
+                   = elf_getdata_rawchunk (file->elf,
+                                           offs[i_strtab],
+                                           strsz,
+                                           ELF_T_BYTE);
+                 if (file->symstrdata == NULL)
+                   file->symdata = NULL;
+               }
+             if (file->symdata == NULL)
+               return DWFL_E (LIBELF, elf_errno ());
+             else
+               return DWFL_E_NOERROR;
+           }
+       }
+    }
+  return DWFL_E_NO_SYMTAB;
+}
+
+/* Try to find a symbol table or dynamic symbol table in FILE.  */
+Dwfl_Error
+internal_function
+__libdwfl_find_symtab (struct dwfl_shared_file *file)
+{
+  if (file->symdata != NULL /* Already done.  */
+      || file->symerr != DWFL_E_NOERROR) /* Cached previous failure.  */
+    return file->symerr;
+
+  /* First see if .symtab is present.  */
+  GElf_Word strshndx = 0;
+  file->symerr = find_symtab (file, &strshndx);
+
+  if (file->symerr == DWFL_E_NOERROR)
+    file->is_symtab = true;
+  else if (file->symerr == DWFL_E_NO_SYMTAB)
+    {
+      /* .symtab not present, try .dynsym */
+      file->symerr = find_dynsym (file);
+
+      if (file->symerr != DWFL_E_NOERROR)
+       return file->symerr;
+    }
+  else
+    return file->symerr;
+
+  file->symstrdata = elf_getdata (elf_getscn (file->elf, strshndx), NULL);
+  if (file->symstrdata == NULL)
+    file->symerr = DWFL_E (LIBELF, elf_errno ());
+  else
+    file->symerr = DWFL_E_NOERROR;
+
+  return file->symerr;
+}
index a01293e8e7885ef475a0c4c2dfa3b145f2be1a0d..9f6f4c7f115841fc891152a423005b230c47106c 100644 (file)
@@ -91,27 +91,27 @@ check_crc (int fd, GElf_Word debuglink_crc)
 }
 
 static bool
-validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
+validate (struct dwfl_build_id **build_idp, GElf_Addr bias,
+         int fd, bool check, GElf_Word debuglink_crc)
 {
   /* If we have a build ID, check only that.  */
-  if (mod->build_id_len > 0)
+  if (BUILD_ID_PTR (*build_idp))
     {
       /* We need to open an Elf handle on the file so we can check its
-        build ID note for validation.  Backdoor the handle into the
-        module data structure since we had to open it early anyway.  */
-      mod->debug.elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
-      if (likely (__libdwfl_find_build_id (mod, false, mod->debug.elf) == 2))
-       /* Also backdoor the gratuitous flag.  */
-       mod->debug.valid = true;
-      else
+        build ID note for validation.
+        XXX: Maybe backdoor the handle into the module data structure
+        since we had to open it early anyway?  */
+
+      Elf * elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+      if (unlikely (__libdwfl_find_build_id (build_idp, bias,
+                                            false, elf) != 2))
        {
-         /* A mismatch!  */
-         elf_end (mod->debug.elf);
-         mod->debug.elf = NULL;
-         mod->debug.valid = false;
+         free (*build_idp);
+         *build_idp = NULL;
        }
+      elf_end (elf);
 
-      return mod->debug.valid;
+      return *build_idp != NULL;
     }
 
   return !check || check_crc (fd, debuglink_crc);
@@ -203,7 +203,9 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
          default:
            return -1;
          }
-      if (validate (mod, fd, check, debuglink_crc))
+
+      if (validate (&mod->main.shared->build_id, mod->bias,
+                   fd, check, debuglink_crc))
        {
          *debuginfo_file_name = fname;
          return fd;
index 6ba5c96e80c9b9ad511aba4b551180cc79642004..6cf32eca851ce2c8a80d532c9db1646d8bdb6ba6 100644 (file)
@@ -128,15 +128,43 @@ struct Dwfl
 
 #define OFFLINE_REDZONE                0x10000
 
-struct dwfl_file
+struct dwfl_build_id
+{
+  GElf_Addr vaddr;             /* Address where they reside. */
+  int len;
+  unsigned char bits[0];       /* malloc'd copy of build ID bits.  */
+};
+
+struct dwfl_shared_file
 {
-  char *name;
   int fd;
-  bool valid;                  /* The build ID note has been matched.  */
   bool relocated;              /* Partial relocation of all sections done.  */
 
   Elf *elf;
-  GElf_Addr bias;              /* Actual load address - p_vaddr.  */
+  GElf_Addr start;             /* p_vaddr */
+  Dwfl_Error elferr;           /* Previous failure to get Elf handle. */
+
+  Elf_Data *symdata;           /* Data in the ELF symbol table section.  */
+  size_t syments;              /* sh_size / sh_entsize of that section.  */
+  Elf_Data *symstrdata;                /* Data for its string table.  */
+  Elf_Data *symxndxdata;       /* Data in the extended section index table. */
+  GElf_Addr align;             /* Alignment requirements. */
+  bool is_symtab;              /* Whether the symfile has a .symtab or a .dynsym. */
+  Dwfl_Error symerr;           /* Previous failure to load symbols.  */
+
+  struct dwfl_build_id *build_id;
+
+  Dwarf *dw;                   /* libdw handle for its debugging info.  */
+  Dwfl_Error dwerr;            /* Previous failure to load debuginfo.  */
+  Ebl *ebl;
+};
+
+struct dwfl_file
+{
+  char *name;
+  struct dwfl_shared_file *shared;     /* Shared portion of file. */
+  Dwfl_Error cberr;    /* Error related to use of find_elf (main.cberr)
+                          or find_debuginfo (debug.cberr) callbacks.  */
 };
 
 struct Dwfl_Module
@@ -149,26 +177,20 @@ struct Dwfl_Module
   char *name;                  /* Iterator name for this module.  */
   GElf_Addr low_addr, high_addr;
 
-  void *build_id_bits;         /* malloc'd copy of build ID bits.  */
-  GElf_Addr build_id_vaddr;    /* Address where they reside, 0 if unknown.  */
-  int build_id_len;            /* -1 for prior failure, 0 if unset.  */
-
-  struct dwfl_file main, debug;
-  Ebl *ebl;
+  struct dwfl_file main;
+  struct dwfl_file debug;
   GElf_Half e_type;            /* GElf_Ehdr.e_type cache.  */
-  Dwfl_Error elferr;           /* Previous failure to open main file.  */
+
+  GElf_Addr bias;              /* Actual load address - p_vaddr of main. */
+
+  struct dwfl_build_id *build_id; /* Build ID data are stored here
+                                    before we have main file. */
 
   struct dwfl_relocation *reloc_info; /* Relocatable sections.  */
 
-  struct dwfl_file *symfile;   /* Either main or debug.  */
-  Elf_Data *symdata;           /* Data in the ELF symbol table section.  */
-  size_t syments;              /* sh_size / sh_entsize of that section.  */
-  Elf_Data *symstrdata;                /* Data for its string table.  */
-  Elf_Data *symxndxdata;       /* Data in the extended section index table. */
-  Dwfl_Error symerr;           /* Previous failure to load symbols.  */
+  struct dwfl_file *symfile;   /* Points either to main or debug.  */
 
-  Dwarf *dw;                   /* libdw handle for its debugging info.  */
-  Dwfl_Error dwerr;            /* Previous failure to load info.  */
+  Dwfl_Error dwerr;            /* Previous failure to load debuginfo.  */
 
   /* Known CU's in this module.  */
   struct dwfl_cu *first_cu, **cu;
@@ -241,18 +263,21 @@ extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function;
 
 
 /* Process relocations in debugging sections in an ET_REL file.
-   FILE must be opened with ELF_C_READ_MMAP_PRIVATE or ELF_C_READ,
+   FILE->elf must be opened with ELF_C_READ_MMAP_PRIVATE or ELF_C_READ,
    to make it possible to relocate the data in place (or ELF_C_RDWR or
    ELF_C_RDWR_MMAP if you intend to modify the Elf file on disk).  After
    this, dwarf_begin_elf on FILE will read the relocated data.
 
    When DEBUG is false, apply partial relocation to all sections.  */
-extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *file, bool debug)
+extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod,
+                                     struct dwfl_shared_file *file,
+                                     bool debug)
   internal_function;
 
 /* Process (simple) relocations in arbitrary section TSCN of an ET_REL file.
    RELOCSCN is SHT_REL or SHT_RELA and TSCN is its sh_info target section.  */
-extern Dwfl_Error __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
+extern Dwfl_Error __libdwfl_relocate_section (Dwfl_Module *mod,
+                                             struct dwfl_shared_file *relocated,
                                              Elf_Scn *relocscn, Elf_Scn *tscn,
                                              bool partial)
   internal_function;
@@ -284,16 +309,25 @@ extern Dwfl_Error __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr,
 extern Dwfl_Error __libdwfl_cu_getsrclines (struct dwfl_cu *cu)
   internal_function;
 
-/* Look in ELF for an NT_GNU_BUILD_ID note.  If SET is true, store it
-   in MOD and return its length.  If SET is false, instead compare it
-   to that stored in MOD and return 2 if they match, 1 if they do not.
-   Returns -1 for errors, 0 if no note is found.  */
-extern int __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
+/* Look in ELF for an NT_GNU_BUILD_ID note.  If CHECK is NULL, store
+   it in MOD and return its length.  If CHECK is non-NULL, instead
+   compare it to build ID stored there and return 2 if they match, 1
+   if they do not.  Returns -1 for errors, 0 if no note is found.  */
+extern int __libdwfl_find_build_id (struct dwfl_build_id **build_idp,
+                                   GElf_Addr bias, bool set, Elf *elf)
+  internal_function;
+
+extern int __libdwfl_found_build_id (struct dwfl_build_id **build_idp, bool set,
+                                    const void *bits, int len, GElf_Addr vaddr)
   internal_function;
 
 /* Open a main or debuginfo file by its build ID, returns the fd.  */
-extern int __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug,
-                                      char **file_name) internal_function;
+extern bool __libdwfl_open_by_build_id (const Dwfl_Callbacks *const cb,
+                                       struct dwfl_file *file,
+                                       const struct dwfl_build_id *build_id,
+                                       GElf_Addr bias,
+                                       bool debug, char **file_name)
+  internal_function;
 
 extern uint32_t __libdwfl_crc32 (uint32_t crc, unsigned char *buf, size_t len)
   attribute_hidden;
@@ -362,6 +396,33 @@ extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
 /* Examine an ET_CORE file and report modules based on its contents.  */
 extern int dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const GElf_Ehdr *ehdr);
 
+/* Allocate dwfl_shared_file from path FILE_NAME.  When successful,
+   fills in TGT structure.  Caches previous lookups and will use the
+   same TGT->shared when the same file is asked for several times.
+
+   FD may be -1 to open FILE_NAME, or you can provide pre-opened FD.
+   In both cases FD is consumed, and FILE_NAME is used to initialize
+   TGT->name.
+
+   The case when FD is -1 and ELF is non-NULL is handled specially.
+   Such an ELF is considered to have no file backing, and is not
+   shared.
+
+   Optional parameter ELF is used to initialize TGT->shared->elf
+   member; if NULL is provided instead, new Elf file is allocated via
+   elf_begin.  In both cases ELF is consumed. */
+extern Dwfl_Error __libdwfl_open_file (struct dwfl_file *tgt,
+                                      const char *file_name,
+                                      int fd, Elf *elf)
+  internal_function;
+
+/* Close the file. */
+extern void __libdwfl_close_file (struct dwfl_file *file)
+  internal_function;
+
+extern Dwfl_Error __libdwfl_find_symtab (struct dwfl_shared_file *file)
+  internal_function;
+
 
 /* Avoid PLT entries.  */
 INTDECL (dwfl_begin)
@@ -408,6 +469,17 @@ INTDECL (dwfl_module_relocate_address)
 #define MODCB_ARGS(mod)        (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
 #define CBFAIL         (errno ? DWFL_E (ERRNO, errno) : DWFL_E_CB);
 
+/* The addresses in an ET_EXEC file are absolute.  The lowest p_vaddr
+   of the main file can differ from that of the debug file due to
+   prelink.  But that doesn't not change addresses that symbols,
+   debuginfo, or sh_addr of any program sections refer to.  */
+#define DWBIAS(mod)                                                    \
+  (((mod)->e_type == ET_EXEC) ? 0                                      \
+   : (mod)->bias - (mod)->main.shared->start + (mod)->debug.shared->start)
+#define SYMBIAS(mod) ((mod)->bias - (mod)->main.shared->start + (mod)->symfile->shared->start)
+
+#define BUILD_ID_NOT_FOUND ((void *) -1L)
+#define BUILD_ID_PTR(ptr) ((ptr) != NULL && (ptr) != BUILD_ID_NOT_FOUND)
 
 /* The default used by dwfl_standard_find_debuginfo.  */
 #define DEFAULT_DEBUGINFO_PATH ":.debug:/usr/lib/debug"
index e98903846591e9396a356556f3da042c8e895f98..81d8957c48471a52fa7ffbc2dfc14a619328d45c 100644 (file)
@@ -399,7 +399,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
             name will be the fallback when no build ID match is found.
             XXX hook for sysroot */
          if (name != NULL
-             && mod->main.elf == NULL
+             && mod->main.shared == NULL
              && mod->main.name == NULL)
            mod->main.name = strdup (name);
        }
@@ -448,7 +448,7 @@ consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
                     void *memory_callback_arg)
 {
   GElf_Ehdr ehdr;
-  if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
+  if (unlikely (gelf_getehdr (mod->main.shared->elf, &ehdr) == NULL))
     return 0;
 
   if (at_entry != 0)
@@ -478,7 +478,7 @@ consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
   for (uint_fast16_t i = 0; i < ehdr.e_phnum; ++i)
     {
       GElf_Phdr phdr_mem;
-      GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
+      GElf_Phdr *phdr = gelf_getphdr (mod->main.shared->elf, i, &phdr_mem);
       if (phdr == NULL)
        break;
 
@@ -517,11 +517,11 @@ consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
 
              /* If we're changing the module's address range,
                 we've just invalidated the module lookup table.  */
-             if (bias != mod->main.bias)
+             if (bias != mod->bias)
                {
-                 mod->low_addr -= mod->main.bias;
-                 mod->high_addr -= mod->main.bias;
-                 mod->main.bias = bias;
+                 mod->low_addr -= mod->bias;
+                 mod->high_addr -= mod->bias;
+                 mod->bias = bias;
                  mod->low_addr += bias;
                  mod->high_addr += bias;
 
@@ -533,11 +533,12 @@ consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
 
       if (phdr->p_type == PT_DYNAMIC)
        {
-         Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
+         Elf_Data *data = elf_getdata_rawchunk (mod->main.shared->elf,
+                                                phdr->p_offset,
                                                 phdr->p_filesz, ELF_T_DYN);
          if (data == NULL)
            continue;
-         const size_t entsize = gelf_fsize (mod->main.elf,
+         const size_t entsize = gelf_fsize (mod->main.shared->elf,
                                             ELF_T_DYN, 1, EV_CURRENT);
          const size_t n = data->d_size / entsize;
          for (size_t j = 0; j < n; ++j)
@@ -556,7 +557,7 @@ consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
   if (d_val_vaddr != 0)
     {
       /* Now we have the final address from which to read &r_debug.  */
-      d_val_vaddr += mod->main.bias;
+      d_val_vaddr += mod->bias;
 
       void *buffer = NULL;
       size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
@@ -613,7 +614,7 @@ find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
                 void *memory_callback_arg)
 {
   for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
-    if (mod->main.elf != NULL)
+    if (mod->main.shared != NULL)
       {
        GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
                                                       elfclass, elfdata,
@@ -763,7 +764,7 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
               presupplied ET_EXEC, then look for a presupplied module,
               which might be a PIE (ET_DYN) that needs its bias adjusted.  */
            r_debug_vaddr = ((phdr_mod == NULL
-                             || phdr_mod->main.elf == NULL
+                             || phdr_mod->main.shared == NULL
                              || phdr_mod->e_type != ET_EXEC)
                             ? find_executable (dwfl, phdr, entry,
                                                &elfclass, &elfdata,
index 5bbb384adeb920b1e265e5541d33805472ad0bca..ccc62c526842bfeec283d091f73d7751e13ad6cc 100644 (file)
@@ -593,7 +593,7 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod,
                            Dwarf_Addr base __attribute__ ((unused)),
                            char **file_name, Elf **elfp)
 {
-  if (mod->build_id_len > 0)
+  if (BUILD_ID_PTR (mod->build_id))
     {
       int fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0,
                                               file_name, elfp);
index b3a95dd991c9a3dce1a41a3b1a41f7c48ba99c42..578b8b753b3c5a60514546721088e3f03268333e 100644 (file)
@@ -70,7 +70,8 @@ dwfl_offline_section_address (Dwfl_Module *mod,
   assert (shdr->sh_addr == 0);
   assert (shdr->sh_flags & SHF_ALLOC);
 
-  if (mod->debug.elf == NULL)
+  if (mod->debug.shared == NULL
+      || mod->debug.shared->elf == NULL)
     /* We are only here because sh_addr is zero even though layout is complete.
        The first section in the first file under -e is placed at 0.  */
     return 0;
@@ -78,10 +79,11 @@ dwfl_offline_section_address (Dwfl_Module *mod,
   /* The section numbers might not match between the two files.
      The best we can rely on is the order of SHF_ALLOC sections.  */
 
-  Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
+  Elf *debug_elf = mod->debug.shared->elf;
+  Elf_Scn *ourscn = elf_getscn (debug_elf, shndx);
   Elf_Scn *scn = NULL;
   uint_fast32_t skip_alloc = 0;
-  while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
+  while ((scn = elf_nextscn (debug_elf, scn)) != ourscn)
     {
       assert (scn != NULL);
       GElf_Shdr shdr_mem;
@@ -93,7 +95,7 @@ dwfl_offline_section_address (Dwfl_Module *mod,
     }
 
   scn = NULL;
-  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+  while ((scn = elf_nextscn (mod->main.shared->elf, scn)) != NULL)
     {
       GElf_Shdr shdr_mem;
       GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
@@ -161,13 +163,6 @@ process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
           || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
          && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
        dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
-
-      /* Don't keep the file descriptor around.  */
-      if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
-       {
-         close (mod->main.fd);
-         mod->main.fd = -1;
-       }
     }
 
   return mod;
@@ -237,7 +232,7 @@ process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
        }
     }
 
-  /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
+  /* We let __libdwfl_report_elf cache the fd in mod->main->fd,
      though it's the same fd for all the members.
      On module teardown we will close it only on the last Elf reference.  */
   *mod = process_file (dwfl, name, member_name, fd, member, predicate);
index abacc0410a0e2237c8ee582465d1744ad127422d..78705b89e9134014ff80b9e802faa13c1016f6a9 100644 (file)
@@ -101,100 +101,6 @@ __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
 }
 
 
-/* Cache used by relocate_getsym.  */
-struct reloc_symtab_cache
-{
-  Elf *symelf;
-  Elf_Data *symdata;
-  Elf_Data *symxndxdata;
-  Elf_Data *symstrdata;
-  size_t symshstrndx;
-  size_t strtabndx;
-};
-#define RELOC_SYMTAB_CACHE(cache)      \
-  struct reloc_symtab_cache cache =    \
-    { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
-
-/* This is just doing dwfl_module_getsym, except that we must always use
-   the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
-static Dwfl_Error
-relocate_getsym (Dwfl_Module *mod,
-                Elf *relocated, struct reloc_symtab_cache *cache,
-                int symndx, GElf_Sym *sym, GElf_Word *shndx)
-{
-  if (cache->symdata == NULL)
-    {
-      if (mod->symfile == NULL || mod->symfile->elf != relocated)
-       {
-         /* We have to look up the symbol table in the file we are
-            relocating, if it has its own.  These reloc sections refer to
-            the symbol table in this file, and a symbol table in the main
-            file might not match.  However, some tools did produce ET_REL
-            .debug files with relocs but no symtab of their own.  */
-         Elf_Scn *scn = NULL;
-         while ((scn = elf_nextscn (relocated, scn)) != NULL)
-           {
-             GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
-             if (shdr != NULL)
-               switch (shdr->sh_type)
-                 {
-                 default:
-                   continue;
-                 case SHT_SYMTAB:
-                   cache->symelf = relocated;
-                   cache->symdata = elf_getdata (scn, NULL);
-                   cache->strtabndx = shdr->sh_link;
-                   if (unlikely (cache->symdata == NULL))
-                     return DWFL_E_LIBELF;
-                   break;
-                 case SHT_SYMTAB_SHNDX:
-                   cache->symxndxdata = elf_getdata (scn, NULL);
-                   if (unlikely (cache->symxndxdata == NULL))
-                     return DWFL_E_LIBELF;
-                   break;
-                 }
-             if (cache->symdata != NULL && cache->symxndxdata != NULL)
-               break;
-           }
-       }
-      if (cache->symdata == NULL)
-       {
-         /* We might not have looked for a symbol table file yet,
-            when coming from __libdwfl_relocate_section.  */
-         if (unlikely (mod->symfile == NULL)
-             && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
-           return dwfl_errno ();
-
-         /* The symbol table we have already cached is the one from
-            the file being relocated, so it's what we need.  Or else
-            this is an ET_REL .debug file with no .symtab of its own;
-            the symbols refer to the section indices in the main file.  */
-         cache->symelf = mod->symfile->elf;
-         cache->symdata = mod->symdata;
-         cache->symxndxdata = mod->symxndxdata;
-         cache->symstrdata = mod->symstrdata;
-       }
-    }
-
-  if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
-                                 symndx, sym, shndx) == NULL))
-    return DWFL_E_LIBELF;
-
-  if (sym->st_shndx != SHN_XINDEX)
-    *shndx = sym->st_shndx;
-
-  switch (*shndx)
-    {
-    case SHN_ABS:
-    case SHN_UNDEF:
-    case SHN_COMMON:
-      return DWFL_E_NOERROR;
-    }
-
-  return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
-                                  *shndx, &sym->st_value);
-}
-
 /* Handle an undefined symbol.  We really only support ET_REL for Linux
    kernel modules, and offline archives.  The behavior of the Linux module
    loader is very simple and easy to mimic.  It only matches magically
@@ -202,27 +108,16 @@ relocate_getsym (Dwfl_Module *mod,
    answer except when the module's symbols are undefined and would prevent
    it from being loaded.  */
 static Dwfl_Error
-resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
+resolve_symbol (Dwfl_Module *referer, struct dwfl_shared_file *symfile,
                GElf_Sym *sym, GElf_Word shndx)
 {
   /* First we need its name.  */
   if (sym->st_name != 0)
     {
-      if (symtab->symstrdata == NULL)
-       {
-         /* Cache the strtab for this symtab.  */
-         assert (referer->symfile == NULL
-                 || referer->symfile->elf != symtab->symelf);
-         symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
-                                                       symtab->strtabndx),
-                                           NULL);
-         if (unlikely (symtab->symstrdata == NULL))
-           return DWFL_E_LIBELF;
-       }
-      if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
+      if (unlikely (sym->st_name >= symfile->symstrdata->d_size))
        return DWFL_E_BADSTROFF;
 
-      const char *name = symtab->symstrdata->d_buf;
+      const char *name = symfile->symstrdata->d_buf;
       name += sym->st_name;
 
       for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
@@ -231,15 +126,21 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
            /* Get this module's symtab.
               If we got a fresh error reading the table, report it.
               If we just have no symbols in this module, no harm done.  */
-           if (m->symdata == NULL
-               && m->symerr == DWFL_E_NOERROR
-               && INTUSE(dwfl_module_getsymtab) (m) < 0
-               && m->symerr != DWFL_E_NO_SYMTAB)
-             return m->symerr;
+           if (m->symfile == NULL
+               && m->main.cberr == DWFL_E_NOERROR
+               && m->debug.cberr == DWFL_E_NOERROR
+               && INTUSE(dwfl_module_getsymtab) (m) < 0)
+             {
+               Dwfl_Error err = m->main.cberr ?: m->debug.cberr;
+               if (err != DWFL_E_NO_SYMTAB)
+                 return err;
+             }
 
-           for (size_t ndx = 1; ndx < m->syments; ++ndx)
+           struct dwfl_shared_file *m_shared = m->symfile->shared;
+           for (size_t ndx = 1; ndx < m_shared->syments; ++ndx)
              {
-               sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
+               sym = gelf_getsymshndx (m_shared->symdata,
+                                       m_shared->symxndxdata,
                                        ndx, sym, &shndx);
                if (unlikely (sym == NULL))
                  return DWFL_E_LIBELF;
@@ -253,9 +154,9 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
                  continue;
 
                /* Get this candidate symbol's name.  */
-               if (unlikely (sym->st_name >= m->symstrdata->d_size))
+               if (unlikely (sym->st_name >= m_shared->symstrdata->d_size))
                  return DWFL_E_BADSTROFF;
-               const char *n = m->symstrdata->d_buf;
+               const char *n = m_shared->symstrdata->d_buf;
                n += sym->st_name;
 
                /* Does the name match?  */
@@ -269,7 +170,7 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
                /* In an ET_REL file, the symbol table values are relative
                   to the section, not to the module's load base.  */
                size_t symshstrndx = SHN_UNDEF;
-               return __libdwfl_relocate_value (m, m->symfile->elf,
+               return __libdwfl_relocate_value (m, m_shared->elf,
                                                 &symshstrndx,
                                                 shndx, &sym->st_value);
              }
@@ -280,19 +181,21 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
 }
 
 static Dwfl_Error
-relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
-                 size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
+relocate_section (Dwfl_Module *mod,
+                 struct dwfl_shared_file *relocated,
+                 struct dwfl_shared_file *symfile,
+                 const GElf_Ehdr *ehdr, size_t shstrndx,
                  Elf_Scn *scn, GElf_Shdr *shdr,
                  Elf_Scn *tscn, bool debugscn, bool partial)
 {
   /* First, fetch the name of the section these relocations apply to.  */
   GElf_Shdr tshdr_mem;
   GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
-  const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
+  const char *tname = elf_strptr (relocated->elf, shstrndx, tshdr->sh_name);
   if (tname == NULL)
     return DWFL_E_LIBELF;
 
-  if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
+  if (debugscn && ! ebl_debugscn_p (mod->main.shared->ebl, tname))
     /* This relocation section is not for a debugging section.
        Nothing to do here.  */
     return DWFL_E_NOERROR;
@@ -308,7 +211,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
   {
     /* First see if this is a reloc we can handle.
        If we are skipping it, don't bother resolving the symbol.  */
-    Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
+    Elf_Type type = ebl_reloc_simple_type (mod->main.shared->ebl, rtype);
     if (unlikely (type == ELF_T_NUM))
       return DWFL_E_BADRELTYPE;
 
@@ -327,19 +230,38 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
       {
        GElf_Sym sym;
        GElf_Word shndx;
-       Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
-                                           symndx, &sym, &shndx);
-       if (unlikely (error != DWFL_E_NOERROR))
-         return error;
 
-       if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
+       if (unlikely (gelf_getsymshndx (symfile->symdata,
+                                       symfile->symxndxdata,
+                                       symndx, &sym, &shndx) == NULL))
+         return DWFL_E_LIBELF;
+
+       if (sym.st_shndx != SHN_XINDEX)
+         shndx = sym.st_shndx;
+
+       Dwfl_Error err = DWFL_E_NOERROR;
+       switch (shndx)
          {
-           /* Maybe we can figure it out anyway.  */
-           error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
-           if (error != DWFL_E_NOERROR)
-             return error;
+         case SHN_ABS:
+           break;
+         case SHN_UNDEF:
+         case SHN_COMMON:
+           {
+             /* Maybe we can figure it out anyway.  */
+             err = resolve_symbol (mod, symfile, &sym, shndx);
+             break;
+           }
+         default:
+           {
+             err = __libdwfl_relocate_value (mod, relocated->elf, &shstrndx,
+                                             shndx, &sym.st_value);
+             break;
+           }
          }
 
+       if (unlikely (err != DWFL_E_NOERROR))
+         return err;
+
        value = sym.st_value;
       }
 
@@ -401,7 +323,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
     else
       {
        /* Extract the original value and apply the reloc.  */
-       Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
+       Elf_Data *d = gelf_xlatetom (relocated->elf, &tmpdata, &rdata,
                                     ehdr->e_ident[EI_DATA]);
        if (d == NULL)
          return DWFL_E_LIBELF;
@@ -422,7 +344,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
     /* Now convert the relocated datum back to the target
        format.  This will write into rdata.d_buf, which
        points into the raw section data being relocated.  */
-    Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
+    Elf_Data *s = gelf_xlatetof (relocated->elf, &rdata, &tmpdata,
                                 ehdr->e_ident[EI_DATA]);
     if (s == NULL)
       return DWFL_E_LIBELF;
@@ -444,7 +366,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
     if (first_badreltype)
       {
        first_badreltype = false;
-       if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
+       if (ebl_get_elfmachine (mod->main.shared->ebl) == EM_NONE)
          /* This might be because ebl_openbackend failed to find
             any libebl_CPU.so library.  Diagnose that clearly.  */
          result = DWFL_E_UNKNOWN_MACHINE;
@@ -560,29 +482,50 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
   return result;
 }
 
+static Dwfl_Error
+find_relocation_symfile (Dwfl_Module *mod,
+                        struct dwfl_shared_file *relocated,
+                        struct dwfl_shared_file **symfile)
+{
+  Dwfl_Error err = __libdwfl_find_symtab (relocated);
+  if (err == DWFL_E_NOERROR)
+    *symfile = relocated;
+  else if (err == DWFL_E_NO_SYMTAB)
+    {
+      err = __libdwfl_find_symtab (mod->main.shared);
+      if (err == DWFL_E_NOERROR)
+       *symfile = relocated;
+    }
+
+  return err;
+}
+
 Dwfl_Error
 internal_function
-__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
+__libdwfl_relocate (Dwfl_Module *mod, struct dwfl_shared_file *debugfile,
+                   bool debug)
 {
   assert (mod->e_type == ET_REL);
 
   GElf_Ehdr ehdr_mem;
-  const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
+  const GElf_Ehdr *ehdr = gelf_getehdr (debugfile->elf, &ehdr_mem);
   if (ehdr == NULL)
     return DWFL_E_LIBELF;
 
   size_t d_shstrndx;
-  if (elf_getshstrndx (debugfile, &d_shstrndx) < 0)
+  if (elf_getshstrndx (debugfile->elf, &d_shstrndx) < 0)
     return DWFL_E_LIBELF;
 
-  RELOC_SYMTAB_CACHE (reloc_symtab);
+  struct dwfl_shared_file *symfile;
+  Dwfl_Error result = find_relocation_symfile (mod, debugfile, &symfile);
+  if (result != DWFL_E_NOERROR)
+    return result;
 
   /* Look at each section in the debuginfo file, and process the
      relocation sections for debugging sections.  */
-  Dwfl_Error result = DWFL_E_NOERROR;
   Elf_Scn *scn = NULL;
   while (result == DWFL_E_NOERROR
-        && (scn = elf_nextscn (debugfile, scn)) != NULL)
+        && (scn = elf_nextscn (debugfile->elf, scn)) != NULL)
     {
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
@@ -592,12 +535,13 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
        {
          /* It's a relocation section.  */
 
-         Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
+         Elf_Scn *tscn = elf_getscn (debugfile->elf, shdr->sh_info);
          if (unlikely (tscn == NULL))
            result = DWFL_E_LIBELF;
          else
-           result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
-                                      &reloc_symtab, scn, shdr, tscn,
+           result = relocate_section (mod, debugfile, symfile,
+                                      ehdr, d_shstrndx,
+                                      scn, shdr, tscn,
                                       debug, !debug);
        }
     }
@@ -607,22 +551,29 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
 
 Dwfl_Error
 internal_function
-__libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
+__libdwfl_relocate_section (Dwfl_Module *mod,
+                           struct dwfl_shared_file *relocated,
                            Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
 {
   GElf_Ehdr ehdr_mem;
   GElf_Shdr shdr_mem;
 
-  RELOC_SYMTAB_CACHE (reloc_symtab);
-
   size_t shstrndx;
-  if (elf_getshstrndx (relocated, &shstrndx) < 0)
+  if (elf_getshstrndx (relocated->elf, &shstrndx) < 0)
     return DWFL_E_LIBELF;
 
-  return (__libdwfl_module_getebl (mod)
-         ?: relocate_section (mod, relocated,
-                              gelf_getehdr (relocated, &ehdr_mem), shstrndx,
-                              &reloc_symtab,
-                              relocscn, gelf_getshdr (relocscn, &shdr_mem),
-                              tscn, false, partial));
+  Dwfl_Error error = __libdwfl_module_getebl (mod);
+  if (error != DWFL_E_NOERROR)
+    return error;
+
+  struct dwfl_shared_file *symfile;
+  Dwfl_Error result = find_relocation_symfile (mod, relocated, &symfile);
+  if (result != DWFL_E_NOERROR)
+    return result;
+
+  return relocate_section (mod, relocated, symfile,
+                          gelf_getehdr (relocated->elf, &ehdr_mem),
+                          shstrndx,
+                          relocscn, gelf_getshdr (relocscn, &shdr_mem),
+                          tscn, false, partial);
 }
index 61e4e0a29adb122eb27b7b74c5de59d1f8166742..648bcbf70c0d194501014ba1e630b3337b1540ca 100644 (file)
@@ -76,8 +76,7 @@ elf_getarhdr (elf)
     }
 
   /* Make sure we have read the archive header.  */
-  if (parent->state.ar.elf_ar_hdr.ar_name == NULL
-      && __libelf_next_arhdr_wrlock (parent) != 0)
+  if (parent->state.ar.elf_ar_hdr.ar_name == NULL)
     {
       rwlock_wrlock (parent->lock);
       int st = __libelf_next_arhdr_wrlock (parent);
index b1471c1b08a0fd9b9b38c038830db6704d1f757d..5d82e5945dded2a06efcd0f2601cad8ff9edaea6 100644 (file)
        * testfile47.bz2: New data file.
        * Makefile.am (TESTS, EXTRA_DIST): Add them.
 
+2008-04-29  Petr Machata  <pmachata@redhat.com>
+
+       * run-debuginfo.sh: New file.
+       * debuginfo.c: New file.
+       * Makefile.am (noinst_PROGRAMS, TESTS, EXTRA_DIST): Add them.
+       (debuginfo_LDADD): New variable.
+
 2008-03-31  Roland McGrath  <roland@redhat.com>
 
        * run-early-offscn.sh: New file.
 
        * run-addrname-test.sh: Add a new case.
 
+2008-03-13  Petr Machata  <pmachata@redhat.com>
+
+       * run-relocate.sh: New test.
+       * relocate.c: New file.
+
+2008-03-13  Petr Machata  <pmachata@redhat.com>
+
+       * sharing1.c: Test feeding bogus file to libdwfl.
+       * run-sharing1.sh: Adjust to above.
+
+2008-03-05  Petr Machata  <pmachata@redhat.com>
+
+       * sharing1.c: Adjust for changes in libdwfl.
+
 2008-02-22  Roland McGrath  <roland@redhat.com>
 
        * run-elflint-test.sh: Typo fix.
 
        * run-allregs.sh: Change expected output for powerpc spefscr.
 
+2007-12-10  Petr Machata  <pmachata@redhat.com>
+
+       * run-sharing1.sh: New file.
+       * sharing1.c: New file.
+       * Makefile.am (noinst_PROGRAMS, EXTRA_DIST, TESTS): Add it.
+
 2007-10-20  Roland McGrath  <roland@redhat.com>
 
        * run-dwfl-addr-sect.sh: Change expected output, no errors.
index b533521c5988fdbd6aa19e4cb5f43fb62306d083..c9d2bc47e6e17de65d00a457c3912b72bc5d781e 100644 (file)
@@ -60,7 +60,8 @@ noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  find-prologues funcretval allregs rdwrmmap \
                  dwfl-bug-addr-overflow arls dwfl-bug-fd-leak \
                  dwfl-addr-sect dwfl-bug-report early-offscn \
-                 dwfl-bug-getmodules
+                 dwfl-bug-getmodules \
+                 sharing1 relocate debuginfo
 # get-ciefde
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
            asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -86,6 +87,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        dwfl-bug-fd-leak dwfl-bug-report \
        run-dwfl-bug-offline-rel.sh run-dwfl-addr-sect.sh \
        run-disasm-x86.sh run-disasm-x86-64.sh \
+       sharing1 run-relocate.sh run-debuginfo.sh \
        run-early-offscn.sh
 # run-show-ciefde.sh
 
@@ -141,7 +143,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile44.S.bz2 testfile44.expect.bz2 run-disasm-x86.sh \
             testfile45.S.bz2 testfile45.expect.bz2 run-disasm-x86-64.sh \
             testfile46.bz2 testfile47.bz2 testfile48.bz2 testfile48.debug.bz2 \
-            testfile49.bz2
+            testfile49.bz2 run-relocate.sh
 
 installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \
                              bindir=$(DESTDIR)$(bindir) \
@@ -233,6 +235,9 @@ dwfl_bug_report_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 dwfl_bug_getmodules_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 dwfl_addr_sect_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 sha1_tst_LDADD = $(libeu) $(libmudflap)
+sharing1_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
+relocate_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
+debuginfo_LDADD = $(libdw) $(libebl) $(libelf) $(libmudflap) -ldl
 
 CLEANFILES = xxx *.gcno *.gcda *gconv
 
diff --git a/tests/debuginfo.c b/tests/debuginfo.c
new file mode 100644 (file)
index 0000000..cf621ac
--- /dev/null
@@ -0,0 +1,114 @@
+/* Copyright (C) 2008 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include ELFUTILS_HEADER(dwfl)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+static char *filename = NULL;
+static char *dfilename = NULL;
+bool was_there = false;
+
+static char *debuginfo_path = NULL;
+
+static void
+die (const char *message)
+{
+  fprintf (stderr, "%s\n", message);
+  exit (1);
+}
+
+int
+my_find_debuginfo (Dwfl_Module *mod,
+                  void **userdata,
+                  const char *modname,
+                  GElf_Addr base,
+                  const char *file_name,
+                  const char *debuglink_file,
+                  GElf_Word debuglink_crc,
+                  char **debuginfo_file_name)
+{
+  int ret = dwfl_standard_find_debuginfo (mod, userdata, modname, base,
+                                         file_name, debuglink_file,
+                                         debuglink_crc, debuginfo_file_name);
+
+  if (*debuginfo_file_name == NULL
+      || strcmp (*debuginfo_file_name, dfilename))
+    die ("Unexpected debuginfo found.");
+
+  was_there = true;
+  return ret;
+}
+
+static const Dwfl_Callbacks my_callbacks =
+{
+  .find_debuginfo = my_find_debuginfo,
+  .debuginfo_path = &debuginfo_path,
+};
+
+int
+main(int argc, char ** argv)
+{
+  if (argc != 3)
+    die ("Usage: debuginfo <binary> <matching debuginfo>\n");
+  filename = argv[1];
+  dfilename = argv[2];
+
+  Dwfl *dwfl = dwfl_begin (&my_callbacks);
+  if (dwfl == NULL)
+    die ("Couldn't create dwfl.");
+  dwfl_report_begin (dwfl);
+  Dwfl_Module *mod1 = dwfl_report_elf (dwfl, "mod1", filename, -1, 0);
+  if (mod1 == NULL)
+    die ("Couldn't create a module.");
+  dwfl_report_end (dwfl, NULL, NULL);
+
+  const unsigned char *bits;
+  GElf_Addr vaddr;
+  GElf_Addr bias;
+  dwfl_module_getelf (mod1, &bias);
+  int bytes = dwfl_module_build_id (mod1, &bits, &vaddr);
+  if (bytes != 20)
+    die ("Expected 20 bytes of debuginfo.");
+
+  Dwarf_Die *d = dwfl_module_nextcu (mod1, NULL, &bias);
+  if (!was_there)
+    die ("Suspicious: find_debuginfo hook not called.");
+  if (d == NULL)
+    die ("No dwarf die found in debuginfo.");
+
+  dwfl_end (dwfl);
+
+  return 0;
+}
diff --git a/tests/relocate.c b/tests/relocate.c
new file mode 100644 (file)
index 0000000..2669a7c
--- /dev/null
@@ -0,0 +1,109 @@
+/* Copyright (C) 2007,2008 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+   Written by Petr Machata <pmachata@redhat.com>, 2007.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include ELFUTILS_HEADER(dwfl)
+#include <unistd.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+
+static int my_find_elf (Dwfl_Module *, void **, const char *, Dwarf_Addr,
+                       char **, Elf **);
+
+static const Dwfl_Callbacks my_callbacks =
+{
+  .find_elf = my_find_elf,
+};
+
+static int
+my_find_elf (Dwfl_Module * mod __attribute__ ((unused)),
+            void ** userdata __attribute__ ((unused)),
+            const char * module_name __attribute__ ((unused)),
+            Dwarf_Addr addr __attribute__ ((unused)),
+            char ** file_name __attribute__ ((unused)),
+            Elf ** elf __attribute__ ((unused)))
+{
+  return 0;
+}
+
+int
+main(int argc, char ** argv)
+{
+  /* We use no threads here which can interfere with handling a stream.  */
+  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
+
+  /* Order is significant.  If in doubt, check that libdwfl's
+   * resolve_symbol still gets hit:
+   *  $ ftrace -sym=resolve_symbol ./relocate ~/testfile9
+   * should give you roughly:
+   *  14395.14395 attached /home/ant/elfutils-mtn/build/tests/relocate
+   *  14395.14395 call libdw.so.1->resolve_symbol(0x96e6758, 0x96e6800, 0xbfa4b474, 0x0, 0xbfa4b470, 0xbfa4b4ac) = 12
+   *  14395.14395 call libdw.so.1->resolve_symbol(0x96e6758, 0x96e6800, 0xbfa4b474, 0x0, 0xbfa4b470, 0xbfa4b4ac) = 12
+   *  14395.14395 call libdw.so.1->resolve_symbol(0x96e6758, 0x96e6800, 0xbfa4b474, 0x0, 0xbfa4b470, 0xbfa4b4ac) = 12
+   *  14395.14395 exited with status 0
+   *
+   * Granted this test is very fragile, and depends a lot on knowledge
+   * of libdwfl internals.
+   */
+  if (argc < 2)
+    exit(77);
+  char const *name = argv[1];
+  char const *name2 = argv[0];
+
+  Dwfl *dwfl = dwfl_begin (&my_callbacks);
+  dwfl_report_begin (dwfl);
+  Dwfl_Module *module = dwfl_report_offline (dwfl, name, name, -1);
+  if (module == NULL)
+    {
+      fprintf (stderr, "DWFL error 1: %s\n", dwfl_errmsg (dwfl_errno ()));
+      exit (1);
+    }
+  Dwfl_Module *module2 = dwfl_report_offline (dwfl, name2, name2, -1);
+  if (module2 == NULL)
+    {
+      fprintf (stderr, "DWFL error 2: %s\n", dwfl_errmsg (dwfl_errno ()));
+      exit (1);
+    }
+  if (dwfl_report_end (dwfl, NULL, NULL) != 0)
+    {
+      fprintf (stderr, "DWFL error 3: %s\n", dwfl_errmsg (dwfl_errno ()));
+      exit (1);
+    }
+  Dwarf_Addr base;
+  Elf * elf = dwfl_module_getelf (module, &base);
+  if (elf == NULL)
+    {
+      fprintf (stderr, "DWFL error 4: %s\n", dwfl_errmsg (dwfl_errno ()));
+      exit (1);
+    }
+
+  dwfl_end (dwfl);
+  exit(0);
+}
diff --git a/tests/run-debuginfo.sh b/tests/run-debuginfo.sh
new file mode 100755 (executable)
index 0000000..7a20791
--- /dev/null
@@ -0,0 +1,34 @@
+#! /bin/sh
+# Copyright (C) 2008 Red Hat, Inc.
+# This file is part of Red Hat elfutils.
+#
+# Red Hat elfutils is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# Red Hat elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Red Hat elfutils; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+#
+# Red Hat elfutils is an included package of the Open Invention Network.
+# An included package of the Open Invention Network is a package for which
+# Open Invention Network licensees cross-license their patents.  No patent
+# license is granted, either expressly or impliedly, by designation as an
+# included package.  Should you wish to participate in the Open Invention
+# Network licensing program, please visit www.openinventionnetwork.com
+# <http://www.openinventionnetwork.com>.
+
+. $srcdir/test-subr.sh
+
+files="testfile40 testfile40.debug"
+testfiles $files
+
+export LC_ALL=C
+testrun ./debuginfo $files
+
+exit 0
diff --git a/tests/run-relocate.sh b/tests/run-relocate.sh
new file mode 100755 (executable)
index 0000000..0929ed1
--- /dev/null
@@ -0,0 +1,34 @@
+#! /bin/sh
+# Copyright (C) 2008 Red Hat, Inc.
+# This file is part of Red Hat elfutils.
+#
+# Red Hat elfutils is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# Red Hat elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Red Hat elfutils; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+#
+# Red Hat elfutils is an included package of the Open Invention Network.
+# An included package of the Open Invention Network is a package for which
+# Open Invention Network licensees cross-license their patents.  No patent
+# license is granted, either expressly or impliedly, by designation as an
+# included package.  Should you wish to participate in the Open Invention
+# Network licensing program, please visit www.openinventionnetwork.com
+# <http://www.openinventionnetwork.com>.
+
+. $srcdir/test-subr.sh
+
+files=testfile9
+testfiles $files
+
+export LC_ALL=C
+testrun ./relocate $files
+
+exit 0
diff --git a/tests/sharing1.c b/tests/sharing1.c
new file mode 100644 (file)
index 0000000..7b03ce9
--- /dev/null
@@ -0,0 +1,178 @@
+/* Copyright (C) 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+   Written by Petr Machata <pmachata@redhat.com>, 2007.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include ELFUTILS_HEADER(dwflP)
+#include <unistd.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+static int bogus_find_elf (Dwfl_Module *, void **,
+                          const char *, Dwarf_Addr,
+                          char **, Elf **);
+
+static char *debuginfo_path;
+static const Dwfl_Callbacks proc_callbacks =
+{
+  .find_debuginfo = dwfl_standard_find_debuginfo,
+  .debuginfo_path = &debuginfo_path,
+
+  .find_elf = dwfl_linux_proc_find_elf,
+};
+
+static const Dwfl_Callbacks bogus_callbacks =
+{
+  .find_debuginfo = dwfl_standard_find_debuginfo,
+  .debuginfo_path = &debuginfo_path,
+
+  .find_elf = bogus_find_elf,
+};
+
+struct testdata
+{
+  Dwfl_Module *module;
+  char *name;
+  Elf *elf;
+};
+
+
+static int
+bogus_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
+               void **userdata __attribute__ ((unused)),
+               const char *modname __attribute__ ((unused)),
+               Dwarf_Addr base __attribute__ ((unused)),
+               char ** file_name __attribute__ ((unused)),
+               Elf ** elf __attribute__ ((unused)))
+{
+  char * fn = strdup (".");
+  *file_name = fn;
+  int fd = open(fn, O_RDONLY);
+  return fd;
+}
+
+int
+each_module (Dwfl_Module *module,
+            void **userdata __attribute__ ((unused)),
+            const char *name,
+            Dwarf_Addr base __attribute__ ((unused)),
+            void *arg)
+{
+  struct testdata *t = (struct testdata *)arg;
+
+  GElf_Addr bias;
+  Elf *elf = dwfl_module_getelf (module, &bias);
+
+  if (elf == NULL
+      || dwfl_module_getsymtab (module) <= 0)
+    return DWARF_CB_OK; /* Continue iteration until first ordinary
+                          mapping with symbol table is found. */
+  else
+    {
+      t->name = strdup (name);
+      t->elf = elf;
+      t->module = module;
+      return DWARF_CB_ABORT;
+    }
+}
+
+Dwfl *
+initdwfl (pid_t pid, struct testdata *t, Dwfl_Callbacks const *cb, bool check)
+{
+  Dwfl *dwfl = dwfl_begin (cb);
+  if (dwfl == NULL)
+    error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
+
+  int result = dwfl_linux_proc_report (dwfl, pid);
+  if (result < 0)
+    error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1));
+  else if (result > 0)
+    error (2, result, "dwfl_linux_proc_report");
+
+  if (dwfl_report_end (dwfl, NULL, NULL) != 0)
+    error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
+
+  t->module = NULL;
+  t->elf = NULL;
+  t->name = NULL;
+  dwfl_getmodules (dwfl, each_module, (void*)t, 0);
+  if (check && (t->elf == NULL || t->name == NULL || t->module == NULL))
+    error (2, 0, "couldn't init testdata.");
+
+  return dwfl;
+}
+
+int
+proc_test (void)
+{
+  struct testdata ta;
+  Dwfl *a = initdwfl (getpid(), &ta, &proc_callbacks, true);
+
+  struct testdata tb;
+  Dwfl *b = initdwfl (getpid(), &tb, &proc_callbacks, true);
+
+  if (ta.module == tb.module)
+    error (2, 0, "Strange.  Both dwfls contain the same module?");
+
+  if (strcmp (ta.name, tb.name))
+    error (2, 0, "ELF files from different files.");
+
+  if (ta.elf != tb.elf)
+    error (2, 0, "ELF files not shared.");
+
+  if (ta.module->symfile->shared->symdata != tb.module->symfile->shared->symdata)
+    error (2, 0, "Symdata not shared.");
+
+  dwfl_end (a);
+  dwfl_end (b);
+  return 0;
+}
+
+int
+bogus_test (void)
+{
+  struct testdata ta;
+  Dwfl *a = initdwfl (getpid(), &ta, &bogus_callbacks, false);
+  dwfl_end (a);
+  return 0;
+}
+
+int
+main (void)
+{
+  /* We use no threads here which can interfere with handling a stream.  */
+  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
+
+  return proc_test ()
+    | bogus_test ();
+}