Add support for only a .eh_frame.
Static executables only have a .eh_frame section and no .eh_frame_hdr section. Add support for this by rearranging the class hierarchy and creating a DwarfEhFrameWithHdr class and a DwarfEhFrame class to handle the different cases. Add new unit tests for DwarfEhFrame and for the new functionality. Bug: 68820189 Test: Passes new unit tests, unwinds static executables. Change-Id: I63d7cb8c52a686e96579a2266e18c0d06bbb6e63
This commit is contained in:
parent
1e0b9672de
commit
c9dee84d81
|
@ -48,8 +48,7 @@ cc_library {
|
|||
srcs: [
|
||||
"ArmExidx.cpp",
|
||||
"DwarfCfa.cpp",
|
||||
"DwarfDebugFrame.cpp",
|
||||
"DwarfEhFrame.cpp",
|
||||
"DwarfEhFrameWithHdr.cpp",
|
||||
"DwarfMemory.cpp",
|
||||
"DwarfOp.cpp",
|
||||
"DwarfSection.cpp",
|
||||
|
@ -106,6 +105,7 @@ cc_test {
|
|||
"tests/DwarfCfaTest.cpp",
|
||||
"tests/DwarfDebugFrameTest.cpp",
|
||||
"tests/DwarfEhFrameTest.cpp",
|
||||
"tests/DwarfEhFrameWithHdrTest.cpp",
|
||||
"tests/DwarfMemoryTest.cpp",
|
||||
"tests/DwarfOpLogTest.cpp",
|
||||
"tests/DwarfOpTest.cpp",
|
||||
|
|
|
@ -1,316 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <unwindstack/DwarfStructs.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
|
||||
#include "DwarfDebugFrame.h"
|
||||
#include "DwarfEncoding.h"
|
||||
#include "DwarfError.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfDebugFrame<AddressType>::Init(uint64_t offset, uint64_t size) {
|
||||
offset_ = offset;
|
||||
end_offset_ = offset + size;
|
||||
|
||||
memory_.clear_func_offset();
|
||||
memory_.clear_text_offset();
|
||||
memory_.set_data_offset(offset);
|
||||
memory_.set_cur_offset(offset);
|
||||
|
||||
return CreateSortedFdeList();
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfDebugFrame<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) {
|
||||
uint8_t version;
|
||||
if (!memory_.ReadBytes(&version, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
// Read the augmentation string.
|
||||
std::vector<char> aug_string;
|
||||
char aug_value;
|
||||
bool get_encoding = false;
|
||||
do {
|
||||
if (!memory_.ReadBytes(&aug_value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
if (aug_value == 'R') {
|
||||
get_encoding = true;
|
||||
}
|
||||
aug_string.push_back(aug_value);
|
||||
} while (aug_value != '\0');
|
||||
|
||||
if (version == 4) {
|
||||
// Skip the Address Size field.
|
||||
memory_.set_cur_offset(memory_.cur_offset() + 1);
|
||||
|
||||
// Read the segment size.
|
||||
if (!memory_.ReadBytes(segment_size, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*segment_size = 0;
|
||||
}
|
||||
|
||||
if (aug_string[0] != 'z' || !get_encoding) {
|
||||
// No encoding
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip code alignment factor
|
||||
uint8_t value;
|
||||
do {
|
||||
if (!memory_.ReadBytes(&value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} while (value & 0x80);
|
||||
|
||||
// Skip data alignment factor
|
||||
do {
|
||||
if (!memory_.ReadBytes(&value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} while (value & 0x80);
|
||||
|
||||
if (version == 1) {
|
||||
// Skip return address register.
|
||||
memory_.set_cur_offset(memory_.cur_offset() + 1);
|
||||
} else {
|
||||
// Skip return address register.
|
||||
do {
|
||||
if (!memory_.ReadBytes(&value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} while (value & 0x80);
|
||||
}
|
||||
|
||||
// Skip the augmentation length.
|
||||
do {
|
||||
if (!memory_.ReadBytes(&value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} while (value & 0x80);
|
||||
|
||||
for (size_t i = 1; i < aug_string.size(); i++) {
|
||||
if (aug_string[i] == 'R') {
|
||||
if (!memory_.ReadBytes(encoding, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
// Got the encoding, that's all we are looking for.
|
||||
return true;
|
||||
} else if (aug_string[i] == 'L') {
|
||||
memory_.set_cur_offset(memory_.cur_offset() + 1);
|
||||
} else if (aug_string[i] == 'P') {
|
||||
uint8_t encoding;
|
||||
if (!memory_.ReadBytes(&encoding, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
uint64_t value;
|
||||
if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It should be impossible to get here.
|
||||
abort();
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfDebugFrame<AddressType>::AddFdeInfo(uint64_t entry_offset, uint8_t segment_size,
|
||||
uint8_t encoding) {
|
||||
if (segment_size != 0) {
|
||||
memory_.set_cur_offset(memory_.cur_offset() + 1);
|
||||
}
|
||||
|
||||
uint64_t start;
|
||||
if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &start)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t length;
|
||||
if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &length)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
if (length != 0) {
|
||||
fdes_.emplace_back(entry_offset, start, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfDebugFrame<AddressType>::CreateSortedFdeList() {
|
||||
memory_.set_cur_offset(offset_);
|
||||
|
||||
// Loop through all of the entries and read just enough to create
|
||||
// a sorted list of pcs.
|
||||
// This code assumes that first comes the cie, then the fdes that
|
||||
// it applies to.
|
||||
uint64_t cie_offset = 0;
|
||||
uint8_t address_encoding;
|
||||
uint8_t segment_size;
|
||||
while (memory_.cur_offset() < end_offset_) {
|
||||
uint64_t cur_entry_offset = memory_.cur_offset();
|
||||
|
||||
// Figure out the entry length and type.
|
||||
uint32_t value32;
|
||||
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t next_entry_offset;
|
||||
if (value32 == static_cast<uint32_t>(-1)) {
|
||||
uint64_t value64;
|
||||
if (!memory_.ReadBytes(&value64, sizeof(value64))) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
next_entry_offset = memory_.cur_offset() + value64;
|
||||
|
||||
// Read the Cie Id of a Cie or the pointer of the Fde.
|
||||
if (!memory_.ReadBytes(&value64, sizeof(value64))) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value64 == static_cast<uint64_t>(-1)) {
|
||||
// Cie 64 bit
|
||||
address_encoding = DW_EH_PE_sdata8;
|
||||
if (!GetCieInfo(&segment_size, &address_encoding)) {
|
||||
return false;
|
||||
}
|
||||
cie_offset = cur_entry_offset;
|
||||
} else {
|
||||
if (offset_ + value64 != cie_offset) {
|
||||
// This means that this Fde is not following the Cie.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fde 64 bit
|
||||
if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
next_entry_offset = memory_.cur_offset() + value32;
|
||||
|
||||
// Read the Cie Id of a Cie or the pointer of the Fde.
|
||||
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value32 == static_cast<uint32_t>(-1)) {
|
||||
// Cie 32 bit
|
||||
address_encoding = DW_EH_PE_sdata4;
|
||||
if (!GetCieInfo(&segment_size, &address_encoding)) {
|
||||
return false;
|
||||
}
|
||||
cie_offset = cur_entry_offset;
|
||||
} else {
|
||||
if (offset_ + value32 != cie_offset) {
|
||||
// This means that this Fde is not following the Cie.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fde 32 bit
|
||||
if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next_entry_offset < memory_.cur_offset()) {
|
||||
// This indicates some kind of corruption, or malformed section data.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
}
|
||||
memory_.set_cur_offset(next_entry_offset);
|
||||
}
|
||||
|
||||
// Sort the entries.
|
||||
std::sort(fdes_.begin(), fdes_.end(), [](const FdeInfo& a, const FdeInfo& b) {
|
||||
if (a.start == b.start) return a.end < b.end;
|
||||
return a.start < b.start;
|
||||
});
|
||||
|
||||
fde_count_ = fdes_.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfDebugFrame<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
|
||||
if (fde_count_ == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t first = 0;
|
||||
size_t last = fde_count_;
|
||||
while (first < last) {
|
||||
size_t current = (first + last) / 2;
|
||||
const FdeInfo* info = &fdes_[current];
|
||||
if (pc >= info->start && pc <= info->end) {
|
||||
*fde_offset = info->offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pc < info->start) {
|
||||
last = current;
|
||||
} else {
|
||||
first = current + 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
const DwarfFde* DwarfDebugFrame<AddressType>::GetFdeFromIndex(size_t index) {
|
||||
if (index >= fdes_.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return this->GetFdeFromOffset(fdes_[index].offset);
|
||||
}
|
||||
|
||||
// Explicitly instantiate DwarfDebugFrame.
|
||||
template class DwarfDebugFrame<uint32_t>;
|
||||
template class DwarfDebugFrame<uint64_t>;
|
||||
|
||||
} // namespace unwindstack
|
|
@ -28,51 +28,21 @@ namespace unwindstack {
|
|||
template <typename AddressType>
|
||||
class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
|
||||
public:
|
||||
// Add these so that the protected members of DwarfSectionImpl
|
||||
// can be accessed without needing a this->.
|
||||
using DwarfSectionImpl<AddressType>::memory_;
|
||||
using DwarfSectionImpl<AddressType>::fde_count_;
|
||||
using DwarfSectionImpl<AddressType>::last_error_;
|
||||
|
||||
struct FdeInfo {
|
||||
FdeInfo(uint64_t offset, uint64_t start, uint64_t length)
|
||||
: offset(offset), start(start), end(start + length) {}
|
||||
|
||||
uint64_t offset;
|
||||
AddressType start;
|
||||
AddressType end;
|
||||
};
|
||||
|
||||
DwarfDebugFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
|
||||
DwarfDebugFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {
|
||||
this->cie32_value_ = static_cast<uint32_t>(-1);
|
||||
this->cie64_value_ = static_cast<uint64_t>(-1);
|
||||
}
|
||||
virtual ~DwarfDebugFrame() = default;
|
||||
|
||||
bool Init(uint64_t offset, uint64_t size) override;
|
||||
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
|
||||
return this->entries_offset_ + pointer;
|
||||
}
|
||||
|
||||
bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
|
||||
|
||||
const DwarfFde* GetFdeFromIndex(size_t index) override;
|
||||
|
||||
bool IsCie32(uint32_t value32) override { return value32 == static_cast<uint32_t>(-1); }
|
||||
|
||||
bool IsCie64(uint64_t value64) override { return value64 == static_cast<uint64_t>(-1); }
|
||||
|
||||
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override { return offset_ + pointer; }
|
||||
|
||||
uint64_t GetCieOffsetFromFde64(uint64_t pointer) override { return offset_ + pointer; }
|
||||
uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
|
||||
return this->entries_offset_ + pointer;
|
||||
}
|
||||
|
||||
uint64_t AdjustPcFromFde(uint64_t pc) override { return pc; }
|
||||
|
||||
bool GetCieInfo(uint8_t* segment_size, uint8_t* encoding);
|
||||
|
||||
bool AddFdeInfo(uint64_t entry_offset, uint8_t segment_size, uint8_t encoding);
|
||||
|
||||
bool CreateSortedFdeList();
|
||||
|
||||
protected:
|
||||
uint64_t offset_;
|
||||
uint64_t end_offset_;
|
||||
|
||||
std::vector<FdeInfo> fdes_;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
@ -20,74 +20,30 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <unwindstack/DwarfSection.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
|
||||
template <typename AddressType>
|
||||
class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
|
||||
public:
|
||||
// Add these so that the protected members of DwarfSectionImpl
|
||||
// can be accessed without needing a this->.
|
||||
using DwarfSectionImpl<AddressType>::memory_;
|
||||
using DwarfSectionImpl<AddressType>::fde_count_;
|
||||
using DwarfSectionImpl<AddressType>::last_error_;
|
||||
|
||||
struct FdeInfo {
|
||||
AddressType pc;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
DwarfEhFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
|
||||
virtual ~DwarfEhFrame() = default;
|
||||
|
||||
bool Init(uint64_t offset, uint64_t size) override;
|
||||
|
||||
bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
|
||||
|
||||
const DwarfFde* GetFdeFromIndex(size_t index) override;
|
||||
|
||||
bool IsCie32(uint32_t value32) override { return value32 == 0; }
|
||||
|
||||
bool IsCie64(uint64_t value64) override { return value64 == 0; }
|
||||
|
||||
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
|
||||
return memory_.cur_offset() - pointer - 4;
|
||||
return this->memory_.cur_offset() - pointer - 4;
|
||||
}
|
||||
|
||||
uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
|
||||
return memory_.cur_offset() - pointer - 8;
|
||||
return this->memory_.cur_offset() - pointer - 8;
|
||||
}
|
||||
|
||||
uint64_t AdjustPcFromFde(uint64_t pc) override {
|
||||
// The eh_frame uses relative pcs.
|
||||
return pc + memory_.cur_offset();
|
||||
return pc + this->memory_.cur_offset();
|
||||
}
|
||||
|
||||
const FdeInfo* GetFdeInfoFromIndex(size_t index);
|
||||
|
||||
bool GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset);
|
||||
|
||||
bool GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, uint64_t total_entries);
|
||||
|
||||
protected:
|
||||
uint8_t version_;
|
||||
uint8_t ptr_encoding_;
|
||||
uint8_t table_encoding_;
|
||||
size_t table_entry_size_;
|
||||
|
||||
uint64_t ptr_offset_;
|
||||
|
||||
uint64_t entries_offset_;
|
||||
uint64_t entries_end_;
|
||||
uint64_t entries_data_offset_;
|
||||
uint64_t cur_entries_offset_ = 0;
|
||||
|
||||
std::unordered_map<uint64_t, FdeInfo> fde_info_;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_H
|
||||
#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
#include <unwindstack/Memory.h>
|
||||
|
||||
#include "Check.h"
|
||||
#include "DwarfEhFrame.h"
|
||||
#include "DwarfEhFrameWithHdr.h"
|
||||
#include "DwarfError.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfEhFrame<AddressType>::Init(uint64_t offset, uint64_t size) {
|
||||
bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size) {
|
||||
uint8_t data[4];
|
||||
|
||||
memory_.clear_func_offset();
|
||||
|
@ -73,7 +73,7 @@ bool DwarfEhFrame<AddressType>::Init(uint64_t offset, uint64_t size) {
|
|||
}
|
||||
|
||||
template <typename AddressType>
|
||||
const DwarfFde* DwarfEhFrame<AddressType>::GetFdeFromIndex(size_t index) {
|
||||
const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromIndex(size_t index) {
|
||||
const FdeInfo* info = GetFdeInfoFromIndex(index);
|
||||
if (info == nullptr) {
|
||||
return nullptr;
|
||||
|
@ -82,8 +82,8 @@ const DwarfFde* DwarfEhFrame<AddressType>::GetFdeFromIndex(size_t index) {
|
|||
}
|
||||
|
||||
template <typename AddressType>
|
||||
const typename DwarfEhFrame<AddressType>::FdeInfo* DwarfEhFrame<AddressType>::GetFdeInfoFromIndex(
|
||||
size_t index) {
|
||||
const typename DwarfEhFrameWithHdr<AddressType>::FdeInfo*
|
||||
DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
|
||||
auto entry = fde_info_.find(index);
|
||||
if (entry != fde_info_.end()) {
|
||||
return &fde_info_[index];
|
||||
|
@ -105,8 +105,8 @@ const typename DwarfEhFrame<AddressType>::FdeInfo* DwarfEhFrame<AddressType>::Ge
|
|||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfEhFrame<AddressType>::GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset,
|
||||
uint64_t total_entries) {
|
||||
bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset,
|
||||
uint64_t total_entries) {
|
||||
CHECK(fde_count_ > 0);
|
||||
CHECK(total_entries <= fde_count_);
|
||||
|
||||
|
@ -134,7 +134,7 @@ bool DwarfEhFrame<AddressType>::GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_of
|
|||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfEhFrame<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) {
|
||||
bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset) {
|
||||
CHECK(fde_count_ != 0);
|
||||
last_error_ = DWARF_ERROR_NONE;
|
||||
// We can do a binary search if the pc is in the range of the elements
|
||||
|
@ -196,7 +196,7 @@ bool DwarfEhFrame<AddressType>::GetFdeOffsetSequential(uint64_t pc, uint64_t* fd
|
|||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfEhFrame<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
|
||||
bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
|
||||
if (fde_count_ == 0) {
|
||||
return false;
|
||||
}
|
||||
|
@ -210,8 +210,8 @@ bool DwarfEhFrame<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_of
|
|||
}
|
||||
}
|
||||
|
||||
// Explicitly instantiate DwarfEhFrame.
|
||||
template class DwarfEhFrame<uint32_t>;
|
||||
template class DwarfEhFrame<uint64_t>;
|
||||
// Explicitly instantiate DwarfEhFrameWithHdr
|
||||
template class DwarfEhFrameWithHdr<uint32_t>;
|
||||
template class DwarfEhFrameWithHdr<uint64_t>;
|
||||
|
||||
} // namespace unwindstack
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
|
||||
#define _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "DwarfEhFrame.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
|
||||
template <typename AddressType>
|
||||
class DwarfEhFrameWithHdr : public DwarfEhFrame<AddressType> {
|
||||
public:
|
||||
// Add these so that the protected members of DwarfSectionImpl
|
||||
// can be accessed without needing a this->.
|
||||
using DwarfSectionImpl<AddressType>::memory_;
|
||||
using DwarfSectionImpl<AddressType>::fde_count_;
|
||||
using DwarfSectionImpl<AddressType>::entries_offset_;
|
||||
using DwarfSectionImpl<AddressType>::entries_end_;
|
||||
using DwarfSectionImpl<AddressType>::last_error_;
|
||||
|
||||
struct FdeInfo {
|
||||
AddressType pc;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
DwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrame<AddressType>(memory) {}
|
||||
virtual ~DwarfEhFrameWithHdr() = default;
|
||||
|
||||
bool Init(uint64_t offset, uint64_t size) override;
|
||||
|
||||
bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
|
||||
|
||||
const DwarfFde* GetFdeFromIndex(size_t index) override;
|
||||
|
||||
const FdeInfo* GetFdeInfoFromIndex(size_t index);
|
||||
|
||||
bool GetFdeOffsetSequential(uint64_t pc, uint64_t* fde_offset);
|
||||
|
||||
bool GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, uint64_t total_entries);
|
||||
|
||||
protected:
|
||||
uint8_t version_;
|
||||
uint8_t ptr_encoding_;
|
||||
uint8_t table_encoding_;
|
||||
size_t table_entry_size_;
|
||||
|
||||
uint64_t ptr_offset_;
|
||||
|
||||
uint64_t entries_data_offset_;
|
||||
uint64_t cur_entries_offset_ = 0;
|
||||
|
||||
std::unordered_map<uint64_t, FdeInfo> fde_info_;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
|
|
@ -29,6 +29,9 @@
|
|||
#include "DwarfError.h"
|
||||
#include "DwarfOp.h"
|
||||
|
||||
#include "DwarfDebugFrame.h"
|
||||
#include "DwarfEhFrame.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
|
||||
|
@ -282,7 +285,7 @@ bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
|
|||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
if (!IsCie64(cie_id)) {
|
||||
if (cie_id != cie64_value_) {
|
||||
// This is not a Cie, something has gone horribly wrong.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
|
@ -297,7 +300,7 @@ bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
|
|||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
if (!IsCie32(cie_id)) {
|
||||
if (cie_id != cie32_value_) {
|
||||
// This is not a Cie, something has gone horribly wrong.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
|
@ -440,7 +443,7 @@ bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
|
|||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
if (IsCie64(value64)) {
|
||||
if (value64 == cie64_value_) {
|
||||
// This is a Cie, this means something has gone wrong.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
|
@ -458,7 +461,7 @@ bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
|
|||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
if (IsCie32(value32)) {
|
||||
if (value32 == cie32_value_) {
|
||||
// This is a Cie, this means something has gone wrong.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
|
@ -556,8 +559,301 @@ bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, uint64_t lo
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size) {
|
||||
entries_offset_ = offset;
|
||||
entries_end_ = offset + size;
|
||||
|
||||
memory_.clear_func_offset();
|
||||
memory_.clear_text_offset();
|
||||
memory_.set_data_offset(offset);
|
||||
memory_.set_cur_offset(offset);
|
||||
memory_.set_pc_offset(offset);
|
||||
|
||||
return CreateSortedFdeList();
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfSectionImpl<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) {
|
||||
uint8_t version;
|
||||
if (!memory_.ReadBytes(&version, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
// Read the augmentation string.
|
||||
std::vector<char> aug_string;
|
||||
char aug_value;
|
||||
bool get_encoding = false;
|
||||
do {
|
||||
if (!memory_.ReadBytes(&aug_value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
if (aug_value == 'R') {
|
||||
get_encoding = true;
|
||||
}
|
||||
aug_string.push_back(aug_value);
|
||||
} while (aug_value != '\0');
|
||||
|
||||
if (version == 4) {
|
||||
// Skip the Address Size field.
|
||||
memory_.set_cur_offset(memory_.cur_offset() + 1);
|
||||
|
||||
// Read the segment size.
|
||||
if (!memory_.ReadBytes(segment_size, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*segment_size = 0;
|
||||
}
|
||||
|
||||
if (aug_string[0] != 'z' || !get_encoding) {
|
||||
// No encoding
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip code alignment factor
|
||||
uint8_t value;
|
||||
do {
|
||||
if (!memory_.ReadBytes(&value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} while (value & 0x80);
|
||||
|
||||
// Skip data alignment factor
|
||||
do {
|
||||
if (!memory_.ReadBytes(&value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} while (value & 0x80);
|
||||
|
||||
if (version == 1) {
|
||||
// Skip return address register.
|
||||
memory_.set_cur_offset(memory_.cur_offset() + 1);
|
||||
} else {
|
||||
// Skip return address register.
|
||||
do {
|
||||
if (!memory_.ReadBytes(&value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} while (value & 0x80);
|
||||
}
|
||||
|
||||
// Skip the augmentation length.
|
||||
do {
|
||||
if (!memory_.ReadBytes(&value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
} while (value & 0x80);
|
||||
|
||||
for (size_t i = 1; i < aug_string.size(); i++) {
|
||||
if (aug_string[i] == 'R') {
|
||||
if (!memory_.ReadBytes(encoding, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
// Got the encoding, that's all we are looking for.
|
||||
return true;
|
||||
} else if (aug_string[i] == 'L') {
|
||||
memory_.set_cur_offset(memory_.cur_offset() + 1);
|
||||
} else if (aug_string[i] == 'P') {
|
||||
uint8_t encoding;
|
||||
if (!memory_.ReadBytes(&encoding, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
uint64_t value;
|
||||
if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It should be impossible to get here.
|
||||
abort();
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfSectionImpl<AddressType>::AddFdeInfo(uint64_t entry_offset, uint8_t segment_size,
|
||||
uint8_t encoding) {
|
||||
if (segment_size != 0) {
|
||||
memory_.set_cur_offset(memory_.cur_offset() + 1);
|
||||
}
|
||||
|
||||
uint64_t start;
|
||||
if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &start)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
start = AdjustPcFromFde(start);
|
||||
|
||||
uint64_t length;
|
||||
if (!memory_.template ReadEncodedValue<AddressType>(encoding & 0xf, &length)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
if (length != 0) {
|
||||
fdes_.emplace_back(entry_offset, start, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfSectionImpl<AddressType>::CreateSortedFdeList() {
|
||||
memory_.set_cur_offset(entries_offset_);
|
||||
|
||||
// Loop through all of the entries and read just enough to create
|
||||
// a sorted list of pcs.
|
||||
// This code assumes that first comes the cie, then the fdes that
|
||||
// it applies to.
|
||||
uint64_t cie_offset = 0;
|
||||
uint8_t address_encoding;
|
||||
uint8_t segment_size;
|
||||
while (memory_.cur_offset() < entries_end_) {
|
||||
uint64_t cur_entry_offset = memory_.cur_offset();
|
||||
|
||||
// Figure out the entry length and type.
|
||||
uint32_t value32;
|
||||
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t next_entry_offset;
|
||||
if (value32 == static_cast<uint32_t>(-1)) {
|
||||
uint64_t value64;
|
||||
if (!memory_.ReadBytes(&value64, sizeof(value64))) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
next_entry_offset = memory_.cur_offset() + value64;
|
||||
|
||||
// Read the Cie Id of a Cie or the pointer of the Fde.
|
||||
if (!memory_.ReadBytes(&value64, sizeof(value64))) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value64 == cie64_value_) {
|
||||
// Cie 64 bit
|
||||
address_encoding = DW_EH_PE_sdata8;
|
||||
if (!GetCieInfo(&segment_size, &address_encoding)) {
|
||||
return false;
|
||||
}
|
||||
cie_offset = cur_entry_offset;
|
||||
} else {
|
||||
uint64_t last_cie_offset = GetCieOffsetFromFde64(value64);
|
||||
if (last_cie_offset != cie_offset) {
|
||||
// This means that this Fde is not following the Cie.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fde 64 bit
|
||||
if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
next_entry_offset = memory_.cur_offset() + value32;
|
||||
|
||||
// Read the Cie Id of a Cie or the pointer of the Fde.
|
||||
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value32 == cie32_value_) {
|
||||
// Cie 32 bit
|
||||
address_encoding = DW_EH_PE_sdata4;
|
||||
if (!GetCieInfo(&segment_size, &address_encoding)) {
|
||||
return false;
|
||||
}
|
||||
cie_offset = cur_entry_offset;
|
||||
} else {
|
||||
uint64_t last_cie_offset = GetCieOffsetFromFde32(value32);
|
||||
if (last_cie_offset != cie_offset) {
|
||||
// This means that this Fde is not following the Cie.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fde 32 bit
|
||||
if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next_entry_offset < memory_.cur_offset()) {
|
||||
// This indicates some kind of corruption, or malformed section data.
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
}
|
||||
memory_.set_cur_offset(next_entry_offset);
|
||||
}
|
||||
|
||||
// Sort the entries.
|
||||
std::sort(fdes_.begin(), fdes_.end(), [](const FdeInfo& a, const FdeInfo& b) {
|
||||
if (a.start == b.start) return a.end < b.end;
|
||||
return a.start < b.start;
|
||||
});
|
||||
|
||||
fde_count_ = fdes_.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfSectionImpl<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
|
||||
if (fde_count_ == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t first = 0;
|
||||
size_t last = fde_count_;
|
||||
while (first < last) {
|
||||
size_t current = (first + last) / 2;
|
||||
const FdeInfo* info = &fdes_[current];
|
||||
if (pc >= info->start && pc <= info->end) {
|
||||
*fde_offset = info->offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pc < info->start) {
|
||||
last = current;
|
||||
} else {
|
||||
first = current + 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromIndex(size_t index) {
|
||||
if (index >= fdes_.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return this->GetFdeFromOffset(fdes_[index].offset);
|
||||
}
|
||||
|
||||
// Explicitly instantiate DwarfSectionImpl
|
||||
template class DwarfSectionImpl<uint32_t>;
|
||||
template class DwarfSectionImpl<uint64_t>;
|
||||
|
||||
// Explicitly instantiate DwarfDebugFrame
|
||||
template class DwarfDebugFrame<uint32_t>;
|
||||
template class DwarfDebugFrame<uint64_t>;
|
||||
|
||||
// Explicitly instantiate DwarfEhFrame
|
||||
template class DwarfEhFrame<uint32_t>;
|
||||
template class DwarfEhFrame<uint64_t>;
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "DwarfDebugFrame.h"
|
||||
#include "DwarfEhFrame.h"
|
||||
#include "DwarfEhFrameWithHdr.h"
|
||||
#include "Symbols.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
@ -98,7 +99,17 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() {
|
|||
|
||||
template <typename AddressType>
|
||||
void ElfInterface::InitHeadersWithTemplate() {
|
||||
if (eh_frame_offset_ != 0) {
|
||||
if (eh_frame_hdr_offset_ != 0) {
|
||||
eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_));
|
||||
if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_)) {
|
||||
// Even if the eh_frame_offset_ is non-zero, do not bother
|
||||
// trying to read that since something has gone wrong.
|
||||
eh_frame_.reset(nullptr);
|
||||
eh_frame_hdr_offset_ = 0;
|
||||
eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
|
||||
}
|
||||
} else if (eh_frame_offset_ != 0) {
|
||||
// If there is a eh_frame section without a eh_frame_hdr section.
|
||||
eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
|
||||
if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
|
||||
eh_frame_.reset(nullptr);
|
||||
|
@ -181,11 +192,12 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias)
|
|||
if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
|
||||
return false;
|
||||
}
|
||||
eh_frame_offset_ = phdr.p_offset;
|
||||
// This is really the pointer to the .eh_frame_hdr section.
|
||||
eh_frame_hdr_offset_ = phdr.p_offset;
|
||||
if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
|
||||
return false;
|
||||
}
|
||||
eh_frame_size_ = phdr.p_memsz;
|
||||
eh_frame_hdr_size_ = phdr.p_memsz;
|
||||
break;
|
||||
|
||||
case PT_DYNAMIC:
|
||||
|
@ -271,6 +283,12 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
|
|||
} else if (name == ".gnu_debugdata") {
|
||||
offset_ptr = &gnu_debugdata_offset_;
|
||||
size_ptr = &gnu_debugdata_size_;
|
||||
} else if (name == ".eh_frame") {
|
||||
offset_ptr = &eh_frame_offset_;
|
||||
size_ptr = &eh_frame_size_;
|
||||
} else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
|
||||
offset_ptr = &eh_frame_hdr_offset_;
|
||||
size_ptr = &eh_frame_hdr_size_;
|
||||
}
|
||||
if (offset_ptr != nullptr &&
|
||||
memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
|
||||
|
|
|
@ -90,10 +90,6 @@ class DwarfSection {
|
|||
|
||||
virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) = 0;
|
||||
|
||||
virtual bool IsCie32(uint32_t value32) = 0;
|
||||
|
||||
virtual bool IsCie64(uint64_t value64) = 0;
|
||||
|
||||
virtual uint64_t GetCieOffsetFromFde32(uint32_t pointer) = 0;
|
||||
|
||||
virtual uint64_t GetCieOffsetFromFde64(uint64_t pointer) = 0;
|
||||
|
@ -106,6 +102,9 @@ class DwarfSection {
|
|||
DwarfMemory memory_;
|
||||
DwarfError last_error_;
|
||||
|
||||
uint32_t cie32_value_ = 0;
|
||||
uint64_t cie64_value_ = 0;
|
||||
|
||||
uint64_t fde_count_ = 0;
|
||||
std::unordered_map<uint64_t, DwarfFde> fde_entries_;
|
||||
std::unordered_map<uint64_t, DwarfCie> cie_entries_;
|
||||
|
@ -115,9 +114,24 @@ class DwarfSection {
|
|||
template <typename AddressType>
|
||||
class DwarfSectionImpl : public DwarfSection {
|
||||
public:
|
||||
struct FdeInfo {
|
||||
FdeInfo(uint64_t offset, uint64_t start, uint64_t length)
|
||||
: offset(offset), start(start), end(start + length) {}
|
||||
|
||||
uint64_t offset;
|
||||
AddressType start;
|
||||
AddressType end;
|
||||
};
|
||||
|
||||
DwarfSectionImpl(Memory* memory) : DwarfSection(memory) {}
|
||||
virtual ~DwarfSectionImpl() = default;
|
||||
|
||||
bool Init(uint64_t offset, uint64_t size) override;
|
||||
|
||||
bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
|
||||
|
||||
const DwarfFde* GetFdeFromIndex(size_t index) override;
|
||||
|
||||
bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
|
||||
Regs* regs, bool* finished) override;
|
||||
|
||||
|
@ -134,6 +148,16 @@ class DwarfSectionImpl : public DwarfSection {
|
|||
protected:
|
||||
bool EvalExpression(const DwarfLocation& loc, uint8_t version, Memory* regular_memory,
|
||||
AddressType* value);
|
||||
|
||||
bool GetCieInfo(uint8_t* segment_size, uint8_t* encoding);
|
||||
|
||||
bool AddFdeInfo(uint64_t entry_offset, uint8_t segment_size, uint8_t encoding);
|
||||
|
||||
bool CreateSortedFdeList();
|
||||
|
||||
std::vector<FdeInfo> fdes_;
|
||||
uint64_t entries_offset_;
|
||||
uint64_t entries_end_;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
|
@ -70,6 +70,8 @@ class ElfInterface {
|
|||
|
||||
uint64_t dynamic_offset() { return dynamic_offset_; }
|
||||
uint64_t dynamic_size() { return dynamic_size_; }
|
||||
uint64_t eh_frame_hdr_offset() { return eh_frame_hdr_offset_; }
|
||||
uint64_t eh_frame_hdr_size() { return eh_frame_hdr_size_; }
|
||||
uint64_t eh_frame_offset() { return eh_frame_offset_; }
|
||||
uint64_t eh_frame_size() { return eh_frame_size_; }
|
||||
uint64_t debug_frame_offset() { return debug_frame_offset_; }
|
||||
|
@ -112,6 +114,9 @@ class ElfInterface {
|
|||
uint64_t dynamic_offset_ = 0;
|
||||
uint64_t dynamic_size_ = 0;
|
||||
|
||||
uint64_t eh_frame_hdr_offset_ = 0;
|
||||
uint64_t eh_frame_hdr_size_ = 0;
|
||||
|
||||
uint64_t eh_frame_offset_ = 0;
|
||||
uint64_t eh_frame_size_ = 0;
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ class MockDwarfDebugFrame : public DwarfDebugFrame<TypeParam> {
|
|||
~MockDwarfDebugFrame() = default;
|
||||
|
||||
void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
|
||||
void TestSetOffset(uint64_t offset) { this->offset_ = offset; }
|
||||
void TestSetEndOffset(uint64_t offset) { this->end_offset_ = offset; }
|
||||
void TestSetOffset(uint64_t offset) { this->entries_offset_ = offset; }
|
||||
void TestSetEndOffset(uint64_t offset) { this->entries_end_ = offset; }
|
||||
void TestPushFdeInfo(const typename DwarfDebugFrame<TypeParam>::FdeInfo& info) {
|
||||
this->fdes_.push_back(info);
|
||||
}
|
||||
|
|
|
@ -34,28 +34,19 @@ class MockDwarfEhFrame : public DwarfEhFrame<TypeParam> {
|
|||
MockDwarfEhFrame(Memory* memory) : DwarfEhFrame<TypeParam>(memory) {}
|
||||
~MockDwarfEhFrame() = default;
|
||||
|
||||
void TestSetTableEncoding(uint8_t encoding) { this->table_encoding_ = encoding; }
|
||||
void TestSetEntriesOffset(uint64_t offset) { this->entries_offset_ = offset; }
|
||||
void TestSetEntriesEnd(uint64_t end) { this->entries_end_ = end; }
|
||||
void TestSetEntriesDataOffset(uint64_t offset) { this->entries_data_offset_ = offset; }
|
||||
void TestSetCurEntriesOffset(uint64_t offset) { this->cur_entries_offset_ = offset; }
|
||||
void TestSetTableEntrySize(size_t size) { this->table_entry_size_ = size; }
|
||||
|
||||
void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
|
||||
void TestSetFdeInfo(uint64_t index, const typename DwarfEhFrame<TypeParam>::FdeInfo& info) {
|
||||
this->fde_info_[index] = info;
|
||||
void TestSetOffset(uint64_t offset) { this->entries_offset_ = offset; }
|
||||
void TestSetEndOffset(uint64_t offset) { this->entries_end_ = offset; }
|
||||
void TestPushFdeInfo(const typename DwarfEhFrame<TypeParam>::FdeInfo& info) {
|
||||
this->fdes_.push_back(info);
|
||||
}
|
||||
|
||||
uint8_t TestGetVersion() { return this->version_; }
|
||||
uint8_t TestGetPtrEncoding() { return this->ptr_encoding_; }
|
||||
uint64_t TestGetPtrOffset() { return this->ptr_offset_; }
|
||||
uint8_t TestGetTableEncoding() { return this->table_encoding_; }
|
||||
uint64_t TestGetTableEntrySize() { return this->table_entry_size_; }
|
||||
uint64_t TestGetFdeCount() { return this->fde_count_; }
|
||||
uint64_t TestGetEntriesOffset() { return this->entries_offset_; }
|
||||
uint64_t TestGetEntriesEnd() { return this->entries_end_; }
|
||||
uint64_t TestGetEntriesDataOffset() { return this->entries_data_offset_; }
|
||||
uint64_t TestGetCurEntriesOffset() { return this->cur_entries_offset_; }
|
||||
uint8_t TestGetOffset() { return this->offset_; }
|
||||
uint8_t TestGetEndOffset() { return this->end_offset_; }
|
||||
void TestGetFdeInfo(size_t index, typename DwarfEhFrame<TypeParam>::FdeInfo* info) {
|
||||
*info = this->fdes_[index];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TypeParam>
|
||||
|
@ -76,248 +67,304 @@ TYPED_TEST_CASE_P(DwarfEhFrameTest);
|
|||
|
||||
// NOTE: All test class variables need to be referenced as this->.
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, Init) {
|
||||
this->memory_.SetMemory(
|
||||
0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4, DW_EH_PE_sdata4});
|
||||
this->memory_.SetData16(0x1004, 0x500);
|
||||
this->memory_.SetData32(0x1006, 126);
|
||||
TYPED_TEST_P(DwarfEhFrameTest, Init32) {
|
||||
// CIE 32 information.
|
||||
this->memory_.SetData32(0x5000, 0xfc);
|
||||
this->memory_.SetData32(0x5004, 0);
|
||||
this->memory_.SetData8(0x5008, 1);
|
||||
this->memory_.SetData8(0x5009, '\0');
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100));
|
||||
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
|
||||
EXPECT_EQ(DW_EH_PE_udata2, this->eh_frame_->TestGetPtrEncoding());
|
||||
EXPECT_EQ(DW_EH_PE_sdata4, this->eh_frame_->TestGetTableEncoding());
|
||||
EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
|
||||
EXPECT_EQ(126U, this->eh_frame_->TestGetFdeCount());
|
||||
EXPECT_EQ(0x500U, this->eh_frame_->TestGetPtrOffset());
|
||||
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetEntriesOffset());
|
||||
EXPECT_EQ(0x1100U, this->eh_frame_->TestGetEntriesEnd());
|
||||
EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
|
||||
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
|
||||
// FDE 32 information.
|
||||
this->memory_.SetData32(0x5100, 0xfc);
|
||||
this->memory_.SetData32(0x5104, 0x104);
|
||||
this->memory_.SetData32(0x5108, 0x1500);
|
||||
this->memory_.SetData32(0x510c, 0x200);
|
||||
|
||||
// Verify an unexpected version will cause a fail.
|
||||
this->memory_.SetData8(0x1000, 0);
|
||||
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
|
||||
ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
|
||||
this->memory_.SetData8(0x1000, 2);
|
||||
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
|
||||
ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
|
||||
this->memory_.SetData32(0x5200, 0xfc);
|
||||
this->memory_.SetData32(0x5204, 0x204);
|
||||
this->memory_.SetData32(0x5208, 0x2500);
|
||||
this->memory_.SetData32(0x520c, 0x300);
|
||||
|
||||
// CIE 32 information.
|
||||
this->memory_.SetData32(0x5300, 0xfc);
|
||||
this->memory_.SetData32(0x5304, 0);
|
||||
this->memory_.SetData8(0x5308, 1);
|
||||
this->memory_.SetData8(0x5309, '\0');
|
||||
|
||||
// FDE 32 information.
|
||||
this->memory_.SetData32(0x5400, 0xfc);
|
||||
this->memory_.SetData32(0x5404, 0x104);
|
||||
this->memory_.SetData32(0x5408, 0x3500);
|
||||
this->memory_.SetData32(0x540c, 0x400);
|
||||
|
||||
this->memory_.SetData32(0x5500, 0xfc);
|
||||
this->memory_.SetData32(0x5504, 0x204);
|
||||
this->memory_.SetData32(0x5508, 0x4500);
|
||||
this->memory_.SetData32(0x550c, 0x500);
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600));
|
||||
ASSERT_EQ(4U, this->eh_frame_->TestGetFdeCount());
|
||||
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
|
||||
|
||||
this->eh_frame_->TestGetFdeInfo(0, &info);
|
||||
EXPECT_EQ(0x5100U, info.offset);
|
||||
EXPECT_EQ(0x660cU, info.start);
|
||||
EXPECT_EQ(0x680cU, info.end);
|
||||
|
||||
this->eh_frame_->TestGetFdeInfo(1, &info);
|
||||
EXPECT_EQ(0x5200U, info.offset);
|
||||
EXPECT_EQ(0x770cU, info.start);
|
||||
EXPECT_EQ(0x7a0cU, info.end);
|
||||
|
||||
this->eh_frame_->TestGetFdeInfo(2, &info);
|
||||
EXPECT_EQ(0x5400U, info.offset);
|
||||
EXPECT_EQ(0x890cU, info.start);
|
||||
EXPECT_EQ(0x8d0cU, info.end);
|
||||
|
||||
this->eh_frame_->TestGetFdeInfo(3, &info);
|
||||
EXPECT_EQ(0x5500U, info.offset);
|
||||
EXPECT_EQ(0x9a0cU, info.start);
|
||||
EXPECT_EQ(0x9f0cU, info.end);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeInfoFromIndex_expect_cache_fail) {
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
|
||||
ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
|
||||
ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
|
||||
TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) {
|
||||
// CIE 32 information.
|
||||
this->memory_.SetData32(0x5000, 0xfc);
|
||||
this->memory_.SetData32(0x5004, 0);
|
||||
this->memory_.SetData8(0x5008, 1);
|
||||
this->memory_.SetData8(0x5009, '\0');
|
||||
|
||||
// FDE 32 information.
|
||||
this->memory_.SetData32(0x5100, 0xfc);
|
||||
this->memory_.SetData32(0x5104, 0x1000);
|
||||
this->memory_.SetData32(0x5108, 0x1500);
|
||||
this->memory_.SetData32(0x510c, 0x200);
|
||||
|
||||
ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
|
||||
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeInfoFromIndex_read_pcrel) {
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_pcrel | DW_EH_PE_udata4);
|
||||
this->eh_frame_->TestSetEntriesOffset(0x1000);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x3000);
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
TYPED_TEST_P(DwarfEhFrameTest, Init64) {
|
||||
// CIE 64 information.
|
||||
this->memory_.SetData32(0x5000, 0xffffffff);
|
||||
this->memory_.SetData64(0x5004, 0xf4);
|
||||
this->memory_.SetData64(0x500c, 0);
|
||||
this->memory_.SetData8(0x5014, 1);
|
||||
this->memory_.SetData8(0x5015, '\0');
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
// FDE 64 information.
|
||||
this->memory_.SetData32(0x5100, 0xffffffff);
|
||||
this->memory_.SetData64(0x5104, 0xf4);
|
||||
this->memory_.SetData64(0x510c, 0x10c);
|
||||
this->memory_.SetData64(0x5114, 0x1500);
|
||||
this->memory_.SetData64(0x511c, 0x200);
|
||||
|
||||
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
|
||||
ASSERT_TRUE(info != nullptr);
|
||||
EXPECT_EQ(0x1384U, info->pc);
|
||||
EXPECT_EQ(0x1540U, info->offset);
|
||||
this->memory_.SetData32(0x5200, 0xffffffff);
|
||||
this->memory_.SetData64(0x5204, 0xf4);
|
||||
this->memory_.SetData64(0x520c, 0x20c);
|
||||
this->memory_.SetData64(0x5214, 0x2500);
|
||||
this->memory_.SetData64(0x521c, 0x300);
|
||||
|
||||
// CIE 64 information.
|
||||
this->memory_.SetData32(0x5300, 0xffffffff);
|
||||
this->memory_.SetData64(0x5304, 0xf4);
|
||||
this->memory_.SetData64(0x530c, 0);
|
||||
this->memory_.SetData8(0x5314, 1);
|
||||
this->memory_.SetData8(0x5315, '\0');
|
||||
|
||||
// FDE 64 information.
|
||||
this->memory_.SetData32(0x5400, 0xffffffff);
|
||||
this->memory_.SetData64(0x5404, 0xf4);
|
||||
this->memory_.SetData64(0x540c, 0x10c);
|
||||
this->memory_.SetData64(0x5414, 0x3500);
|
||||
this->memory_.SetData64(0x541c, 0x400);
|
||||
|
||||
this->memory_.SetData32(0x5500, 0xffffffff);
|
||||
this->memory_.SetData64(0x5504, 0xf4);
|
||||
this->memory_.SetData64(0x550c, 0x20c);
|
||||
this->memory_.SetData64(0x5514, 0x4500);
|
||||
this->memory_.SetData64(0x551c, 0x500);
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600));
|
||||
ASSERT_EQ(4U, this->eh_frame_->TestGetFdeCount());
|
||||
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
|
||||
|
||||
this->eh_frame_->TestGetFdeInfo(0, &info);
|
||||
EXPECT_EQ(0x5100U, info.offset);
|
||||
EXPECT_EQ(0x661cU, info.start);
|
||||
EXPECT_EQ(0x681cU, info.end);
|
||||
|
||||
this->eh_frame_->TestGetFdeInfo(1, &info);
|
||||
EXPECT_EQ(0x5200U, info.offset);
|
||||
EXPECT_EQ(0x771cU, info.start);
|
||||
EXPECT_EQ(0x7a1cU, info.end);
|
||||
|
||||
this->eh_frame_->TestGetFdeInfo(2, &info);
|
||||
EXPECT_EQ(0x5400U, info.offset);
|
||||
EXPECT_EQ(0x891cU, info.start);
|
||||
EXPECT_EQ(0x8d1cU, info.end);
|
||||
|
||||
this->eh_frame_->TestGetFdeInfo(3, &info);
|
||||
EXPECT_EQ(0x5500U, info.offset);
|
||||
EXPECT_EQ(0x9a1cU, info.start);
|
||||
EXPECT_EQ(0x9f1cU, info.end);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeInfoFromIndex_read_datarel) {
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_datarel | DW_EH_PE_udata4);
|
||||
this->eh_frame_->TestSetEntriesOffset(0x1000);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x3000);
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
TYPED_TEST_P(DwarfEhFrameTest, Init64_fde_not_following_cie) {
|
||||
// CIE 64 information.
|
||||
this->memory_.SetData32(0x5000, 0xffffffff);
|
||||
this->memory_.SetData64(0x5004, 0xf4);
|
||||
this->memory_.SetData64(0x500c, 0);
|
||||
this->memory_.SetData8(0x5014, 1);
|
||||
this->memory_.SetData8(0x5015, '\0');
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
// FDE 64 information.
|
||||
this->memory_.SetData32(0x5100, 0xffffffff);
|
||||
this->memory_.SetData64(0x5104, 0xf4);
|
||||
this->memory_.SetData64(0x510c, 0x1000);
|
||||
this->memory_.SetData64(0x5114, 0x1500);
|
||||
this->memory_.SetData64(0x511c, 0x200);
|
||||
|
||||
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
|
||||
ASSERT_TRUE(info != nullptr);
|
||||
EXPECT_EQ(0x3344U, info->pc);
|
||||
EXPECT_EQ(0x3500U, info->offset);
|
||||
ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
|
||||
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeInfoFromIndex_cached) {
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
this->eh_frame_->TestSetEntriesOffset(0x1000);
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
|
||||
// CIE 32 information.
|
||||
this->memory_.SetData32(0x5000, 0xfc);
|
||||
this->memory_.SetData32(0x5004, 0);
|
||||
this->memory_.SetData8(0x5008, 1);
|
||||
// Augment string.
|
||||
this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'R', 'P', 'L', '\0'});
|
||||
// Code alignment factor.
|
||||
this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x80, 0x00});
|
||||
// Data alignment factor.
|
||||
this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
|
||||
// Return address register
|
||||
this->memory_.SetData8(0x5014, 0x84);
|
||||
// Augmentation length
|
||||
this->memory_.SetMemory(0x5015, std::vector<uint8_t>{0x84, 0x00});
|
||||
// R data.
|
||||
this->memory_.SetData8(0x5017, DW_EH_PE_pcrel | DW_EH_PE_udata2);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
// FDE 32 information.
|
||||
this->memory_.SetData32(0x5100, 0xfc);
|
||||
this->memory_.SetData32(0x5104, 0x104);
|
||||
this->memory_.SetData16(0x5108, 0x1500);
|
||||
this->memory_.SetData16(0x510a, 0x200);
|
||||
|
||||
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
|
||||
ASSERT_TRUE(info != nullptr);
|
||||
EXPECT_EQ(0x344U, info->pc);
|
||||
EXPECT_EQ(0x500U, info->offset);
|
||||
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200));
|
||||
ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
|
||||
|
||||
// Clear the memory so that this will fail if it doesn't read cached data.
|
||||
this->memory_.Clear();
|
||||
|
||||
info = this->eh_frame_->GetFdeInfoFromIndex(2);
|
||||
ASSERT_TRUE(info != nullptr);
|
||||
EXPECT_EQ(0x344U, info->pc);
|
||||
EXPECT_EQ(0x500U, info->offset);
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
|
||||
this->eh_frame_->TestGetFdeInfo(0, &info);
|
||||
EXPECT_EQ(0x5100U, info.offset);
|
||||
EXPECT_EQ(0x660aU, info.start);
|
||||
EXPECT_EQ(0x680aU, info.end);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetBinary_verify) {
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
TYPED_TEST_P(DwarfEhFrameTest, Init_version4) {
|
||||
// CIE 32 information.
|
||||
this->memory_.SetData32(0x5000, 0xfc);
|
||||
this->memory_.SetData32(0x5004, 0);
|
||||
this->memory_.SetData8(0x5008, 4);
|
||||
// Augment string.
|
||||
this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'L', 'P', 'R', '\0'});
|
||||
// Address size.
|
||||
this->memory_.SetData8(0x500e, 4);
|
||||
// Segment size.
|
||||
this->memory_.SetData8(0x500f, 0);
|
||||
// Code alignment factor.
|
||||
this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x80, 0x00});
|
||||
// Data alignment factor.
|
||||
this->memory_.SetMemory(0x5012, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
|
||||
// Return address register
|
||||
this->memory_.SetMemory(0x5016, std::vector<uint8_t>{0x85, 0x10});
|
||||
// Augmentation length
|
||||
this->memory_.SetMemory(0x5018, std::vector<uint8_t>{0x84, 0x00});
|
||||
// L data.
|
||||
this->memory_.SetData8(0x501a, 0x10);
|
||||
// P data.
|
||||
this->memory_.SetData8(0x501b, DW_EH_PE_udata4);
|
||||
this->memory_.SetData32(0x501c, 0x100);
|
||||
// R data.
|
||||
this->memory_.SetData8(0x5020, DW_EH_PE_pcrel | DW_EH_PE_udata2);
|
||||
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info;
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
info.pc = 0x1000 * (i + 1);
|
||||
// FDE 32 information.
|
||||
this->memory_.SetData32(0x5100, 0xfc);
|
||||
this->memory_.SetData32(0x5104, 0x104);
|
||||
this->memory_.SetData16(0x5108, 0x1500);
|
||||
this->memory_.SetData16(0x510a, 0x200);
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200));
|
||||
ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
|
||||
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
|
||||
this->eh_frame_->TestGetFdeInfo(0, &info);
|
||||
EXPECT_EQ(0x5100U, info.offset);
|
||||
EXPECT_EQ(0x660aU, info.start);
|
||||
EXPECT_EQ(0x680aU, info.end);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) {
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
|
||||
for (size_t i = 0; i < 9; i++) {
|
||||
info.start = 0x1000 * (i + 1);
|
||||
info.end = 0x1000 * (i + 2) - 0x10;
|
||||
info.offset = 0x5000 + i * 0x20;
|
||||
this->eh_frame_->TestSetFdeInfo(i, info);
|
||||
this->eh_frame_->TestPushFdeInfo(info);
|
||||
}
|
||||
|
||||
this->eh_frame_->TestSetFdeCount(0);
|
||||
uint64_t fde_offset;
|
||||
EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x100, &fde_offset, 10));
|
||||
// Not an error, just not found.
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
|
||||
this->eh_frame_->TestSetFdeCount(9);
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
// Even number of elements.
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
TypeParam pc = 0x1000 * (i + 1);
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc, &fde_offset, 10)) << "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 1, &fde_offset, 10)) << "Failed at index "
|
||||
<< i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 0xfff, &fde_offset, 10))
|
||||
<< "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
}
|
||||
// Odd number of elements.
|
||||
for (size_t i = 0; i < 9; i++) {
|
||||
TypeParam pc = 0x1000 * (i + 1);
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc, &fde_offset, 9)) << "Failed at index " << i;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 1, &fde_offset, 9)) << "Failed at index "
|
||||
<< i;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 0xfff, &fde_offset, 9))
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
|
||||
<< "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
|
||||
<< "Failed at index " << i;
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
// Even number of elements.
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
info.start = 0xa000;
|
||||
info.end = 0xaff0;
|
||||
info.offset = 0x5120;
|
||||
this->eh_frame_->TestPushFdeInfo(info);
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
TypeParam pc = 0x1000 * (i + 1);
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
|
||||
<< "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
|
||||
<< "Failed at index " << i;
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetSequential) {
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x100);
|
||||
this->eh_frame_->TestSetEntriesEnd(0x2000);
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
this->memory_.SetData32(0x1048, 0x440);
|
||||
this->memory_.SetData32(0x104c, 0x600);
|
||||
|
||||
// Verify that if entries is zero, that it fails.
|
||||
uint64_t fde_offset;
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
|
||||
this->eh_frame_->TestSetCurEntriesOffset(0x1040);
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
|
||||
EXPECT_EQ(0x500U, fde_offset);
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
|
||||
EXPECT_EQ(0x600U, fde_offset);
|
||||
|
||||
// Expect that the data is cached so no more memory reads will occur.
|
||||
this->memory_.Clear();
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
|
||||
EXPECT_EQ(0x600U, fde_offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetSequential_last_element) {
|
||||
this->eh_frame_->TestSetFdeCount(2);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x100);
|
||||
this->eh_frame_->TestSetEntriesEnd(0x2000);
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
this->eh_frame_->TestSetCurEntriesOffset(0x1040);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
this->memory_.SetData32(0x1048, 0x440);
|
||||
this->memory_.SetData32(0x104c, 0x600);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
|
||||
EXPECT_EQ(0x600U, fde_offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetSequential_end_check) {
|
||||
this->eh_frame_->TestSetFdeCount(2);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x100);
|
||||
this->eh_frame_->TestSetEntriesEnd(0x1048);
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
this->memory_.SetData32(0x1048, 0x440);
|
||||
this->memory_.SetData32(0x104c, 0x600);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc_fail_fde_count) {
|
||||
this->eh_frame_->TestSetFdeCount(0);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc_binary_search) {
|
||||
this->eh_frame_->TestSetTableEntrySize(16);
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info;
|
||||
info.pc = 0x550;
|
||||
info.offset = 0x10500;
|
||||
this->eh_frame_->TestSetFdeInfo(5, info);
|
||||
info.pc = 0x750;
|
||||
info.offset = 0x10700;
|
||||
this->eh_frame_->TestSetFdeInfo(7, info);
|
||||
info.pc = 0x850;
|
||||
info.offset = 0x10800;
|
||||
this->eh_frame_->TestSetFdeInfo(8, info);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(0x800, &fde_offset));
|
||||
EXPECT_EQ(0x10700U, fde_offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc_sequential_search) {
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
this->eh_frame_->TestSetTableEntrySize(0);
|
||||
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info;
|
||||
info.pc = 0x50;
|
||||
info.offset = 0x10000;
|
||||
this->eh_frame_->TestSetFdeInfo(0, info);
|
||||
info.pc = 0x150;
|
||||
info.offset = 0x10100;
|
||||
this->eh_frame_->TestSetFdeInfo(1, info);
|
||||
info.pc = 0x250;
|
||||
info.offset = 0x10200;
|
||||
this->eh_frame_->TestSetFdeInfo(2, info);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(0x200, &fde_offset));
|
||||
EXPECT_EQ(0x10100U, fde_offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetCieFde32) {
|
||||
this->eh_frame_->TestSetOffset(0x4000);
|
||||
|
||||
// CIE 32 information.
|
||||
this->memory_.SetData32(0xf000, 0x100);
|
||||
this->memory_.SetData32(0xf004, 0);
|
||||
|
@ -358,6 +405,8 @@ TYPED_TEST_P(DwarfEhFrameTest, GetCieFde32) {
|
|||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetCieFde64) {
|
||||
this->eh_frame_->TestSetOffset(0x2000);
|
||||
|
||||
// CIE 64 information.
|
||||
this->memory_.SetData32(0x6000, 0xffffffff);
|
||||
this->memory_.SetData64(0x6004, 0x100);
|
||||
|
@ -399,25 +448,9 @@ TYPED_TEST_P(DwarfEhFrameTest, GetCieFde64) {
|
|||
EXPECT_EQ(0x20U, fde->cie->return_address_register);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameTest, GetFdeFromPc_fde_not_found) {
|
||||
this->eh_frame_->TestSetTableEntrySize(16);
|
||||
this->eh_frame_->TestSetFdeCount(1);
|
||||
|
||||
typename DwarfEhFrame<TypeParam>::FdeInfo info;
|
||||
info.pc = 0x550;
|
||||
info.offset = 0x10500;
|
||||
this->eh_frame_->TestSetFdeInfo(0, info);
|
||||
|
||||
ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, Init, GetFdeInfoFromIndex_expect_cache_fail,
|
||||
GetFdeInfoFromIndex_read_pcrel, GetFdeInfoFromIndex_read_datarel,
|
||||
GetFdeInfoFromIndex_cached, GetFdeOffsetBinary_verify,
|
||||
GetFdeOffsetSequential, GetFdeOffsetSequential_last_element,
|
||||
GetFdeOffsetSequential_end_check, GetFdeOffsetFromPc_fail_fde_count,
|
||||
GetFdeOffsetFromPc_binary_search, GetFdeOffsetFromPc_sequential_search,
|
||||
GetCieFde32, GetCieFde64, GetFdeFromPc_fde_not_found);
|
||||
REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, Init32, Init32_fde_not_following_cie, Init64,
|
||||
Init64_fde_not_following_cie, Init_version1, Init_version4,
|
||||
GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
|
||||
|
||||
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes);
|
||||
|
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "DwarfEhFrameWithHdr.h"
|
||||
#include "DwarfEncoding.h"
|
||||
#include "DwarfError.h"
|
||||
|
||||
#include "LogFake.h"
|
||||
#include "MemoryFake.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
template <typename TypeParam>
|
||||
class MockDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
|
||||
public:
|
||||
MockDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr<TypeParam>(memory) {}
|
||||
~MockDwarfEhFrameWithHdr() = default;
|
||||
|
||||
void TestSetTableEncoding(uint8_t encoding) { this->table_encoding_ = encoding; }
|
||||
void TestSetEntriesOffset(uint64_t offset) { this->entries_offset_ = offset; }
|
||||
void TestSetEntriesEnd(uint64_t end) { this->entries_end_ = end; }
|
||||
void TestSetEntriesDataOffset(uint64_t offset) { this->entries_data_offset_ = offset; }
|
||||
void TestSetCurEntriesOffset(uint64_t offset) { this->cur_entries_offset_ = offset; }
|
||||
void TestSetTableEntrySize(size_t size) { this->table_entry_size_ = size; }
|
||||
|
||||
void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
|
||||
void TestSetFdeInfo(uint64_t index, const typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo& info) {
|
||||
this->fde_info_[index] = info;
|
||||
}
|
||||
|
||||
uint8_t TestGetVersion() { return this->version_; }
|
||||
uint8_t TestGetPtrEncoding() { return this->ptr_encoding_; }
|
||||
uint64_t TestGetPtrOffset() { return this->ptr_offset_; }
|
||||
uint8_t TestGetTableEncoding() { return this->table_encoding_; }
|
||||
uint64_t TestGetTableEntrySize() { return this->table_entry_size_; }
|
||||
uint64_t TestGetFdeCount() { return this->fde_count_; }
|
||||
uint64_t TestGetEntriesOffset() { return this->entries_offset_; }
|
||||
uint64_t TestGetEntriesEnd() { return this->entries_end_; }
|
||||
uint64_t TestGetEntriesDataOffset() { return this->entries_data_offset_; }
|
||||
uint64_t TestGetCurEntriesOffset() { return this->cur_entries_offset_; }
|
||||
};
|
||||
|
||||
template <typename TypeParam>
|
||||
class DwarfEhFrameWithHdrTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
memory_.Clear();
|
||||
eh_frame_ = new MockDwarfEhFrameWithHdr<TypeParam>(&memory_);
|
||||
ResetLogs();
|
||||
}
|
||||
|
||||
void TearDown() override { delete eh_frame_; }
|
||||
|
||||
MemoryFake memory_;
|
||||
MockDwarfEhFrameWithHdr<TypeParam>* eh_frame_ = nullptr;
|
||||
};
|
||||
TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest);
|
||||
|
||||
// NOTE: All test class variables need to be referenced as this->.
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init) {
|
||||
this->memory_.SetMemory(
|
||||
0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4, DW_EH_PE_sdata4});
|
||||
this->memory_.SetData16(0x1004, 0x500);
|
||||
this->memory_.SetData32(0x1006, 126);
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100));
|
||||
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
|
||||
EXPECT_EQ(DW_EH_PE_udata2, this->eh_frame_->TestGetPtrEncoding());
|
||||
EXPECT_EQ(DW_EH_PE_sdata4, this->eh_frame_->TestGetTableEncoding());
|
||||
EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
|
||||
EXPECT_EQ(126U, this->eh_frame_->TestGetFdeCount());
|
||||
EXPECT_EQ(0x500U, this->eh_frame_->TestGetPtrOffset());
|
||||
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetEntriesOffset());
|
||||
EXPECT_EQ(0x1100U, this->eh_frame_->TestGetEntriesEnd());
|
||||
EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
|
||||
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
|
||||
|
||||
// Verify an unexpected version will cause a fail.
|
||||
this->memory_.SetData8(0x1000, 0);
|
||||
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
|
||||
ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
|
||||
this->memory_.SetData8(0x1000, 2);
|
||||
ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
|
||||
ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
|
||||
ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
|
||||
ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_pcrel | DW_EH_PE_udata4);
|
||||
this->eh_frame_->TestSetEntriesOffset(0x1000);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x3000);
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
|
||||
ASSERT_TRUE(info != nullptr);
|
||||
EXPECT_EQ(0x1384U, info->pc);
|
||||
EXPECT_EQ(0x1540U, info->offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_datarel) {
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_datarel | DW_EH_PE_udata4);
|
||||
this->eh_frame_->TestSetEntriesOffset(0x1000);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x3000);
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
|
||||
ASSERT_TRUE(info != nullptr);
|
||||
EXPECT_EQ(0x3344U, info->pc);
|
||||
EXPECT_EQ(0x3500U, info->offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_cached) {
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
this->eh_frame_->TestSetEntriesOffset(0x1000);
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
|
||||
ASSERT_TRUE(info != nullptr);
|
||||
EXPECT_EQ(0x344U, info->pc);
|
||||
EXPECT_EQ(0x500U, info->offset);
|
||||
|
||||
// Clear the memory so that this will fail if it doesn't read cached data.
|
||||
this->memory_.Clear();
|
||||
|
||||
info = this->eh_frame_->GetFdeInfoFromIndex(2);
|
||||
ASSERT_TRUE(info != nullptr);
|
||||
EXPECT_EQ(0x344U, info->pc);
|
||||
EXPECT_EQ(0x500U, info->offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetBinary_verify) {
|
||||
this->eh_frame_->TestSetTableEntrySize(0x10);
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
|
||||
typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
info.pc = 0x1000 * (i + 1);
|
||||
info.offset = 0x5000 + i * 0x20;
|
||||
this->eh_frame_->TestSetFdeInfo(i, info);
|
||||
}
|
||||
|
||||
uint64_t fde_offset;
|
||||
EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x100, &fde_offset, 10));
|
||||
// Not an error, just not found.
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
// Even number of elements.
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
TypeParam pc = 0x1000 * (i + 1);
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc, &fde_offset, 10)) << "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 1, &fde_offset, 10))
|
||||
<< "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 0xfff, &fde_offset, 10))
|
||||
<< "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
}
|
||||
// Odd number of elements.
|
||||
for (size_t i = 0; i < 9; i++) {
|
||||
TypeParam pc = 0x1000 * (i + 1);
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc, &fde_offset, 9)) << "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 1, &fde_offset, 9))
|
||||
<< "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
EXPECT_TRUE(this->eh_frame_->GetFdeOffsetBinary(pc + 0xfff, &fde_offset, 9))
|
||||
<< "Failed at index " << i;
|
||||
EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential) {
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x100);
|
||||
this->eh_frame_->TestSetEntriesEnd(0x2000);
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
this->memory_.SetData32(0x1048, 0x440);
|
||||
this->memory_.SetData32(0x104c, 0x600);
|
||||
|
||||
// Verify that if entries is zero, that it fails.
|
||||
uint64_t fde_offset;
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
|
||||
this->eh_frame_->TestSetCurEntriesOffset(0x1040);
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x344, &fde_offset));
|
||||
EXPECT_EQ(0x500U, fde_offset);
|
||||
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
|
||||
EXPECT_EQ(0x600U, fde_offset);
|
||||
|
||||
// Expect that the data is cached so no more memory reads will occur.
|
||||
this->memory_.Clear();
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x444, &fde_offset));
|
||||
EXPECT_EQ(0x600U, fde_offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential_last_element) {
|
||||
this->eh_frame_->TestSetFdeCount(2);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x100);
|
||||
this->eh_frame_->TestSetEntriesEnd(0x2000);
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
this->eh_frame_->TestSetCurEntriesOffset(0x1040);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
this->memory_.SetData32(0x1048, 0x440);
|
||||
this->memory_.SetData32(0x104c, 0x600);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
|
||||
EXPECT_EQ(0x600U, fde_offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetSequential_end_check) {
|
||||
this->eh_frame_->TestSetFdeCount(2);
|
||||
this->eh_frame_->TestSetEntriesDataOffset(0x100);
|
||||
this->eh_frame_->TestSetEntriesEnd(0x1048);
|
||||
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
|
||||
|
||||
this->memory_.SetData32(0x1040, 0x340);
|
||||
this->memory_.SetData32(0x1044, 0x500);
|
||||
|
||||
this->memory_.SetData32(0x1048, 0x440);
|
||||
this->memory_.SetData32(0x104c, 0x600);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) {
|
||||
this->eh_frame_->TestSetFdeCount(0);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
|
||||
ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_binary_search) {
|
||||
this->eh_frame_->TestSetTableEntrySize(16);
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
|
||||
typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
|
||||
info.pc = 0x550;
|
||||
info.offset = 0x10500;
|
||||
this->eh_frame_->TestSetFdeInfo(5, info);
|
||||
info.pc = 0x750;
|
||||
info.offset = 0x10700;
|
||||
this->eh_frame_->TestSetFdeInfo(7, info);
|
||||
info.pc = 0x850;
|
||||
info.offset = 0x10800;
|
||||
this->eh_frame_->TestSetFdeInfo(8, info);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(0x800, &fde_offset));
|
||||
EXPECT_EQ(0x10700U, fde_offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_sequential_search) {
|
||||
this->eh_frame_->TestSetFdeCount(10);
|
||||
this->eh_frame_->TestSetTableEntrySize(0);
|
||||
|
||||
typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
|
||||
info.pc = 0x50;
|
||||
info.offset = 0x10000;
|
||||
this->eh_frame_->TestSetFdeInfo(0, info);
|
||||
info.pc = 0x150;
|
||||
info.offset = 0x10100;
|
||||
this->eh_frame_->TestSetFdeInfo(1, info);
|
||||
info.pc = 0x250;
|
||||
info.offset = 0x10200;
|
||||
this->eh_frame_->TestSetFdeInfo(2, info);
|
||||
|
||||
uint64_t fde_offset;
|
||||
ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(0x200, &fde_offset));
|
||||
EXPECT_EQ(0x10100U, fde_offset);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde32) {
|
||||
// CIE 32 information.
|
||||
this->memory_.SetData32(0xf000, 0x100);
|
||||
this->memory_.SetData32(0xf004, 0);
|
||||
this->memory_.SetData8(0xf008, 0x1);
|
||||
this->memory_.SetData8(0xf009, '\0');
|
||||
this->memory_.SetData8(0xf00a, 4);
|
||||
this->memory_.SetData8(0xf00b, 8);
|
||||
this->memory_.SetData8(0xf00c, 0x20);
|
||||
|
||||
// FDE 32 information.
|
||||
this->memory_.SetData32(0x14000, 0x20);
|
||||
this->memory_.SetData32(0x14004, 0x5004);
|
||||
this->memory_.SetData32(0x14008, 0x9000);
|
||||
this->memory_.SetData32(0x1400c, 0x100);
|
||||
|
||||
const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x14000);
|
||||
ASSERT_TRUE(fde != nullptr);
|
||||
EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
|
||||
EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
|
||||
EXPECT_EQ(0x1d00cU, fde->pc_start);
|
||||
EXPECT_EQ(0x1d10cU, fde->pc_end);
|
||||
EXPECT_EQ(0xf000U, fde->cie_offset);
|
||||
EXPECT_EQ(0U, fde->lsda_address);
|
||||
|
||||
ASSERT_TRUE(fde->cie != nullptr);
|
||||
EXPECT_EQ(1U, fde->cie->version);
|
||||
EXPECT_EQ(DW_EH_PE_sdata4, fde->cie->fde_address_encoding);
|
||||
EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
|
||||
EXPECT_EQ(0U, fde->cie->segment_size);
|
||||
EXPECT_EQ(1U, fde->cie->augmentation_string.size());
|
||||
EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
|
||||
EXPECT_EQ(0U, fde->cie->personality_handler);
|
||||
EXPECT_EQ(0xf00dU, fde->cie->cfa_instructions_offset);
|
||||
EXPECT_EQ(0xf104U, fde->cie->cfa_instructions_end);
|
||||
EXPECT_EQ(4U, fde->cie->code_alignment_factor);
|
||||
EXPECT_EQ(8, fde->cie->data_alignment_factor);
|
||||
EXPECT_EQ(0x20U, fde->cie->return_address_register);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde64) {
|
||||
// CIE 64 information.
|
||||
this->memory_.SetData32(0x6000, 0xffffffff);
|
||||
this->memory_.SetData64(0x6004, 0x100);
|
||||
this->memory_.SetData64(0x600c, 0);
|
||||
this->memory_.SetData8(0x6014, 0x1);
|
||||
this->memory_.SetData8(0x6015, '\0');
|
||||
this->memory_.SetData8(0x6016, 4);
|
||||
this->memory_.SetData8(0x6017, 8);
|
||||
this->memory_.SetData8(0x6018, 0x20);
|
||||
|
||||
// FDE 64 information.
|
||||
this->memory_.SetData32(0x8000, 0xffffffff);
|
||||
this->memory_.SetData64(0x8004, 0x200);
|
||||
this->memory_.SetData64(0x800c, 0x200c);
|
||||
this->memory_.SetData64(0x8014, 0x5000);
|
||||
this->memory_.SetData64(0x801c, 0x300);
|
||||
|
||||
const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x8000);
|
||||
ASSERT_TRUE(fde != nullptr);
|
||||
EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
|
||||
EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
|
||||
EXPECT_EQ(0xd01cU, fde->pc_start);
|
||||
EXPECT_EQ(0xd31cU, fde->pc_end);
|
||||
EXPECT_EQ(0x6000U, fde->cie_offset);
|
||||
EXPECT_EQ(0U, fde->lsda_address);
|
||||
|
||||
ASSERT_TRUE(fde->cie != nullptr);
|
||||
EXPECT_EQ(1U, fde->cie->version);
|
||||
EXPECT_EQ(DW_EH_PE_sdata8, fde->cie->fde_address_encoding);
|
||||
EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
|
||||
EXPECT_EQ(0U, fde->cie->segment_size);
|
||||
EXPECT_EQ(1U, fde->cie->augmentation_string.size());
|
||||
EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
|
||||
EXPECT_EQ(0U, fde->cie->personality_handler);
|
||||
EXPECT_EQ(0x6019U, fde->cie->cfa_instructions_offset);
|
||||
EXPECT_EQ(0x610cU, fde->cie->cfa_instructions_end);
|
||||
EXPECT_EQ(4U, fde->cie->code_alignment_factor);
|
||||
EXPECT_EQ(8, fde->cie->data_alignment_factor);
|
||||
EXPECT_EQ(0x20U, fde->cie->return_address_register);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeFromPc_fde_not_found) {
|
||||
this->eh_frame_->TestSetTableEntrySize(16);
|
||||
this->eh_frame_->TestSetFdeCount(1);
|
||||
|
||||
typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
|
||||
info.pc = 0x550;
|
||||
info.offset = 0x10500;
|
||||
this->eh_frame_->TestSetFdeInfo(0, info);
|
||||
|
||||
ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, GetFdeInfoFromIndex_expect_cache_fail,
|
||||
GetFdeInfoFromIndex_read_pcrel, GetFdeInfoFromIndex_read_datarel,
|
||||
GetFdeInfoFromIndex_cached, GetFdeOffsetBinary_verify,
|
||||
GetFdeOffsetSequential, GetFdeOffsetSequential_last_element,
|
||||
GetFdeOffsetSequential_end_check, GetFdeOffsetFromPc_fail_fde_count,
|
||||
GetFdeOffsetFromPc_binary_search, GetFdeOffsetFromPc_sequential_search,
|
||||
GetCieFde32, GetCieFde64, GetFdeFromPc_fde_not_found);
|
||||
|
||||
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameWithHdrTestTypes;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameWithHdrTest, DwarfEhFrameWithHdrTestTypes);
|
||||
|
||||
} // namespace unwindstack
|
|
@ -42,16 +42,16 @@ class MockDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
|
|||
|
||||
MOCK_METHOD1(GetFdeFromIndex, const DwarfFde*(size_t));
|
||||
|
||||
MOCK_METHOD1(IsCie32, bool(uint32_t));
|
||||
|
||||
MOCK_METHOD1(IsCie64, bool(uint64_t));
|
||||
|
||||
MOCK_METHOD1(GetCieOffsetFromFde32, uint64_t(uint32_t));
|
||||
|
||||
MOCK_METHOD1(GetCieOffsetFromFde64, uint64_t(uint64_t));
|
||||
|
||||
MOCK_METHOD1(AdjustPcFromFde, uint64_t(uint64_t));
|
||||
|
||||
void TestSetCie32Value(uint32_t value32) { this->cie32_value_ = value32; }
|
||||
|
||||
void TestSetCie64Value(uint64_t value64) { this->cie64_value_ = value64; }
|
||||
|
||||
void TestSetCachedCieEntry(uint64_t offset, const DwarfCie& cie) {
|
||||
this->cie_entries_[offset] = cie;
|
||||
}
|
||||
|
@ -77,6 +77,8 @@ class DwarfSectionImplTest : public ::testing::Test {
|
|||
memory_.Clear();
|
||||
section_ = new MockDwarfSectionImpl<TypeParam>(&memory_);
|
||||
ResetLogs();
|
||||
section_->TestSetCie32Value(static_cast<uint32_t>(-1));
|
||||
section_->TestSetCie64Value(static_cast<uint64_t>(-1));
|
||||
}
|
||||
|
||||
void TearDown() override { delete section_; }
|
||||
|
@ -448,8 +450,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) {
|
|||
this->memory_.SetData8(0x500b, 8);
|
||||
this->memory_.SetData8(0x500c, 0x20);
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie32(0xffffffff)).WillRepeatedly(::testing::Return(true));
|
||||
|
||||
const DwarfCie* cie = this->section_->GetCie(0x5000);
|
||||
ASSERT_TRUE(cie != nullptr);
|
||||
EXPECT_EQ(1U, cie->version);
|
||||
|
@ -493,8 +493,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) {
|
|||
this->memory_.SetMemory(0x500b, std::vector<uint8_t>{0xfc, 0xff, 0xff, 0xff, 0x7f});
|
||||
this->memory_.SetData8(0x5010, 0x20);
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie32(0xffffffff)).WillRepeatedly(::testing::Return(true));
|
||||
|
||||
const DwarfCie* cie = this->section_->GetCie(0x5000);
|
||||
ASSERT_TRUE(cie != nullptr);
|
||||
EXPECT_EQ(1U, cie->version);
|
||||
|
@ -514,15 +512,13 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) {
|
|||
TYPED_TEST_P(DwarfSectionImplTest, GetCie_64_no_augment) {
|
||||
this->memory_.SetData32(0x8000, 0xffffffff);
|
||||
this->memory_.SetData64(0x8004, 0x200);
|
||||
this->memory_.SetData64(0x800c, 0xffffffff);
|
||||
this->memory_.SetData64(0x800c, 0xffffffffffffffffULL);
|
||||
this->memory_.SetData8(0x8014, 0x1);
|
||||
this->memory_.SetData8(0x8015, '\0');
|
||||
this->memory_.SetData8(0x8016, 4);
|
||||
this->memory_.SetData8(0x8017, 8);
|
||||
this->memory_.SetData8(0x8018, 0x20);
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie64(0xffffffff)).WillRepeatedly(::testing::Return(true));
|
||||
|
||||
const DwarfCie* cie = this->section_->GetCie(0x8000);
|
||||
ASSERT_TRUE(cie != nullptr);
|
||||
EXPECT_EQ(1U, cie->version);
|
||||
|
@ -557,8 +553,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCie_augment) {
|
|||
// R data.
|
||||
this->memory_.SetData8(0x5018, DW_EH_PE_udata2);
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie32(0xffffffff)).WillRepeatedly(::testing::Return(true));
|
||||
|
||||
const DwarfCie* cie = this->section_->GetCie(0x5000);
|
||||
ASSERT_TRUE(cie != nullptr);
|
||||
EXPECT_EQ(1U, cie->version);
|
||||
|
@ -588,8 +582,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_3) {
|
|||
this->memory_.SetData8(0x500b, 8);
|
||||
this->memory_.SetMemory(0x500c, std::vector<uint8_t>{0x81, 0x03});
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie32(0xffffffff)).WillRepeatedly(::testing::Return(true));
|
||||
|
||||
const DwarfCie* cie = this->section_->GetCie(0x5000);
|
||||
ASSERT_TRUE(cie != nullptr);
|
||||
EXPECT_EQ(3U, cie->version);
|
||||
|
@ -617,8 +609,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_4) {
|
|||
this->memory_.SetData8(0x500d, 8);
|
||||
this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x81, 0x03});
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie32(0xffffffff)).WillRepeatedly(::testing::Return(true));
|
||||
|
||||
const DwarfCie* cie = this->section_->GetCie(0x5000);
|
||||
ASSERT_TRUE(cie != nullptr);
|
||||
EXPECT_EQ(4U, cie->version);
|
||||
|
@ -649,7 +639,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment) {
|
|||
this->memory_.SetData32(0x4008, 0x5000);
|
||||
this->memory_.SetData32(0x400c, 0x100);
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie32(0x8000)).WillOnce(::testing::Return(false));
|
||||
EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
|
||||
DwarfCie cie{};
|
||||
cie.fde_address_encoding = DW_EH_PE_udata4;
|
||||
|
@ -673,7 +662,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment_non_zero_segme
|
|||
this->memory_.SetData32(0x4018, 0x5000);
|
||||
this->memory_.SetData32(0x401c, 0x100);
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie32(0x8000)).WillOnce(::testing::Return(false));
|
||||
EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
|
||||
DwarfCie cie{};
|
||||
cie.fde_address_encoding = DW_EH_PE_udata4;
|
||||
|
@ -700,7 +688,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_augment) {
|
|||
this->memory_.SetMemory(0x4010, std::vector<uint8_t>{0x82, 0x01});
|
||||
this->memory_.SetData16(0x4012, 0x1234);
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie32(0x8000)).WillOnce(::testing::Return(false));
|
||||
EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
|
||||
DwarfCie cie{};
|
||||
cie.fde_address_encoding = DW_EH_PE_udata4;
|
||||
|
@ -727,7 +714,6 @@ TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_64_no_augment) {
|
|||
this->memory_.SetData32(0x4014, 0x5000);
|
||||
this->memory_.SetData32(0x4018, 0x100);
|
||||
|
||||
EXPECT_CALL(*this->section_, IsCie64(0x12345678)).WillOnce(::testing::Return(false));
|
||||
EXPECT_CALL(*this->section_, GetCieOffsetFromFde64(0x12345678))
|
||||
.WillOnce(::testing::Return(0x12345678));
|
||||
DwarfCie cie{};
|
||||
|
|
|
@ -910,8 +910,32 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
|
|||
memory_.SetMemory(offset, &shdr, sizeof(shdr));
|
||||
offset += ehdr.e_shentsize;
|
||||
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_PROGBITS;
|
||||
shdr.sh_link = 2;
|
||||
shdr.sh_name = 0x300;
|
||||
shdr.sh_addr = 0x7000;
|
||||
shdr.sh_offset = 0x7000;
|
||||
shdr.sh_entsize = 0x100;
|
||||
shdr.sh_size = 0x800;
|
||||
memory_.SetMemory(offset, &shdr, sizeof(shdr));
|
||||
offset += ehdr.e_shentsize;
|
||||
|
||||
memset(&shdr, 0, sizeof(shdr));
|
||||
shdr.sh_type = SHT_PROGBITS;
|
||||
shdr.sh_link = 2;
|
||||
shdr.sh_name = 0x400;
|
||||
shdr.sh_addr = 0x6000;
|
||||
shdr.sh_offset = 0xa000;
|
||||
shdr.sh_entsize = 0x100;
|
||||
shdr.sh_size = 0xf00;
|
||||
memory_.SetMemory(offset, &shdr, sizeof(shdr));
|
||||
offset += ehdr.e_shentsize;
|
||||
|
||||
memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
|
||||
memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
|
||||
memory_.SetMemory(0xf300, ".eh_frame", sizeof(".eh_frame"));
|
||||
memory_.SetMemory(0xf400, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
|
||||
|
||||
uint64_t load_bias = 0;
|
||||
ASSERT_TRUE(elf->Init(&load_bias));
|
||||
|
@ -920,6 +944,10 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
|
|||
EXPECT_EQ(0x500U, elf->debug_frame_size());
|
||||
EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset());
|
||||
EXPECT_EQ(0x800U, elf->gnu_debugdata_size());
|
||||
EXPECT_EQ(0x7000U, elf->eh_frame_offset());
|
||||
EXPECT_EQ(0x800U, elf->eh_frame_size());
|
||||
EXPECT_EQ(0xa000U, elf->eh_frame_hdr_offset());
|
||||
EXPECT_EQ(0xf00U, elf->eh_frame_hdr_size());
|
||||
}
|
||||
|
||||
TEST_F(ElfInterfaceTest, init_section_headers_offsets32) {
|
||||
|
|
Loading…
Reference in New Issue