Merge "Fix static GetLoadBias function." am: 45b570530b
am: 009a10dbe4
Change-Id: I58b28ed18ed9be5ca1ca5d4e1ee538754f8ae2d3
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index bdfee01..be1f092 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -187,8 +187,13 @@
if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
return 0;
}
- if (phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
- return phdr.p_vaddr;
+
+ // Find the first executable load when looking for the load bias.
+ if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
+ if (phdr.p_vaddr > phdr.p_offset) {
+ return phdr.p_vaddr - phdr.p_offset;
+ }
+ break;
}
}
return 0;
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index f9ee9eb..5b2036b 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -131,6 +131,12 @@
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void BuildIDSectionTooSmallForHeader();
+ template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+ void CheckLoadBiasInFirstPhdr(uint64_t load_bias);
+
+ template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+ void CheckLoadBiasInFirstExecPhdr(uint64_t offset, uint64_t vaddr, uint64_t load_bias);
+
MemoryFake memory_;
};
@@ -1495,4 +1501,122 @@
BuildIDSectionTooSmallForHeader<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
}
+template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+void ElfInterfaceTest::CheckLoadBiasInFirstPhdr(uint64_t load_bias) {
+ Ehdr ehdr = {};
+ ehdr.e_phoff = 0x100;
+ ehdr.e_phnum = 2;
+ ehdr.e_phentsize = sizeof(Phdr);
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ Phdr phdr = {};
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = 0;
+ phdr.p_vaddr = load_bias;
+ phdr.p_memsz = 0x10000;
+ phdr.p_flags = PF_R | PF_X;
+ phdr.p_align = 0x1000;
+ memory_.SetMemory(0x100, &phdr, sizeof(phdr));
+
+ memset(&phdr, 0, sizeof(phdr));
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = 0x1000;
+ phdr.p_memsz = 0x2000;
+ phdr.p_flags = PF_R | PF_X;
+ phdr.p_align = 0x1000;
+ memory_.SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr));
+
+ uint64_t static_load_bias = ElfInterface::GetLoadBias<Ehdr, Phdr>(&memory_);
+ ASSERT_EQ(load_bias, static_load_bias);
+
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+ uint64_t init_load_bias = 0;
+ ASSERT_TRUE(elf->Init(&init_load_bias));
+ ASSERT_EQ(init_load_bias, static_load_bias);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_zero_32) {
+ CheckLoadBiasInFirstPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_zero_64) {
+ CheckLoadBiasInFirstPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_non_zero_32) {
+ CheckLoadBiasInFirstPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x1000);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_non_zero_64) {
+ CheckLoadBiasInFirstPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x1000);
+}
+
+template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
+void ElfInterfaceTest::CheckLoadBiasInFirstExecPhdr(uint64_t offset, uint64_t vaddr,
+ uint64_t load_bias) {
+ Ehdr ehdr = {};
+ ehdr.e_phoff = 0x100;
+ ehdr.e_phnum = 3;
+ ehdr.e_phentsize = sizeof(Phdr);
+ memory_.SetMemory(0, &ehdr, sizeof(ehdr));
+
+ Phdr phdr = {};
+ phdr.p_type = PT_LOAD;
+ phdr.p_memsz = 0x10000;
+ phdr.p_flags = PF_R;
+ phdr.p_align = 0x1000;
+ memory_.SetMemory(0x100, &phdr, sizeof(phdr));
+
+ memset(&phdr, 0, sizeof(phdr));
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = vaddr;
+ phdr.p_memsz = 0x2000;
+ phdr.p_flags = PF_R | PF_X;
+ phdr.p_align = 0x1000;
+ memory_.SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr));
+
+ // Second executable load should be ignored for load bias computation.
+ memset(&phdr, 0, sizeof(phdr));
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = 0x1234;
+ phdr.p_vaddr = 0x2000;
+ phdr.p_memsz = 0x2000;
+ phdr.p_flags = PF_R | PF_X;
+ phdr.p_align = 0x1000;
+ memory_.SetMemory(0x200 + sizeof(phdr), &phdr, sizeof(phdr));
+
+ uint64_t static_load_bias = ElfInterface::GetLoadBias<Ehdr, Phdr>(&memory_);
+ ASSERT_EQ(load_bias, static_load_bias);
+
+ std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
+ uint64_t init_load_bias = 0;
+ ASSERT_TRUE(elf->Init(&init_load_bias));
+ ASSERT_EQ(init_load_bias, static_load_bias);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_exec_zero_32) {
+ CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x1000, 0x1000, 0);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_exec_zero_64) {
+ CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x1000, 0x1000, 0);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_exec_non_zero_32) {
+ CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x1000, 0x4000, 0x3000);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_exec_non_zero_64) {
+ CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x1000, 0x4000, 0x3000);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_exec_zero_from_error_32) {
+ CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x5000, 0x1000, 0);
+}
+
+TEST_F(ElfInterfaceTest, get_load_bias_exec_zero_from_error_64) {
+ CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x5000, 0x1000, 0);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
index f5ac6cb..2c98928 100644
--- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -141,6 +141,7 @@
phdr.p_type = PT_NULL;
memory->SetMemory(offset + 0x5000, &phdr, sizeof(phdr));
phdr.p_type = PT_LOAD;
+ phdr.p_flags = PF_X;
phdr.p_offset = 0;
phdr.p_vaddr = 0xe000;
memory->SetMemory(offset + 0x5000 + sizeof(phdr), &phdr, sizeof(phdr));