Verify that the elf matches the expected arch.
To avoid a case where a malicious app might try and trick the system to create an elf and register object that mismatches, always verify that they are the same arch. Test: Ran unit tests. Change-Id: I66978e9e02f8e4f396856912e7019528ead4838e
This commit is contained in:
parent
2a8460721c
commit
4568f4bc0f
19 changed files with 164 additions and 106 deletions
|
@ -49,6 +49,7 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
|
|||
unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
|
||||
regs, stack_map->process_memory());
|
||||
unwinder.SetResolveNames(stack_map->ResolveNames());
|
||||
stack_map->SetArch(regs->Arch());
|
||||
if (stack_map->GetJitDebug() != nullptr) {
|
||||
unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Maps.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
#include "UnwindStackMap.h"
|
||||
|
||||
|
@ -106,7 +107,17 @@ std::string UnwindStackMap::GetFunctionName(uint64_t pc, uint64_t* offset) {
|
|||
return "";
|
||||
}
|
||||
|
||||
unwindstack::Elf* elf = map_info->GetElf(process_memory());
|
||||
if (arch_ == unwindstack::ARCH_UNKNOWN) {
|
||||
if (pid_ == getpid()) {
|
||||
arch_ = unwindstack::Regs::CurrentArch();
|
||||
} else {
|
||||
// Create a remote regs, to figure out the architecture.
|
||||
std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::RemoteGet(pid_));
|
||||
arch_ = regs->Arch();
|
||||
}
|
||||
}
|
||||
|
||||
unwindstack::Elf* elf = map_info->GetElf(process_memory(), arch_);
|
||||
|
||||
std::string name;
|
||||
uint64_t func_offset;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#if !defined(NO_LIBDEXFILE_SUPPORT)
|
||||
#include <unwindstack/DexFiles.h>
|
||||
#endif
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/JitDebug.h>
|
||||
#include <unwindstack/Maps.h>
|
||||
|
||||
|
@ -58,6 +59,8 @@ class UnwindStackMap : public BacktraceMap {
|
|||
unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
|
||||
#endif
|
||||
|
||||
void SetArch(unwindstack::ArchEnum arch) { arch_ = arch; }
|
||||
|
||||
protected:
|
||||
uint64_t GetLoadBias(size_t index) override;
|
||||
|
||||
|
@ -67,6 +70,8 @@ class UnwindStackMap : public BacktraceMap {
|
|||
#if !defined(NO_LIBDEXFILE_SUPPORT)
|
||||
std::unique_ptr<unwindstack::DexFiles> dex_files_;
|
||||
#endif
|
||||
|
||||
unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN;
|
||||
};
|
||||
|
||||
class UnwindStackOfflineMap : public UnwindStackMap {
|
||||
|
|
|
@ -54,8 +54,8 @@ DexFiles::~DexFiles() {
|
|||
}
|
||||
}
|
||||
|
||||
void DexFiles::SetArch(ArchEnum arch) {
|
||||
switch (arch) {
|
||||
void DexFiles::ProcessArch() {
|
||||
switch (arch()) {
|
||||
case ARCH_ARM:
|
||||
case ARCH_MIPS:
|
||||
case ARCH_X86:
|
||||
|
|
|
@ -88,6 +88,11 @@ void Elf::InitGnuDebugdata() {
|
|||
}
|
||||
}
|
||||
|
||||
void Elf::Invalidate() {
|
||||
interface_.reset(nullptr);
|
||||
valid_ = false;
|
||||
}
|
||||
|
||||
bool Elf::GetSoname(std::string* name) {
|
||||
std::lock_guard<std::mutex> guard(lock_);
|
||||
return valid_ && interface_->GetSoname(name);
|
||||
|
|
|
@ -31,6 +31,13 @@ Global::Global(std::shared_ptr<Memory>& memory) : memory_(memory) {}
|
|||
Global::Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
|
||||
: memory_(memory), search_libs_(search_libs) {}
|
||||
|
||||
void Global::SetArch(ArchEnum arch) {
|
||||
if (arch_ == ARCH_UNKNOWN) {
|
||||
arch_ = arch;
|
||||
ProcessArch();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) {
|
||||
if (!search_libs_.empty()) {
|
||||
bool found = false;
|
||||
|
@ -46,7 +53,7 @@ uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) {
|
|||
}
|
||||
}
|
||||
|
||||
Elf* elf = info->GetElf(memory_);
|
||||
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) {
|
||||
|
|
|
@ -141,8 +141,8 @@ uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) {
|
|||
return code.next;
|
||||
}
|
||||
|
||||
void JitDebug::SetArch(ArchEnum arch) {
|
||||
switch (arch) {
|
||||
void JitDebug::ProcessArch() {
|
||||
switch (arch()) {
|
||||
case ARCH_X86:
|
||||
read_descriptor_func_ = &JitDebug::ReadDescriptor32;
|
||||
read_entry_func_ = &JitDebug::ReadEntry32Pack;
|
||||
|
|
|
@ -88,6 +88,7 @@ MapInfo* LocalUnwinder::GetMapInfo(uint64_t pc) {
|
|||
bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames) {
|
||||
std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
|
||||
unwindstack::RegsGetLocal(regs.get());
|
||||
ArchEnum arch = regs->Arch();
|
||||
|
||||
size_t num_frames = 0;
|
||||
bool adjust_pc = false;
|
||||
|
@ -100,7 +101,7 @@ bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_f
|
|||
break;
|
||||
}
|
||||
|
||||
Elf* elf = map_info->GetElf(process_memory_);
|
||||
Elf* elf = map_info->GetElf(process_memory_, arch);
|
||||
uint64_t rel_pc = elf->GetRelPc(cur_pc, map_info);
|
||||
uint64_t step_pc = rel_pc;
|
||||
uint64_t pc_adjustment;
|
||||
|
|
|
@ -146,7 +146,7 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory) {
|
||||
Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) {
|
||||
// Make sure no other thread is trying to add the elf to this map.
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
|
||||
|
@ -176,6 +176,10 @@ Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory) {
|
|||
// If the init fails, keep the elf around as an invalid object so we
|
||||
// don't try to reinit the object.
|
||||
elf->Init();
|
||||
if (elf->valid() && expected_arch != elf->arch()) {
|
||||
// Make the elf invalid, mismatch between arch and expected arch.
|
||||
elf->Invalidate();
|
||||
}
|
||||
|
||||
if (locked) {
|
||||
Elf::CacheAdd(this);
|
||||
|
|
|
@ -135,6 +135,8 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
|||
last_error_.code = ERROR_NONE;
|
||||
last_error_.address = 0;
|
||||
|
||||
ArchEnum arch = regs_->Arch();
|
||||
|
||||
bool return_address_attempt = false;
|
||||
bool adjust_pc = false;
|
||||
std::unique_ptr<JitDebug> jit_debug;
|
||||
|
@ -155,7 +157,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
|||
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
|
||||
break;
|
||||
}
|
||||
elf = map_info->GetElf(process_memory_);
|
||||
elf = map_info->GetElf(process_memory_, arch);
|
||||
step_pc = regs_->pc();
|
||||
rel_pc = elf->GetRelPc(step_pc, map_info);
|
||||
// Everyone except elf data in gdb jit debug maps uses the relative pc.
|
||||
|
|
|
@ -47,8 +47,6 @@ class DexFiles : public Global {
|
|||
void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name,
|
||||
uint64_t* method_offset);
|
||||
|
||||
void SetArch(ArchEnum arch);
|
||||
|
||||
private:
|
||||
void Init(Maps* maps);
|
||||
|
||||
|
@ -64,6 +62,8 @@ class DexFiles : public Global {
|
|||
|
||||
bool ReadVariableData(uint64_t ptr_offset) override;
|
||||
|
||||
void ProcessArch() override;
|
||||
|
||||
std::mutex lock_;
|
||||
bool initialized_ = false;
|
||||
std::unordered_map<uint64_t, DexFile*> files_;
|
||||
|
|
|
@ -57,6 +57,8 @@ class Elf {
|
|||
|
||||
void InitGnuDebugdata();
|
||||
|
||||
void Invalidate();
|
||||
|
||||
bool GetSoname(std::string* name);
|
||||
|
||||
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
@ -39,12 +40,20 @@ class Global {
|
|||
Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
|
||||
virtual ~Global() = default;
|
||||
|
||||
void SetArch(ArchEnum arch);
|
||||
|
||||
ArchEnum arch() { return arch_; }
|
||||
|
||||
protected:
|
||||
uint64_t GetVariableOffset(MapInfo* info, const std::string& variable);
|
||||
void FindAndReadVariable(Maps* maps, const char* variable);
|
||||
|
||||
virtual bool ReadVariableData(uint64_t offset) = 0;
|
||||
|
||||
virtual void ProcessArch() = 0;
|
||||
|
||||
ArchEnum arch_ = ARCH_UNKNOWN;
|
||||
|
||||
std::shared_ptr<Memory> memory_;
|
||||
std::vector<std::string> search_libs_;
|
||||
};
|
||||
|
|
|
@ -42,17 +42,9 @@ class JitDebug : public Global {
|
|||
|
||||
Elf* GetElf(Maps* maps, uint64_t pc);
|
||||
|
||||
void SetArch(ArchEnum arch);
|
||||
|
||||
private:
|
||||
void Init(Maps* maps);
|
||||
|
||||
uint64_t entry_addr_ = 0;
|
||||
bool initialized_ = false;
|
||||
std::vector<Elf*> elf_list_;
|
||||
|
||||
std::mutex lock_;
|
||||
|
||||
uint64_t (JitDebug::*read_descriptor_func_)(uint64_t) = nullptr;
|
||||
uint64_t (JitDebug::*read_entry_func_)(uint64_t*, uint64_t*) = nullptr;
|
||||
|
||||
|
@ -64,6 +56,14 @@ class JitDebug : public Global {
|
|||
uint64_t ReadEntry64(uint64_t* start, uint64_t* size);
|
||||
|
||||
bool ReadVariableData(uint64_t ptr_offset) override;
|
||||
|
||||
void ProcessArch() override;
|
||||
|
||||
uint64_t entry_addr_ = 0;
|
||||
bool initialized_ = false;
|
||||
std::vector<Elf*> elf_list_;
|
||||
|
||||
std::mutex lock_;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
@ -72,7 +72,7 @@ struct MapInfo {
|
|||
std::atomic_uint64_t load_bias;
|
||||
|
||||
// This function guarantees it will never return nullptr.
|
||||
Elf* GetElf(const std::shared_ptr<Memory>& process_memory);
|
||||
Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
|
||||
|
||||
uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);
|
||||
|
||||
|
|
|
@ -36,12 +36,20 @@ namespace unwindstack {
|
|||
|
||||
class DexFilesTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
memory_ = new MemoryFake;
|
||||
process_memory_.reset(memory_);
|
||||
void CreateFakeElf(MapInfo* map_info) {
|
||||
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);
|
||||
map_info->elf.reset(elf);
|
||||
}
|
||||
|
||||
void Init(ArchEnum arch) {
|
||||
dex_files_.reset(new DexFiles(process_memory_));
|
||||
dex_files_->SetArch(ARCH_ARM);
|
||||
dex_files_->SetArch(arch);
|
||||
|
||||
maps_.reset(
|
||||
new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
|
||||
|
@ -58,35 +66,24 @@ 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);
|
||||
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);
|
||||
map_info->elf.reset(elf);
|
||||
CreateFakeElf(map_info);
|
||||
|
||||
// Global variable not set by default.
|
||||
map_info = maps_->Get(kMapGlobalSetToZero);
|
||||
ASSERT_TRUE(map_info != nullptr);
|
||||
memory = new MemoryFake;
|
||||
elf = new ElfFake(memory);
|
||||
elf->FakeSetValid(true);
|
||||
interface = new ElfInterfaceFake(memory);
|
||||
elf->FakeSetInterface(interface);
|
||||
interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
|
||||
map_info->elf.reset(elf);
|
||||
CreateFakeElf(map_info);
|
||||
|
||||
// Global variable set in this map.
|
||||
map_info = maps_->Get(kMapGlobal);
|
||||
ASSERT_TRUE(map_info != nullptr);
|
||||
memory = new MemoryFake;
|
||||
elf = new ElfFake(memory);
|
||||
elf->FakeSetValid(true);
|
||||
interface = new ElfInterfaceFake(memory);
|
||||
elf->FakeSetInterface(interface);
|
||||
interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
|
||||
map_info->elf.reset(elf);
|
||||
CreateFakeElf(map_info);
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
memory_ = new MemoryFake;
|
||||
process_memory_.reset(memory_);
|
||||
|
||||
Init(ARCH_ARM);
|
||||
}
|
||||
|
||||
void WriteDescriptor32(uint64_t addr, uint32_t head);
|
||||
|
@ -169,11 +166,12 @@ TEST_F(DexFilesTest, get_method_information_32) {
|
|||
}
|
||||
|
||||
TEST_F(DexFilesTest, get_method_information_64) {
|
||||
Init(ARCH_ARM64);
|
||||
|
||||
std::string method_name = "nothing";
|
||||
uint64_t method_offset = 0x124;
|
||||
MapInfo* info = maps_->Get(kMapDexFiles);
|
||||
|
||||
dex_files_->SetArch(ARCH_ARM64);
|
||||
WriteDescriptor64(0xf800, 0x200000);
|
||||
WriteEntry64(0x200000, 0, 0, 0x301000);
|
||||
WriteDex(0x301000);
|
||||
|
@ -199,11 +197,12 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
|
|||
}
|
||||
|
||||
TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
|
||||
Init(ARCH_ARM64);
|
||||
|
||||
std::string method_name = "nothing";
|
||||
uint64_t method_offset = 0x124;
|
||||
MapInfo* info = maps_->Get(kMapDexFiles);
|
||||
|
||||
dex_files_->SetArch(ARCH_ARM64);
|
||||
WriteDescriptor64(0xf800, 0x200000);
|
||||
WriteEntry64(0x200000, 0x200100, 0, 0x100000);
|
||||
WriteEntry64(0x200100, 0, 0x200000, 0x300000);
|
||||
|
@ -297,6 +296,8 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
|
|||
}
|
||||
|
||||
TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
|
||||
Init(ARCH_ARM64);
|
||||
|
||||
std::string method_name = "nothing";
|
||||
uint64_t method_offset = 0x124;
|
||||
MapInfo* info = maps_->Get(kMapDexFiles);
|
||||
|
@ -308,7 +309,6 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
|
|||
WriteEntry64(0x200000, 0, 0, 0x300000);
|
||||
WriteDex(0x300000);
|
||||
|
||||
dex_files_->SetArch(ARCH_ARM64);
|
||||
dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
|
||||
EXPECT_EQ("Main.<init>", method_name);
|
||||
EXPECT_EQ(0U, method_offset);
|
||||
|
|
|
@ -82,9 +82,9 @@ void ElfCacheTest::VerifySameMap(bool cache_enabled) {
|
|||
MapInfo info1(nullptr, start, end, 0, 0x5, tf.path);
|
||||
MapInfo info2(nullptr, start, end, 0, 0x5, tf.path);
|
||||
|
||||
Elf* elf1 = info1.GetElf(memory_);
|
||||
Elf* elf1 = info1.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf1->valid());
|
||||
Elf* elf2 = info2.GetElf(memory_);
|
||||
Elf* elf2 = info2.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf2->valid());
|
||||
|
||||
if (cache_enabled) {
|
||||
|
@ -132,10 +132,10 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
|
|||
MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path);
|
||||
MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path);
|
||||
|
||||
Elf* elf0_1 = info0_1.GetElf(memory_);
|
||||
Elf* elf0_1 = info0_1.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf0_1->valid());
|
||||
EXPECT_EQ(ARCH_ARM, elf0_1->arch());
|
||||
Elf* elf0_2 = info0_2.GetElf(memory_);
|
||||
Elf* elf0_2 = info0_2.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf0_2->valid());
|
||||
EXPECT_EQ(ARCH_ARM, elf0_2->arch());
|
||||
EXPECT_EQ(0U, info0_1.elf_offset);
|
||||
|
@ -146,10 +146,10 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
|
|||
EXPECT_NE(elf0_1, elf0_2);
|
||||
}
|
||||
|
||||
Elf* elf100_1 = info100_1.GetElf(memory_);
|
||||
Elf* elf100_1 = info100_1.GetElf(memory_, ARCH_X86);
|
||||
ASSERT_TRUE(elf100_1->valid());
|
||||
EXPECT_EQ(ARCH_X86, elf100_1->arch());
|
||||
Elf* elf100_2 = info100_2.GetElf(memory_);
|
||||
Elf* elf100_2 = info100_2.GetElf(memory_, ARCH_X86);
|
||||
ASSERT_TRUE(elf100_2->valid());
|
||||
EXPECT_EQ(ARCH_X86, elf100_2->arch());
|
||||
EXPECT_EQ(0U, info100_1.elf_offset);
|
||||
|
@ -160,10 +160,10 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
|
|||
EXPECT_NE(elf100_1, elf100_2);
|
||||
}
|
||||
|
||||
Elf* elf200_1 = info200_1.GetElf(memory_);
|
||||
Elf* elf200_1 = info200_1.GetElf(memory_, ARCH_X86_64);
|
||||
ASSERT_TRUE(elf200_1->valid());
|
||||
EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
|
||||
Elf* elf200_2 = info200_2.GetElf(memory_);
|
||||
Elf* elf200_2 = info200_2.GetElf(memory_, ARCH_X86_64);
|
||||
ASSERT_TRUE(elf200_2->valid());
|
||||
EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
|
||||
EXPECT_EQ(0U, info200_1.elf_offset);
|
||||
|
@ -174,10 +174,10 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
|
|||
EXPECT_NE(elf200_1, elf200_2);
|
||||
}
|
||||
|
||||
Elf* elf300_1 = info300_1.GetElf(memory_);
|
||||
Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf300_1->valid());
|
||||
EXPECT_EQ(ARCH_ARM, elf300_1->arch());
|
||||
Elf* elf300_2 = info300_2.GetElf(memory_);
|
||||
Elf* elf300_2 = info300_2.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf300_2->valid());
|
||||
EXPECT_EQ(ARCH_ARM, elf300_2->arch());
|
||||
EXPECT_EQ(0x300U, info300_1.elf_offset);
|
||||
|
@ -222,10 +222,10 @@ void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) {
|
|||
MapInfo info400_1(nullptr, start, end, 0x400, 0x5, tf.path);
|
||||
MapInfo info400_2(nullptr, start, end, 0x400, 0x5, tf.path);
|
||||
|
||||
Elf* elf300_1 = info300_1.GetElf(memory_);
|
||||
Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf300_1->valid());
|
||||
EXPECT_EQ(ARCH_ARM, elf300_1->arch());
|
||||
Elf* elf300_2 = info300_2.GetElf(memory_);
|
||||
Elf* elf300_2 = info300_2.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf300_2->valid());
|
||||
EXPECT_EQ(ARCH_ARM, elf300_2->arch());
|
||||
EXPECT_EQ(0x300U, info300_1.elf_offset);
|
||||
|
@ -236,10 +236,10 @@ void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) {
|
|||
EXPECT_NE(elf300_1, elf300_2);
|
||||
}
|
||||
|
||||
Elf* elf400_1 = info400_1.GetElf(memory_);
|
||||
Elf* elf400_1 = info400_1.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf400_1->valid());
|
||||
EXPECT_EQ(ARCH_ARM, elf400_1->arch());
|
||||
Elf* elf400_2 = info400_2.GetElf(memory_);
|
||||
Elf* elf400_2 = info400_2.GetElf(memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf400_2->valid());
|
||||
EXPECT_EQ(ARCH_ARM, elf400_2->arch());
|
||||
EXPECT_EQ(0x400U, info400_1.elf_offset);
|
||||
|
|
|
@ -35,12 +35,19 @@ namespace unwindstack {
|
|||
|
||||
class JitDebugTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
memory_ = new MemoryFake;
|
||||
process_memory_.reset(memory_);
|
||||
void CreateFakeElf(MapInfo* map_info) {
|
||||
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);
|
||||
map_info->elf.reset(elf);
|
||||
}
|
||||
|
||||
void Init(ArchEnum arch) {
|
||||
jit_debug_.reset(new JitDebug(process_memory_));
|
||||
jit_debug_->SetArch(ARCH_ARM);
|
||||
jit_debug_->SetArch(arch);
|
||||
|
||||
maps_.reset(
|
||||
new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
|
||||
|
@ -57,33 +64,22 @@ class JitDebugTest : public ::testing::Test {
|
|||
|
||||
MapInfo* map_info = maps_->Get(3);
|
||||
ASSERT_TRUE(map_info != nullptr);
|
||||
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);
|
||||
map_info->elf.reset(elf);
|
||||
CreateFakeElf(map_info);
|
||||
|
||||
map_info = maps_->Get(5);
|
||||
ASSERT_TRUE(map_info != nullptr);
|
||||
memory = new MemoryFake;
|
||||
elf = new ElfFake(memory);
|
||||
elf->FakeSetValid(true);
|
||||
interface = new ElfInterfaceFake(memory);
|
||||
elf->FakeSetInterface(interface);
|
||||
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
||||
map_info->elf.reset(elf);
|
||||
CreateFakeElf(map_info);
|
||||
|
||||
map_info = maps_->Get(7);
|
||||
ASSERT_TRUE(map_info != nullptr);
|
||||
memory = new MemoryFake;
|
||||
elf = new ElfFake(memory);
|
||||
elf->FakeSetValid(true);
|
||||
interface = new ElfInterfaceFake(memory);
|
||||
elf->FakeSetInterface(interface);
|
||||
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
|
||||
map_info->elf.reset(elf);
|
||||
CreateFakeElf(map_info);
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
memory_ = new MemoryFake;
|
||||
process_memory_.reset(memory_);
|
||||
|
||||
Init(ARCH_ARM);
|
||||
}
|
||||
|
||||
template <typename EhdrType, typename ShdrType>
|
||||
|
@ -326,6 +322,8 @@ TEST_F(JitDebugTest, get_multiple_jit_debug_descriptors_valid) {
|
|||
}
|
||||
|
||||
TEST_F(JitDebugTest, get_elf_x86) {
|
||||
Init(ARCH_X86);
|
||||
|
||||
CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
|
||||
|
||||
WriteDescriptor32(0xf800, 0x200000);
|
||||
|
@ -343,12 +341,13 @@ TEST_F(JitDebugTest, get_elf_x86) {
|
|||
}
|
||||
|
||||
TEST_F(JitDebugTest, get_elf_64) {
|
||||
Init(ARCH_ARM64);
|
||||
|
||||
CreateElf<Elf64_Ehdr, Elf64_Shdr>(0x4000, ELFCLASS64, EM_AARCH64, 0x1500, 0x200);
|
||||
|
||||
WriteDescriptor64(0xf800, 0x200000);
|
||||
WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000);
|
||||
|
||||
jit_debug_->SetArch(ARCH_ARM64);
|
||||
Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ TEST_F(MapInfoGetElfTest, invalid) {
|
|||
MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
|
||||
|
||||
// The map is empty, but this should still create an invalid elf object.
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_FALSE(elf->valid());
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ TEST_F(MapInfoGetElfTest, valid32) {
|
|||
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
|
||||
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
|
||||
|
@ -98,13 +98,25 @@ TEST_F(MapInfoGetElfTest, valid64) {
|
|||
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
|
||||
memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
|
||||
EXPECT_EQ(ELFCLASS64, elf->class_type());
|
||||
}
|
||||
|
||||
TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) {
|
||||
MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
|
||||
|
||||
Elf32_Ehdr ehdr;
|
||||
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
|
||||
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_X86);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_FALSE(elf->valid());
|
||||
}
|
||||
|
||||
TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
|
||||
MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
|
||||
|
||||
|
@ -113,7 +125,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
|
|||
memory_->SetMemory(0x2000 + offset, ptr, size);
|
||||
});
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
|
||||
|
@ -129,7 +141,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
|
|||
memory_->SetMemory(0x5000 + offset, ptr, size);
|
||||
});
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
|
||||
|
@ -144,20 +156,20 @@ TEST_F(MapInfoGetElfTest, end_le_start) {
|
|||
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_FALSE(elf->valid());
|
||||
|
||||
info.elf.reset();
|
||||
info.end = 0xfff;
|
||||
elf = info.GetElf(process_memory_);
|
||||
elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_FALSE(elf->valid());
|
||||
|
||||
// Make sure this test is valid.
|
||||
info.elf.reset();
|
||||
info.end = 0x2000;
|
||||
elf = info.GetElf(process_memory_);
|
||||
elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
}
|
||||
|
@ -174,7 +186,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
|
|||
memcpy(buffer.data(), &ehdr, sizeof(ehdr));
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
ASSERT_TRUE(elf->memory() != nullptr);
|
||||
|
@ -203,7 +215,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
|
|||
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
ASSERT_TRUE(elf->memory() != nullptr);
|
||||
|
@ -236,7 +248,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32)
|
|||
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
ASSERT_TRUE(elf->memory() != nullptr);
|
||||
|
@ -264,7 +276,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64)
|
|||
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
|
||||
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
ASSERT_TRUE(elf->memory() != nullptr);
|
||||
|
@ -290,13 +302,13 @@ TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
|
|||
ehdr.e_shnum = 0;
|
||||
memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_FALSE(elf->valid());
|
||||
|
||||
info.elf.reset();
|
||||
info.flags = PROT_READ;
|
||||
elf = info.GetElf(process_memory_);
|
||||
elf = info.GetElf(process_memory_, ARCH_ARM64);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
}
|
||||
|
||||
|
@ -313,20 +325,20 @@ TEST_F(MapInfoGetElfTest, check_device_maps) {
|
|||
ehdr.e_shnum = 0;
|
||||
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
|
||||
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
|
||||
ASSERT_TRUE(elf != nullptr);
|
||||
ASSERT_FALSE(elf->valid());
|
||||
|
||||
// Set the name to nothing to verify that it still fails.
|
||||
info.elf.reset();
|
||||
info.name = "";
|
||||
elf = info.GetElf(process_memory_);
|
||||
elf = info.GetElf(process_memory_, ARCH_X86_64);
|
||||
ASSERT_FALSE(elf->valid());
|
||||
|
||||
// Change the flags and verify the elf is valid now.
|
||||
info.elf.reset();
|
||||
info.flags = PROT_READ;
|
||||
elf = info.GetElf(process_memory_);
|
||||
elf = info.GetElf(process_memory_, ARCH_X86_64);
|
||||
ASSERT_TRUE(elf->valid());
|
||||
}
|
||||
|
||||
|
@ -352,7 +364,7 @@ TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
|
|||
std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
|
||||
while (wait)
|
||||
;
|
||||
Elf* elf = info.GetElf(process_memory_);
|
||||
Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
|
||||
elf_in_threads[i] = elf;
|
||||
});
|
||||
threads.push_back(thread);
|
||||
|
|
Loading…
Reference in a new issue