Fix missing load bias.
There are binaries that have non-executable LOAD with p_offset=0.
E.g.,
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0002a0 0x0002a0 R 0x8
INTERP 0x0002e0 0x00000000004002e0 0x00000000004002e0 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0059e0 0x0059e0 R 0x1000
LOAD 0x006000 0x0000000000406000 0x0000000000406000 0x10f2b05 0x10f2b05 R E 0x1000
LOAD 0x10f9000 0x00000000014f9000 0x00000000014f9000 0x70f634 0x70f634 R 0x1000
LOAD 0x1808f18 0x0000000001c09f18 0x0000000001c09f18 0x089fc8 0x0a7ab8 RW 0x1000
DYNAMIC 0x1864ce0 0x0000000001c65ce0 0x0000000001c65ce0 0x000240 0x000240 RW 0x8
NOTE 0x0002fc 0x00000000004002fc 0x00000000004002fc 0x000020 0x000020 R 0x4
TLS 0x1808f18 0x0000000001c09f18 0x0000000001c09f18 0x000010 0x000010 R 0x8
GNU_EH_FRAME 0x11abde8 0x00000000015abde8 0x00000000015abde8 0x14484c 0x14484c R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10
GNU_RELRO 0x1808f18 0x0000000001c09f18 0x0000000001c09f18 0x05c0e8 0x05c0e8 R 0x1
Test: host libunwindstack_test passes.
Test: Modified unit tests and new offline test.
Change-Id: I3992f712be238c7d4109556580b5dcc71175fe19
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index f0e4138..bdfee01 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -197,6 +197,7 @@
template <typename EhdrType, typename PhdrType>
void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
uint64_t offset = ehdr.e_phoff;
+ bool first_exec_load_header = true;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
@@ -212,9 +213,11 @@
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
static_cast<size_t>(phdr.p_memsz)};
- if (phdr.p_offset == 0) {
- *load_bias = phdr.p_vaddr;
+ // Only set the load bias from the first executable load header.
+ if (first_exec_load_header && phdr.p_vaddr > phdr.p_offset) {
+ *load_bias = phdr.p_vaddr - phdr.p_offset;
}
+ first_exec_load_header = false;
break;
}