diff options
author | Christopher Ferris <cferris@google.com> | 2017-11-03 14:50:27 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2017-11-07 13:22:39 -0800 |
commit | c9dee84d81e4672dee5dd08890c904d1ab841e56 (patch) | |
tree | b71dfd2d4adf1041b6420cef62492494d00e864c /libunwindstack | |
parent | 1e0b9672defa3504915741c8d4cec3cc73f89568 (diff) | |
download | core-c9dee84d81e4672dee5dd08890c904d1ab841e56.tar.gz core-c9dee84d81e4672dee5dd08890c904d1ab841e56.tar.bz2 core-c9dee84d81e4672dee5dd08890c904d1ab841e56.zip |
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
Diffstat (limited to 'libunwindstack')
-rw-r--r-- | libunwindstack/Android.bp | 4 | ||||
-rw-r--r-- | libunwindstack/DwarfDebugFrame.cpp | 316 | ||||
-rw-r--r-- | libunwindstack/DwarfDebugFrame.h | 50 | ||||
-rw-r--r-- | libunwindstack/DwarfEhFrame.h | 54 | ||||
-rw-r--r-- | libunwindstack/DwarfEhFrameWithHdr.cpp (renamed from libunwindstack/DwarfEhFrame.cpp) | 24 | ||||
-rw-r--r-- | libunwindstack/DwarfEhFrameWithHdr.h | 78 | ||||
-rw-r--r-- | libunwindstack/DwarfSection.cpp | 304 | ||||
-rw-r--r-- | libunwindstack/ElfInterface.cpp | 24 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/DwarfSection.h | 32 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/ElfInterface.h | 5 | ||||
-rw-r--r-- | libunwindstack/tests/DwarfDebugFrameTest.cpp | 4 | ||||
-rw-r--r-- | libunwindstack/tests/DwarfEhFrameTest.cpp | 517 | ||||
-rw-r--r-- | libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp | 425 | ||||
-rw-r--r-- | libunwindstack/tests/DwarfSectionImplTest.cpp | 28 | ||||
-rw-r--r-- | libunwindstack/tests/ElfInterfaceTest.cpp | 28 |
15 files changed, 1198 insertions, 695 deletions
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index c885c3f9b..40364fe40 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -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", diff --git a/libunwindstack/DwarfDebugFrame.cpp b/libunwindstack/DwarfDebugFrame.cpp deleted file mode 100644 index 57075962a..000000000 --- a/libunwindstack/DwarfDebugFrame.cpp +++ /dev/null @@ -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 diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h index 6a6178e6f..635cefdf2 100644 --- a/libunwindstack/DwarfDebugFrame.h +++ b/libunwindstack/DwarfDebugFrame.h @@ -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; - - 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 this->entries_offset_ + pointer; + } - 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 diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h index 4207b42f2..561d23a88 100644 --- a/libunwindstack/DwarfEhFrame.h +++ b/libunwindstack/DwarfEhFrame.h @@ -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 diff --git a/libunwindstack/DwarfEhFrame.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp index db8f558ff..d8cbdf439 100644 --- a/libunwindstack/DwarfEhFrame.cpp +++ b/libunwindstack/DwarfEhFrameWithHdr.cpp @@ -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 diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h new file mode 100644 index 000000000..357116620 --- /dev/null +++ b/libunwindstack/DwarfEhFrameWithHdr.h @@ -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 diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index 91aef8045..805dcd34b 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -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 diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 20cc1b06c..d5d158f82 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -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)) && diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h index 1e843c359..10be6b48f 100644 --- a/libunwindstack/include/unwindstack/DwarfSection.h +++ b/libunwindstack/include/unwindstack/DwarfSection.h @@ -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 diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index 319623d01..86e51b382 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -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; diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp index 90baabedc..07204bcec 100644 --- a/libunwindstack/tests/DwarfDebugFrameTest.cpp +++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp @@ -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); } diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp index 3dbabe185..53ee719d2 100644 --- a/libunwindstack/tests/DwarfEhFrameTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameTest.cpp @@ -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); - - 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(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'); -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()); -} + // FDE 32 information. + this->memory_.SetData32(0x5100, 0xfc); + this->memory_.SetData32(0x5104, 0x104); + this->memory_.SetData32(0x5108, 0x1500); + this->memory_.SetData32(0x510c, 0x200); -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); + this->memory_.SetData32(0x5200, 0xfc); + this->memory_.SetData32(0x5204, 0x204); + this->memory_.SetData32(0x5208, 0x2500); + this->memory_.SetData32(0x520c, 0x300); - this->memory_.SetData32(0x1040, 0x340); - this->memory_.SetData32(0x1044, 0x500); + // CIE 32 information. + this->memory_.SetData32(0x5300, 0xfc); + this->memory_.SetData32(0x5304, 0); + this->memory_.SetData8(0x5308, 1); + this->memory_.SetData8(0x5309, '\0'); - auto info = this->eh_frame_->GetFdeInfoFromIndex(2); - ASSERT_TRUE(info != nullptr); - EXPECT_EQ(0x1384U, info->pc); - EXPECT_EQ(0x1540U, info->offset); + // 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_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, 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'); - this->memory_.SetData32(0x1040, 0x340); - this->memory_.SetData32(0x1044, 0x500); + // FDE 32 information. + this->memory_.SetData32(0x5100, 0xfc); + this->memory_.SetData32(0x5104, 0x1000); + this->memory_.SetData32(0x5108, 0x1500); + this->memory_.SetData32(0x510c, 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, 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'); + + // 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); + + 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); - this->memory_.SetData32(0x1040, 0x340); - this->memory_.SetData32(0x1044, 0x500); + // 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'); - auto info = this->eh_frame_->GetFdeInfoFromIndex(2); - ASSERT_TRUE(info != nullptr); - EXPECT_EQ(0x344U, info->pc); - EXPECT_EQ(0x500U, info->offset); + // 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); +} - // Clear the memory so that this will fail if it doesn't read cached data. - this->memory_.Clear(); +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'); - info = this->eh_frame_->GetFdeInfoFromIndex(2); - ASSERT_TRUE(info != nullptr); - EXPECT_EQ(0x344U, info->pc); - EXPECT_EQ(0x500U, info->offset); + // 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); + + ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600)); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error()); } -TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetBinary_verify) { - this->eh_frame_->TestSetTableEntrySize(0x10); - this->eh_frame_->TestSetFdeCount(10); +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); - 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, 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); + + // 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()); - // Even number of elements. - for (size_t i = 0; i < 10; i++) { + + this->eh_frame_->TestSetFdeCount(9); + ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset)); + ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error()); + // 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, 10)) << "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, 10)) << "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, 10)) + 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()); } - // Odd number of elements. - for (size_t i = 0; i < 9; i++) { + + // 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); - 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()); } } -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); diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp new file mode 100644 index 000000000..7c8fc6cc4 --- /dev/null +++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp @@ -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 diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp index 5b9f3ee19..d54b0bf59 100644 --- a/libunwindstack/tests/DwarfSectionImplTest.cpp +++ b/libunwindstack/tests/DwarfSectionImplTest.cpp @@ -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{}; diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp index 2752e99c2..e138c3acf 100644 --- a/libunwindstack/tests/ElfInterfaceTest.cpp +++ b/libunwindstack/tests/ElfInterfaceTest.cpp @@ -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) { |