summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRomain Geissler <romain.geissler@amadeus.com>2021-01-28 13:41:20 +0000
committerDave Watson <dade.watson@gmail.com>2021-02-17 09:13:55 -0800
commit3ad1017bdb3508cb0d4cce4d6e3dccd4ab71816e (patch)
tree7f5be2958886196d526d3a805c7bb33ef687f0ad
parent4ed2ac7c9ff3b2be0baed294d79cdbc481a53296 (diff)
downloadlibunwind-3ad1017bdb3508cb0d4cce4d6e3dccd4ab71816e.tar.gz
Fix elf get_load_offset when the binary was linked by lld, which defines read/executable program header offsets not always aligned on a page size.
For example, the same library, linked with ld.bfd will show these PT_LOAD mappings: LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x000000000002b3d0 0x000000000002b3d0 R 0x1000 LOAD 0x000000000002c000 0x000000000002c000 0x000000000002c000 0x000000000001b729 0x000000000001b729 R E 0x1000 LOAD 0x0000000000048000 0x0000000000048000 0x0000000000048000 0x000000000000fb17 0x000000000000fb17 R 0x1000 LOAD 0x0000000000057fb0 0x0000000000058fb0 0x0000000000058fb0 0x00000000000010b0 0x0000000000001508 RW 0x1000 while ld.lld, from the very same .o files, will link it like this: LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x000000000003b32c 0x000000000003b32c R 0x1000 LOAD 0x000000000003b330 0x000000000003c330 0x000000000003c330 0x000000000001b740 0x000000000001b740 R E 0x1000 LOAD 0x0000000000056a70 0x0000000000058a70 0x0000000000058a70 0x0000000000001050 0x0000000000001050 RW 0x1000 LOAD 0x0000000000057ac0 0x000000000005aac0 0x000000000005aac0 0x0000000000000060 0x00000000000004b3 RW 0x1000 Failure to identify the load_offset from iterating the program header lead to later being unable to find the correct proc_info for a given symbol.
-rw-r--r--src/elfxx.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/src/elfxx.c b/src/elfxx.c
index 2589a3d4..c6baa098 100644
--- a/src/elfxx.c
+++ b/src/elfxx.c
@@ -165,12 +165,17 @@ elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase,
Elf_W (Ehdr) *ehdr;
Elf_W (Phdr) *phdr;
int i;
+ // mapoff is obtained from mmap informations, so is always aligned on a page size.
+ // PT_LOAD program headers p_offset however is not guaranteed to be aligned on a
+ // page size, ld.lld generate libraries where this is not the case. So we must
+ // make sure we compare both values with the same alignment.
+ unsigned long pagesize_aligment_mask = ~(((unsigned long)getpagesize()) - 1UL);
ehdr = ei->image;
phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; ++i)
- if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff)
+ if (phdr[i].p_type == PT_LOAD && (phdr[i].p_offset & pagesize_aligment_mask) == mapoff)
{
offset = segbase - phdr[i].p_vaddr;
break;