From df683b7439a15f1d116a4b3a30410e174b44561c Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 3 Dec 2019 17:13:49 -0800 Subject: [PATCH] Fix support finding global variables. The code was not properly getting the variable addresses and using the offset and address fields of the .data section. Fix all of that, and update the tests. Bug: 145162678 Test: Unit tests pass. Test: ./art/test/run-test --dex2oat-jobs 4 --host --prebuild --compact-dex-level fast --jit --no-relocate --runtime-option -Xcheck:jni 137-cfi Test: ./art/test/testrunner/testrunner.py -t 137 --host Change-Id: Ic61c4487334fd2273cda9c56eb1a3b525a03edb7 --- libunwindstack/Elf.cpp | 34 +++-- libunwindstack/ElfInterface.cpp | 18 ++- libunwindstack/Global.cpp | 59 ++++----- libunwindstack/include/unwindstack/Elf.h | 2 +- .../include/unwindstack/ElfInterface.h | 15 ++- libunwindstack/include/unwindstack/Global.h | 2 +- libunwindstack/tests/DexFilesTest.cpp | 44 ++++--- libunwindstack/tests/ElfFake.h | 8 ++ libunwindstack/tests/ElfTest.cpp | 120 ++++++------------ libunwindstack/tests/JitDebugTest.cpp | 48 +++---- .../offline/art_quick_osr_stub_arm/maps.txt | 2 +- .../files/offline/jit_debug_arm/maps.txt | 4 +- .../files/offline/jit_debug_x86/maps.txt | 2 +- 13 files changed, 171 insertions(+), 187 deletions(-) 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