+2010-11-12 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (struct Dwfl_Module): New member main_bias.
+ (dwfl_adjusted_address, dwfl_deadjust_address): Use it.
+ * dwfl_module_getdwarf.c (__libdwfl_getelf): Initialize it.
+
+ * libdwflP.h (dwfl_deadjust_address): New function.
+ (dwfl_deadjust_dwarf_addr, dwfl_deadjust_st_value): New functions.
+ * cu.c (addrarange): Use dwfl_deadjust_dwarf_addr.
+ * dwfl_module_addrsym.c: Use dwfl_deadjust_st_value.
+
+2010-11-11 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (struct dwfl_file): Remove bias member.
+ Add vaddr and address_sync members instead.
+ (dwfl_adjusted_address): Calculate using vaddr.
+ (dwfl_adjusted_dwarf_addr): Calculate using address_sync and call that.
+ (dwfl_adjusted_st_value): Use one of those calls.
+ * dwfl_module_getdwarf.c (open_elf): Initialize vaddr and address_sync.
+ * dwfl_segment_report_module.c (dwfl_segment_report_module): Likewise.
+ * derelocate.c (dwfl_module_relocations): Update ET_EXEC assertions.
+ * link_map.c (consider_executable): Adjust only MOD->low_addr for
+ detected PIE bias change.
+
+ * libdwflP.h (dwfl_adjusted_dwarf_addr): New function.
+ * dwfl_module_info.c: Use it.
+ * cu.c (addrarange): Likewise.
+ * dwfl_dwarf_line.c: Likewise.
+ * dwfl_module_dwarf_cfi.c: Likewise.
+ * dwfl_lineinfo.c: Likewise.
+ * dwfl_nextcu.c: Likewise.
+ * dwfl_module_getdwarf.c (dwfl_module_getdwarf): Likewise.
+
+ * libdwflP.h (dwfl_adjusted_st_value): New function.
+ * relocate.c (resolve_symbol): Use it.
+ * dwfl_module_getsym.c: Likewise.
+ * dwfl_module_addrsym.c: Likewise.
+ * dwfl_module_info.c: Likewise.
+
+ * libdwflP.h (dwfl_adjusted_address): New function.
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Use it.
+ * relocate.c (__libdwfl_relocate_value): Likewise.
+ * derelocate.c (cache_sections): Likewise.
+ (dwfl_module_address_section): Likewise.
+ * dwfl_module_getelf.c: Likewise.
+ * dwfl_module_eh_cfi.c: Likewise.
+ * link_map.c (consider_executable): Likewise.
+
2010-08-24 Roland McGrath <roland@redhat.com>
* dwfl_dwarf_line.c: New file.
}
/* The address must be inside the module to begin with. */
- addr -= mod->debug.bias;
+ addr = dwfl_deadjust_dwarf_addr (mod, addr);
/* The ranges are sorted by address, so we can use binary search. */
size_t l = 0, u = mod->naranges;
newref->scn = scn;
newref->relocs = NULL;
newref->name = name;
- newref->start = shdr->sh_addr + mod->main.bias;
+ newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
newref->end = newref->start + shdr->sh_size;
newref->next = refs;
refs = newref;
return 1;
case ET_EXEC:
- assert (mod->main.bias == 0);
- assert (mod->debug.bias == 0);
+ assert (mod->main.vaddr == mod->low_addr);
+ assert (mod->debug.address_sync == mod->main.address_sync);
break;
}
}
}
- *bias = mod->main.bias;
+ *bias = dwfl_adjusted_address (mod, 0);
return mod->reloc_info->refs[idx].scn;
}
INTDEF (dwfl_module_address_section)
struct dwfl_cu *cu = dwfl_linecu (line);
const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx];
- *bias = cu->mod->debug.bias;
+ *bias = dwfl_adjusted_dwarf_addr (cu->mod, 0);
return (Dwarf_Line *) info;
}
/* Get information from a source line record returned by libdwfl.
- Copyright (C) 2005, 2006 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
const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx];
if (addr != NULL)
- *addr = info->addr + cu->mod->debug.bias;
+ *addr = dwfl_adjusted_dwarf_addr (cu->mod, info->addr);
if (linep != NULL)
*linep = info->line;
if (colp != NULL)
/* Find debugging and symbol information for a module 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
/* Figure out what section ADDR lies in. */
if (addr_shndx == SHN_UNDEF)
{
- GElf_Addr mod_addr = addr - mod->symfile->bias;
+ GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
Elf_Scn *scn = NULL;
addr_shndx = SHN_ABS;
while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
phdr->p_offset,
phdr->p_filesz,
ELF_T_NHDR),
- phdr->p_vaddr + mod->main.bias);
+ dwfl_adjusted_address (mod, phdr->p_vaddr));
}
}
else
if (!(shdr->sh_flags & SHF_ALLOC))
vaddr = NO_VADDR;
else if (mod->e_type != ET_REL)
- vaddr = shdr->sh_addr + mod->main.bias;
+ vaddr = dwfl_adjusted_address (mod, shdr->sh_addr);
else if (__libdwfl_relocate_value (mod, elf, &shstrndx,
elf_ndxscn (scn), &vaddr))
vaddr = NO_VADDR;
/* Find DWARF CFI for a module in libdwfl.
- Copyright (C) 2009 Red Hat, Inc.
+ Copyright (C) 2009-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->dwarf_cfi != NULL)
{
- *bias = mod->debug.bias;
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
return mod->dwarf_cfi;
}
/* Find EH CFI for a module in libdwfl.
- Copyright (C) 2009 Red Hat, Inc.
+ Copyright (C) 2009-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->eh_cfi != NULL)
{
- *bias = mod->main.bias;
+ *bias = dwfl_adjusted_address (mod, 0);
return mod->eh_cfi;
}
return NULL;
}
- *bias = mod->main.bias;
+ *bias = dwfl_adjusted_address (mod, 0);
return __libdwfl_set_cfi (mod, &mod->eh_cfi,
INTUSE(dwarf_getcfi_elf) (mod->main.elf));
}
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)
+ if (mod->e_type != ET_REL)
{
size_t phnum;
if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0))
goto elf_error;
+ file->vaddr = file->address_sync = 0;
for (size_t i = 0; i < phnum; ++i)
{
GElf_Phdr ph_mem;
GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
- if (ph == NULL)
+ if (unlikely (ph == NULL))
goto elf_error;
if (ph->p_type == PT_LOAD)
{
- GElf_Addr align = mod->dwfl->segment_align;
- if (align <= 1)
- {
- if ((mod->low_addr & (ph->p_align - 1)) == 0)
- align = ph->p_align;
- else
- align = ((GElf_Addr) 1 << ffsll (mod->low_addr)) >> 1;
- }
-
- file->bias = ((mod->low_addr & -align) - (ph->p_vaddr & -align));
+ file->vaddr = ph->p_vaddr & -ph->p_align;
+ file->address_sync = ph->p_vaddr + ph->p_memsz;
break;
}
}
mod->e_type = ehdr->e_type;
/* Relocatable Linux kernels are ET_EXEC but act like ET_DYN. */
- if (mod->e_type == ET_EXEC && file->bias != 0)
+ if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr)
mod->e_type = ET_DYN;
return DWFL_E_NOERROR;
mod->main.fd = -1;
}
}
+
+ mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr;
}
/* Search an ELF file for a ".gnu_debuglink" section. */
{
case DWFL_E_NOERROR:
mod->debug.elf = mod->main.elf;
- mod->debug.bias = mod->main.bias;
+ mod->debug.address_sync = mod->main.address_sync;
return;
case DWFL_E_NO_DWARF:
(void) __libdwfl_relocate (mod, mod->debug.elf, false);
}
- *bias = mod->debug.bias;
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
return mod->dw;
}
/* Find debugging and symbol information for a module in libdwfl.
- Copyright (C) 2009 Red Hat, Inc.
+ Copyright (C) 2009-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
}
}
- *loadbase = mod->main.bias;
+ *loadbase = dwfl_adjusted_address (mod, 0);
return mod->main.elf;
}
/* 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
}
else if (alloc)
/* Apply the bias to the symbol value. */
- sym->st_value += mod->symfile->bias;
+ sym->st_value = dwfl_adjusted_st_value (mod, sym->st_value);
break;
}
/* Return information about a module.
- Copyright (C) 2005 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
*end = mod->high_addr;
if (dwbias)
- *dwbias = mod->debug.elf == NULL ? (Dwarf_Addr) -1 : mod->debug.bias;
+ *dwbias = (mod->debug.elf == NULL ? (Dwarf_Addr) -1
+ : dwfl_adjusted_dwarf_addr (mod, 0));
if (symbias)
- *symbias = mod->symfile == NULL ? (Dwarf_Addr) -1 : mod->symfile->bias;
+ *symbias = (mod->symfile == NULL ? (Dwarf_Addr) -1
+ : dwfl_adjusted_st_value (mod, 0));
if (mainfile)
*mainfile = mod->main.name;
/* Iterate through DWARF compilation units across all modules.
- Copyright (C) 2005 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 (cu != NULL)
{
- *bias = mod->debug.bias;
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
return &cu->die;
}
return NULL;
}
+ GElf_Addr vaddr = 0;
+ GElf_Addr address_sync = 0;
GElf_Addr start = 0, end = 0, bias = 0;
switch (ehdr->e_type)
{
goto elf_error;
if (ph->p_type == PT_LOAD)
{
+ vaddr = ph->p_vaddr & -ph->p_align;
+ address_sync = ph->p_vaddr + ph->p_memsz;
if ((base & (ph->p_align - 1)) != 0)
base = (base + ph->p_align - 1) & -ph->p_align;
start = base + (ph->p_vaddr & -ph->p_align);
break;
}
}
- bias = base;
+ bias = start - vaddr;
for (size_t i = phnum; i-- > 0;)
{
if (m->main.elf == NULL)
{
m->main.elf = elf;
- m->main.bias = bias;
+ m->main.vaddr = vaddr;
+ m->main.address_sync = address_sync;
+ m->main_bias = bias;
m->e_type = ehdr->e_type;
}
else
{
elf_end (elf);
- if (m->main.bias != base)
+ if (m->main_bias != bias
+ || m->main.vaddr != vaddr || m->main.address_sync != address_sync)
goto overlap;
}
}
/* Collect the unbiased bounds of the module here. */
GElf_Addr module_start = -1l;
GElf_Addr module_end = 0;
+ GElf_Addr module_address_sync = 0;
/* If we see PT_DYNAMIC, record it here. */
GElf_Addr dyn_vaddr = 0;
found_bias = true;
}
- vaddr &= -align;
- if (vaddr < module_start)
- module_start = vaddr;
+ if ((vaddr & -align) < module_start)
+ {
+ module_start = vaddr & -align;
+ module_address_sync = vaddr + memsz;
+ }
if (module_end < vaddr_end)
module_end = vaddr_end;
{
/* Install the file in the module. */
mod->main.elf = elf;
- mod->main.bias = bias;
+ mod->main.vaddr = module_start - bias;
+ mod->main.address_sync = module_address_sync;
}
return finish ();
bool relocated; /* Partial relocation of all sections done. */
Elf *elf;
- GElf_Addr bias; /* Actual load address - p_vaddr. */
+
+ /* This is the lowest p_vaddr in this ELF file, aligned to p_align.
+ For a file without phdrs, this is zero. */
+ GElf_Addr vaddr;
+
+ /* This is an address chosen for synchronization between the main file
+ and the debug file. In a file without phdrs, this is zero. In
+ other files it is the address at the end of the first PT_LOAD
+ segment. When prelink converts REL to RELA in an ET_DYN file, it
+ expands the space between the beginning of the segment and the
+ actual code/data addresses. Since that change wasn't made in the
+ debug file, the distance from p_vaddr to an address of interest (in
+ an st_value or DWARF data) now differs between the main and debug
+ files. The distance from address_sync to an address of interest
+ remains consistent. */
+ GElf_Addr address_sync;
};
struct Dwfl_Module
GElf_Addr low_addr, high_addr;
struct dwfl_file main, debug;
+ GElf_Addr main_bias;
Ebl *ebl;
GElf_Half e_type; /* GElf_Ehdr.e_type cache. */
Dwfl_Error elferr; /* Previous failure to open main file. */
}
#define dwfl_linecu dwfl_linecu_inline
+static inline GElf_Addr
+dwfl_adjusted_address (Dwfl_Module *mod, GElf_Addr addr)
+{
+ return addr + mod->main_bias;
+}
+
+static inline GElf_Addr
+dwfl_deadjust_address (Dwfl_Module *mod, GElf_Addr addr)
+{
+ return addr - mod->main_bias;
+}
+
+static inline Dwarf_Addr
+dwfl_adjusted_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr)
+{
+ return dwfl_adjusted_address (mod, (addr
+ - mod->debug.address_sync
+ + mod->main.address_sync));
+}
+
+static inline Dwarf_Addr
+dwfl_deadjust_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr)
+{
+ return (dwfl_deadjust_address (mod, addr)
+ - mod->main.address_sync
+ + mod->debug.address_sync);
+}
+
+static inline GElf_Addr
+dwfl_adjusted_st_value (Dwfl_Module *mod, GElf_Addr addr)
+{
+ if (mod->symfile == &mod->main)
+ return dwfl_adjusted_address (mod, addr);
+ return dwfl_adjusted_dwarf_addr (mod, addr);
+}
+
+static inline GElf_Addr
+dwfl_deadjust_st_value (Dwfl_Module *mod, GElf_Addr addr)
+{
+ if (mod->symfile == &mod->main)
+ return dwfl_deadjust_address (mod, addr);
+ return dwfl_deadjust_dwarf_addr (mod, addr);
+}
+
/* This describes a contiguous address range that lies in a single CU.
We condense runs of Dwarf_Arange entries for the same CU into this. */
struct dwfl_arange
/* If we're changing the module's address range,
we've just invalidated the module lookup table. */
- if (bias != mod->main.bias)
+ GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
+ 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->low_addr += bias;
mod->high_addr += bias;
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 = dwfl_adjusted_address (mod, d_val_vaddr);
void *buffer = NULL;
size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
if (refshdr->sh_flags & SHF_ALLOC)
/* Apply the adjustment. */
- *value += refshdr->sh_addr + mod->main.bias;
+ *value += dwfl_adjusted_address (mod, refshdr->sh_addr);
return DWFL_E_NOERROR;
}
if (m->e_type != ET_REL)
{
- sym->st_value += m->symfile->bias;
+ sym->st_value = dwfl_adjusted_st_value (m, sym->st_value);
return DWFL_E_NOERROR;
}