Elf_Scn * dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address, Dwarf_Addr *bias) { if (check_module (mod)) return NULL; int idx = find_section (mod, address); if (idx < 0) return NULL; if (mod->reloc_info->refs[idx].relocs != NULL) { assert (mod->e_type == ET_REL); 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, relocscn, tscn, true); if (likely (result == DWFL_E_NOERROR)) mod->reloc_info->refs[idx].relocs = NULL; else { __libdwfl_seterrno (result); return NULL; } } *bias = dwfl_adjusted_address (mod, 0); return mod->reloc_info->refs[idx].scn; }
Dwarf_CFI * dwfl_module_eh_cfi (Dwfl_Module *mod, Dwarf_Addr *bias) { if (mod == NULL) return NULL; if (mod->eh_cfi != NULL) { *bias = dwfl_adjusted_address (mod, 0); return mod->eh_cfi; } __libdwfl_getelf (mod); if (mod->elferr != DWFL_E_NOERROR) { __libdwfl_seterrno (mod->elferr); return NULL; } *bias = dwfl_adjusted_address (mod, 0); return __libdwfl_set_cfi (mod, &mod->eh_cfi, INTUSE(dwarf_getcfi_elf) (mod->main.elf)); }
Dwfl_Error internal_function __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx, Elf32_Word shndx, GElf_Addr *value) { assert (mod->e_type == ET_REL); Elf_Scn *refscn = elf_getscn (elf, shndx); GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem); if (refshdr == NULL) return DWFL_E_LIBELF; if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC)) { /* This is a loaded section. Find its actual address and update the section header. */ if (*shstrndx == SHN_UNDEF && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0)) return DWFL_E_LIBELF; const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name); if (unlikely (name == NULL)) return DWFL_E_LIBELF; if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod), name, shndx, refshdr, &refshdr->sh_addr)) return CBFAIL; if (refshdr->sh_addr == (Dwarf_Addr) -1l) /* The callback indicated this section wasn't really loaded but we don't really care. */ refshdr->sh_addr = 0; /* Make no adjustment below. */ /* Update the in-core file's section header to show the final load address (or unloadedness). This serves as a cache, so we won't get here again for the same section. */ if (likely (refshdr->sh_addr != 0) && unlikely (! gelf_update_shdr (refscn, refshdr))) return DWFL_E_LIBELF; } if (refshdr->sh_flags & SHF_ALLOC) /* Apply the adjustment. */ *value += dwfl_adjusted_address (mod, refshdr->sh_addr); return DWFL_E_NOERROR; }
Elf * dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase) { if (mod == NULL) return NULL; __libdwfl_getelf (mod); if (mod->elferr == DWFL_E_NOERROR) { if (mod->e_type == ET_REL && ! mod->main.relocated) { /* Before letting them get at the Elf handle, apply all the relocations we know how to. */ mod->main.relocated = true; if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR)) { (void) __libdwfl_relocate (mod, mod->main.elf, false); if (mod->debug.elf == mod->main.elf) mod->debug.relocated = true; else if (mod->debug.elf != NULL && ! mod->debug.relocated) { mod->debug.relocated = true; (void) __libdwfl_relocate (mod, mod->debug.elf, false); } } } *loadbase = dwfl_adjusted_address (mod, 0); return mod->main.elf; } __libdwfl_seterrno (mod->elferr); return NULL; }
static int cache_sections (Dwfl_Module *mod) { 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; 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, elf_ndxscn (scn), &shdr->sh_addr) != DWFL_E_NOERROR) continue; shdr = gelf_getshdr (scn, &shdr_mem); if (unlikely (shdr == NULL)) goto elf_error; } if (shdr->sh_flags & SHF_ALLOC) { const char *name = elf_strptr (mod->main.elf, shstrndx, shdr->sh_name); if (unlikely (name == NULL)) goto elf_error; struct secref *newref = alloca (sizeof *newref); newref->scn = scn; newref->relocs = NULL; newref->name = name; newref->start = dwfl_adjusted_address (mod, shdr->sh_addr); newref->end = newref->start + shdr->sh_size; newref->next = refs; refs = newref; ++nrefs; } if (mod->e_type == ET_REL && shdr->sh_size != 0 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) && mod->dwfl->callbacks->section_address != NULL) { 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); if (likely (tscn != NULL)) for (struct secref *sec = refs; sec != NULL; sec = sec->next) if (sec->scn == tscn) { sec->relocs = scn; break; } } else /* We'll have to do a second pass. */ check_reloc_sections = true; } } mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs])); if (mod->reloc_info == NULL) { __libdwfl_seterrno (DWFL_E_NOMEM); return -1; } struct secref **sortrefs = alloca (nrefs * sizeof sortrefs[0]); for (size_t i = nrefs; i-- > 0; refs = refs->next) sortrefs[i] = refs; assert (refs == NULL); qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs); mod->reloc_info->count = nrefs; for (size_t i = 0; i < nrefs; ++i) { mod->reloc_info->refs[i].name = sortrefs[i]->name; mod->reloc_info->refs[i].scn = sortrefs[i]->scn; mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs; mod->reloc_info->refs[i].start = sortrefs[i]->start; mod->reloc_info->refs[i].end = sortrefs[i]->end; } if (unlikely (check_reloc_sections)) { /* There was a reloc section that preceded its target section. So we have to scan again now that we have cached all the possible target sections we care about. */ 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; 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); if (likely (tscn != NULL)) for (size_t i = 0; i < nrefs; ++i) if (mod->reloc_info->refs[i].scn == tscn) { mod->reloc_info->refs[i].relocs = scn; break; } } } } return nrefs; }