diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index f01b0926b..286febcdc 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp @@ -124,6 +124,12 @@ bool Elf::GetGlobalVariableOffset(const std::string& name, uint64_t* memory_offs return false; } + if (arch() == ARCH_ARM64) { + // Tagged pointer after Android R would lead top byte to have random values + // https://source.android.com/devices/tech/debug/tagged-pointers + vaddr &= (1ULL << 56) - 1; + } + // Check the .data section. uint64_t vaddr_start = interface_->data_vaddr_start(); if (vaddr >= vaddr_start && vaddr < interface_->data_vaddr_end()) { diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h index fc90dab8e..3b6cb8032 100644 --- a/libunwindstack/tests/ElfFake.h +++ b/libunwindstack/tests/ElfFake.h @@ -55,6 +55,8 @@ class ElfFake : public Elf { void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; } + void FakeSetArch(ArchEnum arch) { arch_ = arch; } + void FakeSetInterface(ElfInterface* interface) { interface_.reset(interface); } void FakeSetGnuDebugdataInterface(ElfInterface* interface) { gnu_debugdata_interface_.reset(interface); diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index 1f3ed8190..f0852a4ee 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -438,6 +438,48 @@ TEST_F(ElfTest, get_global_vaddr_in_dynamic_section) { EXPECT_EQ(0xc080U, offset); } +TEST_F(ElfTest, get_global_vaddr_with_tagged_pointer) { + ElfFake elf(memory_); + elf.FakeSetValid(true); + elf.FakeSetArch(ARCH_ARM64); + + ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); + elf.FakeSetInterface(interface); + interface->MockSetDataVaddrStart(0x500); + interface->MockSetDataVaddrEnd(0x600); + interface->MockSetDataOffset(0xa000); + + std::string global("something"); + EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_)) + .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x8800000000000580), + ::testing::Return(true))); + + uint64_t offset; + ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset)); + EXPECT_EQ(0xa080U, offset); +} + +TEST_F(ElfTest, get_global_vaddr_without_tagged_pointer) { + ElfFake elf(memory_); + elf.FakeSetValid(true); + elf.FakeSetArch(ARCH_X86_64); + + ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); + elf.FakeSetInterface(interface); + interface->MockSetDataVaddrStart(0x8800000000000500); + interface->MockSetDataVaddrEnd(0x8800000000000600); + interface->MockSetDataOffset(0x880000000000a000); + + std::string global("something"); + EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_)) + .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x8800000000000580), + ::testing::Return(true))); + + uint64_t offset; + ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset)); + EXPECT_EQ(0x880000000000a080U, offset); +} + TEST_F(ElfTest, is_valid_pc_elf_invalid) { ElfFake elf(memory_); elf.FakeSetValid(false);