diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index c141b2e00..66277874e 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp @@ -112,35 +112,33 @@ bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offse gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset))); } -bool Elf::GetGlobalVariable(const std::string& name, uint64_t* memory_address) { +bool Elf::GetGlobalVariableOffset(const std::string& name, uint64_t* memory_offset) { if (!valid_) { return false; } - if (!interface_->GetGlobalVariable(name, memory_address) && + uint64_t vaddr; + if (!interface_->GetGlobalVariable(name, &vaddr) && (gnu_debugdata_interface_ == nullptr || - !gnu_debugdata_interface_->GetGlobalVariable(name, memory_address))) { + !gnu_debugdata_interface_->GetGlobalVariable(name, &vaddr))) { return false; } - // Adjust by the load bias. - if (load_bias_ > 0 && *memory_address < static_cast(load_bias_)) { - return false; + // Check the .data section. + uint64_t vaddr_start = interface_->data_vaddr_start(); + if (vaddr >= vaddr_start && vaddr < interface_->data_vaddr_end()) { + *memory_offset = vaddr - vaddr_start + interface_->data_offset(); + return true; } - *memory_address -= load_bias_; - - // If this winds up in the dynamic section, then we might need to adjust - // the address. - uint64_t dynamic_end = interface_->dynamic_vaddr() + interface_->dynamic_size(); - if (*memory_address >= interface_->dynamic_vaddr() && *memory_address < dynamic_end) { - if (interface_->dynamic_vaddr() > interface_->dynamic_offset()) { - *memory_address -= interface_->dynamic_vaddr() - interface_->dynamic_offset(); - } else { - *memory_address += interface_->dynamic_offset() - interface_->dynamic_vaddr(); - } + // Check the .dynamic section. + vaddr_start = interface_->dynamic_vaddr_start(); + if (vaddr >= vaddr_start && vaddr < interface_->dynamic_vaddr_end()) { + *memory_offset = vaddr - vaddr_start + interface_->dynamic_offset(); + return true; } - return true; + + return false; } std::string Elf::GetBuildID() { diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 5f95fa81b..767628979 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -236,8 +236,12 @@ void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias) case PT_DYNAMIC: dynamic_offset_ = phdr.p_offset; - dynamic_vaddr_ = phdr.p_vaddr; - dynamic_size_ = phdr.p_memsz; + dynamic_vaddr_start_ = phdr.p_vaddr; + if (__builtin_add_overflow(dynamic_vaddr_start_, phdr.p_memsz, &dynamic_vaddr_end_)) { + dynamic_offset_ = 0; + dynamic_vaddr_start_ = 0; + dynamic_vaddr_end_ = 0; + } break; default: @@ -360,6 +364,14 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { eh_frame_hdr_offset_ = shdr.sh_offset; eh_frame_hdr_section_bias_ = static_cast(shdr.sh_addr) - shdr.sh_offset; eh_frame_hdr_size_ = shdr.sh_size; + } else if (name == ".data") { + data_offset_ = shdr.sh_offset; + data_vaddr_start_ = shdr.sh_addr; + if (__builtin_add_overflow(data_vaddr_start_, shdr.sh_size, &data_vaddr_end_)) { + data_offset_ = 0; + data_vaddr_start_ = 0; + data_vaddr_end_ = 0; + } } } } @@ -398,7 +410,7 @@ std::string ElfInterface::GetSonameWithTemplate() { // Find the soname location from the dynamic headers section. DynType dyn; uint64_t offset = dynamic_offset_; - uint64_t max_offset = offset + dynamic_size_; + uint64_t max_offset = offset + dynamic_vaddr_end_ - dynamic_vaddr_start_; for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) { if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) { last_error_.code = ERROR_MEMORY_INVALID; diff --git a/libunwindstack/Global.cpp b/libunwindstack/Global.cpp index a20be0009..ec977e1c4 100644 --- a/libunwindstack/Global.cpp +++ b/libunwindstack/Global.cpp @@ -39,28 +39,22 @@ void Global::SetArch(ArchEnum arch) { } } -uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) { - if (!search_libs_.empty()) { - bool found = false; - const char* lib = basename(info->name.c_str()); - for (const std::string& name : search_libs_) { - if (name == lib) { - found = true; - break; - } - } - if (!found) { - return 0; - } +bool Global::Searchable(const std::string& name) { + if (search_libs_.empty()) { + return true; } - Elf* elf = info->GetElf(memory_, arch()); - uint64_t ptr; - // Find first non-empty list (libraries might be loaded multiple times). - if (elf->GetGlobalVariable(variable, &ptr) && ptr != 0) { - return ptr + info->start; + if (name.empty()) { + return false; } - return 0; + + const char* base_name = basename(name.c_str()); + for (const std::string& lib : search_libs_) { + if (base_name == lib) { + return true; + } + } + return false; } void Global::FindAndReadVariable(Maps* maps, const char* var_str) { @@ -78,24 +72,27 @@ void Global::FindAndReadVariable(Maps* maps, const char* var_str) { // f2000-f3000 2000 rw- /system/lib/libc.so MapInfo* map_start = nullptr; for (const auto& info : *maps) { - if (map_start != nullptr) { - if (map_start->name == info->name) { - if (info->offset != 0 && - (info->flags & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) { - uint64_t ptr = GetVariableOffset(map_start, variable); - if (ptr != 0 && ReadVariableData(ptr)) { - break; - } else { - // Failed to find the global variable, do not bother trying again. - map_start = nullptr; + if (map_start != nullptr && map_start->name == info->name) { + if (info->offset != 0 && + (info->flags & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) { + Elf* elf = map_start->GetElf(memory_, arch()); + uint64_t ptr; + if (elf->GetGlobalVariableOffset(variable, &ptr) && ptr != 0) { + uint64_t offset_end = info->offset + info->end - info->start; + if (ptr >= info->offset && ptr < offset_end) { + ptr = info->start + ptr - info->offset; + if (ReadVariableData(ptr)) { + break; + } } } - } else { map_start = nullptr; } + } else { + map_start = nullptr; } if (map_start == nullptr && (info->flags & PROT_READ) && info->offset == 0 && - !info->name.empty()) { + Searchable(info->name)) { map_start = info.get(); } } diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h index fc3f2a610..472ed925c 100644 --- a/libunwindstack/include/unwindstack/Elf.h +++ b/libunwindstack/include/unwindstack/Elf.h @@ -63,7 +63,7 @@ class Elf { bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset); - bool GetGlobalVariable(const std::string& name, uint64_t* memory_address); + bool GetGlobalVariableOffset(const std::string& name, uint64_t* memory_offset); uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info); diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index ae9bd9a61..0c39b238b 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -77,8 +77,11 @@ class ElfInterface { void SetGnuDebugdataInterface(ElfInterface* interface) { gnu_debugdata_interface_ = interface; } uint64_t dynamic_offset() { return dynamic_offset_; } - uint64_t dynamic_vaddr() { return dynamic_vaddr_; } - uint64_t dynamic_size() { return dynamic_size_; } + uint64_t dynamic_vaddr_start() { return dynamic_vaddr_start_; } + uint64_t dynamic_vaddr_end() { return dynamic_vaddr_end_; } + uint64_t data_offset() { return data_offset_; } + uint64_t data_vaddr_start() { return data_vaddr_start_; } + uint64_t data_vaddr_end() { return data_vaddr_end_; } uint64_t eh_frame_hdr_offset() { return eh_frame_hdr_offset_; } int64_t eh_frame_hdr_section_bias() { return eh_frame_hdr_section_bias_; } uint64_t eh_frame_hdr_size() { return eh_frame_hdr_size_; } @@ -141,8 +144,12 @@ class ElfInterface { // Stored elf data. uint64_t dynamic_offset_ = 0; - uint64_t dynamic_vaddr_ = 0; - uint64_t dynamic_size_ = 0; + uint64_t dynamic_vaddr_start_ = 0; + uint64_t dynamic_vaddr_end_ = 0; + + uint64_t data_offset_ = 0; + uint64_t data_vaddr_start_ = 0; + uint64_t data_vaddr_end_ = 0; uint64_t eh_frame_hdr_offset_ = 0; int64_t eh_frame_hdr_section_bias_ = 0; diff --git a/libunwindstack/include/unwindstack/Global.h b/libunwindstack/include/unwindstack/Global.h index a7e6c15ba..b9bb141b1 100644 --- a/libunwindstack/include/unwindstack/Global.h +++ b/libunwindstack/include/unwindstack/Global.h @@ -45,7 +45,7 @@ class Global { ArchEnum arch() { return arch_; } protected: - uint64_t GetVariableOffset(MapInfo* info, const std::string& variable); + bool Searchable(const std::string& name); void FindAndReadVariable(Maps* maps, const char* variable); virtual bool ReadVariableData(uint64_t offset) = 0; diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp index 1ea9e5c03..0dd3af60b 100644 --- a/libunwindstack/tests/DexFilesTest.cpp +++ b/libunwindstack/tests/DexFilesTest.cpp @@ -36,14 +36,18 @@ namespace unwindstack { class DexFilesTest : public ::testing::Test { protected: - void CreateFakeElf(MapInfo* map_info) { + void CreateFakeElf(MapInfo* map_info, uint64_t global_offset, uint64_t data_offset, + uint64_t data_vaddr, uint64_t data_size) { MemoryFake* memory = new MemoryFake; ElfFake* elf = new ElfFake(memory); elf->FakeSetValid(true); ElfInterfaceFake* interface = new ElfInterfaceFake(memory); elf->FakeSetInterface(interface); - interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800); + interface->FakeSetGlobalVariable("__dex_debug_descriptor", global_offset); + interface->FakeSetDataOffset(data_offset); + interface->FakeSetDataVaddrStart(data_vaddr); + interface->FakeSetDataVaddrEnd(data_vaddr + data_size); map_info->elf.reset(elf); } @@ -54,11 +58,11 @@ class DexFilesTest : public ::testing::Test { maps_.reset( new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n" "4000-6000 r--s 00000000 00:00 0 /fake/elf\n" - "6000-8000 -wxs 00000000 00:00 0 /fake/elf\n" + "6000-8000 -wxs 00002000 00:00 0 /fake/elf\n" "a000-c000 r--p 00000000 00:00 0 /fake/elf2\n" - "c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n" + "c000-f000 rw-p 00002000 00:00 0 /fake/elf2\n" "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n" - "100000-110000 rw-p 0001000 00:00 0 /fake/elf3\n" + "100000-110000 rw-p 00f1000 00:00 0 /fake/elf3\n" "200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n" "300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n")); ASSERT_TRUE(maps_->Parse()); @@ -66,17 +70,17 @@ class DexFilesTest : public ::testing::Test { // Global variable in a section that is not readable. MapInfo* map_info = maps_->Get(kMapGlobalNonReadable); ASSERT_TRUE(map_info != nullptr); - CreateFakeElf(map_info); + CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000); // Global variable not set by default. map_info = maps_->Get(kMapGlobalSetToZero); ASSERT_TRUE(map_info != nullptr); - CreateFakeElf(map_info); + CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000); // Global variable set in this map. map_info = maps_->Get(kMapGlobal); ASSERT_TRUE(map_info != nullptr); - CreateFakeElf(map_info); + CreateFakeElf(map_info, 0xf1800, 0xf1000, 0xf1000, 0x10000); } void SetUp() override { @@ -156,7 +160,7 @@ TEST_F(DexFilesTest, get_method_information_32) { uint64_t method_offset = 0x124; MapInfo* info = maps_->Get(kMapDexFiles); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x100800, 0x200000); WriteEntry32(0x200000, 0, 0, 0x300000); WriteDex(0x300000); @@ -172,7 +176,7 @@ TEST_F(DexFilesTest, get_method_information_64) { uint64_t method_offset = 0x124; MapInfo* info = maps_->Get(kMapDexFiles); - WriteDescriptor64(0xf800, 0x200000); + WriteDescriptor64(0x100800, 0x200000); WriteEntry64(0x200000, 0, 0, 0x301000); WriteDex(0x301000); @@ -186,7 +190,7 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_32) { uint64_t method_offset = 0x124; MapInfo* info = maps_->Get(kMapDexFiles); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x100800, 0x200000); WriteEntry32(0x200000, 0x200100, 0, 0x100000); WriteEntry32(0x200100, 0, 0x200000, 0x300000); WriteDex(0x300000); @@ -203,7 +207,7 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_64) { uint64_t method_offset = 0x124; MapInfo* info = maps_->Get(kMapDexFiles); - WriteDescriptor64(0xf800, 0x200000); + WriteDescriptor64(0x100800, 0x200000); WriteEntry64(0x200000, 0x200100, 0, 0x100000); WriteEntry64(0x200100, 0, 0x200000, 0x300000); WriteDex(0x300000); @@ -218,7 +222,7 @@ TEST_F(DexFilesTest, get_method_information_cached) { uint64_t method_offset = 0x124; MapInfo* info = maps_->Get(kMapDexFiles); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x100800, 0x200000); WriteEntry32(0x200000, 0, 0, 0x300000); WriteDex(0x300000); @@ -238,7 +242,7 @@ TEST_F(DexFilesTest, get_method_information_search_libs) { uint64_t method_offset = 0x124; MapInfo* info = maps_->Get(kMapDexFiles); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x100800, 0x200000); WriteEntry32(0x200000, 0x200100, 0, 0x100000); WriteEntry32(0x200100, 0, 0x200000, 0x300000); WriteDex(0x300000); @@ -274,9 +278,9 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) { MapInfo* info = maps_->Get(kMapDexFiles); // First global variable found, but value is zero. - WriteDescriptor32(0xa800, 0); + WriteDescriptor32(0xc800, 0); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x100800, 0x200000); WriteEntry32(0x200000, 0, 0, 0x300000); WriteDex(0x300000); @@ -289,7 +293,7 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) { dex_files_->SetArch(ARCH_ARM); method_name = "fail"; method_offset = 0x123; - WriteDescriptor32(0xa800, 0x100000); + WriteDescriptor32(0xc800, 0x100000); dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("fail", method_name); EXPECT_EQ(0x123U, method_offset); @@ -303,9 +307,9 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { MapInfo* info = maps_->Get(kMapDexFiles); // First global variable found, but value is zero. - WriteDescriptor64(0xa800, 0); + WriteDescriptor64(0xc800, 0); - WriteDescriptor64(0xf800, 0x200000); + WriteDescriptor64(0x100800, 0x200000); WriteEntry64(0x200000, 0, 0, 0x300000); WriteDex(0x300000); @@ -318,7 +322,7 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { dex_files_->SetArch(ARCH_ARM64); method_name = "fail"; method_offset = 0x123; - WriteDescriptor64(0xa800, 0x100000); + WriteDescriptor64(0xc800, 0x100000); dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("fail", method_name); EXPECT_EQ(0x123U, method_offset); diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h index 832e64ab1..c33908d23 100644 --- a/libunwindstack/tests/ElfFake.h +++ b/libunwindstack/tests/ElfFake.h @@ -97,6 +97,14 @@ class ElfInterfaceFake : public ElfInterface { void FakeSetErrorAddress(uint64_t address) { last_error_.address = address; } + void FakeSetDataOffset(uint64_t offset) { data_offset_ = offset; } + void FakeSetDataVaddrStart(uint64_t vaddr) { data_vaddr_start_ = vaddr; } + void FakeSetDataVaddrEnd(uint64_t vaddr) { data_vaddr_end_ = vaddr; } + + void FakeSetDynamicOffset(uint64_t offset) { dynamic_offset_ = offset; } + void FakeSetDynamicVaddrStart(uint64_t vaddr) { dynamic_vaddr_start_ = vaddr; } + void FakeSetDynamicVaddrEnd(uint64_t vaddr) { dynamic_vaddr_end_ = vaddr; } + private: std::unordered_map globals_; std::string fake_build_id_; diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index e6728a0f9..d227b60bd 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -320,9 +320,13 @@ class ElfInterfaceMock : public ElfInterface { MOCK_METHOD(bool, GetGlobalVariable, (const std::string&, uint64_t*), (override)); MOCK_METHOD(bool, IsValidPc, (uint64_t), (override)); + void MockSetDataOffset(uint64_t offset) { data_offset_ = offset; } + void MockSetDataVaddrStart(uint64_t vaddr) { data_vaddr_start_ = vaddr; } + void MockSetDataVaddrEnd(uint64_t vaddr) { data_vaddr_end_ = vaddr; } + void MockSetDynamicOffset(uint64_t offset) { dynamic_offset_ = offset; } - void MockSetDynamicVaddr(uint64_t vaddr) { dynamic_vaddr_ = vaddr; } - void MockSetDynamicSize(uint64_t size) { dynamic_size_ = size; } + void MockSetDynamicVaddrStart(uint64_t vaddr) { dynamic_vaddr_start_ = vaddr; } + void MockSetDynamicVaddrEnd(uint64_t vaddr) { dynamic_vaddr_end_ = vaddr; } }; TEST_F(ElfTest, step_in_interface) { @@ -348,7 +352,7 @@ TEST_F(ElfTest, get_global_invalid_elf) { std::string global("something"); uint64_t offset; - ASSERT_FALSE(elf.GetGlobalVariable(global, &offset)); + ASSERT_FALSE(elf.GetGlobalVariableOffset(global, &offset)); } TEST_F(ElfTest, get_global_valid_not_in_interface) { @@ -358,119 +362,69 @@ TEST_F(ElfTest, get_global_valid_not_in_interface) { ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); elf.FakeSetInterface(interface); - uint64_t offset; std::string global("something"); - EXPECT_CALL(*interface, GetGlobalVariable(global, &offset)).WillOnce(::testing::Return(false)); + EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_)) + .WillOnce(::testing::Return(false)); - ASSERT_FALSE(elf.GetGlobalVariable(global, &offset)); + uint64_t offset; + ASSERT_FALSE(elf.GetGlobalVariableOffset(global, &offset)); } -TEST_F(ElfTest, get_global_valid_below_load_bias) { +TEST_F(ElfTest, get_global_vaddr_in_no_sections) { ElfFake elf(memory_); elf.FakeSetValid(true); - elf.FakeSetLoadBias(0x1000); ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); elf.FakeSetInterface(interface); - uint64_t offset; std::string global("something"); - EXPECT_CALL(*interface, GetGlobalVariable(global, &offset)) + EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_)) .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x300), ::testing::Return(true))); - ASSERT_FALSE(elf.GetGlobalVariable(global, &offset)); -} - -TEST_F(ElfTest, get_global_valid_dynamic_zero_non_zero_load_bias) { - ElfFake elf(memory_); - elf.FakeSetValid(true); - elf.FakeSetLoadBias(0x100); - - ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); - elf.FakeSetInterface(interface); - uint64_t offset; - std::string global("something"); - EXPECT_CALL(*interface, GetGlobalVariable(global, &offset)) - .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x300), ::testing::Return(true))); - - ASSERT_TRUE(elf.GetGlobalVariable(global, &offset)); - EXPECT_EQ(0x200U, offset); + ASSERT_FALSE(elf.GetGlobalVariableOffset(global, &offset)); } -TEST_F(ElfTest, get_global_valid_dynamic_zero) { +TEST_F(ElfTest, get_global_vaddr_in_data_section) { ElfFake elf(memory_); elf.FakeSetValid(true); ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); elf.FakeSetInterface(interface); + interface->MockSetDataVaddrStart(0x500); + interface->MockSetDataVaddrEnd(0x600); + interface->MockSetDataOffset(0xa000); - ElfInterfaceMock* gnu_interface = new ElfInterfaceMock(memory_); - elf.FakeSetGnuDebugdataInterface(gnu_interface); + std::string global("something"); + EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_)) + .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x580), ::testing::Return(true))); uint64_t offset; - std::string global("something"); - EXPECT_CALL(*interface, GetGlobalVariable(global, &offset)).WillOnce(::testing::Return(false)); - - EXPECT_CALL(*gnu_interface, GetGlobalVariable(global, &offset)) - .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x500), ::testing::Return(true))); - - ASSERT_TRUE(elf.GetGlobalVariable(global, &offset)); - EXPECT_EQ(0x500U, offset); + ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset)); + EXPECT_EQ(0xa080U, offset); } -TEST_F(ElfTest, get_global_valid_in_gnu_debugdata_dynamic_zero) { +TEST_F(ElfTest, get_global_vaddr_in_dynamic_section) { ElfFake elf(memory_); elf.FakeSetValid(true); ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); elf.FakeSetInterface(interface); + interface->MockSetDataVaddrStart(0x500); + interface->MockSetDataVaddrEnd(0x600); + interface->MockSetDataOffset(0xa000); + + interface->MockSetDynamicVaddrStart(0x800); + interface->MockSetDynamicVaddrEnd(0x900); + interface->MockSetDynamicOffset(0xc000); + + std::string global("something"); + EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_)) + .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x880), ::testing::Return(true))); uint64_t offset; - std::string global("something"); - EXPECT_CALL(*interface, GetGlobalVariable(global, &offset)) - .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x300), ::testing::Return(true))); - - ASSERT_TRUE(elf.GetGlobalVariable(global, &offset)); - EXPECT_EQ(0x300U, offset); -} - -TEST_F(ElfTest, get_global_valid_dynamic_adjust_negative) { - ElfFake elf(memory_); - elf.FakeSetValid(true); - - ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); - interface->MockSetDynamicOffset(0x400); - interface->MockSetDynamicVaddr(0x800); - interface->MockSetDynamicSize(0x100); - elf.FakeSetInterface(interface); - - uint64_t offset; - std::string global("something"); - EXPECT_CALL(*interface, GetGlobalVariable(global, &offset)) - .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x850), ::testing::Return(true))); - - ASSERT_TRUE(elf.GetGlobalVariable(global, &offset)); - EXPECT_EQ(0x450U, offset); -} - -TEST_F(ElfTest, get_global_valid_dynamic_adjust_positive) { - ElfFake elf(memory_); - elf.FakeSetValid(true); - - ElfInterfaceMock* interface = new ElfInterfaceMock(memory_); - interface->MockSetDynamicOffset(0x1000); - interface->MockSetDynamicVaddr(0x800); - interface->MockSetDynamicSize(0x100); - elf.FakeSetInterface(interface); - - uint64_t offset; - std::string global("something"); - EXPECT_CALL(*interface, GetGlobalVariable(global, &offset)) - .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x850), ::testing::Return(true))); - - ASSERT_TRUE(elf.GetGlobalVariable(global, &offset)); - EXPECT_EQ(0x1050U, offset); + ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset)); + EXPECT_EQ(0xc080U, offset); } TEST_F(ElfTest, is_valid_pc_elf_invalid) { diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp index b1ca111cb..9b32a3a43 100644 --- a/libunwindstack/tests/JitDebugTest.cpp +++ b/libunwindstack/tests/JitDebugTest.cpp @@ -35,13 +35,17 @@ namespace unwindstack { class JitDebugTest : public ::testing::Test { protected: - void CreateFakeElf(MapInfo* map_info) { + void CreateFakeElf(MapInfo* map_info, uint64_t global_offset, uint64_t data_offset, + uint64_t data_vaddr, uint64_t data_size) { MemoryFake* memory = new MemoryFake; ElfFake* elf = new ElfFake(memory); elf->FakeSetValid(true); ElfInterfaceFake* interface = new ElfInterfaceFake(memory); elf->FakeSetInterface(interface); - interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800); + interface->FakeSetGlobalVariable("__jit_debug_descriptor", global_offset); + interface->FakeSetDataOffset(data_offset); + interface->FakeSetDataVaddrStart(data_vaddr); + interface->FakeSetDataVaddrEnd(data_vaddr + data_size); map_info->elf.reset(elf); } @@ -52,27 +56,27 @@ class JitDebugTest : public ::testing::Test { maps_.reset( new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n" "4000-6000 r--s 00000000 00:00 0 /fake/elf1\n" - "6000-8000 -wxs 00000000 00:00 0 /fake/elf1\n" + "6000-8000 -wxs 00002000 00:00 0 /fake/elf1\n" "a000-c000 --xp 00000000 00:00 0 /fake/elf2\n" - "c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n" + "c000-f000 rw-p 00002000 00:00 0 /fake/elf2\n" "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n" - "11000-12000 rw-p 00001000 00:00 0 /fake/elf3\n" + "11000-12000 rw-p 00002000 00:00 0 /fake/elf3\n" "12000-14000 r--p 00000000 00:00 0 /fake/elf4\n" - "100000-110000 rw-p 0001000 00:00 0 /fake/elf4\n" - "200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n")); + "100000-110000 rw-p 00ee000 00:00 0 /fake/elf4\n" + "200000-210000 rw-p 01ee000 00:00 0 /fake/elf4\n")); ASSERT_TRUE(maps_->Parse()); MapInfo* map_info = maps_->Get(3); ASSERT_TRUE(map_info != nullptr); - CreateFakeElf(map_info); + CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000); map_info = maps_->Get(5); ASSERT_TRUE(map_info != nullptr); - CreateFakeElf(map_info); + CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000); map_info = maps_->Get(7); ASSERT_TRUE(map_info != nullptr); - CreateFakeElf(map_info); + CreateFakeElf(map_info, 0xee800, 0xee000, 0xee000, 0x10000); } void SetUp() override { @@ -258,7 +262,7 @@ TEST_F(JitDebugTest, get_elf_no_valid_descriptor_in_memory) { TEST_F(JitDebugTest, get_elf_no_valid_code_entry) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x11800, 0x200000); Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); @@ -267,7 +271,7 @@ TEST_F(JitDebugTest, get_elf_no_valid_code_entry) { TEST_F(JitDebugTest, get_elf_invalid_descriptor_first_entry) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); - WriteDescriptor32(0xf800, 0); + WriteDescriptor32(0x11800, 0); Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); @@ -276,9 +280,9 @@ TEST_F(JitDebugTest, get_elf_invalid_descriptor_first_entry) { TEST_F(JitDebugTest, get_elf_invalid_descriptor_version) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); - WriteDescriptor32(0xf800, 0x20000); + WriteDescriptor32(0x11800, 0x20000); // Set the version to an invalid value. - memory_->SetData32(0xf800, 2); + memory_->SetData32(0x11800, 2); Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); @@ -287,7 +291,7 @@ TEST_F(JitDebugTest, get_elf_invalid_descriptor_version) { TEST_F(JitDebugTest, get_elf_32) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x11800, 0x200000); WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000); Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); @@ -304,16 +308,16 @@ TEST_F(JitDebugTest, get_multiple_jit_debug_descriptors_valid) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); CreateElf(0x5000, ELFCLASS32, EM_ARM, 0x2000, 0x300); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x11800, 0x200000); WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000); - WriteDescriptor32(0x12800, 0x201000); + WriteDescriptor32(0x100800, 0x201000); WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000); ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr); ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr); // Now clear the descriptor entry for the first one. - WriteDescriptor32(0xf800, 0); + WriteDescriptor32(0x11800, 0); jit_debug_.reset(new JitDebug(process_memory_)); jit_debug_->SetArch(ARCH_ARM); @@ -326,7 +330,7 @@ TEST_F(JitDebugTest, get_elf_x86) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x11800, 0x200000); WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000); jit_debug_->SetArch(ARCH_X86); @@ -345,7 +349,7 @@ TEST_F(JitDebugTest, get_elf_64) { CreateElf(0x4000, ELFCLASS64, EM_AARCH64, 0x1500, 0x200); - WriteDescriptor64(0xf800, 0x200000); + WriteDescriptor64(0x11800, 0x200000); WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000); Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); @@ -362,7 +366,7 @@ TEST_F(JitDebugTest, get_elf_multiple_entries) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); CreateElf(0x5000, ELFCLASS32, EM_ARM, 0x2300, 0x400); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x11800, 0x200000); WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000); WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000); @@ -385,7 +389,7 @@ TEST_F(JitDebugTest, get_elf_multiple_entries) { TEST_F(JitDebugTest, get_elf_search_libs) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); - WriteDescriptor32(0xf800, 0x200000); + WriteDescriptor32(0x11800, 0x200000); WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000); // Only search a given named list of libs. diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt index 5657373e4..1ff12db1e 100644 --- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt +++ b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt @@ -1,4 +1,4 @@ d0250000-d2600000 r-xp 0 00:00 0 e466e000-e4ae8000 r-xp 0 00:00 0 libart.so -e4ae8000-e4ae9000 rw-p 1000 00:00 0 libart.so +e4af1000-e4af2000 rw-p 482000 00:00 0 libart.so e7d91000-e7e31000 r-xp 0 00:00 0 libc.so diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt index 4043122de..3b87f2f62 100644 --- a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt +++ b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt @@ -4,8 +4,8 @@ e0445000-e0447000 r--p 0 00:00 0 137-cfi.odex e0447000-e0448000 r-xp 2000 00:00 0 137-cfi.odex e2796000-e4796000 r-xp 0 00:00 0 anonymous:e2796000 e648e000-e690f000 r-xp 0 00:00 0 libart.so -e690f000-e6910000 rw-p 1000 00:00 0 libart.so +e6918000-e6919000 rw-p 489000 00:00 0 libart.so ed306000-ed801000 r-xp 0 00:00 0 libartd.so -ed801000-ed802000 rw-p 1000 00:00 0 libartd.so +ed80a000-ed80b000 rw-p 503000 00:00 0 libartd.so eda88000-edb23000 r-xp 0 00:00 0 libc.so ede4e000-ede50000 r-xp 0 00:00 0 anonymous:ede4e000 diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt index f255a44e0..c22b5deaf 100644 --- a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt +++ b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt @@ -4,5 +4,5 @@ ec604000-ec606000 r--p 0 00:00 0 137-cfi.odex ec606000-ec607000 r-xp 2000 00:00 0 137-cfi.odex ee74c000-f074c000 r-xp 0 00:00 0 anonymous:ee74c000 f6be1000-f732b000 r-xp 0 00:00 0 libartd.so -f732b000-f732c000 rw-p 1000 00:00 0 libartd.so +f7334000-f7335000 rw-p 752000 00:00 0 libartd.so f734b000-f74fc000 r-xp 0 00:00 0 libc.so