2010-06-29 Roland McGrath <roland@redhat.com>
+ * libdwP.h (dwarf_file_reloc): Remove resolve_symbol member,
+ add dwflmod member instead.
+ * relocate.h: Declare __libdwfl_relocate_setup and
+ __libdwfl_relocate_symbol.
+ * relocate.c (noresolve_symbol): Removed.
+ (__libdw_relocate_begin): Initialize dwflmod instead of resolve_symbol.
+ (__libdw_relocate_shndx): Removed, now in libdwfl.
+ (digest_relocs): Call __libdwfl_relocate_setup.
+ (__libdw_relocate_address): Call __libdwfl_relocate_symbol.
+
* dwarf_lineaddr.c: Add INTDEF.
* libdwP.h: Add INTDECL.
struct ebl *ebl;
- int (*resolve_symbol) (bool undef, Dwarf *dbg,
- GElf_Sym *sym, GElf_Word shndx)
- internal_function;
+ struct Dwfl_Module *dwflmod;
};
#include <stdlib.h>
-static int
-internal_function
-noresolve_symbol (bool undef,
- Dwarf *dbg __attribute__ ((unused)),
- GElf_Sym *sym __attribute__ ((unused)),
- GElf_Word shndx __attribute__ ((unused)))
-{
- __libdw_seterrno (undef ? DWARF_E_RELUNDEF : DWARF_E_RELOC);
- return -1;
-}
-
void
internal_function
__libdw_relocate_begin (Dwarf *dbg, Elf_Scn *relscn[IDX_last], bool incomplete)
dbg->relocate = libdw_typed_alloc (dbg, struct dwarf_file_reloc);
dbg->relocate->ebl = NULL;
- dbg->relocate->resolve_symbol = &noresolve_symbol;
+ dbg->relocate->dwflmod = NULL;
/* All we do to start with is cache the section pointers.
We'll do the rest on demand in digest_relocs, below. */
internal_function
__libdw_relocate_end (Dwarf *dbg)
{
- // XXX let dwfl preinstall, don't close here
ebl_closebackend (dbg->relocate->ebl);
}
\f
if (unlikely (gelf_getshdr (r->scn, &shdr) == NULL))
assert (!"impossible gelf_getshdr failure");
- /* XXX let dwfl supply defaults from main file for separate debug
- with relocs pointing to SHT_NOBITS symtab
- r->symdata = dbg->relocate->symdata;
- r->symstrdata = dbg->relocate->symstrdata;
- */
- {
- GElf_Shdr symshdr;
- Elf_Scn *const symscn = elf_getscn (r->scn->elf, shdr.sh_link);
- if (unlikely (gelf_getshdr (symscn, &symshdr) == NULL))
- return DWARF_E_RELBADSYM;
- if (symshdr.sh_type != SHT_NOBITS)
- {
- r->symdata = elf_getdata (symscn, NULL);
- if (unlikely (r->symdata == NULL))
- return DWARF_E_RELBADSYM;
- r->symstrdata = elf_getdata (elf_getscn (r->scn->elf, symshdr.sh_link),
- NULL);
- if (unlikely (r->symstrdata == NULL))
- return DWARF_E_RELBADSYM;
- }
- }
+ /* Look for the symtab section this reloc section refers to. */
+ GElf_Shdr symshdr;
+ Elf_Scn *const symscn = elf_getscn (r->scn->elf, shdr.sh_link);
+ if (likely (gelf_getshdr (symscn, &symshdr) != NULL)
+ && symshdr.sh_type != SHT_NOBITS)
+ {
+ r->symdata = elf_getdata (symscn, NULL);
+ r->symstrdata = elf_getdata (elf_getscn (r->scn->elf, symshdr.sh_link),
+ NULL);
+ }
+
+ /* Let libdwfl set up ebl and symtab pointers if it can. */
+ if (dbg->relocate->dwflmod != NULL)
+ __libdwfl_relocate_setup (dbg, r);
+
+ /* Fail if neither direct pointers nor libdwfl backup found a symtab. */
+ if (unlikely (r->symdata == NULL) || unlikely (r->symstrdata == NULL))
+ return DWARF_E_RELBADSYM;
if (dbg->relocate->ebl == NULL)
{
return result;
}
-int
-internal_function
-__libdw_relocate_shndx (Dwarf *dbg, GElf_Word shndx, GElf_Sxword addend,
- Dwarf_Addr *val)
-{
- GElf_Sym sym =
- {
- .st_shndx = shndx < SHN_LORESERVE ? shndx : SHN_XINDEX,
- .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
- };
- int result = (*dbg->relocate->resolve_symbol) (false, dbg, &sym, shndx);
- if (result == 0)
- *val = sym.st_value + addend;
- return result;
-}
-
int
internal_function
__libdw_relocate_address (Dwarf *dbg, int sec_index,
int result = __libdw_relocatable_getsym (dbg, sec_index, datum, width,
&symndx, &sym, &shndx, &addend);
if (result > 0 && symndx != STN_UNDEF)
- {
- result = (*dbg->relocate->resolve_symbol)
- (sym.st_shndx == SHN_UNDEF || sym.st_shndx == SHN_COMMON
- || GELF_ST_BIND (sym.st_info) > STB_WEAK,
- dbg, &sym, sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx);
- addend += sym.st_value;
- }
+ result = __libdwfl_relocate_symbol
+ (dbg->relocate->sectionrel[sec_index],
+ sym.st_shndx == SHN_UNDEF || sym.st_shndx == SHN_COMMON
+ || GELF_ST_BIND (sym.st_info) > STB_WEAK,
+ dbg, &sym, sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx, &addend);
if (result >= 0)
*val = addend;
return result;
Dwarf_Relocatable *endp,
Dwarf_Block *exprloc)
__nonnull_attribute__ (1, 4, 5, 6) internal_function;
+
+extern void __libdwfl_relocate_setup (Dwarf *dbg, struct dwarf_section_reloc *r)
+ __nonnull_attribute__ (1, 2) internal_function;
+
+extern int __libdwfl_relocate_symbol (struct dwarf_section_reloc *r, bool undef,
+ Dwarf *dbg, GElf_Sym *sym,
+ GElf_Word shndx, GElf_Sxword *addend)
+ __nonnull_attribute__ (1, 3, 4) internal_function;
2010-06-29 Roland McGrath <roland@redhat.com>
+ * derelocate.c (check_module): Don't call dwfl_module_getdwarf.
+
+ * dwfl_module_getdwarf.c (__libdwfl_relocate_setup): New function.
+ (load_dw): Set MOD->dw->relocate->dwflmod.
+ * dwfl_module.c (__libdwfl_module_free): Clear MOD->dw->relocate->ebl
+ if we set it.
+ * relocate.c (__libdw_relocate_shndx): New function.
+ (__libdwfl_relocate_symbol): New function.
+
+ * libdwflP.h (struct dwfl_file): Add member shstrndx.
+ * dwfl_module_getdwarf.c (open_elf): Set it.
+ * dwfl_report_elf.c (__libdwfl_report_elf): Likewise.
+ * derelocate.c (cache_sections): Use it.
+ * dwfl_module_getsym.c: Likewise.
+
* dwfl_lineinfo.c: Use dwarf_lineaddr.
* relocate.c (relocate_section): Remove PARTIAL flag argument.
struct secref *refs = NULL;
size_t nrefs = 0;
- size_t shstrndx;
- if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
- {
- elf_error:
- __libdwfl_seterrno (DWFL_E_LIBELF);
- return -1;
- }
-
bool check_reloc_sections = false;
Elf_Scn *scn = NULL;
while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr == NULL)
- goto elf_error;
+ {
+ elf_error:
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return -1;
+ }
if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
&& mod->e_type == ET_REL)
{
/* This section might not yet have been looked at. */
- if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
+ if (__libdwfl_relocate_value (mod, mod->main.elf, &mod->main.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 (mod->main.elf, mod->main.shstrndx,
shdr->sh_name);
if (unlikely (name == NULL))
goto elf_error;
}
}
- if (mod->dw == NULL)
- {
- Dwarf_Addr bias;
- if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
- {
- Dwfl_Error error = dwfl_errno ();
- if (error != DWFL_E_NO_DWARF)
- {
- __libdwfl_seterrno (error);
- return true;
- }
- }
- }
-
return false;
}
/* Maintenance of module list in libdwfl.
- Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
+ Copyright (C) 2005-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
}
if (mod->dw != NULL)
- INTUSE(dwarf_end) (mod->dw);
+ {
+ if (mod->dw->relocate != NULL)
+ {
+ if (mod->dw->relocate->ebl == mod->ebl)
+ mod->dw->relocate->ebl = NULL;
+ }
+
+ INTUSE(dwarf_end) (mod->dw);
+ }
if (mod->ebl != NULL)
ebl_closebackend (mod->ebl);
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
-#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */
+#include "../libdw/relocate.h"
/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
return DWFL_E (LIBELF, elf_errno ());
}
+ if (unlikely (elf_getshdrstrndx (file->elf, &file->shstrndx)))
+ file->shstrndx = SHN_UNDEF;
+
/* 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
if (mod->dw->relocate != NULL)
{
assert (mod->e_type == ET_REL);
- // mod->dw->relocate->dwflmod = mod;
+ mod->dw->relocate->dwflmod = mod;
}
/* Until we have iterated through all CU's, we might do lazy lookups. */
return DWFL_E_NOERROR;
}
+/* This is called from libdw/relocate.c when we need to digest relocs. */
+void
+internal_function
+__libdwfl_relocate_setup (Dwarf *dbg, struct dwarf_section_reloc *r)
+{
+ Dwfl_Module *const mod = dbg->relocate->dwflmod;
+
+ assert (mod->dw == dbg);
+
+ if (dbg->relocate->ebl == NULL)
+ {
+ (void) __libdwfl_module_getebl (mod);
+ dbg->relocate->ebl = mod->ebl;
+ }
+
+ if (r->symdata == NULL)
+ {
+ find_symtab (mod);
+ r->symdata = mod->symdata;
+ r->symstrdata = mod->symstrdata;
+ r->symxndxdata = mod->symxndxdata;
+ }
+}
+
/* Try to start up libdw on either the main file or the debuginfo file. */
static void
find_dw (Dwfl_Module *mod)
/* Find debugging and symbol information for a module in libdwfl.
- Copyright (C) 2006,2007,2009 Red Hat, Inc.
+ Copyright (C) 2006-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
{
/* 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,
+ &mod->symfile->shstrndx,
shndx, &sym->st_value);
if (unlikely (result != DWFL_E_NOERROR))
{
m->main.elf = elf;
m->main.bias = bias;
m->e_type = ehdr->e_type;
+ if (unlikely (elf_getshdrstrndx (elf, &m->main.shstrndx)))
+ m->main.shstrndx = SHN_UNDEF;
}
else
{
bool relocated; /* Partial relocation of all sections done. */
Elf *elf;
+ size_t shstrndx; /* Cache of elf_getshdrstrndx on elf. */
GElf_Addr bias; /* Actual load address - p_vaddr. */
};
<http://www.openinventionnetwork.com>. */
#include "libdwflP.h"
+#include "../libdw/relocate.h"
typedef uint8_t GElf_Byte;
relocscn, gelf_getshdr (relocscn, &shdr_mem),
tscn, false));
}
+
+int
+internal_function
+__libdw_relocate_shndx (Dwarf *dbg, GElf_Word shndx, GElf_Sxword addend,
+ Dwarf_Addr *val)
+{
+ Dwfl_Module *const mod = dbg->relocate->dwflmod;
+
+ if (unlikely (mod == NULL)
+ || unlikely (mod->dwfl->callbacks->section_address == NULL))
+ {
+ __libdw_seterrno (DWARF_E_RELOC);
+ return -1;
+ }
+
+ assert (mod->dw == dbg);
+ assert (dbg->elf == mod->debug.elf);
+
+ *val = addend;
+ switch (__libdwfl_relocate_value (mod, mod->debug.elf, &mod->debug.shstrndx,
+ shndx, val))
+ {
+ case DWFL_E_NOERROR:
+ return 0;
+
+ case DWFL_E_LIBELF:
+ __libdw_seterrno (DWARF_E_RELBADSYM);
+ break;
+
+ default:
+ __libdw_seterrno (DWARF_E_RELUNDEF);
+ break;
+ }
+
+ return -1;
+}
+
+int
+internal_function
+__libdwfl_relocate_symbol (struct dwarf_section_reloc *r, bool undef,
+ Dwarf *dbg, GElf_Sym *sym, GElf_Word shndx,
+ GElf_Sxword *addend)
+{
+ if (!undef)
+ {
+ if (likely (__libdw_relocate_shndx (dbg, shndx, sym->st_value,
+ &sym->st_value) == 0))
+ {
+ *addend += sym->st_value;
+ return 1;
+ }
+ }
+ else
+ {
+ Dwfl_Module *const mod = dbg->relocate->dwflmod;
+
+ if (unlikely (mod == NULL)
+ || unlikely (mod->dwfl->callbacks->section_address == NULL))
+ {
+ __libdw_seterrno (DWARF_E_RELOC);
+ return -1;
+ }
+
+ assert (mod->dw == dbg);
+ assert (dbg->elf == mod->debug.elf);
+
+ assert (r->symdata != NULL);
+ assert (r->symstrdata != NULL);
+
+ Elf *symelf = ((Elf_Data_Scn *) r->symdata)->s->elf;
+ assert (symelf == mod->debug.elf || symelf == mod->main.elf);
+ struct reloc_symtab_cache symtab =
+ {
+ .symelf = symelf,
+ .symdata = r->symdata,
+ .symstrdata = r->symstrdata,
+ .symxndxdata = r->symxndxdata,
+ .symshstrndx = (symelf == mod->main.elf ? mod->main.shstrndx
+ : mod->debug.shstrndx),
+ };
+
+ switch (resolve_symbol (mod, &symtab, sym, shndx))
+ {
+ case DWFL_E_NOERROR:
+ return 0;
+
+ case DWFL_E_LIBELF:
+ case DWFL_E_BADSTROFF:
+ __libdw_seterrno (DWARF_E_RELBADSYM);
+ break;
+
+ default:
+ __libdw_seterrno (DWARF_E_RELUNDEF);
+ break;
+ }
+ }
+
+ return -1;
+}