Merge "Multiple bugfixes, small restructuring."
This commit is contained in:
commit
26b614ddf6
19 changed files with 453 additions and 288 deletions
|
|
@ -35,7 +35,8 @@
|
|||
|
||||
namespace unwindstack {
|
||||
|
||||
bool Elf::Init() {
|
||||
bool Elf::Init(bool init_gnu_debugdata) {
|
||||
load_bias_ = 0;
|
||||
if (!memory_) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -45,9 +46,14 @@ bool Elf::Init() {
|
|||
return false;
|
||||
}
|
||||
|
||||
valid_ = interface_->Init();
|
||||
valid_ = interface_->Init(&load_bias_);
|
||||
if (valid_) {
|
||||
interface_->InitHeaders();
|
||||
if (init_gnu_debugdata) {
|
||||
InitGnuDebugdata();
|
||||
} else {
|
||||
gnu_debugdata_interface_.reset(nullptr);
|
||||
}
|
||||
} else {
|
||||
interface_.reset(nullptr);
|
||||
}
|
||||
|
|
@ -67,7 +73,11 @@ void Elf::InitGnuDebugdata() {
|
|||
if (gnu == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (gnu->Init()) {
|
||||
|
||||
// Ignore the load_bias from the compressed section, the correct load bias
|
||||
// is in the uncompressed data.
|
||||
uint64_t load_bias;
|
||||
if (gnu->Init(&load_bias)) {
|
||||
gnu->InitHeaders();
|
||||
} else {
|
||||
// Free all of the memory associated with the gnu_debugdata section.
|
||||
|
|
@ -81,38 +91,39 @@ bool Elf::GetSoname(std::string* name) {
|
|||
}
|
||||
|
||||
uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
|
||||
uint64_t load_bias = 0;
|
||||
if (valid()) {
|
||||
load_bias = interface_->load_bias();
|
||||
}
|
||||
|
||||
return pc - map_info->start + load_bias + map_info->elf_offset;
|
||||
return pc - map_info->start + load_bias_ + map_info->elf_offset;
|
||||
}
|
||||
|
||||
bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
|
||||
return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
|
||||
(gnu_debugdata_interface_ &&
|
||||
gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
|
||||
return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
|
||||
(gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
|
||||
addr, load_bias_, name, func_offset)));
|
||||
}
|
||||
|
||||
bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
|
||||
// The relative pc is always relative to the start of the map from which it comes.
|
||||
bool Elf::Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
|
||||
bool* finished) {
|
||||
if (!valid_) {
|
||||
return false;
|
||||
}
|
||||
if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
|
||||
|
||||
// The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
|
||||
if (regs->StepIfSignalHandler(rel_pc + elf_offset, this, process_memory)) {
|
||||
*finished = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adjust the load bias to get the real relative pc.
|
||||
if (rel_pc < load_bias_) {
|
||||
return false;
|
||||
}
|
||||
rel_pc -= load_bias_;
|
||||
|
||||
return interface_->Step(rel_pc, regs, process_memory, finished) ||
|
||||
(gnu_debugdata_interface_ &&
|
||||
gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished));
|
||||
}
|
||||
|
||||
uint64_t Elf::GetLoadBias() {
|
||||
if (!valid_) return 0;
|
||||
return interface_->load_bias();
|
||||
}
|
||||
|
||||
bool Elf::IsValidElf(Memory* memory) {
|
||||
if (memory == nullptr) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -118,13 +118,13 @@ void ElfInterface::InitHeadersWithTemplate() {
|
|||
}
|
||||
|
||||
template <typename EhdrType, typename PhdrType, typename ShdrType>
|
||||
bool ElfInterface::ReadAllHeaders() {
|
||||
bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
|
||||
EhdrType ehdr;
|
||||
if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
|
||||
if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ bool ElfInterface::ReadAllHeaders() {
|
|||
}
|
||||
|
||||
template <typename EhdrType, typename PhdrType>
|
||||
bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
|
||||
bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
|
||||
uint64_t offset = ehdr.e_phoff;
|
||||
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
|
||||
PhdrType phdr;
|
||||
|
|
@ -145,7 +145,7 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (HandleType(offset, phdr.p_type)) {
|
||||
if (HandleType(offset, phdr.p_type, *load_bias)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
|
|||
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
|
||||
static_cast<size_t>(phdr.p_memsz)};
|
||||
if (phdr.p_offset == 0) {
|
||||
load_bias_ = phdr.p_vaddr;
|
||||
*load_bias = phdr.p_vaddr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -334,14 +334,14 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
|
|||
}
|
||||
|
||||
template <typename SymType>
|
||||
bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
|
||||
bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
|
||||
uint64_t* func_offset) {
|
||||
if (symbols_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto symbol : symbols_) {
|
||||
if (symbol->GetName<SymType>(addr, load_bias_, memory_, name, func_offset)) {
|
||||
if (symbol->GetName<SymType>(addr, load_bias, memory_, name, func_offset)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -349,12 +349,6 @@ bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
|
|||
}
|
||||
|
||||
bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
|
||||
// Need to subtract off the load_bias to get the correct pc.
|
||||
if (pc < load_bias_) {
|
||||
return false;
|
||||
}
|
||||
pc -= load_bias_;
|
||||
|
||||
// Try the eh_frame first.
|
||||
DwarfSection* eh_frame = eh_frame_.get();
|
||||
if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
|
||||
|
|
@ -389,11 +383,11 @@ void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
|
|||
template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
|
||||
template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
|
||||
|
||||
template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
|
||||
template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
|
||||
template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
|
||||
template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
|
||||
|
||||
template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
|
||||
template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
|
||||
template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
|
||||
template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
|
||||
|
||||
template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
|
||||
template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
|
||||
|
|
@ -401,9 +395,9 @@ template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf
|
|||
template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
|
||||
template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
|
||||
|
||||
template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
|
||||
template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, uint64_t, std::string*,
|
||||
uint64_t*);
|
||||
template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
|
||||
template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, uint64_t, std::string*,
|
||||
uint64_t*);
|
||||
|
||||
template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
|
||||
|
|
|
|||
|
|
@ -31,12 +31,6 @@ bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Need to subtract the load_bias from the pc.
|
||||
if (pc < load_bias_) {
|
||||
return false;
|
||||
}
|
||||
pc -= load_bias_;
|
||||
|
||||
size_t first = 0;
|
||||
size_t last = total_entries_;
|
||||
while (first < last) {
|
||||
|
|
@ -81,7 +75,7 @@ bool ElfInterfaceArm::GetPrel31Addr(uint32_t offset, uint32_t* addr) {
|
|||
#define PT_ARM_EXIDX 0x70000001
|
||||
#endif
|
||||
|
||||
bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) {
|
||||
bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) {
|
||||
if (type != PT_ARM_EXIDX) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -93,8 +87,7 @@ bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) {
|
|||
if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
|
||||
return true;
|
||||
}
|
||||
// The load_bias_ should always be set by this time.
|
||||
start_offset_ = phdr.p_vaddr - load_bias_;
|
||||
start_offset_ = phdr.p_vaddr - load_bias;
|
||||
total_entries_ = phdr.p_memsz / 8;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class ElfInterfaceArm : public ElfInterface32 {
|
|||
|
||||
bool FindEntry(uint32_t pc, uint64_t* entry_offset);
|
||||
|
||||
bool HandleType(uint64_t offset, uint32_t type) override;
|
||||
bool HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) override;
|
||||
|
||||
bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
|
||||
|
||||
|
|
@ -76,13 +76,9 @@ class ElfInterfaceArm : public ElfInterface32 {
|
|||
|
||||
uint64_t start_offset() { return start_offset_; }
|
||||
|
||||
void set_start_offset(uint64_t start_offset) { start_offset_ = start_offset; }
|
||||
|
||||
size_t total_entries() { return total_entries_; }
|
||||
|
||||
void set_total_entries(size_t total_entries) { total_entries_ = total_entries; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
uint64_t start_offset_ = 0;
|
||||
size_t total_entries_ = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -110,9 +110,8 @@ Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gn
|
|||
}
|
||||
|
||||
elf = new Elf(CreateMemory(process_memory));
|
||||
if (elf->Init() && init_gnu_debugdata) {
|
||||
elf->InitGnuDebugdata();
|
||||
}
|
||||
elf->Init(init_gnu_debugdata);
|
||||
|
||||
// If the init fails, keep the elf around as an invalid object so we
|
||||
// don't try to reinit the object.
|
||||
return elf;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
|
|||
return rel_pc;
|
||||
}
|
||||
|
||||
uint64_t load_bias = elf->interface()->load_bias();
|
||||
uint64_t load_bias = elf->GetLoadBias();
|
||||
if (rel_pc < load_bias) {
|
||||
return rel_pc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,19 @@ void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool ad
|
|||
}
|
||||
}
|
||||
|
||||
void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) {
|
||||
static bool ShouldStop(const std::set<std::string>* map_suffixes_to_ignore, std::string& map_name) {
|
||||
if (map_suffixes_to_ignore == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto pos = map_name.find_last_of('.');
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
return map_suffixes_to_ignore->find(map_name.substr(pos + 1)) != map_suffixes_to_ignore->end();
|
||||
}
|
||||
|
||||
void Unwinder::Unwind(const std::set<std::string>* initial_map_names_to_skip,
|
||||
const std::set<std::string>* map_suffixes_to_ignore) {
|
||||
frames_.clear();
|
||||
|
||||
bool return_address_attempt = false;
|
||||
|
|
@ -77,6 +89,9 @@ void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) {
|
|||
if (map_info == nullptr) {
|
||||
rel_pc = regs_->pc();
|
||||
} else {
|
||||
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
|
||||
break;
|
||||
}
|
||||
elf = map_info->GetElf(process_memory_, true);
|
||||
rel_pc = elf->GetRelPc(regs_->pc(), map_info);
|
||||
}
|
||||
|
|
@ -111,8 +126,7 @@ void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) {
|
|||
in_device_map = true;
|
||||
} else {
|
||||
bool finished;
|
||||
stepped =
|
||||
elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished);
|
||||
stepped = elf->Step(rel_pc, map_info->elf_offset, regs_, process_memory_.get(), &finished);
|
||||
if (stepped && finished) {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class Elf {
|
|||
Elf(Memory* memory) : memory_(memory) {}
|
||||
virtual ~Elf() = default;
|
||||
|
||||
bool Init();
|
||||
bool Init(bool init_gnu_debugdata);
|
||||
|
||||
void InitGnuDebugdata();
|
||||
|
||||
|
|
@ -50,11 +50,12 @@ class Elf {
|
|||
|
||||
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
|
||||
|
||||
bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
|
||||
bool Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
|
||||
bool* finished);
|
||||
|
||||
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
|
||||
|
||||
uint64_t GetLoadBias();
|
||||
uint64_t GetLoadBias() { return load_bias_; }
|
||||
|
||||
bool valid() { return valid_; }
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ class Elf {
|
|||
|
||||
protected:
|
||||
bool valid_ = false;
|
||||
uint64_t load_bias_ = 0;
|
||||
std::unique_ptr<ElfInterface> interface_;
|
||||
std::unique_ptr<Memory> memory_;
|
||||
uint32_t machine_type_;
|
||||
|
|
|
|||
|
|
@ -51,13 +51,14 @@ class ElfInterface {
|
|||
ElfInterface(Memory* memory) : memory_(memory) {}
|
||||
virtual ~ElfInterface();
|
||||
|
||||
virtual bool Init() = 0;
|
||||
virtual bool Init(uint64_t* load_bias) = 0;
|
||||
|
||||
virtual void InitHeaders() = 0;
|
||||
|
||||
virtual bool GetSoname(std::string* name) = 0;
|
||||
|
||||
virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0;
|
||||
virtual bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
|
||||
uint64_t* offset) = 0;
|
||||
|
||||
virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
|
||||
|
||||
|
|
@ -66,8 +67,6 @@ class ElfInterface {
|
|||
Memory* memory() { return memory_; }
|
||||
|
||||
const std::unordered_map<uint64_t, LoadInfo>& pt_loads() { return pt_loads_; }
|
||||
uint64_t load_bias() { return load_bias_; }
|
||||
void set_load_bias(uint64_t load_bias) { load_bias_ = load_bias; }
|
||||
|
||||
uint64_t dynamic_offset() { return dynamic_offset_; }
|
||||
uint64_t dynamic_size() { return dynamic_size_; }
|
||||
|
|
@ -86,10 +85,10 @@ class ElfInterface {
|
|||
void InitHeadersWithTemplate();
|
||||
|
||||
template <typename EhdrType, typename PhdrType, typename ShdrType>
|
||||
bool ReadAllHeaders();
|
||||
bool ReadAllHeaders(uint64_t* load_bias);
|
||||
|
||||
template <typename EhdrType, typename PhdrType>
|
||||
bool ReadProgramHeaders(const EhdrType& ehdr);
|
||||
bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
|
||||
|
||||
template <typename EhdrType, typename ShdrType>
|
||||
bool ReadSectionHeaders(const EhdrType& ehdr);
|
||||
|
|
@ -98,16 +97,16 @@ class ElfInterface {
|
|||
bool GetSonameWithTemplate(std::string* soname);
|
||||
|
||||
template <typename SymType>
|
||||
bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset);
|
||||
bool GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
|
||||
uint64_t* func_offset);
|
||||
|
||||
virtual bool HandleType(uint64_t, uint32_t) { return false; }
|
||||
virtual bool HandleType(uint64_t, uint32_t, uint64_t) { return false; }
|
||||
|
||||
template <typename EhdrType>
|
||||
static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
|
||||
|
||||
Memory* memory_;
|
||||
std::unordered_map<uint64_t, LoadInfo> pt_loads_;
|
||||
uint64_t load_bias_ = 0;
|
||||
|
||||
// Stored elf data.
|
||||
uint64_t dynamic_offset_ = 0;
|
||||
|
|
@ -136,8 +135,8 @@ class ElfInterface32 : public ElfInterface {
|
|||
ElfInterface32(Memory* memory) : ElfInterface(memory) {}
|
||||
virtual ~ElfInterface32() = default;
|
||||
|
||||
bool Init() override {
|
||||
return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
|
||||
bool Init(uint64_t* load_bias) override {
|
||||
return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(load_bias);
|
||||
}
|
||||
|
||||
void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint32_t>(); }
|
||||
|
|
@ -146,8 +145,9 @@ class ElfInterface32 : public ElfInterface {
|
|||
return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname);
|
||||
}
|
||||
|
||||
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
|
||||
return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
|
||||
bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
|
||||
uint64_t* func_offset) override {
|
||||
return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, load_bias, name, func_offset);
|
||||
}
|
||||
|
||||
static void GetMaxSize(Memory* memory, uint64_t* size) {
|
||||
|
|
@ -160,8 +160,8 @@ class ElfInterface64 : public ElfInterface {
|
|||
ElfInterface64(Memory* memory) : ElfInterface(memory) {}
|
||||
virtual ~ElfInterface64() = default;
|
||||
|
||||
bool Init() override {
|
||||
return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
|
||||
bool Init(uint64_t* load_bias) override {
|
||||
return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(load_bias);
|
||||
}
|
||||
|
||||
void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint64_t>(); }
|
||||
|
|
@ -170,8 +170,9 @@ class ElfInterface64 : public ElfInterface {
|
|||
return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname);
|
||||
}
|
||||
|
||||
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
|
||||
return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
|
||||
bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
|
||||
uint64_t* func_offset) override {
|
||||
return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, load_bias, name, func_offset);
|
||||
}
|
||||
|
||||
static void GetMaxSize(Memory* memory, uint64_t* size) {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ class Unwinder {
|
|||
}
|
||||
~Unwinder() = default;
|
||||
|
||||
void Unwind(std::set<std::string>* initial_map_names_to_skip = nullptr);
|
||||
void Unwind(const std::set<std::string>* initial_map_names_to_skip = nullptr,
|
||||
const std::set<std::string>* map_suffixes_to_ignore = nullptr);
|
||||
|
||||
size_t NumFrames() { return frames_.size(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace unwindstack {
|
|||
std::deque<FunctionData> ElfInterfaceFake::functions_;
|
||||
std::deque<StepData> ElfInterfaceFake::steps_;
|
||||
|
||||
bool ElfInterfaceFake::GetFunctionName(uint64_t, std::string* name, uint64_t* offset) {
|
||||
bool ElfInterfaceFake::GetFunctionName(uint64_t, uint64_t, std::string* name, uint64_t* offset) {
|
||||
if (functions_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
#include "ElfInterfaceArm.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
struct StepData {
|
||||
|
|
@ -48,6 +50,10 @@ class ElfFake : public Elf {
|
|||
ElfFake(Memory* memory) : Elf(memory) { valid_ = true; }
|
||||
virtual ~ElfFake() = default;
|
||||
|
||||
void FakeSetValid(bool valid) { valid_ = valid; }
|
||||
|
||||
void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
|
||||
|
||||
void FakeSetInterface(ElfInterface* interface) { interface_.reset(interface); }
|
||||
};
|
||||
|
||||
|
|
@ -56,15 +62,14 @@ class ElfInterfaceFake : public ElfInterface {
|
|||
ElfInterfaceFake(Memory* memory) : ElfInterface(memory) {}
|
||||
virtual ~ElfInterfaceFake() = default;
|
||||
|
||||
bool Init() override { return false; }
|
||||
bool Init(uint64_t*) override { return false; }
|
||||
void InitHeaders() override {}
|
||||
bool GetSoname(std::string*) override { return false; }
|
||||
|
||||
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
|
||||
bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override;
|
||||
|
||||
bool Step(uint64_t, Regs*, Memory*, bool*) override;
|
||||
|
||||
void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
|
||||
|
||||
static void FakePushFunctionData(const FunctionData data) { functions_.push_back(data); }
|
||||
static void FakePushStepData(const StepData data) { steps_.push_back(data); }
|
||||
|
|
@ -79,6 +84,37 @@ class ElfInterfaceFake : public ElfInterface {
|
|||
static std::deque<StepData> steps_;
|
||||
};
|
||||
|
||||
class ElfInterface32Fake : public ElfInterface32 {
|
||||
public:
|
||||
ElfInterface32Fake(Memory* memory) : ElfInterface32(memory) {}
|
||||
virtual ~ElfInterface32Fake() = default;
|
||||
|
||||
void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
|
||||
void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
|
||||
void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
|
||||
void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
|
||||
};
|
||||
|
||||
class ElfInterface64Fake : public ElfInterface64 {
|
||||
public:
|
||||
ElfInterface64Fake(Memory* memory) : ElfInterface64(memory) {}
|
||||
virtual ~ElfInterface64Fake() = default;
|
||||
|
||||
void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
|
||||
void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
|
||||
void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
|
||||
void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
|
||||
};
|
||||
|
||||
class ElfInterfaceArmFake : public ElfInterfaceArm {
|
||||
public:
|
||||
ElfInterfaceArmFake(Memory* memory) : ElfInterfaceArm(memory) {}
|
||||
virtual ~ElfInterfaceArmFake() = default;
|
||||
|
||||
void FakeSetStartOffset(uint64_t offset) { start_offset_ = offset; }
|
||||
void FakeSetTotalEntries(size_t entries) { total_entries_ = entries; }
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "ElfInterfaceArm.h"
|
||||
#include "Machine.h"
|
||||
|
||||
#include "ElfFake.h"
|
||||
#include "MemoryFake.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
|
@ -41,7 +42,7 @@ class ElfInterfaceArmTest : public ::testing::Test {
|
|||
};
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, GetPrel32Addr) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
memory_.SetData32(0x1000, 0x230000);
|
||||
|
||||
uint32_t value;
|
||||
|
|
@ -58,36 +59,36 @@ TEST_F(ElfInterfaceArmTest, GetPrel32Addr) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_start_zero) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0);
|
||||
interface.set_total_entries(10);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0);
|
||||
interface.FakeSetTotalEntries(10);
|
||||
|
||||
uint64_t entry_offset;
|
||||
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_no_entries) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x100);
|
||||
interface.set_total_entries(0);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x100);
|
||||
interface.FakeSetTotalEntries(0);
|
||||
|
||||
uint64_t entry_offset;
|
||||
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_no_valid_memory) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x100);
|
||||
interface.set_total_entries(2);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x100);
|
||||
interface.FakeSetTotalEntries(2);
|
||||
|
||||
uint64_t entry_offset;
|
||||
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_ip_before_first) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(1);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(1);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
|
||||
uint64_t entry_offset;
|
||||
|
|
@ -95,9 +96,9 @@ TEST_F(ElfInterfaceArmTest, FindEntry_ip_before_first) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_single_entry_negative_value) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x8000);
|
||||
interface.set_total_entries(1);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x8000);
|
||||
interface.FakeSetTotalEntries(1);
|
||||
memory_.SetData32(0x8000, 0x7fffff00);
|
||||
|
||||
uint64_t entry_offset;
|
||||
|
|
@ -106,9 +107,9 @@ TEST_F(ElfInterfaceArmTest, FindEntry_single_entry_negative_value) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_two_entries) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(2);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(2);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
memory_.SetData32(0x1008, 0x7000);
|
||||
|
||||
|
|
@ -117,11 +118,10 @@ TEST_F(ElfInterfaceArmTest, FindEntry_two_entries) {
|
|||
ASSERT_EQ(0x1000U, entry_offset);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_last_check_single_entry) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(1);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(1);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
|
||||
uint64_t entry_offset;
|
||||
|
|
@ -136,9 +136,9 @@ TEST_F(ElfInterfaceArmTest, FindEntry_last_check_single_entry) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_last_check_multiple_entries) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(2);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(2);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
memory_.SetData32(0x1008, 0x8000);
|
||||
|
||||
|
|
@ -155,9 +155,9 @@ TEST_F(ElfInterfaceArmTest, FindEntry_last_check_multiple_entries) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_even) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(4);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(4);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
memory_.SetData32(0x1008, 0x7000);
|
||||
memory_.SetData32(0x1010, 0x8000);
|
||||
|
|
@ -178,9 +178,9 @@ TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_even) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_odd) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(5);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(5);
|
||||
memory_.SetData32(0x1000, 0x5000);
|
||||
memory_.SetData32(0x1008, 0x6000);
|
||||
memory_.SetData32(0x1010, 0x7000);
|
||||
|
|
@ -203,9 +203,9 @@ TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_odd) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, iterate) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(5);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(5);
|
||||
memory_.SetData32(0x1000, 0x5000);
|
||||
memory_.SetData32(0x1008, 0x6000);
|
||||
memory_.SetData32(0x1010, 0x7000);
|
||||
|
|
@ -242,56 +242,36 @@ TEST_F(ElfInterfaceArmTest, iterate) {
|
|||
ASSERT_EQ(0xa020U, entries[4]);
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, FindEntry_load_bias) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(2);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
memory_.SetData32(0x1008, 0x8000);
|
||||
|
||||
uint64_t entry_offset;
|
||||
interface.set_load_bias(0x2000);
|
||||
ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
|
||||
ASSERT_FALSE(interface.FindEntry(0x8000, &entry_offset));
|
||||
ASSERT_FALSE(interface.FindEntry(0x8fff, &entry_offset));
|
||||
ASSERT_TRUE(interface.FindEntry(0x9000, &entry_offset));
|
||||
ASSERT_EQ(0x1000U, entry_offset);
|
||||
ASSERT_TRUE(interface.FindEntry(0xb007, &entry_offset));
|
||||
ASSERT_EQ(0x1000U, entry_offset);
|
||||
ASSERT_TRUE(interface.FindEntry(0xb008, &entry_offset));
|
||||
ASSERT_EQ(0x1008U, entry_offset);
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, HandleType_not_arm_exidx) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME, 0));
|
||||
ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK, 0));
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
|
||||
Elf32_Phdr phdr;
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(100);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(100);
|
||||
phdr.p_vaddr = 0x2000;
|
||||
phdr.p_memsz = 0xa00;
|
||||
|
||||
// Verify that if reads fail, we don't set the values but still get true.
|
||||
ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
|
||||
ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
|
||||
ASSERT_EQ(0x1000U, interface.start_offset());
|
||||
ASSERT_EQ(100U, interface.total_entries());
|
||||
|
||||
|
|
@ -299,7 +279,7 @@ TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
|
|||
memory_.SetData32(
|
||||
0x1000 + reinterpret_cast<uint64_t>(&phdr.p_vaddr) - reinterpret_cast<uint64_t>(&phdr),
|
||||
phdr.p_vaddr);
|
||||
ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
|
||||
ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
|
||||
ASSERT_EQ(0x1000U, interface.start_offset());
|
||||
ASSERT_EQ(100U, interface.total_entries());
|
||||
|
||||
|
|
@ -307,27 +287,26 @@ TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
|
|||
memory_.SetData32(
|
||||
0x1000 + reinterpret_cast<uint64_t>(&phdr.p_memsz) - reinterpret_cast<uint64_t>(&phdr),
|
||||
phdr.p_memsz);
|
||||
ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
|
||||
ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
|
||||
ASSERT_EQ(0x2000U, interface.start_offset());
|
||||
ASSERT_EQ(320U, interface.total_entries());
|
||||
|
||||
// Non-zero load bias.
|
||||
interface.set_load_bias(0x1000);
|
||||
ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
|
||||
ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0x1000));
|
||||
ASSERT_EQ(0x1000U, interface.start_offset());
|
||||
ASSERT_EQ(320U, interface.total_entries());
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, StepExidx) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
|
||||
// FindEntry fails.
|
||||
bool finished;
|
||||
ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr, &finished));
|
||||
|
||||
// ExtractEntry should fail.
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(2);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(2);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
memory_.SetData32(0x1008, 0x8000);
|
||||
|
||||
|
|
@ -353,10 +332,10 @@ TEST_F(ElfInterfaceArmTest, StepExidx) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(2);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(2);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
memory_.SetData32(0x1004, 0x808800b0);
|
||||
memory_.SetData32(0x1008, 0x8000);
|
||||
|
|
@ -379,10 +358,10 @@ TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(1);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(1);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
memory_.SetData32(0x1004, 1);
|
||||
|
||||
|
|
@ -401,10 +380,10 @@ TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) {
|
||||
ElfInterfaceArm interface(&memory_);
|
||||
ElfInterfaceArmFake interface(&memory_);
|
||||
|
||||
interface.set_start_offset(0x1000);
|
||||
interface.set_total_entries(1);
|
||||
interface.FakeSetStartOffset(0x1000);
|
||||
interface.FakeSetTotalEntries(1);
|
||||
memory_.SetData32(0x1000, 0x6000);
|
||||
memory_.SetData32(0x1004, 0x808000b0);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "DwarfEncoding.h"
|
||||
#include "ElfInterfaceArm.h"
|
||||
|
||||
#include "ElfFake.h"
|
||||
#include "MemoryFake.h"
|
||||
|
||||
#if !defined(PT_ARM_EXIDX)
|
||||
|
|
@ -134,7 +135,9 @@ void ElfInterfaceTest::SinglePtLoad() {
|
|||
phdr.p_align = 0x1000;
|
||||
memory_.SetMemory(0x100, &phdr, sizeof(phdr));
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0x2000U, load_bias);
|
||||
|
||||
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
|
||||
ASSERT_EQ(1U, pt_loads.size());
|
||||
|
|
@ -190,7 +193,9 @@ void ElfInterfaceTest::MultipleExecutablePtLoads() {
|
|||
phdr.p_align = 0x1002;
|
||||
memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0x2000U, load_bias);
|
||||
|
||||
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
|
||||
ASSERT_EQ(3U, pt_loads.size());
|
||||
|
|
@ -257,7 +262,9 @@ void ElfInterfaceTest::MultipleExecutablePtLoadsIncrementsNotSizeOfPhdr() {
|
|||
phdr.p_align = 0x1002;
|
||||
memory_.SetMemory(0x100 + 2 * (sizeof(phdr) + 100), &phdr, sizeof(phdr));
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0x2000U, load_bias);
|
||||
|
||||
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
|
||||
ASSERT_EQ(3U, pt_loads.size());
|
||||
|
|
@ -326,7 +333,9 @@ void ElfInterfaceTest::NonExecutablePtLoads() {
|
|||
phdr.p_align = 0x1002;
|
||||
memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0U, load_bias);
|
||||
|
||||
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
|
||||
ASSERT_EQ(1U, pt_loads.size());
|
||||
|
|
@ -398,7 +407,9 @@ void ElfInterfaceTest::ManyPhdrs() {
|
|||
memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
|
||||
phdr_offset += sizeof(phdr);
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0x2000U, load_bias);
|
||||
|
||||
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
|
||||
ASSERT_EQ(1U, pt_loads.size());
|
||||
|
|
@ -438,7 +449,9 @@ TEST_F(ElfInterfaceTest, elf32_arm) {
|
|||
memory_.SetData32(0x2000, 0x1000);
|
||||
memory_.SetData32(0x2008, 0x1000);
|
||||
|
||||
ASSERT_TRUE(elf_arm.Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf_arm.Init(&load_bias));
|
||||
EXPECT_EQ(0U, load_bias);
|
||||
|
||||
std::vector<uint32_t> entries;
|
||||
for (auto addr : elf_arm) {
|
||||
|
|
@ -493,7 +506,10 @@ void ElfInterfaceTest::Soname() {
|
|||
|
||||
SetStringMemory(0x10010, "fake_soname.so");
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0U, load_bias);
|
||||
|
||||
std::string name;
|
||||
ASSERT_TRUE(elf->GetSoname(&name));
|
||||
ASSERT_STREQ("fake_soname.so", name.c_str());
|
||||
|
|
@ -549,7 +565,10 @@ void ElfInterfaceTest::SonameAfterDtNull() {
|
|||
|
||||
SetStringMemory(0x10010, "fake_soname.so");
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0U, load_bias);
|
||||
|
||||
std::string name;
|
||||
ASSERT_FALSE(elf->GetSoname(&name));
|
||||
}
|
||||
|
|
@ -603,7 +622,10 @@ void ElfInterfaceTest::SonameSize() {
|
|||
|
||||
SetStringMemory(0x10010, "fake_soname.so");
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0U, load_bias);
|
||||
|
||||
std::string name;
|
||||
ASSERT_FALSE(elf->GetSoname(&name));
|
||||
}
|
||||
|
|
@ -616,38 +638,14 @@ TEST_F(ElfInterfaceTest, elf64_soname_size) {
|
|||
SonameSize<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
|
||||
}
|
||||
|
||||
class MockElfInterface32 : public ElfInterface32 {
|
||||
public:
|
||||
MockElfInterface32(Memory* memory) : ElfInterface32(memory) {}
|
||||
virtual ~MockElfInterface32() = default;
|
||||
|
||||
void TestSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
|
||||
void TestSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
|
||||
|
||||
void TestSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
|
||||
void TestSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
|
||||
};
|
||||
|
||||
class MockElfInterface64 : public ElfInterface64 {
|
||||
public:
|
||||
MockElfInterface64(Memory* memory) : ElfInterface64(memory) {}
|
||||
virtual ~MockElfInterface64() = default;
|
||||
|
||||
void TestSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
|
||||
void TestSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
|
||||
|
||||
void TestSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
|
||||
void TestSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
|
||||
};
|
||||
|
||||
template <typename ElfType>
|
||||
void ElfInterfaceTest::InitHeadersEhFrameTest() {
|
||||
ElfType elf(&memory_);
|
||||
|
||||
elf.TestSetEhFrameOffset(0x10000);
|
||||
elf.TestSetEhFrameSize(0);
|
||||
elf.TestSetDebugFrameOffset(0);
|
||||
elf.TestSetDebugFrameSize(0);
|
||||
elf.FakeSetEhFrameOffset(0x10000);
|
||||
elf.FakeSetEhFrameSize(0);
|
||||
elf.FakeSetDebugFrameOffset(0);
|
||||
elf.FakeSetDebugFrameSize(0);
|
||||
|
||||
memory_.SetMemory(0x10000,
|
||||
std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata2, DW_EH_PE_udata2});
|
||||
|
|
@ -661,21 +659,21 @@ void ElfInterfaceTest::InitHeadersEhFrameTest() {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_headers_eh_frame32) {
|
||||
InitHeadersEhFrameTest<MockElfInterface32>();
|
||||
InitHeadersEhFrameTest<ElfInterface32Fake>();
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_headers_eh_frame64) {
|
||||
InitHeadersEhFrameTest<MockElfInterface64>();
|
||||
InitHeadersEhFrameTest<ElfInterface64Fake>();
|
||||
}
|
||||
|
||||
template <typename ElfType>
|
||||
void ElfInterfaceTest::InitHeadersDebugFrame() {
|
||||
ElfType elf(&memory_);
|
||||
|
||||
elf.TestSetEhFrameOffset(0);
|
||||
elf.TestSetEhFrameSize(0);
|
||||
elf.TestSetDebugFrameOffset(0x5000);
|
||||
elf.TestSetDebugFrameSize(0x200);
|
||||
elf.FakeSetEhFrameOffset(0);
|
||||
elf.FakeSetEhFrameSize(0);
|
||||
elf.FakeSetDebugFrameOffset(0x5000);
|
||||
elf.FakeSetDebugFrameSize(0x200);
|
||||
|
||||
memory_.SetData32(0x5000, 0xfc);
|
||||
memory_.SetData32(0x5004, 0xffffffff);
|
||||
|
|
@ -694,21 +692,21 @@ void ElfInterfaceTest::InitHeadersDebugFrame() {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_headers_debug_frame32) {
|
||||
InitHeadersDebugFrame<MockElfInterface32>();
|
||||
InitHeadersDebugFrame<ElfInterface32Fake>();
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_headers_debug_frame64) {
|
||||
InitHeadersDebugFrame<MockElfInterface64>();
|
||||
InitHeadersDebugFrame<ElfInterface64Fake>();
|
||||
}
|
||||
|
||||
template <typename ElfType>
|
||||
void ElfInterfaceTest::InitHeadersEhFrameFail() {
|
||||
ElfType elf(&memory_);
|
||||
|
||||
elf.TestSetEhFrameOffset(0x1000);
|
||||
elf.TestSetEhFrameSize(0x100);
|
||||
elf.TestSetDebugFrameOffset(0);
|
||||
elf.TestSetDebugFrameSize(0);
|
||||
elf.FakeSetEhFrameOffset(0x1000);
|
||||
elf.FakeSetEhFrameSize(0x100);
|
||||
elf.FakeSetDebugFrameOffset(0);
|
||||
elf.FakeSetDebugFrameSize(0);
|
||||
|
||||
elf.InitHeaders();
|
||||
|
||||
|
|
@ -719,21 +717,21 @@ void ElfInterfaceTest::InitHeadersEhFrameFail() {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_headers_eh_frame32_fail) {
|
||||
InitHeadersEhFrameFail<MockElfInterface32>();
|
||||
InitHeadersEhFrameFail<ElfInterface32Fake>();
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_headers_eh_frame64_fail) {
|
||||
InitHeadersEhFrameFail<MockElfInterface64>();
|
||||
InitHeadersEhFrameFail<ElfInterface64Fake>();
|
||||
}
|
||||
|
||||
template <typename ElfType>
|
||||
void ElfInterfaceTest::InitHeadersDebugFrameFail() {
|
||||
ElfType elf(&memory_);
|
||||
|
||||
elf.TestSetEhFrameOffset(0);
|
||||
elf.TestSetEhFrameSize(0);
|
||||
elf.TestSetDebugFrameOffset(0x1000);
|
||||
elf.TestSetDebugFrameSize(0x100);
|
||||
elf.FakeSetEhFrameOffset(0);
|
||||
elf.FakeSetEhFrameSize(0);
|
||||
elf.FakeSetDebugFrameOffset(0x1000);
|
||||
elf.FakeSetDebugFrameSize(0x100);
|
||||
|
||||
elf.InitHeaders();
|
||||
|
||||
|
|
@ -744,11 +742,11 @@ void ElfInterfaceTest::InitHeadersDebugFrameFail() {
|
|||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) {
|
||||
InitHeadersDebugFrameFail<MockElfInterface32>();
|
||||
InitHeadersDebugFrameFail<ElfInterface32Fake>();
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) {
|
||||
InitHeadersDebugFrameFail<MockElfInterface64>();
|
||||
InitHeadersDebugFrameFail<ElfInterface64Fake>();
|
||||
}
|
||||
|
||||
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
|
||||
|
|
@ -762,7 +760,9 @@ void ElfInterfaceTest::InitSectionHeadersMalformed() {
|
|||
ehdr.e_shentsize = sizeof(Shdr);
|
||||
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0U, load_bias);
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_section_headers_malformed32) {
|
||||
|
|
@ -827,7 +827,9 @@ void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) {
|
|||
InitSym<Sym>(0x5000, 0x90000, 0x1000, 0x100, 0xf000, "function_one");
|
||||
InitSym<Sym>(0x6000, 0xd0000, 0x1000, 0x300, 0xf000, "function_two");
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0U, load_bias);
|
||||
EXPECT_EQ(0U, elf->debug_frame_offset());
|
||||
EXPECT_EQ(0U, elf->debug_frame_size());
|
||||
EXPECT_EQ(0U, elf->gnu_debugdata_offset());
|
||||
|
|
@ -836,10 +838,10 @@ void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) {
|
|||
// Look in the first symbol table.
|
||||
std::string name;
|
||||
uint64_t name_offset;
|
||||
ASSERT_TRUE(elf->GetFunctionName(0x90010, &name, &name_offset));
|
||||
ASSERT_TRUE(elf->GetFunctionName(0x90010, 0, &name, &name_offset));
|
||||
EXPECT_EQ("function_one", name);
|
||||
EXPECT_EQ(16U, name_offset);
|
||||
ASSERT_TRUE(elf->GetFunctionName(0xd0020, &name, &name_offset));
|
||||
ASSERT_TRUE(elf->GetFunctionName(0xd0020, 0, &name, &name_offset));
|
||||
EXPECT_EQ("function_two", name);
|
||||
EXPECT_EQ(32U, name_offset);
|
||||
}
|
||||
|
|
@ -911,7 +913,9 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
|
|||
memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
|
||||
memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
|
||||
|
||||
ASSERT_TRUE(elf->Init());
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
EXPECT_EQ(0U, load_bias);
|
||||
EXPECT_EQ(0x6000U, elf->debug_frame_offset());
|
||||
EXPECT_EQ(0x500U, elf->debug_frame_size());
|
||||
EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset());
|
||||
|
|
|
|||
|
|
@ -20,11 +20,13 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
|
||||
#include "ElfFake.h"
|
||||
#include "ElfTestUtils.h"
|
||||
#include "LogFake.h"
|
||||
#include "MemoryFake.h"
|
||||
|
|
@ -107,7 +109,7 @@ class ElfTest : public ::testing::Test {
|
|||
TEST_F(ElfTest, invalid_memory) {
|
||||
Elf elf(memory_);
|
||||
|
||||
ASSERT_FALSE(elf.Init());
|
||||
ASSERT_FALSE(elf.Init(false));
|
||||
ASSERT_FALSE(elf.valid());
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +121,7 @@ TEST_F(ElfTest, elf_invalid) {
|
|||
// Corrupt the ELF signature.
|
||||
memory_->SetData32(0, 0x7f000000);
|
||||
|
||||
ASSERT_FALSE(elf.Init());
|
||||
ASSERT_FALSE(elf.Init(false));
|
||||
ASSERT_FALSE(elf.valid());
|
||||
ASSERT_TRUE(elf.interface() == nullptr);
|
||||
|
||||
|
|
@ -130,7 +132,7 @@ TEST_F(ElfTest, elf_invalid) {
|
|||
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
|
||||
|
||||
bool finished;
|
||||
ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
|
||||
ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, elf32_invalid_machine) {
|
||||
|
|
@ -139,7 +141,7 @@ TEST_F(ElfTest, elf32_invalid_machine) {
|
|||
InitElf32(EM_PPC);
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_FALSE(elf.Init());
|
||||
ASSERT_FALSE(elf.Init(false));
|
||||
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
|
||||
|
|
@ -152,7 +154,7 @@ TEST_F(ElfTest, elf64_invalid_machine) {
|
|||
InitElf64(EM_PPC64);
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_FALSE(elf.Init());
|
||||
ASSERT_FALSE(elf.Init(false));
|
||||
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
|
||||
|
|
@ -164,7 +166,7 @@ TEST_F(ElfTest, elf_arm) {
|
|||
|
||||
InitElf32(EM_ARM);
|
||||
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.Init(false));
|
||||
ASSERT_TRUE(elf.valid());
|
||||
ASSERT_EQ(static_cast<uint32_t>(EM_ARM), elf.machine_type());
|
||||
ASSERT_EQ(ELFCLASS32, elf.class_type());
|
||||
|
|
@ -176,7 +178,7 @@ TEST_F(ElfTest, elf_x86) {
|
|||
|
||||
InitElf32(EM_386);
|
||||
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.Init(false));
|
||||
ASSERT_TRUE(elf.valid());
|
||||
ASSERT_EQ(static_cast<uint32_t>(EM_386), elf.machine_type());
|
||||
ASSERT_EQ(ELFCLASS32, elf.class_type());
|
||||
|
|
@ -188,7 +190,7 @@ TEST_F(ElfTest, elf_arm64) {
|
|||
|
||||
InitElf64(EM_AARCH64);
|
||||
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.Init(false));
|
||||
ASSERT_TRUE(elf.valid());
|
||||
ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), elf.machine_type());
|
||||
ASSERT_EQ(ELFCLASS64, elf.class_type());
|
||||
|
|
@ -200,7 +202,7 @@ TEST_F(ElfTest, elf_x86_64) {
|
|||
|
||||
InitElf64(EM_X86_64);
|
||||
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.Init(false));
|
||||
ASSERT_TRUE(elf.valid());
|
||||
ASSERT_EQ(static_cast<uint32_t>(EM_X86_64), elf.machine_type());
|
||||
ASSERT_EQ(ELFCLASS64, elf.class_type());
|
||||
|
|
@ -214,7 +216,7 @@ TEST_F(ElfTest, gnu_debugdata_init_fail32) {
|
|||
});
|
||||
|
||||
Elf elf(memory_);
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.Init(false));
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
|
||||
EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
|
||||
|
|
@ -228,7 +230,7 @@ TEST_F(ElfTest, gnu_debugdata_init_fail64) {
|
|||
});
|
||||
|
||||
Elf elf(memory_);
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.Init(false));
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
|
||||
EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
|
||||
|
|
@ -242,14 +244,11 @@ TEST_F(ElfTest, gnu_debugdata_init32) {
|
|||
});
|
||||
|
||||
Elf elf(memory_);
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.Init(true));
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
|
||||
EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
|
||||
EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size());
|
||||
|
||||
elf.InitGnuDebugdata();
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, gnu_debugdata_init64) {
|
||||
|
|
@ -259,42 +258,109 @@ TEST_F(ElfTest, gnu_debugdata_init64) {
|
|||
});
|
||||
|
||||
Elf elf(memory_);
|
||||
ASSERT_TRUE(elf.Init());
|
||||
ASSERT_TRUE(elf.Init(true));
|
||||
ASSERT_TRUE(elf.interface() != nullptr);
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
|
||||
EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
|
||||
EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size());
|
||||
|
||||
elf.InitGnuDebugdata();
|
||||
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
|
||||
}
|
||||
|
||||
class MockElf : public Elf {
|
||||
public:
|
||||
MockElf(Memory* memory) : Elf(memory) {}
|
||||
virtual ~MockElf() = default;
|
||||
|
||||
void set_valid(bool valid) { valid_ = valid; }
|
||||
void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); }
|
||||
};
|
||||
|
||||
TEST_F(ElfTest, rel_pc) {
|
||||
MockElf elf(memory_);
|
||||
ElfFake elf(memory_);
|
||||
|
||||
ElfInterface* interface = new ElfInterface32(memory_);
|
||||
elf.set_elf_interface(interface);
|
||||
ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
|
||||
elf.FakeSetInterface(interface);
|
||||
|
||||
elf.set_valid(true);
|
||||
interface->set_load_bias(0);
|
||||
elf.FakeSetValid(true);
|
||||
elf.FakeSetLoadBias(0);
|
||||
MapInfo map_info{.start = 0x1000, .end = 0x2000};
|
||||
|
||||
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
|
||||
|
||||
interface->set_load_bias(0x3000);
|
||||
elf.FakeSetLoadBias(0x3000);
|
||||
ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info));
|
||||
|
||||
elf.set_valid(false);
|
||||
elf.FakeSetValid(false);
|
||||
elf.FakeSetLoadBias(0);
|
||||
ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, step_in_signal_map) {
|
||||
ElfFake elf(memory_);
|
||||
|
||||
RegsArm regs;
|
||||
regs[13] = 0x50000;
|
||||
regs[15] = 0x8000;
|
||||
regs.SetFromRaw();
|
||||
|
||||
ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
|
||||
elf.FakeSetInterface(interface);
|
||||
|
||||
memory_->SetData32(0x3000, 0xdf0027ad);
|
||||
MemoryFake process_memory;
|
||||
process_memory.SetData32(0x50000, 0);
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
process_memory.SetData32(0x500a0 + i * sizeof(uint32_t), i);
|
||||
}
|
||||
|
||||
elf.FakeSetValid(true);
|
||||
elf.FakeSetLoadBias(0);
|
||||
bool finished;
|
||||
ASSERT_TRUE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
|
||||
EXPECT_FALSE(finished);
|
||||
EXPECT_EQ(15U, regs.pc());
|
||||
EXPECT_EQ(13U, regs.sp());
|
||||
}
|
||||
|
||||
class ElfInterfaceMock : public ElfInterface {
|
||||
public:
|
||||
ElfInterfaceMock(Memory* memory) : ElfInterface(memory) {}
|
||||
virtual ~ElfInterfaceMock() = default;
|
||||
|
||||
bool Init(uint64_t*) override { return false; }
|
||||
void InitHeaders() override {}
|
||||
bool GetSoname(std::string*) override { return false; }
|
||||
bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override { return false; }
|
||||
MOCK_METHOD4(Step, bool(uint64_t, Regs*, Memory*, bool*));
|
||||
};
|
||||
|
||||
TEST_F(ElfTest, step_in_interface) {
|
||||
ElfFake elf(memory_);
|
||||
elf.FakeSetValid(true);
|
||||
elf.FakeSetLoadBias(0);
|
||||
|
||||
RegsArm regs;
|
||||
|
||||
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
|
||||
elf.FakeSetInterface(interface);
|
||||
MemoryFake process_memory;
|
||||
|
||||
bool finished;
|
||||
EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished))
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
ASSERT_TRUE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
|
||||
ElfFake elf(memory_);
|
||||
elf.FakeSetValid(true);
|
||||
elf.FakeSetLoadBias(0x4000);
|
||||
|
||||
RegsArm regs;
|
||||
|
||||
ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
|
||||
elf.FakeSetInterface(interface);
|
||||
MemoryFake process_memory;
|
||||
|
||||
// Invalid relative pc given load_bias.
|
||||
bool finished;
|
||||
ASSERT_FALSE(elf.Step(0x1000, 0x2000, ®s, &process_memory, &finished));
|
||||
|
||||
EXPECT_CALL(*interface, Step(0x3300, ®s, &process_memory, &finished))
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
ASSERT_TRUE(elf.Step(0x7300, 0x2000, ®s, &process_memory, &finished));
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ TEST_F(RegsTest, rel_pc_arm) {
|
|||
RegsArm arm;
|
||||
|
||||
// Check fence posts.
|
||||
elf_interface_->FakeSetLoadBias(0);
|
||||
elf_->FakeSetLoadBias(0);
|
||||
ASSERT_EQ(3U, arm.GetAdjustedPc(0x5, elf_.get()));
|
||||
ASSERT_EQ(4U, arm.GetAdjustedPc(0x4, elf_.get()));
|
||||
ASSERT_EQ(3U, arm.GetAdjustedPc(0x3, elf_.get()));
|
||||
|
|
@ -123,7 +123,7 @@ TEST_F(RegsTest, rel_pc_arm) {
|
|||
ASSERT_EQ(1U, arm.GetAdjustedPc(0x1, elf_.get()));
|
||||
ASSERT_EQ(0U, arm.GetAdjustedPc(0x0, elf_.get()));
|
||||
|
||||
elf_interface_->FakeSetLoadBias(0x100);
|
||||
elf_->FakeSetLoadBias(0x100);
|
||||
ASSERT_EQ(0xffU, arm.GetAdjustedPc(0xff, elf_.get()));
|
||||
ASSERT_EQ(0x103U, arm.GetAdjustedPc(0x105, elf_.get()));
|
||||
ASSERT_EQ(0x104U, arm.GetAdjustedPc(0x104, elf_.get()));
|
||||
|
|
@ -133,13 +133,13 @@ TEST_F(RegsTest, rel_pc_arm) {
|
|||
ASSERT_EQ(0x100U, arm.GetAdjustedPc(0x100, elf_.get()));
|
||||
|
||||
// Check thumb instructions handling.
|
||||
elf_interface_->FakeSetLoadBias(0);
|
||||
elf_->FakeSetLoadBias(0);
|
||||
memory_->SetData32(0x2000, 0);
|
||||
ASSERT_EQ(0x2003U, arm.GetAdjustedPc(0x2005, elf_.get()));
|
||||
memory_->SetData32(0x2000, 0xe000f000);
|
||||
ASSERT_EQ(0x2001U, arm.GetAdjustedPc(0x2005, elf_.get()));
|
||||
|
||||
elf_interface_->FakeSetLoadBias(0x400);
|
||||
elf_->FakeSetLoadBias(0x400);
|
||||
memory_->SetData32(0x2100, 0);
|
||||
ASSERT_EQ(0x2503U, arm.GetAdjustedPc(0x2505, elf_.get()));
|
||||
memory_->SetData32(0x2100, 0xf111f111);
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ class UnwinderTest : public ::testing::Test {
|
|||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
||||
maps_.FakeAddMapInfo(info);
|
||||
|
||||
info.name = "/fake/compressed.so";
|
||||
info.start = 0x33000;
|
||||
info.end = 0x34000;
|
||||
info.flags = PROT_READ | PROT_WRITE;
|
||||
elf = new ElfFake(nullptr);
|
||||
info.elf = elf;
|
||||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
||||
maps_.FakeAddMapInfo(info);
|
||||
|
||||
info.name = "/fake/fake.apk";
|
||||
info.start = 0x43000;
|
||||
info.end = 0x44000;
|
||||
|
|
@ -105,6 +114,14 @@ class UnwinderTest : public ::testing::Test {
|
|||
info.elf = elf;
|
||||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
||||
maps_.FakeAddMapInfo(info);
|
||||
|
||||
info.name = "/fake/fake.oat";
|
||||
info.start = 0x53000;
|
||||
info.end = 0x54000;
|
||||
info.offset = 0;
|
||||
info.flags = PROT_READ | PROT_WRITE;
|
||||
info.elf = nullptr;
|
||||
maps_.FakeAddMapInfo(info);
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
|
|
@ -345,7 +362,7 @@ TEST_F(UnwinderTest, sp_not_in_map) {
|
|||
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
|
||||
|
||||
regs_.FakeSetPc(0x1000);
|
||||
regs_.FakeSetSp(0x53000);
|
||||
regs_.FakeSetSp(0x63000);
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
|
|
@ -358,7 +375,7 @@ TEST_F(UnwinderTest, sp_not_in_map) {
|
|||
EXPECT_EQ(0U, frame->num);
|
||||
EXPECT_EQ(0U, frame->rel_pc);
|
||||
EXPECT_EQ(0x1000U, frame->pc);
|
||||
EXPECT_EQ(0x53000U, frame->sp);
|
||||
EXPECT_EQ(0x63000U, frame->sp);
|
||||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
|
|
@ -540,6 +557,59 @@ TEST_F(UnwinderTest, speculative_frame_removed) {
|
|||
EXPECT_EQ(0, frame->map_flags);
|
||||
}
|
||||
|
||||
// Verify that an unwind stops when a frame is in given suffix.
|
||||
TEST_F(UnwinderTest, map_ignore_suffixes) {
|
||||
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
|
||||
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
|
||||
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
|
||||
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
|
||||
|
||||
// Fake as if code called a nullptr function.
|
||||
regs_.FakeSetPc(0x1000);
|
||||
regs_.FakeSetSp(0x10000);
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0x43402, 0x10010, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
std::set<std::string> suffixes{"oat"};
|
||||
unwinder.Unwind(nullptr, &suffixes);
|
||||
|
||||
ASSERT_EQ(2U, unwinder.NumFrames());
|
||||
// Make sure the elf was not initialized.
|
||||
MapInfo* map_info = maps_.Find(0x53000);
|
||||
ASSERT_TRUE(map_info != nullptr);
|
||||
EXPECT_TRUE(map_info->elf == nullptr);
|
||||
|
||||
auto* frame = &unwinder.frames()[0];
|
||||
EXPECT_EQ(0U, frame->num);
|
||||
EXPECT_EQ(0U, frame->rel_pc);
|
||||
EXPECT_EQ(0x1000U, frame->pc);
|
||||
EXPECT_EQ(0x10000U, frame->sp);
|
||||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
|
||||
|
||||
frame = &unwinder.frames()[1];
|
||||
EXPECT_EQ(1U, frame->num);
|
||||
EXPECT_EQ(0x400U, frame->rel_pc);
|
||||
EXPECT_EQ(0x43400U, frame->pc);
|
||||
EXPECT_EQ(0x10010U, frame->sp);
|
||||
EXPECT_EQ("Frame1", frame->function_name);
|
||||
EXPECT_EQ(1U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/fake.apk", frame->map_name);
|
||||
EXPECT_EQ(0x1d000U, frame->map_offset);
|
||||
EXPECT_EQ(0x43000U, frame->map_start);
|
||||
EXPECT_EQ(0x44000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
|
||||
}
|
||||
|
||||
// Verify format frame code.
|
||||
TEST_F(UnwinderTest, format_frame_static) {
|
||||
FrameData frame;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ void DumpArm(ElfInterfaceArm* interface) {
|
|||
uint64_t func_offset;
|
||||
uint64_t pc = addr + load_bias;
|
||||
// This might be a thumb function, so set the low bit.
|
||||
if (interface->GetFunctionName(pc | 1, &name, &func_offset) && !name.empty()) {
|
||||
if (interface->GetFunctionName(pc | 1, load_bias, &name, &func_offset) && !name.empty()) {
|
||||
printf(" <%s>", name.c_str());
|
||||
}
|
||||
printf("\n");
|
||||
|
|
@ -92,8 +92,7 @@ void DumpDwarfSection(ElfInterface* interface, DwarfSection* section, uint64_t l
|
|||
printf("\n PC 0x%" PRIx64, fde->pc_start + load_bias);
|
||||
std::string name;
|
||||
uint64_t func_offset;
|
||||
if (interface->GetFunctionName(fde->pc_start + load_bias, &name, &func_offset) &&
|
||||
!name.empty()) {
|
||||
if (interface->GetFunctionName(fde->pc_start, load_bias, &name, &func_offset) && !name.empty()) {
|
||||
printf(" <%s>", name.c_str());
|
||||
}
|
||||
printf("\n");
|
||||
|
|
@ -115,7 +114,7 @@ int GetElfInfo(const char* file) {
|
|||
}
|
||||
|
||||
Elf elf(memory);
|
||||
if (!elf.Init() || !elf.valid()) {
|
||||
if (!elf.Init(true) || !elf.valid()) {
|
||||
printf("%s is not a valid elf file.\n", file);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -128,7 +127,7 @@ int GetElfInfo(const char* file) {
|
|||
|
||||
if (interface->eh_frame() != nullptr) {
|
||||
printf("eh_frame information:\n");
|
||||
DumpDwarfSection(interface, interface->eh_frame(), interface->load_bias());
|
||||
DumpDwarfSection(interface, interface->eh_frame(), elf.GetLoadBias());
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("\nno eh_frame information\n");
|
||||
|
|
@ -136,7 +135,7 @@ int GetElfInfo(const char* file) {
|
|||
|
||||
if (interface->debug_frame() != nullptr) {
|
||||
printf("\ndebug_frame information:\n");
|
||||
DumpDwarfSection(interface, interface->debug_frame(), interface->load_bias());
|
||||
DumpDwarfSection(interface, interface->debug_frame(), elf.GetLoadBias());
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("\nno debug_frame information\n");
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
unwindstack::Elf elf(memory);
|
||||
if (!elf.Init() || !elf.valid()) {
|
||||
if (!elf.Init(true) || !elf.valid()) {
|
||||
printf("%s is not a valid elf file.\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
std::string name;
|
||||
uint64_t load_bias = elf.interface()->load_bias();
|
||||
uint64_t load_bias = elf.GetLoadBias();
|
||||
if (argc == 3) {
|
||||
std::string cur_name;
|
||||
uint64_t func_offset;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue