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
This commit is contained in:
parent
51fb2a0855
commit
df683b7439
13 changed files with 171 additions and 187 deletions
|
|
@ -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<uint64_t>(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() {
|
||||
|
|
|
|||
|
|
@ -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<uint64_t>(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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<std::string, uint64_t> globals_;
|
||||
std::string fake_build_id_;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<Elf32_Ehdr, Elf32_Shdr>(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<Elf32_Ehdr, Elf32_Shdr>(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<Elf32_Ehdr, Elf32_Shdr>(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<Elf32_Ehdr, Elf32_Shdr>(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<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
|
||||
CreateElf<Elf32_Ehdr, Elf32_Shdr>(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<Elf32_Ehdr, Elf32_Shdr>(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<Elf64_Ehdr, Elf64_Shdr>(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<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
|
||||
CreateElf<Elf32_Ehdr, Elf32_Shdr>(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<Elf32_Ehdr, Elf32_Shdr>(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.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
d0250000-d2600000 r-xp 0 00:00 0 <anonymous:d0250000>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue