summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2010-11-12 16:46:47 -0800
committerRoland McGrath <roland@redhat.com>2010-11-12 16:46:47 -0800
commit1743d7f010bead5e869d097e23ce840583913381 (patch)
tree31a98ee593aca90ff62b849bb3c3a580b1465d48
parent58af2001b92a8a8ee21a81b2845449ae8d038b7c (diff)
downloadelfutils-1743d7f010bead5e869d097e23ce840583913381.tar.gz
libdwfl: Revamp bias bookkeeping, account correctly for prelink REL->RELA segment inflation.
-rw-r--r--libdwfl/ChangeLog48
-rw-r--r--libdwfl/cu.c2
-rw-r--r--libdwfl/derelocate.c8
-rw-r--r--libdwfl/dwfl_dwarf_line.c2
-rw-r--r--libdwfl/dwfl_lineinfo.c4
-rw-r--r--libdwfl/dwfl_module_addrsym.c4
-rw-r--r--libdwfl/dwfl_module_build_id.c4
-rw-r--r--libdwfl/dwfl_module_dwarf_cfi.c4
-rw-r--r--libdwfl/dwfl_module_eh_cfi.c6
-rw-r--r--libdwfl/dwfl_module_getdwarf.c30
-rw-r--r--libdwfl/dwfl_module_getelf.c4
-rw-r--r--libdwfl/dwfl_module_getsym.c4
-rw-r--r--libdwfl/dwfl_module_info.c8
-rw-r--r--libdwfl/dwfl_nextcu.c4
-rw-r--r--libdwfl/dwfl_report_elf.c13
-rw-r--r--libdwfl/dwfl_segment_report_module.c12
-rw-r--r--libdwfl/libdwflP.h62
-rw-r--r--libdwfl/link_map.c10
-rw-r--r--libdwfl/relocate.c4
19 files changed, 172 insertions, 61 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index cc6dfb5b..dd4eb10c 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,51 @@
+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.
diff --git a/libdwfl/cu.c b/libdwfl/cu.c
index 5f73d2a3..515aff3b 100644
--- a/libdwfl/cu.c
+++ b/libdwfl/cu.c
@@ -106,7 +106,7 @@ addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
}
/* The address must be inside the module to begin with. */
- addr -= mod->debug.bias;
+ addr = 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;
diff --git a/libdwfl/derelocate.c b/libdwfl/derelocate.c
index 56ba25af..483b75eb 100644
--- a/libdwfl/derelocate.c
+++ b/libdwfl/derelocate.c
@@ -134,7 +134,7 @@ cache_sections (Dwfl_Module *mod)
newref->scn = scn;
newref->relocs = NULL;
newref->name = name;
- newref->start = shdr->sh_addr + mod->main.bias;
+ newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
newref->end = newref->start + shdr->sh_size;
newref->next = refs;
refs = newref;
@@ -239,8 +239,8 @@ dwfl_module_relocations (Dwfl_Module *mod)
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;
}
@@ -406,7 +406,7 @@ dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
}
}
- *bias = mod->main.bias;
+ *bias = dwfl_adjusted_address (mod, 0);
return mod->reloc_info->refs[idx].scn;
}
INTDEF (dwfl_module_address_section)
diff --git a/libdwfl/dwfl_dwarf_line.c b/libdwfl/dwfl_dwarf_line.c
index ee522db4..eb085e4a 100644
--- a/libdwfl/dwfl_dwarf_line.c
+++ b/libdwfl/dwfl_dwarf_line.c
@@ -59,6 +59,6 @@ dwfl_dwarf_line (Dwfl_Line *line, Dwarf_Addr *bias)
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;
}
diff --git a/libdwfl/dwfl_lineinfo.c b/libdwfl/dwfl_lineinfo.c
index 0d8a6887..6049de84 100644
--- a/libdwfl/dwfl_lineinfo.c
+++ b/libdwfl/dwfl_lineinfo.c
@@ -1,5 +1,5 @@
/* 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
@@ -61,7 +61,7 @@ dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr, int *linep, int *colp,
const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx];
if (addr != NULL)
- *addr = info->addr + cu->mod->debug.bias;
+ *addr = dwfl_adjusted_dwarf_addr (cu->mod, info->addr);
if (linep != NULL)
*linep = info->line;
if (colp != NULL)
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index 72280d11..a9f98f44 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -1,5 +1,5 @@
/* 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
@@ -71,7 +71,7 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
/* Figure out what section ADDR lies in. */
if (addr_shndx == SHN_UNDEF)
{
- GElf_Addr mod_addr = addr - mod->symfile->bias;
+ GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
Elf_Scn *scn = NULL;
addr_shndx = SHN_ABS;
while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
diff --git a/libdwfl/dwfl_module_build_id.c b/libdwfl/dwfl_module_build_id.c
index 9dc7f678..f9888660 100644
--- a/libdwfl/dwfl_module_build_id.c
+++ b/libdwfl/dwfl_module_build_id.c
@@ -124,7 +124,7 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
phdr->p_offset,
phdr->p_filesz,
ELF_T_NHDR),
- phdr->p_vaddr + mod->main.bias);
+ dwfl_adjusted_address (mod, phdr->p_vaddr));
}
}
else
@@ -139,7 +139,7 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
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;
diff --git a/libdwfl/dwfl_module_dwarf_cfi.c b/libdwfl/dwfl_module_dwarf_cfi.c
index e851a1f4..96e60fbf 100644
--- a/libdwfl/dwfl_module_dwarf_cfi.c
+++ b/libdwfl/dwfl_module_dwarf_cfi.c
@@ -1,5 +1,5 @@
/* 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
@@ -81,7 +81,7 @@ dwfl_module_dwarf_cfi (mod, bias)
if (mod->dwarf_cfi != NULL)
{
- *bias = mod->debug.bias;
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
return mod->dwarf_cfi;
}
diff --git a/libdwfl/dwfl_module_eh_cfi.c b/libdwfl/dwfl_module_eh_cfi.c
index 36a495f1..79c8279c 100644
--- a/libdwfl/dwfl_module_eh_cfi.c
+++ b/libdwfl/dwfl_module_eh_cfi.c
@@ -1,5 +1,5 @@
/* 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
@@ -60,7 +60,7 @@ dwfl_module_eh_cfi (mod, bias)
if (mod->eh_cfi != NULL)
{
- *bias = mod->main.bias;
+ *bias = dwfl_adjusted_address (mod, 0);
return mod->eh_cfi;
}
@@ -71,7 +71,7 @@ dwfl_module_eh_cfi (mod, bias)
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));
}
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 41ed0730..d89081b7 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -93,35 +93,23 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
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;
}
}
@@ -130,7 +118,7 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
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;
@@ -198,6 +186,8 @@ __libdwfl_getelf (Dwfl_Module *mod)
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. */
@@ -733,7 +723,7 @@ find_dw (Dwfl_Module *mod)
{
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:
@@ -782,7 +772,7 @@ dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
(void) __libdwfl_relocate (mod, mod->debug.elf, false);
}
- *bias = mod->debug.bias;
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
return mod->dw;
}
diff --git a/libdwfl/dwfl_module_getelf.c b/libdwfl/dwfl_module_getelf.c
index 6414a9d3..b4e4a2b7 100644
--- a/libdwfl/dwfl_module_getelf.c
+++ b/libdwfl/dwfl_module_getelf.c
@@ -1,5 +1,5 @@
/* 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
@@ -78,7 +78,7 @@ dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase)
}
}
- *loadbase = mod->main.bias;
+ *loadbase = dwfl_adjusted_address (mod, 0);
return mod->main.elf;
}
diff --git a/libdwfl/dwfl_module_getsym.c b/libdwfl/dwfl_module_getsym.c
index f78e6ec0..6bc063bb 100644
--- a/libdwfl/dwfl_module_getsym.c
+++ b/libdwfl/dwfl_module_getsym.c
@@ -1,5 +1,5 @@
/* 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
@@ -114,7 +114,7 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
}
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;
}
diff --git a/libdwfl/dwfl_module_info.c b/libdwfl/dwfl_module_info.c
index 759cb621..bfde6fc1 100644
--- a/libdwfl/dwfl_module_info.c
+++ b/libdwfl/dwfl_module_info.c
@@ -1,5 +1,5 @@
/* 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
@@ -66,9 +66,11 @@ dwfl_module_info (Dwfl_Module *mod, void ***userdata,
*end = mod->high_addr;
if (dwbias)
- *dwbias = mod->debug.elf == NULL ? (Dwarf_Addr) -1 : mod->debug.bias;
+ *dwbias = (mod->debug.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;
diff --git a/libdwfl/dwfl_nextcu.c b/libdwfl/dwfl_nextcu.c
index 6db3e0f1..90862d20 100644
--- a/libdwfl/dwfl_nextcu.c
+++ b/libdwfl/dwfl_nextcu.c
@@ -1,5 +1,5 @@
/* 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
@@ -75,7 +75,7 @@ dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias)
if (cu != NULL)
{
- *bias = mod->debug.bias;
+ *bias = dwfl_adjusted_dwarf_addr (mod, 0);
return &cu->die;
}
diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c
index 062a647f..4c4132b1 100644
--- a/libdwfl/dwfl_report_elf.c
+++ b/libdwfl/dwfl_report_elf.c
@@ -72,6 +72,8 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
return NULL;
}
+ GElf_Addr vaddr = 0;
+ GElf_Addr address_sync = 0;
GElf_Addr start = 0, end = 0, bias = 0;
switch (ehdr->e_type)
{
@@ -198,13 +200,15 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
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;)
{
@@ -248,13 +252,16 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
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;
}
}
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 3f77cfc7..012a0fde 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -270,6 +270,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
/* 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;
@@ -400,9 +401,11 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
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;
@@ -662,7 +665,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
{
/* 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 ();
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index e4c7e7c8..1003b2d3 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -140,7 +140,22 @@ struct dwfl_file
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
@@ -154,6 +169,7 @@ 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. */
@@ -236,6 +252,50 @@ dwfl_linecu_inline (const Dwfl_Line *line)
}
#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
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 8ec06269..05839b3a 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -515,11 +515,11 @@ consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
/* If we're changing the module's address range,
we've just invalidated the module lookup table. */
- if (bias != mod->main.bias)
+ 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;
@@ -554,7 +554,7 @@ consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
if (d_val_vaddr != 0)
{
/* Now we have the final address from which to read &r_debug. */
- d_val_vaddr += mod->main.bias;
+ d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
void *buffer = NULL;
size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index 0075c7f9..95206f47 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -99,7 +99,7 @@ __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
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;
}
@@ -275,7 +275,7 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
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;
}