summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2008-12-15 14:17:39 +0100
committerPetr Machata <pmachata@redhat.com>2008-12-15 14:17:39 +0100
commit19932ff89b678877a45c25cd7c555db255cacabb (patch)
treea539e43d1a5ad24a2a870695791484348f3f9da3
parent468fe4d81a3e92157f4c0446675487dc230b2ec6 (diff)
Dump com.redhat.elfutils.pmachata.sharing from monotone.upstream/pmachata/sharing
-rw-r--r--libdwfl/ChangeLog269
-rw-r--r--libdwfl/Makefile.am3
-rw-r--r--libdwfl/core-file.c3
-rw-r--r--libdwfl/cu.c22
-rw-r--r--libdwfl/derelocate.c33
-rw-r--r--libdwfl/dwfl_build_id_find_debuginfo.c33
-rw-r--r--libdwfl/dwfl_build_id_find_elf.c76
-rw-r--r--libdwfl/dwfl_file.c281
-rw-r--r--libdwfl/dwfl_lineinfo.c2
-rw-r--r--libdwfl/dwfl_module.c27
-rw-r--r--libdwfl/dwfl_module_addrsym.c4
-rw-r--r--libdwfl/dwfl_module_build_id.c90
-rw-r--r--libdwfl/dwfl_module_getdwarf.c687
-rw-r--r--libdwfl/dwfl_module_getsrc_file.c2
-rw-r--r--libdwfl/dwfl_module_getsym.c18
-rw-r--r--libdwfl/dwfl_module_info.c7
-rw-r--r--libdwfl/dwfl_module_register_names.c9
-rw-r--r--libdwfl/dwfl_module_report_build_id.c30
-rw-r--r--libdwfl/dwfl_module_return_value_location.c6
-rw-r--r--libdwfl/dwfl_nextcu.c6
-rw-r--r--libdwfl/dwfl_report_elf.c49
-rw-r--r--libdwfl/dwfl_segment_report_module.c10
-rw-r--r--libdwfl/dwfl_symtab.c370
-rw-r--r--libdwfl/find-debuginfo.c32
-rw-r--r--libdwfl/libdwflP.h130
-rw-r--r--libdwfl/link_map.c25
-rw-r--r--libdwfl/linux-kernel-modules.c2
-rw-r--r--libdwfl/offline.c19
-rw-r--r--libdwfl/relocate.c259
-rw-r--r--libelf/elf_getarhdr.c3
-rw-r--r--tests/ChangeLog27
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/debuginfo.c114
-rw-r--r--tests/relocate.c109
-rwxr-xr-xtests/run-debuginfo.sh34
-rwxr-xr-xtests/run-relocate.sh34
-rw-r--r--tests/sharing1.c178
37 files changed, 2079 insertions, 933 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 4f03855f..1b4a0463 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -125,11 +125,91 @@
* 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.
@@ -157,6 +237,84 @@
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
@@ -173,11 +331,122 @@
* 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
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index db14db2a..a7d6b2b1 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -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
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index bc881eb9..d34fe0ed 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -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. */
diff --git a/libdwfl/cu.c b/libdwfl/cu.c
index 8f01ea6b..fe6ef1a6 100644
--- a/libdwfl/cu.c
+++ b/libdwfl/cu.c
@@ -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;
diff --git a/libdwfl/derelocate.c b/libdwfl/derelocate.c
index 402bc06f..2e62f6af 100644
--- a/libdwfl/derelocate.c
+++ b/libdwfl/derelocate.c
@@ -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)
diff --git a/libdwfl/dwfl_build_id_find_debuginfo.c b/libdwfl/dwfl_build_id_find_debuginfo.c
index 97def072..e7096723 100644
--- a/libdwfl/dwfl_build_id_find_debuginfo.c
+++ b/libdwfl/dwfl_build_id_find_debuginfo.c
@@ -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)
diff --git a/libdwfl/dwfl_build_id_find_elf.c b/libdwfl/dwfl_build_id_find_elf.c
index 1a226dfd..381203d8 100644
--- a/libdwfl/dwfl_build_id_find_elf.c
+++ b/libdwfl/dwfl_build_id_find_elf.c
@@ -53,18 +53,44 @@
#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
index 00000000..c7927d02
--- /dev/null
+++ b/libdwfl/dwfl_file.c
@@ -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;
+ }
+}
diff --git a/libdwfl/dwfl_lineinfo.c b/libdwfl/dwfl_lineinfo.c
index 0d8a6887..86bae138 100644
--- a/libdwfl/dwfl_lineinfo.c
+++ b/libdwfl/dwfl_lineinfo.c
@@ -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)
diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
index d7e54138..908982a5 100644
--- a/libdwfl/dwfl_module.c
+++ b/libdwfl/dwfl_module.c
@@ -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);
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index 72280d11..6607b274 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -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);
diff --git a/libdwfl/dwfl_module_build_id.c b/libdwfl/dwfl_module_build_id.c
index 8725afbc..d02c89f2 100644
--- a/libdwfl/dwfl_module_build_id.c
+++ b/libdwfl/dwfl_module_build_id.c
@@ -49,34 +49,41 @@
#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)
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 652383be..d8313663 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -53,92 +53,76 @@
#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)
diff --git a/libdwfl/dwfl_module_getsrc_file.c b/libdwfl/dwfl_module_getsrc_file.c
index 9d0c786b..6b0dae6f 100644
--- a/libdwfl/dwfl_module_getsrc_file.c
+++ b/libdwfl/dwfl_module_getsrc_file.c
@@ -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)
diff --git a/libdwfl/dwfl_module_getsym.c b/libdwfl/dwfl_module_getsym.c
index 5f289ccb..f81f555f 100644
--- a/libdwfl/dwfl_module_getsym.c
+++ b/libdwfl/dwfl_module_getsym.c
@@ -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)
diff --git a/libdwfl/dwfl_module_info.c b/libdwfl/dwfl_module_info.c
index 759cb621..f2cf3848 100644
--- a/libdwfl/dwfl_module_info.c
+++ b/libdwfl/dwfl_module_info.c
@@ -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;
diff --git a/libdwfl/dwfl_module_register_names.c b/libdwfl/dwfl_module_register_names.c
index 79a874a8..b9a2d8f3 100644
--- a/libdwfl/dwfl_module_register_names.c
+++ b/libdwfl/dwfl_module_register_names.c
@@ -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))
{
diff --git a/libdwfl/dwfl_module_report_build_id.c b/libdwfl/dwfl_module_report_build_id.c
index 9a1b14f7..beec9f8b 100644
--- a/libdwfl/dwfl_module_report_build_id.c
+++ b/libdwfl/dwfl_module_report_build_id.c
@@ -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)
diff --git a/libdwfl/dwfl_module_return_value_location.c b/libdwfl/dwfl_module_return_value_location.c
index 3d5154e2..35612d6d 100644
--- a/libdwfl/dwfl_module_return_value_location.c
+++ b/libdwfl/dwfl_module_return_value_location.c
@@ -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)
diff --git a/libdwfl/dwfl_nextcu.c b/libdwfl/dwfl_nextcu.c
index 6db3e0f1..db7ec121 100644
--- a/libdwfl/dwfl_nextcu.c
+++ b/libdwfl/dwfl_nextcu.c
@@ -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);
diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c
index 0e5d09bc..9711ba7a 100644
--- a/libdwfl/dwfl_report_elf.c
+++ b/libdwfl/dwfl_report_elf.c
@@ -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;
}
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 50ed140e..53e59926 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -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
index 00000000..dd60eb3a
--- /dev/null
+++ b/libdwfl/dwfl_symtab.c
@@ -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;
+}
diff --git a/libdwfl/find-debuginfo.c b/libdwfl/find-debuginfo.c
index a01293e8..9f6f4c7f 100644
--- a/libdwfl/find-debuginfo.c
+++ b/libdwfl/find-debuginfo.c
@@ -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;
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 6ba5c96e..6cf32eca 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -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"
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index e9890384..81d8957c 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -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,
diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
index 5bbb384a..ccc62c52 100644
--- a/libdwfl/linux-kernel-modules.c
+++ b/libdwfl/linux-kernel-modules.c
@@ -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);
diff --git a/libdwfl/offline.c b/libdwfl/offline.c
index b3a95dd9..578b8b75 100644
--- a/libdwfl/offline.c
+++ b/libdwfl/offline.c
@@ -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);
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index abacc041..78705b89 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -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);
}
diff --git a/libelf/elf_getarhdr.c b/libelf/elf_getarhdr.c
index 61e4e0a2..648bcbf7 100644
--- a/libelf/elf_getarhdr.c
+++ b/libelf/elf_getarhdr.c
@@ -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);
diff --git a/tests/ChangeLog b/tests/ChangeLog
index b1471c1b..5d82e594 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -29,6 +29,13 @@
* 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.
@@ -40,6 +47,20 @@
* 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.
@@ -163,6 +184,12 @@
* 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.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b533521c..c9d2bc47 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -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
index 00000000..cf621ac7
--- /dev/null
+++ b/tests/debuginfo.c
@@ -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
index 00000000..2669a7c1
--- /dev/null
+++ b/tests/relocate.c
@@ -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
index 00000000..7a207911
--- /dev/null
+++ b/tests/run-debuginfo.sh
@@ -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
index 00000000..0929ed17
--- /dev/null
+++ b/tests/run-relocate.sh
@@ -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
index 00000000..7b03ce9b
--- /dev/null
+++ b/tests/sharing1.c
@@ -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 ();
+}