Merge "Add a global elf cache."
This commit is contained in:
commit
bb4d172f70
11 changed files with 313 additions and 30 deletions
|
|
@ -124,6 +124,7 @@ cc_test {
|
||||||
"tests/DwarfOpTest.cpp",
|
"tests/DwarfOpTest.cpp",
|
||||||
"tests/DwarfSectionTest.cpp",
|
"tests/DwarfSectionTest.cpp",
|
||||||
"tests/DwarfSectionImplTest.cpp",
|
"tests/DwarfSectionImplTest.cpp",
|
||||||
|
"tests/ElfCacheTest.cpp",
|
||||||
"tests/ElfFake.cpp",
|
"tests/ElfFake.cpp",
|
||||||
"tests/ElfInterfaceArmTest.cpp",
|
"tests/ElfInterfaceArmTest.cpp",
|
||||||
"tests/ElfInterfaceTest.cpp",
|
"tests/ElfInterfaceTest.cpp",
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,10 @@
|
||||||
|
|
||||||
namespace unwindstack {
|
namespace unwindstack {
|
||||||
|
|
||||||
|
bool Elf::cache_enabled_;
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<Elf>>* Elf::cache_;
|
||||||
|
std::mutex* Elf::cache_lock_;
|
||||||
|
|
||||||
bool Elf::Init(bool init_gnu_debugdata) {
|
bool Elf::Init(bool init_gnu_debugdata) {
|
||||||
load_bias_ = 0;
|
load_bias_ = 0;
|
||||||
if (!memory_) {
|
if (!memory_) {
|
||||||
|
|
@ -301,4 +305,42 @@ uint64_t Elf::GetLoadBias(Memory* memory) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Elf::SetCachingEnabled(bool enable) {
|
||||||
|
if (!cache_enabled_ && enable) {
|
||||||
|
cache_enabled_ = true;
|
||||||
|
cache_ = new std::unordered_map<std::string, std::shared_ptr<Elf>>;
|
||||||
|
cache_lock_ = new std::mutex;
|
||||||
|
} else if (cache_enabled_ && !enable) {
|
||||||
|
cache_enabled_ = false;
|
||||||
|
delete cache_;
|
||||||
|
delete cache_lock_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Elf::CacheLock() {
|
||||||
|
cache_lock_->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Elf::CacheUnlock() {
|
||||||
|
cache_lock_->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Elf::CacheAdd(MapInfo* info) {
|
||||||
|
if (info->offset == 0) {
|
||||||
|
(*cache_)[info->name] = info->elf;
|
||||||
|
} else {
|
||||||
|
std::string name(info->name + ':' + std::to_string(info->offset));
|
||||||
|
(*cache_)[name] = info->elf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Elf::CacheGet(const std::string& name, std::shared_ptr<Elf>* elf) {
|
||||||
|
auto entry = cache_->find(name);
|
||||||
|
if (entry != cache_->end()) {
|
||||||
|
*elf = entry->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace unwindstack
|
} // namespace unwindstack
|
||||||
|
|
|
||||||
|
|
@ -109,16 +109,46 @@ Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gn
|
||||||
// Make sure no other thread is trying to add the elf to this map.
|
// Make sure no other thread is trying to add the elf to this map.
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
|
||||||
if (elf) {
|
if (elf.get() != nullptr) {
|
||||||
return elf;
|
return elf.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
elf = new Elf(CreateMemory(process_memory));
|
bool locked = false;
|
||||||
elf->Init(init_gnu_debugdata);
|
if (Elf::CachingEnabled() && !name.empty()) {
|
||||||
|
Elf::CacheLock();
|
||||||
|
locked = true;
|
||||||
|
if (offset != 0) {
|
||||||
|
std::string hash(name + ':' + std::to_string(offset));
|
||||||
|
if (Elf::CacheGet(hash, &elf)) {
|
||||||
|
Elf::CacheUnlock();
|
||||||
|
return elf.get();
|
||||||
|
}
|
||||||
|
} else if (Elf::CacheGet(name, &elf)) {
|
||||||
|
Elf::CacheUnlock();
|
||||||
|
return elf.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory* memory = CreateMemory(process_memory);
|
||||||
|
if (locked && offset != 0 && elf_offset != 0) {
|
||||||
|
// In this case, the whole file is the elf, need to see if the elf
|
||||||
|
// data was cached.
|
||||||
|
if (Elf::CacheGet(name, &elf)) {
|
||||||
|
delete memory;
|
||||||
|
Elf::CacheUnlock();
|
||||||
|
return elf.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elf.reset(new Elf(memory));
|
||||||
// If the init fails, keep the elf around as an invalid object so we
|
// If the init fails, keep the elf around as an invalid object so we
|
||||||
// don't try to reinit the object.
|
// don't try to reinit the object.
|
||||||
return elf;
|
elf->Init(init_gnu_debugdata);
|
||||||
|
|
||||||
|
if (locked) {
|
||||||
|
Elf::CacheAdd(this);
|
||||||
|
Elf::CacheUnlock();
|
||||||
|
}
|
||||||
|
return elf.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
|
uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <unwindstack/ElfInterface.h>
|
#include <unwindstack/ElfInterface.h>
|
||||||
#include <unwindstack/Memory.h>
|
#include <unwindstack/Memory.h>
|
||||||
|
|
@ -96,6 +97,14 @@ class Elf {
|
||||||
|
|
||||||
static uint64_t GetLoadBias(Memory* memory);
|
static uint64_t GetLoadBias(Memory* memory);
|
||||||
|
|
||||||
|
static void SetCachingEnabled(bool enable);
|
||||||
|
static bool CachingEnabled() { return cache_enabled_; }
|
||||||
|
|
||||||
|
static void CacheLock();
|
||||||
|
static void CacheUnlock();
|
||||||
|
static void CacheAdd(MapInfo* info);
|
||||||
|
static bool CacheGet(const std::string& name, std::shared_ptr<Elf>* elf);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool valid_ = false;
|
bool valid_ = false;
|
||||||
uint64_t load_bias_ = 0;
|
uint64_t load_bias_ = 0;
|
||||||
|
|
@ -109,6 +118,10 @@ class Elf {
|
||||||
|
|
||||||
std::unique_ptr<Memory> gnu_debugdata_memory_;
|
std::unique_ptr<Memory> gnu_debugdata_memory_;
|
||||||
std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
|
std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
|
||||||
|
|
||||||
|
static bool cache_enabled_;
|
||||||
|
static std::unordered_map<std::string, std::shared_ptr<Elf>>* cache_;
|
||||||
|
static std::mutex* cache_lock_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace unwindstack
|
} // namespace unwindstack
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
@ -40,14 +41,14 @@ struct MapInfo {
|
||||||
flags(flags),
|
flags(flags),
|
||||||
name(name),
|
name(name),
|
||||||
load_bias(static_cast<uint64_t>(-1)) {}
|
load_bias(static_cast<uint64_t>(-1)) {}
|
||||||
~MapInfo() { delete elf; }
|
~MapInfo() = default;
|
||||||
|
|
||||||
uint64_t start = 0;
|
uint64_t start = 0;
|
||||||
uint64_t end = 0;
|
uint64_t end = 0;
|
||||||
uint64_t offset = 0;
|
uint64_t offset = 0;
|
||||||
uint16_t flags = 0;
|
uint16_t flags = 0;
|
||||||
std::string name;
|
std::string name;
|
||||||
Elf* elf = nullptr;
|
std::shared_ptr<Elf> elf;
|
||||||
// This value is only non-zero if the offset is non-zero but there is
|
// This value is only non-zero if the offset is non-zero but there is
|
||||||
// no elf signature found at that offset. This indicates that the
|
// no elf signature found at that offset. This indicates that the
|
||||||
// entire file is represented by the Memory object returned by CreateMemory,
|
// entire file is represented by the Memory object returned by CreateMemory,
|
||||||
|
|
|
||||||
201
libunwindstack/tests/ElfCacheTest.cpp
Normal file
201
libunwindstack/tests/ElfCacheTest.cpp
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <android-base/file.h>
|
||||||
|
#include <android-base/test_utils.h>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <unwindstack/Elf.h>
|
||||||
|
#include <unwindstack/MapInfo.h>
|
||||||
|
|
||||||
|
#include "ElfTestUtils.h"
|
||||||
|
#include "MemoryFake.h"
|
||||||
|
|
||||||
|
namespace unwindstack {
|
||||||
|
|
||||||
|
class ElfCacheTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
static void SetUpTestCase() { memory_.reset(new MemoryFake); }
|
||||||
|
|
||||||
|
void SetUp() override { Elf::SetCachingEnabled(true); }
|
||||||
|
|
||||||
|
void TearDown() override { Elf::SetCachingEnabled(false); }
|
||||||
|
|
||||||
|
void WriteElfFile(uint64_t offset, TemporaryFile* tf, uint32_t type) {
|
||||||
|
ASSERT_TRUE(type == EM_ARM || type == EM_386 || type == EM_X86_64);
|
||||||
|
size_t ehdr_size;
|
||||||
|
Elf32_Ehdr ehdr32;
|
||||||
|
Elf64_Ehdr ehdr64;
|
||||||
|
void* ptr;
|
||||||
|
if (type == EM_ARM || type == EM_386) {
|
||||||
|
ehdr_size = sizeof(ehdr32);
|
||||||
|
ptr = &ehdr32;
|
||||||
|
TestInitEhdr(&ehdr32, ELFCLASS32, type);
|
||||||
|
} else {
|
||||||
|
ehdr_size = sizeof(ehdr64);
|
||||||
|
ptr = &ehdr64;
|
||||||
|
TestInitEhdr(&ehdr64, ELFCLASS64, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(offset, static_cast<uint64_t>(lseek(tf->fd, offset, SEEK_SET)));
|
||||||
|
ASSERT_TRUE(android::base::WriteFully(tf->fd, ptr, ehdr_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerifyWithinSameMap(bool cache_enabled);
|
||||||
|
void VerifySameMap(bool cache_enabled);
|
||||||
|
|
||||||
|
static std::shared_ptr<Memory> memory_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<Memory> ElfCacheTest::memory_;
|
||||||
|
|
||||||
|
void ElfCacheTest::VerifySameMap(bool cache_enabled) {
|
||||||
|
if (!cache_enabled) {
|
||||||
|
Elf::SetCachingEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile tf;
|
||||||
|
ASSERT_TRUE(tf.fd != -1);
|
||||||
|
WriteElfFile(0, &tf, EM_ARM);
|
||||||
|
close(tf.fd);
|
||||||
|
|
||||||
|
uint64_t start = 0x1000;
|
||||||
|
uint64_t end = 0x20000;
|
||||||
|
MapInfo info1(start, end, 0, 0x5, tf.path);
|
||||||
|
MapInfo info2(start, end, 0, 0x5, tf.path);
|
||||||
|
|
||||||
|
Elf* elf1 = info1.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf1->valid());
|
||||||
|
Elf* elf2 = info2.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf2->valid());
|
||||||
|
|
||||||
|
if (cache_enabled) {
|
||||||
|
EXPECT_EQ(elf1, elf2);
|
||||||
|
} else {
|
||||||
|
EXPECT_NE(elf1, elf2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ElfCacheTest, no_caching) {
|
||||||
|
VerifySameMap(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ElfCacheTest, caching_invalid_elf) {
|
||||||
|
VerifySameMap(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
|
||||||
|
if (!cache_enabled) {
|
||||||
|
Elf::SetCachingEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile tf;
|
||||||
|
ASSERT_TRUE(tf.fd != -1);
|
||||||
|
WriteElfFile(0, &tf, EM_ARM);
|
||||||
|
WriteElfFile(0x100, &tf, EM_386);
|
||||||
|
WriteElfFile(0x200, &tf, EM_X86_64);
|
||||||
|
lseek(tf.fd, 0x500, SEEK_SET);
|
||||||
|
uint8_t value = 0;
|
||||||
|
write(tf.fd, &value, 1);
|
||||||
|
close(tf.fd);
|
||||||
|
|
||||||
|
uint64_t start = 0x1000;
|
||||||
|
uint64_t end = 0x20000;
|
||||||
|
// Will have an elf at offset 0 in file.
|
||||||
|
MapInfo info0_1(start, end, 0, 0x5, tf.path);
|
||||||
|
MapInfo info0_2(start, end, 0, 0x5, tf.path);
|
||||||
|
// Will have an elf at offset 0x100 in file.
|
||||||
|
MapInfo info100_1(start, end, 0x100, 0x5, tf.path);
|
||||||
|
MapInfo info100_2(start, end, 0x100, 0x5, tf.path);
|
||||||
|
// Will have an elf at offset 0x200 in file.
|
||||||
|
MapInfo info200_1(start, end, 0x200, 0x5, tf.path);
|
||||||
|
MapInfo info200_2(start, end, 0x200, 0x5, tf.path);
|
||||||
|
// Will have an elf at offset 0 in file.
|
||||||
|
MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
|
||||||
|
MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
|
||||||
|
|
||||||
|
Elf* elf0_1 = info0_1.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf0_1->valid());
|
||||||
|
EXPECT_EQ(ARCH_ARM, elf0_1->arch());
|
||||||
|
Elf* elf0_2 = info0_2.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf0_2->valid());
|
||||||
|
EXPECT_EQ(ARCH_ARM, elf0_2->arch());
|
||||||
|
EXPECT_EQ(0U, info0_1.elf_offset);
|
||||||
|
EXPECT_EQ(0U, info0_2.elf_offset);
|
||||||
|
if (cache_enabled) {
|
||||||
|
EXPECT_EQ(elf0_1, elf0_2);
|
||||||
|
} else {
|
||||||
|
EXPECT_NE(elf0_1, elf0_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf* elf100_1 = info100_1.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf100_1->valid());
|
||||||
|
EXPECT_EQ(ARCH_X86, elf100_1->arch());
|
||||||
|
Elf* elf100_2 = info100_2.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf100_2->valid());
|
||||||
|
EXPECT_EQ(ARCH_X86, elf100_2->arch());
|
||||||
|
EXPECT_EQ(0U, info100_1.elf_offset);
|
||||||
|
EXPECT_EQ(0U, info100_2.elf_offset);
|
||||||
|
if (cache_enabled) {
|
||||||
|
EXPECT_EQ(elf100_1, elf100_2);
|
||||||
|
} else {
|
||||||
|
EXPECT_NE(elf100_1, elf100_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf* elf200_1 = info200_1.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf200_1->valid());
|
||||||
|
EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
|
||||||
|
Elf* elf200_2 = info200_2.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf200_2->valid());
|
||||||
|
EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
|
||||||
|
EXPECT_EQ(0U, info200_1.elf_offset);
|
||||||
|
EXPECT_EQ(0U, info200_2.elf_offset);
|
||||||
|
if (cache_enabled) {
|
||||||
|
EXPECT_EQ(elf200_1, elf200_2);
|
||||||
|
} else {
|
||||||
|
EXPECT_NE(elf200_1, elf200_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf* elf300_1 = info300_1.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf300_1->valid());
|
||||||
|
EXPECT_EQ(ARCH_ARM, elf300_1->arch());
|
||||||
|
Elf* elf300_2 = info300_2.GetElf(memory_, true);
|
||||||
|
ASSERT_TRUE(elf300_2->valid());
|
||||||
|
EXPECT_EQ(ARCH_ARM, elf300_2->arch());
|
||||||
|
EXPECT_EQ(0x300U, info300_1.elf_offset);
|
||||||
|
EXPECT_EQ(0x300U, info300_2.elf_offset);
|
||||||
|
if (cache_enabled) {
|
||||||
|
EXPECT_EQ(elf300_1, elf300_2);
|
||||||
|
EXPECT_EQ(elf0_1, elf300_1);
|
||||||
|
} else {
|
||||||
|
EXPECT_NE(elf300_1, elf300_2);
|
||||||
|
EXPECT_NE(elf0_1, elf300_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero) {
|
||||||
|
VerifyWithinSameMap(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero) {
|
||||||
|
VerifyWithinSameMap(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace unwindstack
|
||||||
|
|
@ -62,7 +62,7 @@ class JitDebugTest : public ::testing::Test {
|
||||||
ElfInterfaceFake* interface = new ElfInterfaceFake(elf_memories_.back());
|
ElfInterfaceFake* interface = new ElfInterfaceFake(elf_memories_.back());
|
||||||
elf->FakeSetInterface(interface);
|
elf->FakeSetInterface(interface);
|
||||||
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
||||||
map_info->elf = elf;
|
map_info->elf.reset(elf);
|
||||||
|
|
||||||
map_info = maps_->Get(5);
|
map_info = maps_->Get(5);
|
||||||
ASSERT_TRUE(map_info != nullptr);
|
ASSERT_TRUE(map_info != nullptr);
|
||||||
|
|
@ -72,7 +72,7 @@ class JitDebugTest : public ::testing::Test {
|
||||||
interface = new ElfInterfaceFake(elf_memories_.back());
|
interface = new ElfInterfaceFake(elf_memories_.back());
|
||||||
elf->FakeSetInterface(interface);
|
elf->FakeSetInterface(interface);
|
||||||
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
||||||
map_info->elf = elf;
|
map_info->elf.reset(elf);
|
||||||
|
|
||||||
map_info = maps_->Get(6);
|
map_info = maps_->Get(6);
|
||||||
ASSERT_TRUE(map_info != nullptr);
|
ASSERT_TRUE(map_info != nullptr);
|
||||||
|
|
@ -82,7 +82,7 @@ class JitDebugTest : public ::testing::Test {
|
||||||
interface = new ElfInterfaceFake(elf_memories_.back());
|
interface = new ElfInterfaceFake(elf_memories_.back());
|
||||||
elf->FakeSetInterface(interface);
|
elf->FakeSetInterface(interface);
|
||||||
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
||||||
map_info->elf = elf;
|
map_info->elf.reset(elf);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename EhdrType, typename ShdrType>
|
template <typename EhdrType, typename ShdrType>
|
||||||
|
|
|
||||||
|
|
@ -180,16 +180,14 @@ TEST_F(MapInfoGetElfTest, end_le_start) {
|
||||||
ASSERT_TRUE(elf != nullptr);
|
ASSERT_TRUE(elf != nullptr);
|
||||||
ASSERT_FALSE(elf->valid());
|
ASSERT_FALSE(elf->valid());
|
||||||
|
|
||||||
delete info.elf;
|
info.elf.reset();
|
||||||
info.elf = nullptr;
|
|
||||||
info.end = 0xfff;
|
info.end = 0xfff;
|
||||||
elf = info.GetElf(process_memory_, false);
|
elf = info.GetElf(process_memory_, false);
|
||||||
ASSERT_TRUE(elf != nullptr);
|
ASSERT_TRUE(elf != nullptr);
|
||||||
ASSERT_FALSE(elf->valid());
|
ASSERT_FALSE(elf->valid());
|
||||||
|
|
||||||
// Make sure this test is valid.
|
// Make sure this test is valid.
|
||||||
delete info.elf;
|
info.elf.reset();
|
||||||
info.elf = nullptr;
|
|
||||||
info.end = 0x2000;
|
info.end = 0x2000;
|
||||||
elf = info.GetElf(process_memory_, false);
|
elf = info.GetElf(process_memory_, false);
|
||||||
ASSERT_TRUE(elf != nullptr);
|
ASSERT_TRUE(elf != nullptr);
|
||||||
|
|
@ -328,8 +326,7 @@ TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
|
||||||
ASSERT_TRUE(elf != nullptr);
|
ASSERT_TRUE(elf != nullptr);
|
||||||
ASSERT_FALSE(elf->valid());
|
ASSERT_FALSE(elf->valid());
|
||||||
|
|
||||||
delete info.elf;
|
info.elf.reset();
|
||||||
info.elf = nullptr;
|
|
||||||
info.flags = PROT_READ;
|
info.flags = PROT_READ;
|
||||||
elf = info.GetElf(process_memory_, false);
|
elf = info.GetElf(process_memory_, false);
|
||||||
ASSERT_TRUE(elf->valid());
|
ASSERT_TRUE(elf->valid());
|
||||||
|
|
@ -352,15 +349,13 @@ TEST_F(MapInfoGetElfTest, check_device_maps) {
|
||||||
ASSERT_FALSE(elf->valid());
|
ASSERT_FALSE(elf->valid());
|
||||||
|
|
||||||
// Set the name to nothing to verify that it still fails.
|
// Set the name to nothing to verify that it still fails.
|
||||||
delete info.elf;
|
info.elf.reset();
|
||||||
info.elf = nullptr;
|
|
||||||
info.name = "";
|
info.name = "";
|
||||||
elf = info.GetElf(process_memory_, false);
|
elf = info.GetElf(process_memory_, false);
|
||||||
ASSERT_FALSE(elf->valid());
|
ASSERT_FALSE(elf->valid());
|
||||||
|
|
||||||
// Change the flags and verify the elf is valid now.
|
// Change the flags and verify the elf is valid now.
|
||||||
delete info.elf;
|
info.elf.reset();
|
||||||
info.elf = nullptr;
|
|
||||||
info.flags = PROT_READ;
|
info.flags = PROT_READ;
|
||||||
elf = info.GetElf(process_memory_, false);
|
elf = info.GetElf(process_memory_, false);
|
||||||
ASSERT_TRUE(elf->valid());
|
ASSERT_TRUE(elf->valid());
|
||||||
|
|
@ -403,7 +398,7 @@ TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now verify that all of the elf files are exactly the same and valid.
|
// Now verify that all of the elf files are exactly the same and valid.
|
||||||
Elf* elf = info.elf;
|
Elf* elf = info.elf.get();
|
||||||
ASSERT_TRUE(elf != nullptr);
|
ASSERT_TRUE(elf != nullptr);
|
||||||
EXPECT_TRUE(elf->valid());
|
EXPECT_TRUE(elf->valid());
|
||||||
for (size_t i = 0; i < kNumConcurrentThreads; i++) {
|
for (size_t i = 0; i < kNumConcurrentThreads; i++) {
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ TEST_F(MapInfoGetLoadBiasTest, no_elf_and_no_valid_elf_in_memory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MapInfoGetLoadBiasTest, load_bias_cached_from_elf) {
|
TEST_F(MapInfoGetLoadBiasTest, load_bias_cached_from_elf) {
|
||||||
map_info_->elf = elf_container_.release();
|
map_info_->elf.reset(elf_container_.release());
|
||||||
|
|
||||||
elf_->FakeSetLoadBias(0);
|
elf_->FakeSetLoadBias(0);
|
||||||
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
|
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
|
||||||
|
|
@ -79,7 +79,7 @@ TEST_F(MapInfoGetLoadBiasTest, load_bias_cached_from_elf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MapInfoGetLoadBiasTest, elf_exists) {
|
TEST_F(MapInfoGetLoadBiasTest, elf_exists) {
|
||||||
map_info_->elf = elf_container_.release();
|
map_info_->elf.reset(elf_container_.release());
|
||||||
|
|
||||||
elf_->FakeSetLoadBias(0);
|
elf_->FakeSetLoadBias(0);
|
||||||
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
|
EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
|
||||||
|
|
@ -122,7 +122,7 @@ void MapInfoGetLoadBiasTest::MultipleThreadTest(uint64_t expected_load_bias) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists) {
|
TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists) {
|
||||||
map_info_->elf = elf_container_.release();
|
map_info_->elf.reset(elf_container_.release());
|
||||||
elf_->FakeSetLoadBias(0x1000);
|
elf_->FakeSetLoadBias(0x1000);
|
||||||
|
|
||||||
MultipleThreadTest(0x1000);
|
MultipleThreadTest(0x1000);
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ TEST_F(RegsTest, elf_invalid) {
|
||||||
RegsMips64 regs_mips64;
|
RegsMips64 regs_mips64;
|
||||||
MapInfo map_info(0x1000, 0x2000);
|
MapInfo map_info(0x1000, 0x2000);
|
||||||
Elf* invalid_elf = new Elf(new MemoryFake);
|
Elf* invalid_elf = new Elf(new MemoryFake);
|
||||||
map_info.elf = invalid_elf;
|
map_info.elf.reset(invalid_elf);
|
||||||
|
|
||||||
regs_arm.set_pc(0x1500);
|
regs_arm.set_pc(0x1500);
|
||||||
EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
|
EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ class UnwinderTest : public ::testing::Test {
|
||||||
maps_.FakeClear();
|
maps_.FakeClear();
|
||||||
MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
|
MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
|
||||||
ElfFake* elf = new ElfFake(new MemoryFake);
|
ElfFake* elf = new ElfFake(new MemoryFake);
|
||||||
info->elf = elf;
|
info->elf.reset(elf);
|
||||||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
||||||
maps_.FakeAddMapInfo(info);
|
maps_.FakeAddMapInfo(info);
|
||||||
|
|
||||||
|
|
@ -73,25 +73,25 @@ class UnwinderTest : public ::testing::Test {
|
||||||
|
|
||||||
info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
|
info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
|
||||||
elf = new ElfFake(new MemoryFake);
|
elf = new ElfFake(new MemoryFake);
|
||||||
info->elf = elf;
|
info->elf.reset(elf);
|
||||||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
||||||
maps_.FakeAddMapInfo(info);
|
maps_.FakeAddMapInfo(info);
|
||||||
|
|
||||||
info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
|
info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
|
||||||
elf = new ElfFake(new MemoryFake);
|
elf = new ElfFake(new MemoryFake);
|
||||||
info->elf = elf;
|
info->elf.reset(elf);
|
||||||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
||||||
maps_.FakeAddMapInfo(info);
|
maps_.FakeAddMapInfo(info);
|
||||||
|
|
||||||
info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
|
info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
|
||||||
elf = new ElfFake(new MemoryFake);
|
elf = new ElfFake(new MemoryFake);
|
||||||
info->elf = elf;
|
info->elf.reset(elf);
|
||||||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
||||||
maps_.FakeAddMapInfo(info);
|
maps_.FakeAddMapInfo(info);
|
||||||
|
|
||||||
info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
|
info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
|
||||||
elf = new ElfFake(new MemoryFake);
|
elf = new ElfFake(new MemoryFake);
|
||||||
info->elf = elf;
|
info->elf.reset(elf);
|
||||||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
||||||
maps_.FakeAddMapInfo(info);
|
maps_.FakeAddMapInfo(info);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue