Merge "Fix support finding global variables."

This commit is contained in:
Christopher Ferris 2019-12-04 17:03:44 +00:00 committed by Gerrit Code Review
commit 2da8e3c2ee
13 changed files with 171 additions and 187 deletions

View File

@ -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() {

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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_;

View File

@ -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) {

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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