* linux-kernel-modules.c (check_module_notes): Use FTS_LOGICAL so
we accept symlinks.
+2008-04-30 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_module_getdwarf.c
+ (find_debuginfo): Use mod->debug.cberr to record failure.
+
2008-04-27 Roland McGrath <roland@redhat.com>
* linux-kernel-modules.c (report_kernel): Fix crash when
dwfl_report_elf fails.
+2008-04-22 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h: Move Module.ebl to dwfl_shared_file.
+ * dwfl_module_getdwarf.c: Adjust to change above. Module.main's
+ ebl is always used.
+ * dwfl_module_register_names.c: Likewise.
+ * dwfl_module_return_value_location.c: Likewise.
+ * relocate.c: Likewise.
+ * dwfl_module.c: Move ebl_closebackend...
+ * dwfl_file.c: ... here.
+
+2008-04-22 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h: Add dwerr to dwfl_shared_file. Module.dwerr was
+ retained to record errors in establishing shared debug file.
+ * dwfl_nextcu.c: Adjust to above change.
+ * dwfl_module_getdwarf.c: Likewise.
+ (find_dw): Now returns Dwfl_Error.
+
+2008-04-22 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h: Move Module.dw to struct dwfl_shared_file
+ * cu.c: Adjust to above change.
+ * derelocate.c: Likewise.
+ * dwfl_module_getdwarf.c: Likewise.
+ * dwfl_module_getsrc_file.c: Likewise.
+ * dwfl_nextcu.c: Likewise.
+ * dwfl_module.c: Move dwarf_ending of dw...
+ * dwfl_file.c: ... here.
+
+2008-04-17 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_file.c (__libdwfl_open_file): Handle synthetic
+ ELF (non-null ELF handle, but fd==-1). Key it with all zeroes.
+
+2008-04-16 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_build_id_find_elf.c (open_and_check): New function, opens a
+ file and checks its build ID.
+ (__libdwfl_open_by_build_id): Change prototype.
+ (dwfl_build_id_find_elf): Only call __libdwfl_open_by_build_id.
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Pass build_id
+ pointer instead of dwfl Module argument.
+ (dwfl_module_build_id): Adjust to above: pass NULL instead of true.
+ * libdwflP.h: Adjust to changes above.
+ * dwfl_build_id_find_debuginfo.c
+ (dwfl_build_id_find_debuginfo): Call __libdwfl_open_file_build_id
+ to open file and check build ID.
+ * dwfl_module_getdwarf.c (find_file): Only open file if callback
+ didn't open it via __libdwfl_open_file_build_id already.
+ (find_debuginfo): Likewise.
+
+2008-04-14 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_build_id_find_elf.c (dwfl_build_id_find_elf):
+ Cache build_id if it is found to be valid.
+
+2008-04-11 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_module_build_id.c (found_build_id): Renamed to
+ __libdwfl_found_build_id, exported.
+ Now allocates struct build_id on the heap.
+ * libdwflP.h: Export above.
+ (BUILD_ID_NOT_FOUND): New macro holds value of cached
+ build-id-not-found pointer.
+ (BUILD_ID_PTR): Predicate of validity of build ID pointer.
+ (struct dwfl_shared_file, struct Dwfl_Module): Make struct
+ dwfl_build_id heap-allocated.
+ * dwfl_module_build_id.c (dwfl_module_report_build_id): Call
+ __libdwfl_found_build_id instead of duplicating the work.
+ Adjust to above changes.
+ * dwfl_build_id_find_elf.c, dwfl_file.c, dwfl_module.c,
+ dwfl_module_getdwarf.c, find-debuginfo.c, linux-kernel-modules.c:
+ Adjust to above changes.
+
2008-04-05 Roland McGrath <roland@redhat.com>
* linux-proc-maps.c (proc_maps_report): Don't leak LAST_FILE.
prototype to avoid older compiler's complaint about reuse of the name.
(__libdwfl_canon_error): Likewise.
+2008-03-14 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h (Dwfl_Module.symerr): Delete field.
+ * dwfl_module_getdwarf.c: Adjust to above.
+ * relocate.c: Likewise.
+
+2008-03-14 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h (Dwfl_Module.elferr): Delete field.
+ (dwfl_file.cberr): New field.
+ * dwfl_module_getdwarf.c: Adjust to above.
+
+2008-03-13 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h (dwfl_shared_file.elferr): New field.
+ * dwfl_file.c: When reading of the Elf file failed, keep the cache
+ entry around to cache the failure.
+ * derelocate.c: Adjust to above.
+ * dwfl_module_getdwarf.c: Likewise.
+ * dwfl_module_info.c: Likewise.
+ * offline.c: Likewise.
+
+2008-03-07 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h
+ (struct dwfl_build_id): New structure.
+ (dwfl_shared_file.valid): Dropped.
+ (dwfl_shared_file.build_id): New field.
+ (Dwfl_Module.build_id_*): Dropped.
+ (Dwfl_Module.build_id): New field.
+ * dwfl_file.c
+ (__libdwfl_close_file): Always free filename. Also free build id.
+ * dwfl_module_report_build_id.c: Adjust to above.
+ * linux-kernel-modules.c: Likewise.
+ * dwfl_build_id_find_debuginfo.c: Drop validation.
+ * dwfl_build_id_find_elf.c: Adjust to above, drop validation.
+ * dwfl_module_build_id.c
+ (found_build_id): Take dwfl_build_id arg instead of Dwfl_Module.
+ (check_notes): Likewise.
+ (__libdwfl_find_build_id): Use appropriate build_id cache
+ Adjust the rest to above changes.
+ (dwfl_module_build_id): Likewise.
+ * find-debuginfo.c: Adjust to above.
+ (validate): Drop ELF backdooring for now.
+
+2008-03-07 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_file.c (__libdwfl_open_file): Call elf_cntl ELF_C_FDREAD if
+ possible, and consume fd right away.
+ * dwfl_module_getdwarf.c (load_dw): Remove ELF_C_FDREAD hack.
+ * offline.c (process_elf): Likewise.
+ * dwfl_report_elf.c (__libdwfl_report_elf): Return error instead
+ of asserting.
+
+2008-03-05 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h
+ (dwfl_shared_file): Renamed from dwfl_file.
+ (dwfl_file): New structure.
+ (DWBIAS, SYMBIAS): Adjust code to above change.
+ * delrelocate.c: Likewise.
+ * dwfl_build_id_find_debuginfo.c: Likewise.
+ * dwfl_build_id_find_elf.c: Likewise.
+ * dwfl_module.c: Likewise.
+ * dwfl_module_addrsym.c: Likewise.
+ * dwfl_module_build_id.c: Likewise.
+ * dwfl_module_getdwarf.c: Likewise.
+ * dwfl_module_getsym.c: Likewise.
+ * dwfl_module_info.c: Likewise.
+ * dwfl_module_report_build_id.c: Likewise.
+ * dwfl_report_elf.c: Likewise.
+ * dwfl_symtab.c: Likewise.
+ * find-debuginfo.c: Likewise.
+ * offline.c: Likewise.
+ * relocate.c: Likewise.
+ * dwfl_file.c: Likewise.
+ (__libdwfl_open_file): Consume passed-in Elf on cache hit.
+
2008-02-19 Roland McGrath <roland@redhat.com>
* relocate.c (relocate_section): Check for an unhandled relocation
* dwfl_build_id_find_elf.c (__libdwfl_open_by_build_id): Don't clear
incoming *FILE_NAME at the start.
+2008-01-23 Petr Machata <pmachata@redhat.com>
+
+ * relocate.c (find_relocation_symfile): New function.
+ (relocate_section): Take additional argument SYMFILE.
+ (__libdwfl_relocate, __libdwfl_relocate_section): Use above.
+
+2008-01-22 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_module_getdwarf.c (load_dw): Remove useless call to
+ find_symfile.
+
+2008-01-18 Petr Machata <pmachata@redhat.com>
+
+ * relocate.c:
+ (struct reloc_symtab_cache): Drop.
+ (#define RELOC_SYMTAB_CACHE): Drop.
+ (relocate_getsym): Drop most of the code, inline the rest.
+ (resolve_symbol): Drop loading of symstrdata, that's already done
+ in __libdwfl_find_symtab.
+ (relocate_section): Inlined the rest of relocate_getsym.
+ (__libdwfl_relocate): Take dwfl_file instead of Elf.
+ (__libdwfl_relocate_section): Likewise.
+ * derelocate.c: Adjust to above.
+ * dwfl_module_getdwarf.c: Likewise.
+ * libdwflP.h (__libdwfl_relocate): Adjust prototype.
+ (__libdwfl_relocate_section): Likewise.
+
+2008-01-18 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_symtab.c: New file.
+ (__libdwfl_find_symtab): New function.
+ * Makefile.am: Add dwfl_symtab.c to the build process.
+ * dwfl_module_getdwarf.c
+ (load_symtab, find_offsets, find_dynsym): Move to dwfl_symtab.c
+ * libdwflP.h (struct dwfl_file.is_symtab): New field.
+ (struct dwfl_file.symerr): Likekwise.
+
+2008-01-14 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_file.c (__libdwfl_open_file): close the file descriptor
+ when reusing the node, and even when it was passed in by the caller.
+ (__libdwfl_close_file): Unconditionally close fd and call elf_end.
+ * dwfl_module_build_id.c: Formatting change.
+ * dwfl_module_getdwarf.c
+ (find_file): Return Dwfl_Error instead of void; adjust to changes
+ in __libdwfl_open_file.
+ (find_symtab): Take advantage from find_file returning Dwfl_Error.
+ (__libdwfl_module_getebl, find_dw, dwfl_module_getelf): Likewise.
+
2008-01-08 Roland McGrath <roland@redhat.com>
* Makefile.am (euinclude): Variable removed.
(pkginclude_HEADERS): Set this instead of euinclude_HEADERS.
+2007-12-11 Petr Machata <pmachata@redhat.com>
+
+ * libdwflP.h
+ (struct dwfl_file.bias): Moved to struct Dwfl_Module.
+ (struct dwfl_file.align): New field.
+ (struct dwfl_file.start): New field.
+ (#define DWBIAS): New macro.
+ (#define SYMBIAS): New macro.
+ * cu.c: Use SYMBIAS/DWBIAS instead of main/debug->bias.
+ * derelocate.c: Likewise.
+ * dwfl_lineinfo.c: Likewise.
+ * dwfl_module_addrsym.c: Likewise.
+ * dwfl_module_build_id.c: Likewise.
+ * dwfl_module_getsym.c: Likewise.
+ * dwfl_module_info.c: Likewise.
+ * dwfl_nextcu.c: Likewise.
+ * dwfl_report_elf.c: Likewise.
+ * dwfl_module_getdwarf.c: Likewise.
+
+2007-12-10 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_file.c: Use likely/unlikely where possible.
+ * libdwflP.h (struct Dwfl_Module): Move symdata, syments,
+ symstrdata, symxndxdata, to struct dwfl_file.
+ * dwfl_module_getdwarf.c: Adjust to above changes.
+ (load_symtab): Drop the parameter `syments'.
+ (find_symtab): Use module->main or module->debug to initialize
+ module->symfile when possible.
+ * dwfl_module_getsym.c: Adjust to above changes.
+ * dwfl_report_elf.c: Likewise.
+ * relocate.c: Likewise.
+
+2007-12-05 Petr Machata <pmachata@redhat.com>
+
+ * dwfl_file.c: New file.
+ * Makefile.am (libdwfl_a_SOURCES): Add dwfl_file.c.
+ * libdwflP.h
+ (__libdwfl_open_file): New internal function.
+ (__libdwfl_close_file): New internal function.
+ * cu.c: Adjust to the above change.
+ * derelocate.c: Likewise.
+ * dwfl_build_id_find_debuginfo.c: Likewise.
+ * dwfl_build_id_find_elf.c: Likewise.
+ * dwfl_lineinfo.c: Likewise.
+ * dwfl_module.c: Likewise.
+ * dwfl_module_build_id.c: Likewise.
+ * dwfl_module_getdwarf.c: Likewise.
+ * dwfl_module_info.c: Likewise.
+ * dwfl_module_report_build_id.c: Likewise.
+ * dwfl_nextcu.c: Likewise.
+ * dwfl_report_elf.c: Likewise.
+ * find-debuginfo.c: Likewise.
+ * offline.c: Likewise.
+
+ * dwfl_module.c (free_file): Code moved to dwfl_file.c.
+ (__libdwfl_module_free): Call __libdwfl_release_file.
+ * dwfl_module_getdwarf.c (open_elf): Code moved to dwfl_file.c.
+ (find_file): Call __libdwfl_open_file.
+ (find_debuginfo): Likewise.
+ (find_dw): Call __libdwfl_retain_file instead of copying members.
+ * dwfl_report_elf.c (__libdwfl_report_elf): Call __libdwfl_open_file.
+
2007-10-23 Roland McGrath <roland@redhat.com>
* linux-kernel-modules.c (report_kernel_archive): Reorder the kernel
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
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. */
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];
}
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
}
/* 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;
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;
}
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. */
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);
{
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)
{
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;
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);
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);
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;
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;
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;
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)
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);
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)
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;
}
}
}
- 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)
if (mod->e_type != ET_REL)
{
- *addr -= mod->debug.bias;
+ *addr -= DWBIAS (mod);
return 0;
}
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;
}
}
- *bias = mod->main.bias;
+ *bias = mod->bias;
return mod->reloc_info->refs[idx].scn;
}
INTDEF (dwfl_module_address_section)
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)
#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. */
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);
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
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)
--- /dev/null
+/* 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;
+ }
+}
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)
{
}
-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)
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);
/* 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);
#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;
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)
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
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;
}
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)
#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. */
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;
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);
}
/* 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. */
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);
}
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)
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)
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)
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)
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)
}
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);
/* 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);
}
}
/* 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)
*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;
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)
}
}
- 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)
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))
{
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);
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)
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)
}
}
- 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)
if (cu != NULL)
{
- *bias = mod->debug.bias;
+ *bias = DWBIAS (mod);
return &cu->die;
}
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);
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;
}
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 ();
--- /dev/null
+/* 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;
+}
}
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);
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;
#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
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;
/* 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;
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;
/* 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)
#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"
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);
}
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)
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;
/* 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;
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)
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]);
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,
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,
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);
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;
/* 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;
}
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);
|| 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;
}
}
- /* 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);
}
-/* 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
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)
/* 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;
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? */
/* 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);
}
}
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;
{
/* 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;
{
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;
}
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;
/* 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;
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;
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);
{
/* 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);
}
}
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);
}
}
/* 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);
* testfile47.bz2: New data file.
* Makefile.am (TESTS, EXTRA_DIST): Add them.
+2008-04-29 Petr Machata <pmachata@redhat.com>
+
+ * run-debuginfo.sh: New file.
+ * debuginfo.c: New file.
+ * Makefile.am (noinst_PROGRAMS, TESTS, EXTRA_DIST): Add them.
+ (debuginfo_LDADD): New variable.
+
2008-03-31 Roland McGrath <roland@redhat.com>
* run-early-offscn.sh: New file.
* run-addrname-test.sh: Add a new case.
+2008-03-13 Petr Machata <pmachata@redhat.com>
+
+ * run-relocate.sh: New test.
+ * relocate.c: New file.
+
+2008-03-13 Petr Machata <pmachata@redhat.com>
+
+ * sharing1.c: Test feeding bogus file to libdwfl.
+ * run-sharing1.sh: Adjust to above.
+
+2008-03-05 Petr Machata <pmachata@redhat.com>
+
+ * sharing1.c: Adjust for changes in libdwfl.
+
2008-02-22 Roland McGrath <roland@redhat.com>
* run-elflint-test.sh: Typo fix.
* run-allregs.sh: Change expected output for powerpc spefscr.
+2007-12-10 Petr Machata <pmachata@redhat.com>
+
+ * run-sharing1.sh: New file.
+ * sharing1.c: New file.
+ * Makefile.am (noinst_PROGRAMS, EXTRA_DIST, TESTS): Add it.
+
2007-10-20 Roland McGrath <roland@redhat.com>
* run-dwfl-addr-sect.sh: Change expected output, no errors.
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
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
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) \
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+#! /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
--- /dev/null
+#! /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
--- /dev/null
+/* 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 ();
+}