Fix potential bad info in eh_frame_hdr.

Due to a bug, an elf can have FDEs with a length of zero, while still
having another FDE for the same pc with a non-zero length. The
eh_frame_hdr can sometimes point to the zero length FDE, but it should
have pointed to the non-zero length FDE. In order to fix this, if the
eh_frame_hdr points at the zero length FDE then try and find the real FDE
directly from eh_frame.

The change cleans up and removes unused variables from DwarfEhFrameWithHdr
and changes the objects so that all of the DwarfSection objects and
DwarfEhFrameWithHdr object inherit from the same class.

Add new unit tests to verify this functionality.

Bug: 142483624

Test: Unit tests all pass.
Change-Id: I128a916e3ba378931de7d44ee15e57e24d4073df
This commit is contained in:
Christopher Ferris 2019-10-29 10:21:11 -07:00
parent 85f5a4449c
commit 4ca98e18a4
8 changed files with 227 additions and 125 deletions

View file

@ -26,9 +26,9 @@
namespace unwindstack {
template <typename AddressType>
class DwarfDebugFrame : public DwarfSectionImplNoHdr<AddressType> {
class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
public:
DwarfDebugFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {
DwarfDebugFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {
this->cie32_value_ = static_cast<uint32_t>(-1);
this->cie64_value_ = static_cast<uint64_t>(-1);
}

View file

@ -25,9 +25,9 @@
namespace unwindstack {
template <typename AddressType>
class DwarfEhFrame : public DwarfSectionImplNoHdr<AddressType> {
class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
public:
DwarfEhFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {}
DwarfEhFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
virtual ~DwarfEhFrame() = default;
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {

View file

@ -32,14 +32,19 @@ static inline bool IsEncodingRelative(uint8_t encoding) {
}
template <typename AddressType>
bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) {
section_bias_ = section_bias;
bool DwarfEhFrameWithHdr<AddressType>::EhFrameInit(uint64_t offset, uint64_t size,
int64_t section_bias) {
return DwarfSectionImpl<AddressType>::Init(offset, size, section_bias);
}
template <typename AddressType>
bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t, int64_t section_bias) {
memory_.clear_func_offset();
memory_.clear_text_offset();
memory_.set_data_offset(offset);
memory_.set_cur_offset(offset);
pc_offset_ = offset;
hdr_section_bias_ = section_bias;
// Read the first four bytes all at once.
uint8_t data[4];
@ -56,7 +61,7 @@ bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int6
return false;
}
ptr_encoding_ = data[1];
uint8_t ptr_encoding = data[1];
uint8_t fde_count_encoding = data[2];
table_encoding_ = data[3];
table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
@ -70,7 +75,8 @@ bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int6
}
memory_.set_pc_offset(memory_.cur_offset());
if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) {
uint64_t ptr_offset;
if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding, &ptr_offset)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
@ -88,10 +94,8 @@ bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int6
return false;
}
entries_offset_ = memory_.cur_offset();
entries_end_ = offset + size;
entries_data_offset_ = offset;
cur_entries_offset_ = entries_offset_;
hdr_entries_offset_ = memory_.cur_offset();
hdr_entries_data_offset_ = offset;
return true;
}
@ -107,6 +111,16 @@ const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
return nullptr;
}
// There is a possibility that this entry points to a zero length FDE
// due to a bug. If this happens, try and find the non-zero length FDE
// from eh_frame directly. See b/142483624.
if (fde->pc_start == fde->pc_end) {
fde = DwarfSectionImpl<AddressType>::GetFdeFromPc(pc);
if (fde == nullptr) {
return nullptr;
}
}
// Guaranteed pc >= pc_start, need to check pc in the fde range.
if (pc < fde->pc_end) {
return fde;
@ -124,8 +138,8 @@ DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
}
FdeInfo* info = &fde_info_[index];
memory_.set_data_offset(entries_data_offset_);
memory_.set_cur_offset(entries_offset_ + 2 * index * table_entry_size_);
memory_.set_data_offset(hdr_entries_data_offset_);
memory_.set_cur_offset(hdr_entries_offset_ + 2 * index * table_entry_size_);
memory_.set_pc_offset(0);
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
@ -138,7 +152,7 @@ DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
// Relative encodings require adding in the load bias.
if (IsEncodingRelative(table_encoding_)) {
value += section_bias_;
value += hdr_section_bias_;
}
info->pc = value;
return info;
@ -190,6 +204,16 @@ void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fde
if (fde == nullptr) {
break;
}
// There is a possibility that this entry points to a zero length FDE
// due to a bug. If this happens, try and find the non-zero length FDE
// from eh_frame directly. See b/142483624.
if (fde->pc_start == fde->pc_end) {
const DwarfFde* fde_real = DwarfSectionImpl<AddressType>::GetFdeFromPc(fde->pc_start);
if (fde_real != nullptr) {
fde = fde_real;
}
}
fdes->push_back(fde);
}
}

View file

@ -34,11 +34,7 @@ class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
// Add these so that the protected members of DwarfSectionImpl
// can be accessed without needing a this->.
using DwarfSectionImpl<AddressType>::memory_;
using DwarfSectionImpl<AddressType>::pc_offset_;
using DwarfSectionImpl<AddressType>::entries_offset_;
using DwarfSectionImpl<AddressType>::entries_end_;
using DwarfSectionImpl<AddressType>::last_error_;
using DwarfSectionImpl<AddressType>::section_bias_;
struct FdeInfo {
AddressType pc;
@ -49,18 +45,19 @@ class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
virtual ~DwarfEhFrameWithHdr() = default;
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
return this->memory_.cur_offset() - pointer - 4;
return memory_.cur_offset() - pointer - 4;
}
uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
return this->memory_.cur_offset() - pointer - 8;
return memory_.cur_offset() - pointer - 8;
}
uint64_t AdjustPcFromFde(uint64_t pc) override {
// The eh_frame uses relative pcs.
return pc + this->memory_.cur_offset() - 4;
return pc + memory_.cur_offset() - 4;
}
bool EhFrameInit(uint64_t offset, uint64_t size, int64_t section_bias);
bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
const DwarfFde* GetFdeFromPc(uint64_t pc) override;
@ -72,17 +69,15 @@ class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
void GetFdes(std::vector<const DwarfFde*>* fdes) override;
protected:
uint8_t version_;
uint8_t ptr_encoding_;
uint8_t table_encoding_;
size_t table_entry_size_;
uint8_t version_ = 0;
uint8_t table_encoding_ = 0;
size_t table_entry_size_ = 0;
uint64_t ptr_offset_;
uint64_t hdr_entries_offset_ = 0;
uint64_t hdr_entries_data_offset_ = 0;
uint64_t hdr_section_bias_ = 0;
uint64_t entries_data_offset_;
uint64_t cur_entries_offset_ = 0;
uint64_t fde_count_;
uint64_t fde_count_ = 0;
std::unordered_map<uint64_t, FdeInfo> fde_info_;
};

View file

@ -69,6 +69,7 @@ const DwarfCie* DwarfSectionImpl<AddressType>::GetCieFromOffset(uint64_t offset)
return &cie_entry->second;
}
DwarfCie* cie = &cie_entries_[offset];
memory_.set_data_offset(entries_offset_);
memory_.set_cur_offset(offset);
if (!FillInCieHeader(cie) || !FillInCie(cie)) {
// Erase the cached entry.
@ -251,6 +252,7 @@ const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset)
return &fde_entry->second;
}
DwarfFde* fde = &fde_entries_[offset];
memory_.set_data_offset(entries_offset_);
memory_.set_cur_offset(offset);
if (!FillInFdeHeader(fde) || !FillInFde(fde)) {
fde_entries_.erase(offset);
@ -591,8 +593,7 @@ bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const Dwarf
}
template <typename AddressType>
bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size,
int64_t section_bias) {
bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) {
section_bias_ = section_bias;
entries_offset_ = offset;
next_entries_offset_ = offset;
@ -601,7 +602,6 @@ bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size,
memory_.clear_func_offset();
memory_.clear_text_offset();
memory_.set_cur_offset(offset);
memory_.set_data_offset(offset);
pc_offset_ = offset;
return true;
@ -617,7 +617,7 @@ bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size,
// and an fde has a start pc of 0x100 and end pc of 0x500, two new entries
// will be added: 0x200, 0x100 and 0x500, 0x400.
template <typename AddressType>
void DwarfSectionImplNoHdr<AddressType>::InsertFde(const DwarfFde* fde) {
void DwarfSectionImpl<AddressType>::InsertFde(const DwarfFde* fde) {
uint64_t start = fde->pc_start;
uint64_t end = fde->pc_end;
auto it = fdes_.upper_bound(start);
@ -654,9 +654,10 @@ void DwarfSectionImplNoHdr<AddressType>::InsertFde(const DwarfFde* fde) {
}
template <typename AddressType>
bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
bool DwarfSectionImpl<AddressType>::GetNextCieOrFde(const DwarfFde** fde_entry) {
uint64_t start_offset = next_entries_offset_;
memory_.set_data_offset(entries_offset_);
memory_.set_cur_offset(next_entries_offset_);
uint32_t value32;
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
@ -689,7 +690,7 @@ bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
entry_is_cie = true;
cie_fde_encoding = DW_EH_PE_sdata8;
} else {
cie_offset = this->GetCieOffsetFromFde64(value64);
cie_offset = GetCieOffsetFromFde64(value64);
}
} else {
next_entries_offset_ = memory_.cur_offset() + value32;
@ -705,37 +706,45 @@ bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
entry_is_cie = true;
cie_fde_encoding = DW_EH_PE_sdata4;
} else {
cie_offset = this->GetCieOffsetFromFde32(value32);
cie_offset = GetCieOffsetFromFde32(value32);
}
}
if (entry_is_cie) {
DwarfCie* cie = &cie_entries_[start_offset];
cie->lsda_encoding = DW_EH_PE_omit;
cie->cfa_instructions_end = next_entries_offset_;
cie->fde_address_encoding = cie_fde_encoding;
auto entry = cie_entries_.find(start_offset);
if (entry == cie_entries_.end()) {
DwarfCie* cie = &cie_entries_[start_offset];
cie->lsda_encoding = DW_EH_PE_omit;
cie->cfa_instructions_end = next_entries_offset_;
cie->fde_address_encoding = cie_fde_encoding;
if (!this->FillInCie(cie)) {
cie_entries_.erase(start_offset);
return false;
if (!FillInCie(cie)) {
cie_entries_.erase(start_offset);
return false;
}
}
*fde_entry = nullptr;
} else {
DwarfFde* fde = &fde_entries_[start_offset];
fde->cfa_instructions_end = next_entries_offset_;
fde->cie_offset = cie_offset;
auto entry = fde_entries_.find(start_offset);
if (entry != fde_entries_.end()) {
*fde_entry = &entry->second;
} else {
DwarfFde* fde = &fde_entries_[start_offset];
fde->cfa_instructions_end = next_entries_offset_;
fde->cie_offset = cie_offset;
if (!this->FillInFde(fde)) {
fde_entries_.erase(start_offset);
return false;
if (!FillInFde(fde)) {
fde_entries_.erase(start_offset);
return false;
}
*fde_entry = fde;
}
*fde_entry = fde;
}
return true;
}
template <typename AddressType>
void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
void DwarfSectionImpl<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
// Loop through the already cached entries.
uint64_t entry_offset = entries_offset_;
while (entry_offset < next_entries_offset_) {
@ -754,7 +763,7 @@ void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* f
}
while (next_entries_offset_ < entries_end_) {
DwarfFde* fde;
const DwarfFde* fde;
if (!GetNextCieOrFde(&fde)) {
break;
}
@ -771,7 +780,7 @@ void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* f
}
template <typename AddressType>
const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromPc(uint64_t pc) {
// Search in the list of fdes we already have.
auto it = fdes_.upper_bound(pc);
if (it != fdes_.end()) {
@ -784,7 +793,7 @@ const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
// to do a linear search of the fdes by pc. As fdes are read, a cached
// search map is created.
while (next_entries_offset_ < entries_end_) {
DwarfFde* fde;
const DwarfFde* fde;
if (!GetNextCieOrFde(&fde)) {
return nullptr;
}
@ -807,10 +816,6 @@ const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
template class DwarfSectionImpl<uint32_t>;
template class DwarfSectionImpl<uint64_t>;
// Explicitly instantiate DwarfSectionImplNoHdr
template class DwarfSectionImplNoHdr<uint32_t>;
template class DwarfSectionImplNoHdr<uint64_t>;
// Explicitly instantiate DwarfDebugFrame
template class DwarfDebugFrame<uint32_t>;
template class DwarfDebugFrame<uint64_t>;

View file

@ -126,8 +126,10 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() {
template <typename AddressType>
void ElfInterface::InitHeadersWithTemplate() {
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_, eh_frame_hdr_section_bias_)) {
DwarfEhFrameWithHdr<AddressType>* eh_frame_hdr = new DwarfEhFrameWithHdr<AddressType>(memory_);
eh_frame_.reset(eh_frame_hdr);
if (!eh_frame_hdr->EhFrameInit(eh_frame_offset_, eh_frame_size_, eh_frame_section_bias_) ||
!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_, eh_frame_hdr_section_bias_)) {
eh_frame_.reset(nullptr);
}
}

View file

@ -125,10 +125,16 @@ class DwarfSectionImpl : public DwarfSection {
DwarfSectionImpl(Memory* memory) : DwarfSection(memory) {}
virtual ~DwarfSectionImpl() = default;
bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
const DwarfCie* GetCieFromOffset(uint64_t offset);
const DwarfFde* GetFdeFromOffset(uint64_t offset);
const DwarfFde* GetFdeFromPc(uint64_t pc) override;
void GetFdes(std::vector<const DwarfFde*>* fdes) override;
bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
@ -139,6 +145,8 @@ class DwarfSectionImpl : public DwarfSection {
bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) override;
protected:
bool GetNextCieOrFde(const DwarfFde** fde_entry);
bool FillInCieHeader(DwarfCie* cie);
bool FillInCie(DwarfCie* cie);
@ -150,43 +158,13 @@ class DwarfSectionImpl : public DwarfSection {
bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
void InsertFde(const DwarfFde* fde);
int64_t section_bias_ = 0;
uint64_t entries_offset_ = 0;
uint64_t entries_end_ = 0;
uint64_t pc_offset_ = 0;
};
template <typename AddressType>
class DwarfSectionImplNoHdr : 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>::pc_offset_;
using DwarfSectionImpl<AddressType>::entries_offset_;
using DwarfSectionImpl<AddressType>::entries_end_;
using DwarfSectionImpl<AddressType>::last_error_;
using DwarfSectionImpl<AddressType>::section_bias_;
using DwarfSectionImpl<AddressType>::cie_entries_;
using DwarfSectionImpl<AddressType>::fde_entries_;
using DwarfSectionImpl<AddressType>::cie32_value_;
using DwarfSectionImpl<AddressType>::cie64_value_;
DwarfSectionImplNoHdr(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
virtual ~DwarfSectionImplNoHdr() = default;
bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
const DwarfFde* GetFdeFromPc(uint64_t pc) override;
void GetFdes(std::vector<const DwarfFde*>* fdes) override;
protected:
bool GetNextCieOrFde(DwarfFde** fde_entry);
void InsertFde(const DwarfFde* fde);
uint64_t next_entries_offset_ = 0;
uint64_t pc_offset_ = 0;
std::map<uint64_t, std::pair<uint64_t, const DwarfFde*>> fdes_;
};

View file

@ -36,10 +36,8 @@ class TestDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
~TestDwarfEhFrameWithHdr() = 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 TestSetHdrEntriesOffset(uint64_t offset) { this->hdr_entries_offset_ = offset; }
void TestSetHdrEntriesDataOffset(uint64_t offset) { this->hdr_entries_data_offset_ = offset; }
void TestSetTableEntrySize(size_t size) { this->table_entry_size_ = size; }
void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
@ -48,15 +46,11 @@ class TestDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
}
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_; }
uint64_t TestGetHdrEntriesOffset() { return this->hdr_entries_offset_; }
uint64_t TestGetHdrEntriesDataOffset() { return this->hdr_entries_data_offset_; }
};
template <typename TypeParam>
@ -85,15 +79,11 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init) {
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
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());
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
// Verify a zero table entry size fails to init.
this->memory_.SetData8(0x1003, 0x1);
@ -137,17 +127,14 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias) {
this->memory_.SetData32(0x140c, 0x200);
this->memory_.SetData16(0x1410, 0);
ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x200, 0x2000));
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
EXPECT_EQ(DW_EH_PE_udata2, this->eh_frame_->TestGetPtrEncoding());
EXPECT_EQ(0x1b, this->eh_frame_->TestGetTableEncoding());
EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
EXPECT_EQ(1U, 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());
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
ASSERT_TRUE(fde != nullptr);
@ -155,6 +142,115 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias) {
EXPECT_EQ(0x4700U, fde->pc_end);
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias_different_from_eh_frame_bias) {
this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
DW_EH_PE_pcrel | DW_EH_PE_sdata4});
this->memory_.SetData16(0x1004, 0x500);
this->memory_.SetData32(0x1006, 1);
this->memory_.SetData32(0x100a, 0x2500);
this->memory_.SetData32(0x100e, 0x1400);
// CIE 32 information.
this->memory_.SetData32(0x1300, 0xfc);
this->memory_.SetData32(0x1304, 0);
this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
// FDE 32 information.
this->memory_.SetData32(0x1400, 0xfc);
this->memory_.SetData32(0x1404, 0x104);
this->memory_.SetData32(0x1408, 0x20f8);
this->memory_.SetData32(0x140c, 0x200);
this->memory_.SetData16(0x1410, 0);
ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x200, 0x1000));
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
EXPECT_EQ(0x1b, this->eh_frame_->TestGetTableEncoding());
EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
EXPECT_EQ(1U, this->eh_frame_->TestGetFdeCount());
EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x4500U, fde->pc_start);
EXPECT_EQ(0x4700U, fde->pc_end);
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeFromPc_wtih_empty_fde) {
this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
DW_EH_PE_pcrel | DW_EH_PE_sdata4});
this->memory_.SetData16(0x1004, 0x500);
this->memory_.SetData32(0x1006, 1);
this->memory_.SetData32(0x100a, 0x2500);
this->memory_.SetData32(0x100e, 0x1400);
// CIE 32 information.
this->memory_.SetData32(0x1300, 0xfc);
this->memory_.SetData32(0x1304, 0);
this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
// FDE 32 information.
this->memory_.SetData32(0x1400, 0xfc);
this->memory_.SetData32(0x1404, 0x104);
this->memory_.SetData32(0x1408, 0x30f8);
this->memory_.SetData32(0x140c, 0);
this->memory_.SetData16(0x1410, 0);
// FDE 32 information.
this->memory_.SetData32(0x1500, 0xfc);
this->memory_.SetData32(0x1504, 0x204);
this->memory_.SetData32(0x1508, 0x2ff8);
this->memory_.SetData32(0x150c, 0x200);
this->memory_.SetData16(0x1510, 0);
ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x300, 0));
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x4500U, fde->pc_start);
EXPECT_EQ(0x4700U, fde->pc_end);
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes_with_empty_fde) {
this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
DW_EH_PE_pcrel | DW_EH_PE_sdata4});
this->memory_.SetData16(0x1004, 0x500);
this->memory_.SetData32(0x1006, 1);
this->memory_.SetData32(0x100a, 0x2500);
this->memory_.SetData32(0x100e, 0x1400);
// CIE 32 information.
this->memory_.SetData32(0x1300, 0xfc);
this->memory_.SetData32(0x1304, 0);
this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
// FDE 32 information.
this->memory_.SetData32(0x1400, 0xfc);
this->memory_.SetData32(0x1404, 0x104);
this->memory_.SetData32(0x1408, 0x30f8);
this->memory_.SetData32(0x140c, 0);
this->memory_.SetData16(0x1410, 0);
// FDE 32 information.
this->memory_.SetData32(0x1500, 0xfc);
this->memory_.SetData32(0x1504, 0x204);
this->memory_.SetData32(0x1508, 0x2ff8);
this->memory_.SetData32(0x150c, 0x200);
this->memory_.SetData16(0x1510, 0);
ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x300, 0));
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
std::vector<const DwarfFde*> fdes;
this->eh_frame_->GetFdes(&fdes);
ASSERT_FALSE(fdes.empty());
ASSERT_EQ(1U, fdes.size());
EXPECT_EQ(0x4500U, fdes[0]->pc_start);
EXPECT_EQ(0x4700U, fdes[0]->pc_end);
}
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes) {
this->memory_.SetMemory(
0x1000, std::vector<uint8_t>{1, DW_EH_PE_udata2, DW_EH_PE_udata4, DW_EH_PE_sdata4});
@ -220,7 +316,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes) {
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
this->eh_frame_->TestSetTableEntrySize(0x10);
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
this->eh_frame_->TestSetEntriesOffset(0x1000);
this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
@ -233,8 +329,8 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
// We are assuming that pc rel, is really relative to the load_bias.
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_->TestSetHdrEntriesOffset(0x1000);
this->eh_frame_->TestSetHdrEntriesDataOffset(0x3000);
this->eh_frame_->TestSetTableEntrySize(0x10);
this->memory_.SetData32(0x1040, 0x340);
@ -248,8 +344,8 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
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_->TestSetHdrEntriesOffset(0x1000);
this->eh_frame_->TestSetHdrEntriesDataOffset(0x3000);
this->eh_frame_->TestSetTableEntrySize(0x10);
this->memory_.SetData32(0x1040, 0x340);
@ -263,7 +359,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_datarel) {
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_cached) {
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
this->eh_frame_->TestSetEntriesOffset(0x1000);
this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
this->eh_frame_->TestSetTableEntrySize(0x10);
this->memory_.SetData32(0x1040, 0x340);
@ -446,7 +542,9 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeFromPc_fde_not_found) {
ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
}
REGISTER_TYPED_TEST_SUITE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias, GetFdes,
REGISTER_TYPED_TEST_SUITE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias,
Init_non_zero_load_bias_different_from_eh_frame_bias,
GetFdeFromPc_wtih_empty_fde, GetFdes_with_empty_fde, GetFdes,
GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
GetFdeOffsetFromPc_verify, GetFdeOffsetFromPc_index_fail,