Merge "Refactor the DwarfSection classes."
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
index 635cefd..388ab0a 100644
--- a/libunwindstack/DwarfDebugFrame.h
+++ b/libunwindstack/DwarfDebugFrame.h
@@ -26,9 +26,9 @@
 namespace unwindstack {
 
 template <typename AddressType>
-class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
+class DwarfDebugFrame : public DwarfSectionImplNoHdr<AddressType> {
  public:
-  DwarfDebugFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {
+  DwarfDebugFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {
     this->cie32_value_ = static_cast<uint32_t>(-1);
     this->cie64_value_ = static_cast<uint64_t>(-1);
   }
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 7a41e45..df441fb 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -25,9 +25,9 @@
 namespace unwindstack {
 
 template <typename AddressType>
-class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
+class DwarfEhFrame : public DwarfSectionImplNoHdr<AddressType> {
  public:
-  DwarfEhFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
+  DwarfEhFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {}
   virtual ~DwarfEhFrame() = default;
 
   uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index fd6a457..668527a 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -39,6 +39,7 @@
   memory_.clear_text_offset();
   memory_.set_data_offset(offset);
   memory_.set_cur_offset(offset);
+  pc_offset_ = offset;
 
   // Read the first four bytes all at once.
   uint8_t data[4];
@@ -88,12 +89,22 @@
 }
 
 template <typename AddressType>
-const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromIndex(size_t index) {
-  const FdeInfo* info = GetFdeInfoFromIndex(index);
-  if (info == nullptr) {
+const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
+  uint64_t fde_offset;
+  if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
     return nullptr;
   }
-  return this->GetFdeFromOffset(info->offset);
+  const DwarfFde* fde = this->GetFdeFromOffset(fde_offset);
+  if (fde == nullptr) {
+    return nullptr;
+  }
+
+  // Guaranteed pc >= pc_start, need to check pc in the fde range.
+  if (pc < fde->pc_end) {
+    return fde;
+  }
+  last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
+  return nullptr;
 }
 
 template <typename AddressType>
@@ -241,6 +252,21 @@
   }
 }
 
+template <typename AddressType>
+void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
+  for (size_t i = 0; i < fde_count_; i++) {
+    const FdeInfo* info = GetFdeInfoFromIndex(i);
+    if (info == nullptr) {
+      break;
+    }
+    const DwarfFde* fde = this->GetFdeFromOffset(info->offset);
+    if (fde == nullptr) {
+      break;
+    }
+    fdes->push_back(fde);
+  }
+}
+
 // Explicitly instantiate DwarfEhFrameWithHdr
 template class DwarfEhFrameWithHdr<uint32_t>;
 template class DwarfEhFrameWithHdr<uint64_t>;
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index d16dd10..e3e9ca8 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -21,7 +21,7 @@
 
 #include <unordered_map>
 
-#include "DwarfEhFrame.h"
+#include <unwindstack/DwarfSection.h>
 
 namespace unwindstack {
 
@@ -29,12 +29,12 @@
 class Memory;
 
 template <typename AddressType>
-class DwarfEhFrameWithHdr : public DwarfEhFrame<AddressType> {
+class DwarfEhFrameWithHdr : 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>::pc_offset_;
   using DwarfSectionImpl<AddressType>::entries_offset_;
   using DwarfSectionImpl<AddressType>::entries_end_;
   using DwarfSectionImpl<AddressType>::last_error_;
@@ -45,14 +45,27 @@
     uint64_t offset;
   };
 
-  DwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrame<AddressType>(memory) {}
+  DwarfEhFrameWithHdr(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
   virtual ~DwarfEhFrameWithHdr() = default;
 
+  uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
+    return this->memory_.cur_offset() - pointer - 4;
+  }
+
+  uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
+    return this->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;
+  }
+
   bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
 
-  bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
+  const DwarfFde* GetFdeFromPc(uint64_t pc) override;
 
-  const DwarfFde* GetFdeFromIndex(size_t index) override;
+  bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset);
 
   const FdeInfo* GetFdeInfoFromIndex(size_t index);
 
@@ -60,6 +73,8 @@
 
   bool GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, uint64_t total_entries);
 
+  void GetFdes(std::vector<const DwarfFde*>* fdes) override;
+
  protected:
   uint8_t version_;
   uint8_t ptr_encoding_;
@@ -71,6 +86,7 @@
   uint64_t entries_data_offset_;
   uint64_t cur_entries_offset_ = 0;
 
+  uint64_t fde_count_;
   std::unordered_map<uint64_t, FdeInfo> fde_info_;
 };
 
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index eb83949..6061f61 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -36,24 +36,6 @@
 
 DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
 
-const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
-  uint64_t fde_offset;
-  if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
-    return nullptr;
-  }
-  const DwarfFde* fde = GetFdeFromOffset(fde_offset);
-  if (fde == nullptr) {
-    return nullptr;
-  }
-
-  // Guaranteed pc >= pc_start, need to check pc in the fde range.
-  if (pc < fde->pc_end) {
-    return fde;
-  }
-  last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
-  return nullptr;
-}
-
 bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
   // Lookup the pc in the cache.
   auto it = loc_regs_.upper_bound(pc);
@@ -81,6 +63,314 @@
 }
 
 template <typename AddressType>
+const DwarfCie* DwarfSectionImpl<AddressType>::GetCieFromOffset(uint64_t offset) {
+  auto cie_entry = cie_entries_.find(offset);
+  if (cie_entry != cie_entries_.end()) {
+    return &cie_entry->second;
+  }
+  DwarfCie* cie = &cie_entries_[offset];
+  memory_.set_cur_offset(offset);
+  if (!FillInCieHeader(cie) || !FillInCie(cie)) {
+    // Erase the cached entry.
+    cie_entries_.erase(offset);
+    return nullptr;
+  }
+  return cie;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInCieHeader(DwarfCie* cie) {
+  cie->lsda_encoding = DW_EH_PE_omit;
+  uint32_t length32;
+  if (!memory_.ReadBytes(&length32, sizeof(length32))) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+  if (length32 == static_cast<uint32_t>(-1)) {
+    // 64 bit Cie
+    uint64_t length64;
+    if (!memory_.ReadBytes(&length64, sizeof(length64))) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+
+    cie->cfa_instructions_end = memory_.cur_offset() + length64;
+    cie->fde_address_encoding = DW_EH_PE_sdata8;
+
+    uint64_t cie_id;
+    if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+    if (cie_id != cie64_value_) {
+      // This is not a Cie, something has gone horribly wrong.
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+      return false;
+    }
+  } else {
+    // 32 bit Cie
+    cie->cfa_instructions_end = memory_.cur_offset() + length32;
+    cie->fde_address_encoding = DW_EH_PE_sdata4;
+
+    uint32_t cie_id;
+    if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+    if (cie_id != cie32_value_) {
+      // This is not a Cie, something has gone horribly wrong.
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+      return false;
+    }
+  }
+  return true;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
+  if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+
+  if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
+    // Unrecognized version.
+    last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
+    return false;
+  }
+
+  // Read the augmentation string.
+  char aug_value;
+  do {
+    if (!memory_.ReadBytes(&aug_value, 1)) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+    cie->augmentation_string.push_back(aug_value);
+  } while (aug_value != '\0');
+
+  if (cie->version == 4) {
+    // Skip the Address Size field since we only use it for validation.
+    memory_.set_cur_offset(memory_.cur_offset() + 1);
+
+    // Segment Size
+    if (!memory_.ReadBytes(&cie->segment_size, 1)) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+  }
+
+  // Code Alignment Factor
+  if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+
+  // Data Alignment Factor
+  if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+
+  if (cie->version == 1) {
+    // Return Address is a single byte.
+    uint8_t return_address_register;
+    if (!memory_.ReadBytes(&return_address_register, 1)) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+    cie->return_address_register = return_address_register;
+  } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+
+  if (cie->augmentation_string[0] != 'z') {
+    cie->cfa_instructions_offset = memory_.cur_offset();
+    return true;
+  }
+
+  uint64_t aug_length;
+  if (!memory_.ReadULEB128(&aug_length)) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+  cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
+
+  for (size_t i = 1; i < cie->augmentation_string.size(); i++) {
+    switch (cie->augmentation_string[i]) {
+      case 'L':
+        if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_.cur_offset();
+          return false;
+        }
+        break;
+      case 'P': {
+        uint8_t encoding;
+        if (!memory_.ReadBytes(&encoding, 1)) {
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_.cur_offset();
+          return false;
+        }
+        memory_.set_pc_offset(pc_offset_);
+        if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_.cur_offset();
+          return false;
+        }
+      } break;
+      case 'R':
+        if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
+          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+          last_error_.address = memory_.cur_offset();
+          return false;
+        }
+        break;
+    }
+  }
+  return true;
+}
+
+template <typename AddressType>
+const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) {
+  auto fde_entry = fde_entries_.find(offset);
+  if (fde_entry != fde_entries_.end()) {
+    return &fde_entry->second;
+  }
+  DwarfFde* fde = &fde_entries_[offset];
+  memory_.set_cur_offset(offset);
+  if (!FillInFdeHeader(fde) || !FillInFde(fde)) {
+    fde_entries_.erase(offset);
+    return nullptr;
+  }
+  return fde;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInFdeHeader(DwarfFde* fde) {
+  uint32_t length32;
+  if (!memory_.ReadBytes(&length32, sizeof(length32))) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+
+  if (length32 == static_cast<uint32_t>(-1)) {
+    // 64 bit Fde.
+    uint64_t length64;
+    if (!memory_.ReadBytes(&length64, sizeof(length64))) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+    fde->cfa_instructions_end = memory_.cur_offset() + length64;
+
+    uint64_t value64;
+    if (!memory_.ReadBytes(&value64, sizeof(value64))) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+    if (value64 == cie64_value_) {
+      // This is a Cie, this means something has gone wrong.
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+      return false;
+    }
+
+    // Get the Cie pointer, which is necessary to properly read the rest of
+    // of the Fde information.
+    fde->cie_offset = GetCieOffsetFromFde64(value64);
+  } else {
+    // 32 bit Fde.
+    fde->cfa_instructions_end = memory_.cur_offset() + length32;
+
+    uint32_t value32;
+    if (!memory_.ReadBytes(&value32, sizeof(value32))) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+    if (value32 == cie32_value_) {
+      // This is a Cie, this means something has gone wrong.
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+      return false;
+    }
+
+    // Get the Cie pointer, which is necessary to properly read the rest of
+    // of the Fde information.
+    fde->cie_offset = GetCieOffsetFromFde32(value32);
+  }
+  return true;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
+  uint64_t cur_offset = memory_.cur_offset();
+
+  const DwarfCie* cie = GetCieFromOffset(fde->cie_offset);
+  if (cie == nullptr) {
+    return false;
+  }
+  fde->cie = cie;
+
+  if (cie->segment_size != 0) {
+    // Skip over the segment selector for now.
+    cur_offset += cie->segment_size;
+  }
+  memory_.set_cur_offset(cur_offset);
+
+  // The load bias only applies to the start.
+  memory_.set_pc_offset(load_bias_);
+  bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
+  fde->pc_start = AdjustPcFromFde(fde->pc_start);
+
+  memory_.set_pc_offset(0);
+  if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+  fde->pc_end += fde->pc_start;
+
+  if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
+    // Augmentation Size
+    uint64_t aug_length;
+    if (!memory_.ReadULEB128(&aug_length)) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+    uint64_t cur_offset = memory_.cur_offset();
+
+    memory_.set_pc_offset(pc_offset_);
+    if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+
+    // Set our position to after all of the augmentation data.
+    memory_.set_cur_offset(cur_offset + aug_length);
+  }
+  fde->cfa_instructions_offset = memory_.cur_offset();
+
+  return true;
+}
+
+template <typename AddressType>
 bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, Memory* regular_memory,
                                                    AddressType* value,
                                                    RegsInfo<AddressType>* regs_info,
@@ -260,307 +550,6 @@
 }
 
 template <typename AddressType>
-const DwarfCie* DwarfSectionImpl<AddressType>::GetCie(uint64_t offset) {
-  auto cie_entry = cie_entries_.find(offset);
-  if (cie_entry != cie_entries_.end()) {
-    return &cie_entry->second;
-  }
-  DwarfCie* cie = &cie_entries_[offset];
-  memory_.set_cur_offset(offset);
-  if (!FillInCie(cie)) {
-    // Erase the cached entry.
-    cie_entries_.erase(offset);
-    return nullptr;
-  }
-  return cie;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
-  uint32_t length32;
-  if (!memory_.ReadBytes(&length32, sizeof(length32))) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-  // Set the default for the lsda encoding.
-  cie->lsda_encoding = DW_EH_PE_omit;
-
-  if (length32 == static_cast<uint32_t>(-1)) {
-    // 64 bit Cie
-    uint64_t length64;
-    if (!memory_.ReadBytes(&length64, sizeof(length64))) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-
-    cie->cfa_instructions_end = memory_.cur_offset() + length64;
-    cie->fde_address_encoding = DW_EH_PE_sdata8;
-
-    uint64_t cie_id;
-    if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-    if (cie_id != cie64_value_) {
-      // This is not a Cie, something has gone horribly wrong.
-      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
-      return false;
-    }
-  } else {
-    // 32 bit Cie
-    cie->cfa_instructions_end = memory_.cur_offset() + length32;
-    cie->fde_address_encoding = DW_EH_PE_sdata4;
-
-    uint32_t cie_id;
-    if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-    if (cie_id != cie32_value_) {
-      // This is not a Cie, something has gone horribly wrong.
-      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
-      return false;
-    }
-  }
-
-  if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-
-  if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
-    // Unrecognized version.
-    last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
-    return false;
-  }
-
-  // Read the augmentation string.
-  char aug_value;
-  do {
-    if (!memory_.ReadBytes(&aug_value, 1)) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-    cie->augmentation_string.push_back(aug_value);
-  } while (aug_value != '\0');
-
-  if (cie->version == 4) {
-    // Skip the Address Size field since we only use it for validation.
-    memory_.set_cur_offset(memory_.cur_offset() + 1);
-
-    // Segment Size
-    if (!memory_.ReadBytes(&cie->segment_size, 1)) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-  }
-
-  // Code Alignment Factor
-  if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-
-  // Data Alignment Factor
-  if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-
-  if (cie->version == 1) {
-    // Return Address is a single byte.
-    uint8_t return_address_register;
-    if (!memory_.ReadBytes(&return_address_register, 1)) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-    cie->return_address_register = return_address_register;
-  } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-
-  if (cie->augmentation_string[0] != 'z') {
-    cie->cfa_instructions_offset = memory_.cur_offset();
-    return true;
-  }
-
-  uint64_t aug_length;
-  if (!memory_.ReadULEB128(&aug_length)) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-  cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
-
-  for (size_t i = 1; i < cie->augmentation_string.size(); i++) {
-    switch (cie->augmentation_string[i]) {
-      case 'L':
-        if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
-          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-          last_error_.address = memory_.cur_offset();
-          return false;
-        }
-        break;
-      case 'P': {
-        uint8_t encoding;
-        if (!memory_.ReadBytes(&encoding, 1)) {
-          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-          last_error_.address = memory_.cur_offset();
-          return false;
-        }
-        memory_.set_pc_offset(pc_offset_);
-        if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
-          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-          last_error_.address = memory_.cur_offset();
-          return false;
-        }
-      } break;
-      case 'R':
-        if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
-          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-          last_error_.address = memory_.cur_offset();
-          return false;
-        }
-        break;
-    }
-  }
-  return true;
-}
-
-template <typename AddressType>
-const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) {
-  auto fde_entry = fde_entries_.find(offset);
-  if (fde_entry != fde_entries_.end()) {
-    return &fde_entry->second;
-  }
-  DwarfFde* fde = &fde_entries_[offset];
-  memory_.set_cur_offset(offset);
-  if (!FillInFde(fde)) {
-    fde_entries_.erase(offset);
-    return nullptr;
-  }
-  return fde;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
-  uint32_t length32;
-  if (!memory_.ReadBytes(&length32, sizeof(length32))) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-
-  if (length32 == static_cast<uint32_t>(-1)) {
-    // 64 bit Fde.
-    uint64_t length64;
-    if (!memory_.ReadBytes(&length64, sizeof(length64))) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-    fde->cfa_instructions_end = memory_.cur_offset() + length64;
-
-    uint64_t value64;
-    if (!memory_.ReadBytes(&value64, sizeof(value64))) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-    if (value64 == cie64_value_) {
-      // This is a Cie, this means something has gone wrong.
-      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
-      return false;
-    }
-
-    // Get the Cie pointer, which is necessary to properly read the rest of
-    // of the Fde information.
-    fde->cie_offset = GetCieOffsetFromFde64(value64);
-  } else {
-    // 32 bit Fde.
-    fde->cfa_instructions_end = memory_.cur_offset() + length32;
-
-    uint32_t value32;
-    if (!memory_.ReadBytes(&value32, sizeof(value32))) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-    if (value32 == cie32_value_) {
-      // This is a Cie, this means something has gone wrong.
-      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
-      return false;
-    }
-
-    // Get the Cie pointer, which is necessary to properly read the rest of
-    // of the Fde information.
-    fde->cie_offset = GetCieOffsetFromFde32(value32);
-  }
-  uint64_t cur_offset = memory_.cur_offset();
-
-  const DwarfCie* cie = GetCie(fde->cie_offset);
-  if (cie == nullptr) {
-    return false;
-  }
-  fde->cie = cie;
-
-  if (cie->segment_size != 0) {
-    // Skip over the segment selector for now.
-    cur_offset += cie->segment_size;
-  }
-  memory_.set_cur_offset(cur_offset);
-
-  // The load bias only applies to the start.
-  memory_.set_pc_offset(load_bias_);
-  bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
-  fde->pc_start = AdjustPcFromFde(fde->pc_start);
-
-  memory_.set_pc_offset(0);
-  if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-  fde->pc_end += fde->pc_start;
-
-  if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
-    // Augmentation Size
-    uint64_t aug_length;
-    if (!memory_.ReadULEB128(&aug_length)) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-    uint64_t cur_offset = memory_.cur_offset();
-
-    memory_.set_pc_offset(pc_offset_);
-    if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-
-    // Set our position to after all of the augmentation data.
-    memory_.set_cur_offset(cur_offset + aug_length);
-  }
-  fde->cfa_instructions_offset = memory_.cur_offset();
-
-  return true;
-}
-
-template <typename AddressType>
 bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde,
                                                        dwarf_loc_regs_t* loc_regs) {
   DwarfCfa<AddressType> cfa(&memory_, fde);
@@ -601,9 +590,10 @@
 }
 
 template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
+bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
   load_bias_ = load_bias;
   entries_offset_ = offset;
+  next_entries_offset_ = offset;
   entries_end_ = offset + size;
 
   memory_.clear_func_offset();
@@ -612,298 +602,213 @@
   memory_.set_data_offset(offset);
   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_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    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_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      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_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      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_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      return false;
-    }
-  } while (value & 0x80);
-
-  // Skip data alignment factor
-  do {
-    if (!memory_.ReadBytes(&value, 1)) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      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_.code = DWARF_ERROR_MEMORY_INVALID;
-        last_error_.address = memory_.cur_offset();
-        return false;
-      }
-    } while (value & 0x80);
-  }
-
-  // Skip the augmentation length.
-  do {
-    if (!memory_.ReadBytes(&value, 1)) {
-      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-      last_error_.address = memory_.cur_offset();
-      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_.code = DWARF_ERROR_MEMORY_INVALID;
-        last_error_.address = memory_.cur_offset();
-        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_.code = DWARF_ERROR_MEMORY_INVALID;
-        last_error_.address = memory_.cur_offset();
-        return false;
-      }
-      uint64_t value;
-      memory_.set_pc_offset(pc_offset_);
-      if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
-        last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-        last_error_.address = memory_.cur_offset();
-        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;
-  memory_.set_pc_offset(load_bias_);
-  bool valid = memory_.template ReadEncodedValue<AddressType>(encoding, &start);
-  start = AdjustPcFromFde(start);
-
-  uint64_t length;
-  memory_.set_pc_offset(0);
-  if (!valid || !memory_.template ReadEncodedValue<AddressType>(encoding, &length)) {
-    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
-    last_error_.address = memory_.cur_offset();
-    return false;
-  }
-  if (length != 0) {
-    fdes_.emplace_back(entry_offset, start, length);
-  }
-
   return true;
 }
 
+// Create a cached version of the fde information such that it is a std::map
+// that is indexed by end pc and contains a pair that represents the start pc
+// followed by the fde object. The fde pointers are owned by fde_entries_
+// and not by the map object.
+// It is possible for an fde to be represented by multiple entries in
+// the map. This can happen if the the start pc and end pc overlap already
+// existing entries. For example, if there is already an entry of 0x400, 0x200,
+// 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>
-bool DwarfSectionImpl<AddressType>::CreateSortedFdeList() {
-  memory_.set_cur_offset(entries_offset_);
+void DwarfSectionImplNoHdr<AddressType>::InsertFde(const DwarfFde* fde) {
+  uint64_t start = fde->pc_start;
+  uint64_t end = fde->pc_end;
+  auto it = fdes_.upper_bound(start);
+  bool add_element = false;
+  while (it != fdes_.end() && start < end) {
+    if (add_element) {
+      add_element = false;
+      if (end < it->second.first) {
+        if (it->first == end) {
+          return;
+        }
+        fdes_[end] = std::make_pair(start, fde);
+        return;
+      }
+      if (start != it->second.first) {
+        fdes_[it->second.first] = std::make_pair(start, fde);
+      }
+    }
+    if (start < it->first) {
+      if (end < it->second.first) {
+        if (it->first != end) {
+          fdes_[end] = std::make_pair(start, fde);
+        }
+        return;
+      }
+      add_element = true;
+    }
+    start = it->first;
+    ++it;
+  }
+  if (start < end) {
+    fdes_[end] = std::make_pair(start, fde);
+  }
+}
 
-  // 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();
+template <typename AddressType>
+bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
+  uint64_t start_offset = next_entries_offset_;
 
-    // Figure out the entry length and type.
-    uint32_t value32;
+  memory_.set_cur_offset(next_entries_offset_);
+  uint32_t value32;
+  if (!memory_.ReadBytes(&value32, sizeof(value32))) {
+    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+    last_error_.address = memory_.cur_offset();
+    return false;
+  }
+
+  uint64_t cie_offset;
+  uint8_t cie_fde_encoding;
+  bool entry_is_cie = false;
+  if (value32 == static_cast<uint32_t>(-1)) {
+    // 64 bit entry.
+    uint64_t value64;
+    if (!memory_.ReadBytes(&value64, sizeof(value64))) {
+      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+
+    next_entries_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_.code = DWARF_ERROR_MEMORY_INVALID;
+      last_error_.address = memory_.cur_offset();
+      return false;
+    }
+
+    if (value64 == cie64_value_) {
+      entry_is_cie = true;
+      cie_fde_encoding = DW_EH_PE_sdata8;
+    } else {
+      cie_offset = this->GetCieOffsetFromFde64(value64);
+    }
+  } else {
+    next_entries_offset_ = memory_.cur_offset() + value32;
+
+    // 32 bit Cie
     if (!memory_.ReadBytes(&value32, sizeof(value32))) {
       last_error_.code = DWARF_ERROR_MEMORY_INVALID;
       last_error_.address = memory_.cur_offset();
       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_.code = DWARF_ERROR_MEMORY_INVALID;
-        last_error_.address = memory_.cur_offset();
-        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_.code = DWARF_ERROR_MEMORY_INVALID;
-        last_error_.address = memory_.cur_offset();
-        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_.code = DWARF_ERROR_ILLEGAL_VALUE;
-          return false;
-        }
-
-        // Fde 64 bit
-        if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
-          return false;
-        }
-      }
+    if (value32 == cie32_value_) {
+      entry_is_cie = true;
+      cie_fde_encoding = DW_EH_PE_sdata4;
     } 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_.code = DWARF_ERROR_MEMORY_INVALID;
-        last_error_.address = memory_.cur_offset();
-        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_.code = DWARF_ERROR_ILLEGAL_VALUE;
-          return false;
-        }
-
-        // Fde 32 bit
-        if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
-          return false;
-        }
-      }
+      cie_offset = this->GetCieOffsetFromFde32(value32);
     }
-
-    if (next_entry_offset < memory_.cur_offset()) {
-      // Simply consider the processing done in this case.
-      break;
-    }
-    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;
-  });
+  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;
 
-  fde_count_ = fdes_.size();
+    if (!this->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;
 
+    if (!this->FillInFde(fde)) {
+      fde_entries_.erase(start_offset);
+      return false;
+    }
+    *fde_entry = fde;
+  }
   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;
+void DwarfSectionImplNoHdr<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_) {
+    auto cie_it = cie_entries_.find(entry_offset);
+    if (cie_it != cie_entries_.end()) {
+      entry_offset = cie_it->second.cfa_instructions_end;
     } else {
-      first = current + 1;
+      auto fde_it = fde_entries_.find(entry_offset);
+      if (fde_it == fde_entries_.end()) {
+        // No fde or cie at this entry, should not be possible.
+        return;
+      }
+      entry_offset = fde_it->second.cfa_instructions_end;
+      fdes->push_back(&fde_it->second);
     }
   }
-  return false;
+
+  while (next_entries_offset_ < entries_end_) {
+    DwarfFde* fde;
+    if (!GetNextCieOrFde(&fde)) {
+      break;
+    }
+    if (fde != nullptr) {
+      InsertFde(fde);
+      fdes->push_back(fde);
+    }
+
+    if (next_entries_offset_ < memory_.cur_offset()) {
+      // Simply consider the processing done in this case.
+      break;
+    }
+  }
 }
 
 template <typename AddressType>
-const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromIndex(size_t index) {
-  if (index >= fdes_.size()) {
-    return nullptr;
+const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
+  // Search in the list of fdes we already have.
+  auto it = fdes_.upper_bound(pc);
+  if (it != fdes_.end()) {
+    if (pc >= it->second.first) {
+      return it->second.second;
+    }
   }
-  return this->GetFdeFromOffset(fdes_[index].offset);
+
+  // The section might have overlapping pcs in fdes, so it is necessary
+  // 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;
+    if (!GetNextCieOrFde(&fde)) {
+      return nullptr;
+    }
+    if (fde != nullptr) {
+      InsertFde(fde);
+      if (pc >= fde->pc_start && pc < fde->pc_end) {
+        return fde;
+      }
+    }
+
+    if (next_entries_offset_ < memory_.cur_offset()) {
+      // Simply consider the processing done in this case.
+      break;
+    }
+  }
+  return nullptr;
 }
 
 // Explicitly instantiate DwarfSectionImpl
 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>;
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 847f382..e9942de 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -43,7 +43,12 @@
 
   class iterator : public std::iterator<std::bidirectional_iterator_tag, DwarfFde*> {
    public:
-    iterator(DwarfSection* section, size_t index) : section_(section), index_(index) {}
+    iterator(DwarfSection* section, size_t index) : index_(index) {
+      section->GetFdes(&fdes_);
+      if (index_ == static_cast<size_t>(-1)) {
+        index_ = fdes_.size();
+      }
+    }
 
     iterator& operator++() {
       index_++;
@@ -65,15 +70,18 @@
     bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; }
     bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; }
 
-    const DwarfFde* operator*() { return section_->GetFdeFromIndex(index_); }
+    const DwarfFde* operator*() {
+      if (index_ > fdes_.size()) return nullptr;
+      return fdes_[index_];
+    }
 
    private:
-    DwarfSection* section_ = nullptr;
+    std::vector<const DwarfFde*> fdes_;
     size_t index_ = 0;
   };
 
   iterator begin() { return iterator(this, 0); }
-  iterator end() { return iterator(this, fde_count_); }
+  iterator end() { return iterator(this, static_cast<size_t>(-1)); }
 
   DwarfErrorCode LastErrorCode() { return last_error_.code; }
   uint64_t LastErrorAddress() { return last_error_.address; }
@@ -82,15 +90,11 @@
 
   virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0;
 
-  virtual bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) = 0;
-
   virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) = 0;
 
-  virtual const DwarfFde* GetFdeFromIndex(size_t index) = 0;
+  virtual void GetFdes(std::vector<const DwarfFde*>* fdes) = 0;
 
-  const DwarfFde* GetFdeFromPc(uint64_t pc);
-
-  virtual const DwarfFde* GetFdeFromOffset(uint64_t fde_offset) = 0;
+  virtual const DwarfFde* GetFdeFromPc(uint64_t pc) = 0;
 
   virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) = 0;
 
@@ -109,7 +113,6 @@
   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_;
   std::unordered_map<uint64_t, dwarf_loc_regs_t> cie_loc_regs_;
@@ -119,55 +122,73 @@
 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, uint64_t load_bias) override;
+  const DwarfCie* GetCieFromOffset(uint64_t offset);
 
-  bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
-
-  const DwarfFde* GetFdeFromIndex(size_t index) override;
+  const DwarfFde* GetFdeFromOffset(uint64_t offset);
 
   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,
             Regs* regs, bool* finished) override;
 
-  const DwarfCie* GetCie(uint64_t offset);
-  bool FillInCie(DwarfCie* cie);
-
-  const DwarfFde* GetFdeFromOffset(uint64_t offset) override;
-  bool FillInFde(DwarfFde* fde);
-
   bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) override;
 
   bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) override;
 
  protected:
+  bool FillInCieHeader(DwarfCie* cie);
+
+  bool FillInCie(DwarfCie* cie);
+
+  bool FillInFdeHeader(DwarfFde* fde);
+
+  bool FillInFde(DwarfFde* fde);
+
   bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
                       RegsInfo<AddressType>* regs_info, bool* is_dex_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();
-
   uint64_t load_bias_ = 0;
+  uint64_t entries_offset_ = 0;
+  uint64_t entries_end_ = 0;
   uint64_t pc_offset_ = 0;
+};
 
-  std::vector<FdeInfo> fdes_;
-  uint64_t entries_offset_;
-  uint64_t entries_end_;
+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>::load_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, uint64_t load_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;
+
+  std::map<uint64_t, std::pair<uint64_t, const DwarfFde*>> fdes_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 3a52044..d620934 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -16,7 +16,8 @@
 
 #include <stdint.h>
 
-#include <gmock/gmock.h>
+#include <vector>
+
 #include <gtest/gtest.h>
 
 #include <unwindstack/DwarfError.h>
@@ -30,480 +31,377 @@
 namespace unwindstack {
 
 template <typename TypeParam>
-class MockDwarfDebugFrame : public DwarfDebugFrame<TypeParam> {
- public:
-  MockDwarfDebugFrame(Memory* memory) : DwarfDebugFrame<TypeParam>(memory) {}
-  ~MockDwarfDebugFrame() = default;
-
-  void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
-  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);
-  }
-
-  uint64_t TestGetFdeCount() { return this->fde_count_; }
-  uint8_t TestGetOffset() { return this->offset_; }
-  uint8_t TestGetEndOffset() { return this->end_offset_; }
-  void TestGetFdeInfo(size_t index, typename DwarfDebugFrame<TypeParam>::FdeInfo* info) {
-    *info = this->fdes_[index];
-  }
-};
-
-template <typename TypeParam>
 class DwarfDebugFrameTest : public ::testing::Test {
  protected:
   void SetUp() override {
     memory_.Clear();
-    debug_frame_ = new MockDwarfDebugFrame<TypeParam>(&memory_);
+    debug_frame_ = new DwarfDebugFrame<TypeParam>(&memory_);
     ResetLogs();
   }
 
   void TearDown() override { delete debug_frame_; }
 
   MemoryFake memory_;
-  MockDwarfDebugFrame<TypeParam>* debug_frame_ = nullptr;
+  DwarfDebugFrame<TypeParam>* debug_frame_ = nullptr;
 };
 TYPED_TEST_CASE_P(DwarfDebugFrameTest);
 
 // NOTE: All test class variables need to be referenced as this->.
 
-TYPED_TEST_P(DwarfDebugFrameTest, Init32) {
-  // CIE 32 information.
-  this->memory_.SetData32(0x5000, 0xfc);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 1);
-  this->memory_.SetData8(0x5009, '\0');
+static void SetCie32(MemoryFake* memory, uint64_t offset, uint32_t length,
+                     std::vector<uint8_t> data) {
+  memory->SetData32(offset, length);
+  offset += 4;
+  // Indicates this is a cie.
+  memory->SetData32(offset, 0xffffffff);
+  offset += 4;
+  memory->SetMemory(offset, data);
+}
+
+static void SetCie64(MemoryFake* memory, uint64_t offset, uint64_t length,
+                     std::vector<uint8_t> data) {
+  memory->SetData32(offset, 0xffffffff);
+  offset += 4;
+  memory->SetData64(offset, length);
+  offset += 8;
+  // Indicates this is a cie.
+  memory->SetData64(offset, 0xffffffffffffffffUL);
+  offset += 8;
+  memory->SetMemory(offset, data);
+}
+
+static void SetFde32(MemoryFake* memory, uint64_t offset, uint32_t length, uint64_t cie_offset,
+                     uint32_t pc_start, uint32_t pc_length, uint64_t segment_length = 0,
+                     std::vector<uint8_t>* data = nullptr) {
+  memory->SetData32(offset, length);
+  offset += 4;
+  memory->SetData32(offset, cie_offset);
+  offset += 4 + segment_length;
+  memory->SetData32(offset, pc_start);
+  offset += 4;
+  memory->SetData32(offset, pc_length);
+  if (data != nullptr) {
+    offset += 4;
+    memory->SetMemory(offset, *data);
+  }
+}
+
+static void SetFde64(MemoryFake* memory, uint64_t offset, uint64_t length, uint64_t cie_offset,
+                     uint64_t pc_start, uint64_t pc_length, uint64_t segment_length = 0,
+                     std::vector<uint8_t>* data = nullptr) {
+  memory->SetData32(offset, 0xffffffff);
+  offset += 4;
+  memory->SetData64(offset, length);
+  offset += 8;
+  memory->SetData64(offset, cie_offset);
+  offset += 8 + segment_length;
+  memory->SetData64(offset, pc_start);
+  offset += 8;
+  memory->SetData64(offset, pc_length);
+  if (data != nullptr) {
+    offset += 8;
+    memory->SetMemory(offset, *data);
+  }
+}
+
+static void SetFourFdes32(MemoryFake* memory) {
+  SetCie32(memory, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
 
   // FDE 32 information.
-  this->memory_.SetData32(0x5100, 0xfc);
-  this->memory_.SetData32(0x5104, 0);
-  this->memory_.SetData32(0x5108, 0x1500);
-  this->memory_.SetData32(0x510c, 0x200);
-
-  this->memory_.SetData32(0x5200, 0xfc);
-  this->memory_.SetData32(0x5204, 0);
-  this->memory_.SetData32(0x5208, 0x2500);
-  this->memory_.SetData32(0x520c, 0x300);
+  SetFde32(memory, 0x5100, 0xfc, 0, 0x1500, 0x200);
+  SetFde32(memory, 0x5200, 0xfc, 0, 0x2500, 0x300);
 
   // CIE 32 information.
-  this->memory_.SetData32(0x5300, 0xfc);
-  this->memory_.SetData32(0x5304, 0xffffffff);
-  this->memory_.SetData8(0x5308, 1);
-  this->memory_.SetData8(0x5309, '\0');
+  SetCie32(memory, 0x5300, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
 
   // FDE 32 information.
-  this->memory_.SetData32(0x5400, 0xfc);
-  this->memory_.SetData32(0x5404, 0x300);
-  this->memory_.SetData32(0x5408, 0x3500);
-  this->memory_.SetData32(0x540c, 0x400);
+  SetFde32(memory, 0x5400, 0xfc, 0x300, 0x3500, 0x400);
+  SetFde32(memory, 0x5500, 0xfc, 0x300, 0x4500, 0x500);
+}
 
-  this->memory_.SetData32(0x5500, 0xfc);
-  this->memory_.SetData32(0x5504, 0x300);
-  this->memory_.SetData32(0x5508, 0x4500);
-  this->memory_.SetData32(0x550c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32) {
+  SetFourFdes32(&this->memory_);
   ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-  ASSERT_EQ(4U, this->debug_frame_->TestGetFdeCount());
 
-  typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
+  std::vector<const DwarfFde*> fdes;
+  this->debug_frame_->GetFdes(&fdes);
 
-  this->debug_frame_->TestGetFdeInfo(0, &info);
-  EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x1500U, info.start);
-  EXPECT_EQ(0x1700U, info.end);
+  ASSERT_EQ(4U, fdes.size());
 
-  this->debug_frame_->TestGetFdeInfo(1, &info);
-  EXPECT_EQ(0x5200U, info.offset);
-  EXPECT_EQ(0x2500U, info.start);
-  EXPECT_EQ(0x2800U, info.end);
+  EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
+  EXPECT_EQ(0x5110U, fdes[0]->cfa_instructions_offset);
+  EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
+  EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+  EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+  EXPECT_EQ(0U, fdes[0]->lsda_address);
+  EXPECT_TRUE(fdes[0]->cie != nullptr);
 
-  this->debug_frame_->TestGetFdeInfo(2, &info);
-  EXPECT_EQ(0x5400U, info.offset);
-  EXPECT_EQ(0x3500U, info.start);
-  EXPECT_EQ(0x3900U, info.end);
+  EXPECT_EQ(0x5000U, fdes[1]->cie_offset);
+  EXPECT_EQ(0x5210U, fdes[1]->cfa_instructions_offset);
+  EXPECT_EQ(0x5300U, fdes[1]->cfa_instructions_end);
+  EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+  EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+  EXPECT_EQ(0U, fdes[1]->lsda_address);
+  EXPECT_TRUE(fdes[1]->cie != nullptr);
 
-  this->debug_frame_->TestGetFdeInfo(3, &info);
-  EXPECT_EQ(0x5500U, info.offset);
-  EXPECT_EQ(0x4500U, info.start);
-  EXPECT_EQ(0x4a00U, info.end);
+  EXPECT_EQ(0x5300U, fdes[2]->cie_offset);
+  EXPECT_EQ(0x5410U, fdes[2]->cfa_instructions_offset);
+  EXPECT_EQ(0x5500U, fdes[2]->cfa_instructions_end);
+  EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+  EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+  EXPECT_EQ(0U, fdes[2]->lsda_address);
+  EXPECT_TRUE(fdes[2]->cie != nullptr);
+
+  EXPECT_EQ(0x5300U, fdes[3]->cie_offset);
+  EXPECT_EQ(0x5510U, fdes[3]->cfa_instructions_offset);
+  EXPECT_EQ(0x5600U, fdes[3]->cfa_instructions_end);
+  EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+  EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+  EXPECT_EQ(0U, fdes[3]->lsda_address);
+  EXPECT_TRUE(fdes[3]->cie != nullptr);
 }
 
-TYPED_TEST_P(DwarfDebugFrameTest, Init32_fde_not_following_cie) {
-  // CIE 32 information.
-  this->memory_.SetData32(0x5000, 0xfc);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 1);
-  this->memory_.SetData8(0x5009, '\0');
-
-  // FDE 32 information.
-  this->memory_.SetData32(0x5100, 0xfc);
-  this->memory_.SetData32(0x5104, 0x1000);
-  this->memory_.SetData32(0x5108, 0x1500);
-  this->memory_.SetData32(0x510c, 0x200);
-
-  ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600, 0));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) {
-  // CIE 32 information.
-  this->memory_.SetData32(0x5000, 0xfc);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 1);
-  this->memory_.SetData8(0x5009, '\0');
-
-  // FDE 32 information.
-  this->memory_.SetData32(0x5100, 0xfc);
-  this->memory_.SetData32(0x5104, 0);
-  this->memory_.SetData32(0x5108, 0x1500);
-  this->memory_.SetData32(0x510c, 0x200);
-
-  this->memory_.SetData32(0x5200, 0xfc);
-  this->memory_.SetData32(0x5204, 0);
-  this->memory_.SetData32(0x5208, 0x2500);
-  this->memory_.SetData32(0x520c, 0x300);
-
-  // CIE 32 information.
-  this->memory_.SetData32(0x5300, 0);
-  this->memory_.SetData32(0x5304, 0xffffffff);
-  this->memory_.SetData8(0x5308, 1);
-  this->memory_.SetData8(0x5309, '\0');
-
-  // FDE 32 information.
-  this->memory_.SetData32(0x5400, 0xfc);
-  this->memory_.SetData32(0x5404, 0x300);
-  this->memory_.SetData32(0x5408, 0x3500);
-  this->memory_.SetData32(0x540c, 0x400);
-
-  this->memory_.SetData32(0x5500, 0xfc);
-  this->memory_.SetData32(0x5504, 0x300);
-  this->memory_.SetData32(0x5508, 0x4500);
-  this->memory_.SetData32(0x550c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_after_GetFdeFromPc) {
+  SetFourFdes32(&this->memory_);
   ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-  ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x3600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x3500U, fde->pc_start);
+  EXPECT_EQ(0x3900U, fde->pc_end);
+
+  std::vector<const DwarfFde*> fdes;
+  this->debug_frame_->GetFdes(&fdes);
+  ASSERT_EQ(4U, fdes.size());
+
+  // Verify that they got added in the correct order.
+  EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+  EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+  EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+  EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+  EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+  EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+  EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+  EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
 }
 
-TYPED_TEST_P(DwarfDebugFrameTest, Init64) {
-  // CIE 64 information.
-  this->memory_.SetData32(0x5000, 0xffffffff);
-  this->memory_.SetData64(0x5004, 0xf4);
-  this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
-  this->memory_.SetData8(0x5014, 1);
-  this->memory_.SetData8(0x5015, '\0');
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_not_in_section) {
+  SetFourFdes32(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
 
-  // FDE 64 information.
-  this->memory_.SetData32(0x5100, 0xffffffff);
-  this->memory_.SetData64(0x5104, 0xf4);
-  this->memory_.SetData64(0x510c, 0);
-  this->memory_.SetData64(0x5114, 0x1500);
-  this->memory_.SetData64(0x511c, 0x200);
+  std::vector<const DwarfFde*> fdes;
+  this->debug_frame_->GetFdes(&fdes);
 
-  this->memory_.SetData32(0x5200, 0xffffffff);
-  this->memory_.SetData64(0x5204, 0xf4);
-  this->memory_.SetData64(0x520c, 0);
-  this->memory_.SetData64(0x5214, 0x2500);
-  this->memory_.SetData64(0x521c, 0x300);
+  ASSERT_EQ(3U, fdes.size());
+}
 
-  // CIE 64 information.
-  this->memory_.SetData32(0x5300, 0xffffffff);
-  this->memory_.SetData64(0x5304, 0xf4);
-  this->memory_.SetData64(0x530c, 0xffffffffffffffffULL);
-  this->memory_.SetData8(0x5314, 1);
-  this->memory_.SetData8(0x5315, '\0');
-
-  // FDE 64 information.
-  this->memory_.SetData32(0x5400, 0xffffffff);
-  this->memory_.SetData64(0x5404, 0xf4);
-  this->memory_.SetData64(0x540c, 0x300);
-  this->memory_.SetData64(0x5414, 0x3500);
-  this->memory_.SetData64(0x541c, 0x400);
-
-  this->memory_.SetData32(0x5500, 0xffffffff);
-  this->memory_.SetData64(0x5504, 0xf4);
-  this->memory_.SetData64(0x550c, 0x300);
-  this->memory_.SetData64(0x5514, 0x4500);
-  this->memory_.SetData64(0x551c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32) {
+  SetFourFdes32(&this->memory_);
   ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-  ASSERT_EQ(4U, this->debug_frame_->TestGetFdeCount());
 
-  typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x1600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x1500U, fde->pc_start);
 
-  this->debug_frame_->TestGetFdeInfo(0, &info);
-  EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x1500U, info.start);
-  EXPECT_EQ(0x1700U, info.end);
-
-  this->debug_frame_->TestGetFdeInfo(1, &info);
-  EXPECT_EQ(0x5200U, info.offset);
-  EXPECT_EQ(0x2500U, info.start);
-  EXPECT_EQ(0x2800U, info.end);
-
-  this->debug_frame_->TestGetFdeInfo(2, &info);
-  EXPECT_EQ(0x5400U, info.offset);
-  EXPECT_EQ(0x3500U, info.start);
-  EXPECT_EQ(0x3900U, info.end);
-
-  this->debug_frame_->TestGetFdeInfo(3, &info);
-  EXPECT_EQ(0x5500U, info.offset);
-  EXPECT_EQ(0x4500U, info.start);
-  EXPECT_EQ(0x4a00U, info.end);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init64_fde_not_following_cie) {
-  // CIE 64 information.
-  this->memory_.SetData32(0x5000, 0xffffffff);
-  this->memory_.SetData64(0x5004, 0xf4);
-  this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
-  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, 0x1000);
-  this->memory_.SetData64(0x5114, 0x1500);
-  this->memory_.SetData64(0x511c, 0x200);
-
-  ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600, 0));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) {
-  // CIE 64 information.
-  this->memory_.SetData32(0x5000, 0xffffffff);
-  this->memory_.SetData64(0x5004, 0xf4);
-  this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
-  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, 0);
-  this->memory_.SetData64(0x5114, 0x1500);
-  this->memory_.SetData64(0x511c, 0x200);
-
-  this->memory_.SetData32(0x5200, 0xffffffff);
-  this->memory_.SetData64(0x5204, 0xf4);
-  this->memory_.SetData64(0x520c, 0);
-  this->memory_.SetData64(0x5214, 0x2500);
-  this->memory_.SetData64(0x521c, 0x300);
-
-  // CIE 64 information.
-  this->memory_.SetData32(0x5300, 0xffffffff);
-  this->memory_.SetData64(0x5304, 0);
-  this->memory_.SetData64(0x530c, 0xffffffffffffffffULL);
-  this->memory_.SetData8(0x5314, 1);
-  this->memory_.SetData8(0x5315, '\0');
-
-  // FDE 64 information.
-  this->memory_.SetData32(0x5400, 0xffffffff);
-  this->memory_.SetData64(0x5404, 0xf4);
-  this->memory_.SetData64(0x540c, 0x300);
-  this->memory_.SetData64(0x5414, 0x3500);
-  this->memory_.SetData64(0x541c, 0x400);
-
-  this->memory_.SetData32(0x5500, 0xffffffff);
-  this->memory_.SetData64(0x5504, 0xf4);
-  this->memory_.SetData64(0x550c, 0x300);
-  this->memory_.SetData64(0x5514, 0x4500);
-  this->memory_.SetData64(0x551c, 0x500);
-
-  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-  ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init_non_zero_load_bias) {
-  // CIE 32 information.
-  this->memory_.SetData32(0x5000, 0xfc);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 1);
-  this->memory_.SetData8(0x5009, 'z');
-  this->memory_.SetData8(0x500a, 'R');
-  this->memory_.SetData8(0x500b, '\0');
-  this->memory_.SetData8(0x500c, 0);
-  this->memory_.SetData8(0x500d, 0);
-  this->memory_.SetData8(0x500e, 0);
-  this->memory_.SetData8(0x500f, 0);
-  this->memory_.SetData8(0x5010, 0x1b);
-
-  // FDE 32 information.
-  this->memory_.SetData32(0x5100, 0xfc);
-  this->memory_.SetData32(0x5104, 0);
-  this->memory_.SetData32(0x5108, 0x1500);
-  this->memory_.SetData32(0x510c, 0x200);
-  this->memory_.SetData8(0x5110, 0);
-  this->memory_.SetData8(0x5111, 0);
-
-  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0x1000));
-  ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
-
-  typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
-  this->debug_frame_->TestGetFdeInfo(0, &info);
-  EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x2500U, info.start);
-  EXPECT_EQ(0x2700U, info.end);
-
-  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x2504);
+  fde = this->debug_frame_->GetFdeFromPc(0x2600);
   ASSERT_TRUE(fde != nullptr);
   EXPECT_EQ(0x2500U, fde->pc_start);
-  EXPECT_EQ(0x2700U, fde->pc_end);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x3600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x3500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x4600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x4500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0);
+  ASSERT_TRUE(fde == nullptr);
 }
 
-TYPED_TEST_P(DwarfDebugFrameTest, Init_version1) {
-  // CIE 32 information.
-  this->memory_.SetData32(0x5000, 0xfc);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  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);
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32_reverse) {
+  SetFourFdes32(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
 
-  // FDE 32 information.
-  this->memory_.SetData32(0x5100, 0xfc);
-  this->memory_.SetData32(0x5104, 0);
-  this->memory_.SetData16(0x5108, 0x1500);
-  this->memory_.SetData16(0x510a, 0x200);
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x4500U, fde->pc_start);
 
-  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
-  ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
+  fde = this->debug_frame_->GetFdeFromPc(0x3600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x3500U, fde->pc_start);
 
-  typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
-  this->debug_frame_->TestGetFdeInfo(0, &info);
-  EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x1500U, info.start);
-  EXPECT_EQ(0x1700U, info.end);
+  fde = this->debug_frame_->GetFdeFromPc(0x2600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x2500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x1600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x1500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0);
+  ASSERT_TRUE(fde == nullptr);
 }
 
-TYPED_TEST_P(DwarfDebugFrameTest, Init_version4) {
-  // CIE 32 information.
-  this->memory_.SetData32(0x5000, 0xfc);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  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);
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32_not_in_section) {
+  SetFourFdes32(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
 
-  // FDE 32 information.
-  this->memory_.SetData32(0x5100, 0xfc);
-  this->memory_.SetData32(0x5104, 0);
-  this->memory_.SetData16(0x5108, 0x1500);
-  this->memory_.SetData16(0x510a, 0x200);
-
-  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
-  ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
-
-  typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
-  this->debug_frame_->TestGetFdeInfo(0, &info);
-  EXPECT_EQ(0x5100U, info.offset);
-  EXPECT_EQ(0x1500U, info.start);
-  EXPECT_EQ(0x1700U, info.end);
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+  ASSERT_TRUE(fde == nullptr);
 }
 
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeOffsetFromPc) {
-  typename DwarfDebugFrame<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->debug_frame_->TestPushFdeInfo(info);
-  }
+static void SetFourFdes64(MemoryFake* memory) {
+  // CIE 64 information.
+  SetCie64(memory, 0x5000, 0xf4, std::vector<uint8_t>{1, '\0', 0, 0, 1});
 
-  this->debug_frame_->TestSetFdeCount(0);
-  uint64_t fde_offset;
-  ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  // FDE 64 information.
+  SetFde64(memory, 0x5100, 0xf4, 0, 0x1500, 0x200);
+  SetFde64(memory, 0x5200, 0xf4, 0, 0x2500, 0x300);
 
-  this->debug_frame_->TestSetFdeCount(9);
-  ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
-  // Odd number of elements.
-  for (size_t i = 0; i < 9; i++) {
-    TypeParam pc = 0x1000 * (i + 1);
-    ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index "
-                                                                             << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
-        << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
-        << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
-  }
+  // CIE 64 information.
+  SetCie64(memory, 0x5300, 0xf4, std::vector<uint8_t>{1, '\0', 0, 0, 1});
 
-  // Even number of elements.
-  this->debug_frame_->TestSetFdeCount(10);
-  info.start = 0xa000;
-  info.end = 0xaff0;
-  info.offset = 0x5120;
-  this->debug_frame_->TestPushFdeInfo(info);
+  // FDE 64 information.
+  SetFde64(memory, 0x5400, 0xf4, 0x300, 0x3500, 0x400);
+  SetFde64(memory, 0x5500, 0xf4, 0x300, 0x4500, 0x500);
+}
 
-  for (size_t i = 0; i < 10; i++) {
-    TypeParam pc = 0x1000 * (i + 1);
-    ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index "
-                                                                             << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
-        << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
-        << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
-  }
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64) {
+  SetFourFdes64(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+  std::vector<const DwarfFde*> fdes;
+  this->debug_frame_->GetFdes(&fdes);
+
+  ASSERT_EQ(4U, fdes.size());
+
+  EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
+  EXPECT_EQ(0x5124U, fdes[0]->cfa_instructions_offset);
+  EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
+  EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+  EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+  EXPECT_EQ(0U, fdes[0]->lsda_address);
+  EXPECT_TRUE(fdes[0]->cie != nullptr);
+
+  EXPECT_EQ(0x5000U, fdes[1]->cie_offset);
+  EXPECT_EQ(0x5224U, fdes[1]->cfa_instructions_offset);
+  EXPECT_EQ(0x5300U, fdes[1]->cfa_instructions_end);
+  EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+  EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+  EXPECT_EQ(0U, fdes[1]->lsda_address);
+  EXPECT_TRUE(fdes[1]->cie != nullptr);
+
+  EXPECT_EQ(0x5300U, fdes[2]->cie_offset);
+  EXPECT_EQ(0x5424U, fdes[2]->cfa_instructions_offset);
+  EXPECT_EQ(0x5500U, fdes[2]->cfa_instructions_end);
+  EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+  EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+  EXPECT_EQ(0U, fdes[2]->lsda_address);
+  EXPECT_TRUE(fdes[2]->cie != nullptr);
+
+  EXPECT_EQ(0x5300U, fdes[3]->cie_offset);
+  EXPECT_EQ(0x5524U, fdes[3]->cfa_instructions_offset);
+  EXPECT_EQ(0x5600U, fdes[3]->cfa_instructions_end);
+  EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+  EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+  EXPECT_EQ(0U, fdes[3]->lsda_address);
+  EXPECT_TRUE(fdes[3]->cie != nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64_after_GetFdeFromPc) {
+  SetFourFdes64(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x2600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x2500U, fde->pc_start);
+  EXPECT_EQ(0x2800U, fde->pc_end);
+
+  std::vector<const DwarfFde*> fdes;
+  this->debug_frame_->GetFdes(&fdes);
+  ASSERT_EQ(4U, fdes.size());
+
+  // Verify that they got added in the correct order.
+  EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+  EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+  EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+  EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+  EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+  EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+  EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+  EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64_not_in_section) {
+  SetFourFdes64(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
+
+  std::vector<const DwarfFde*> fdes;
+  this->debug_frame_->GetFdes(&fdes);
+
+  ASSERT_EQ(3U, fdes.size());
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64) {
+  SetFourFdes64(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x1600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x1500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x2600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x2500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x3600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x3500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x4600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x4500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0);
+  ASSERT_TRUE(fde == nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64_reverse) {
+  SetFourFdes64(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x4500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x3600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x3500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x2600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x2500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0x1600);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x1500U, fde->pc_start);
+
+  fde = this->debug_frame_->GetFdeFromPc(0);
+  ASSERT_TRUE(fde == nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64_not_in_section) {
+  SetFourFdes64(&this->memory_);
+  ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+  ASSERT_TRUE(fde == nullptr);
 }
 
 TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde32) {
-  this->debug_frame_->TestSetOffset(0x4000);
-
-  // CIE 32 information.
-  this->memory_.SetData32(0xf000, 0x100);
-  this->memory_.SetData32(0xf004, 0xffffffff);
-  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, 0xb000);
-  this->memory_.SetData32(0x14008, 0x9000);
-  this->memory_.SetData32(0x1400c, 0x100);
+  SetCie32(&this->memory_, 0xf000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+  SetFde32(&this->memory_, 0x14000, 0x20, 0xf000, 0x9000, 0x100);
 
   const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x14000);
   ASSERT_TRUE(fde != nullptr);
@@ -530,24 +428,8 @@
 }
 
 TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde64) {
-  this->debug_frame_->TestSetOffset(0x2000);
-
-  // CIE 64 information.
-  this->memory_.SetData32(0x6000, 0xffffffff);
-  this->memory_.SetData64(0x6004, 0x100);
-  this->memory_.SetData64(0x600c, 0xffffffffffffffffULL);
-  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, 0x4000);
-  this->memory_.SetData64(0x8014, 0x5000);
-  this->memory_.SetData64(0x801c, 0x300);
+  SetCie64(&this->memory_, 0x6000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+  SetFde64(&this->memory_, 0x8000, 0x200, 0x6000, 0x5000, 0x300);
 
   const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x8000);
   ASSERT_TRUE(fde != nullptr);
@@ -573,11 +455,357 @@
   EXPECT_EQ(0x20U, fde->cie->return_address_register);
 }
 
-REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie,
-                           Init32_do_not_fail_on_bad_next_entry, Init64,
-                           Init64_do_not_fail_on_bad_next_entry, Init64_fde_not_following_cie,
-                           Init_non_zero_load_bias, Init_version1, Init_version4,
-                           GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
+static void VerifyCieVersion(const DwarfCie* cie, uint8_t version, uint8_t segment_size,
+                             uint8_t fde_encoding, uint64_t return_address, uint64_t start_offset,
+                             uint64_t end_offset) {
+  EXPECT_EQ(version, cie->version);
+  EXPECT_EQ(fde_encoding, cie->fde_address_encoding);
+  EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+  EXPECT_EQ(segment_size, cie->segment_size);
+  EXPECT_EQ(1U, cie->augmentation_string.size());
+  EXPECT_EQ('\0', cie->augmentation_string[0]);
+  EXPECT_EQ(0U, cie->personality_handler);
+  EXPECT_EQ(4U, cie->code_alignment_factor);
+  EXPECT_EQ(8, cie->data_alignment_factor);
+  EXPECT_EQ(return_address, cie->return_address_register);
+  EXPECT_EQ(0x5000U + start_offset, cie->cfa_instructions_offset);
+  EXPECT_EQ(0x5000U + end_offset, cie->cfa_instructions_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_cie_cached) {
+  SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+
+  std::vector<uint8_t> zero(0x100, 0);
+  this->memory_.SetMemory(0x5000, zero);
+  cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_cie_cached) {
+  SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+
+  std::vector<uint8_t> zero(0x100, 0);
+  this->memory_.SetMemory(0x5000, zero);
+  cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version1) {
+  SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version1) {
+  SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version3) {
+  SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{3, '\0', 4, 8, 0x81, 3});
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata4, 0x181, 0xe, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version3) {
+  SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{3, '\0', 4, 8, 0x81, 3});
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata8, 0x181, 0x1a, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version4) {
+  SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata4, 0x181, 0x10, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version4) {
+  SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset_version_invalid) {
+  SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
+  ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x5000) == nullptr);
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+  SetCie64(&this->memory_, 0x6000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
+  ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x6000) == nullptr);
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+
+  SetCie32(&this->memory_, 0x7000, 0x100, std::vector<uint8_t>{5, '\0', 1, 2, 3, 4, 5, 6, 7});
+  ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x7000) == nullptr);
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+  SetCie64(&this->memory_, 0x8000, 0x100, std::vector<uint8_t>{5, '\0', 1, 2, 3, 4, 5, 6, 7});
+  ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x8000) == nullptr);
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+}
+
+static void VerifyCieAugment(const DwarfCie* cie, uint64_t inst_offset, uint64_t inst_end) {
+  EXPECT_EQ(1U, cie->version);
+  EXPECT_EQ(DW_EH_PE_udata2, cie->fde_address_encoding);
+  EXPECT_EQ(DW_EH_PE_textrel | DW_EH_PE_udata2, cie->lsda_encoding);
+  EXPECT_EQ(0U, cie->segment_size);
+  EXPECT_EQ(5U, cie->augmentation_string.size());
+  EXPECT_EQ('z', cie->augmentation_string[0]);
+  EXPECT_EQ('L', cie->augmentation_string[1]);
+  EXPECT_EQ('P', cie->augmentation_string[2]);
+  EXPECT_EQ('R', cie->augmentation_string[3]);
+  EXPECT_EQ('\0', cie->augmentation_string[4]);
+  EXPECT_EQ(0x12345678U, cie->personality_handler);
+  EXPECT_EQ(4U, cie->code_alignment_factor);
+  EXPECT_EQ(8, cie->data_alignment_factor);
+  EXPECT_EQ(0x10U, cie->return_address_register);
+  EXPECT_EQ(inst_offset, cie->cfa_instructions_offset);
+  EXPECT_EQ(inst_end, cie->cfa_instructions_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_augment) {
+  SetCie32(&this->memory_, 0x5000, 0x100,
+           std::vector<uint8_t>{/* version */ 1,
+                                /* augment string */ 'z', 'L', 'P', 'R', '\0',
+                                /* code alignment factor */ 4,
+                                /* data alignment factor */ 8,
+                                /* return address register */ 0x10,
+                                /* augment length */ 0xf,
+                                /* L data */ DW_EH_PE_textrel | DW_EH_PE_udata2,
+                                /* P data */ DW_EH_PE_udata4, 0x78, 0x56, 0x34, 0x12,
+                                /* R data */ DW_EH_PE_udata2});
+
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieAugment(cie, 0x5021, 0x5104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_augment) {
+  SetCie64(&this->memory_, 0x5000, 0x100,
+           std::vector<uint8_t>{/* version */ 1,
+                                /* augment string */ 'z', 'L', 'P', 'R', '\0',
+                                /* code alignment factor */ 4,
+                                /* data alignment factor */ 8,
+                                /* return address register */ 0x10,
+                                /* augment length */ 0xf,
+                                /* L data */ DW_EH_PE_textrel | DW_EH_PE_udata2,
+                                /* P data */ DW_EH_PE_udata4, 0x78, 0x56, 0x34, 0x12,
+                                /* R data */ DW_EH_PE_udata2});
+
+  const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+  ASSERT_TRUE(cie != nullptr);
+  VerifyCieAugment(cie, 0x502d, 0x510c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset32_augment) {
+  SetCie32(&this->memory_, 0x5000, 0xfc,
+           std::vector<uint8_t>{/* version */ 4,
+                                /* augment string */ 'z', '\0',
+                                /* address size */ 8,
+                                /* segment size */ 0x10,
+                                /* code alignment factor */ 16,
+                                /* data alignment factor */ 32,
+                                /* return address register */ 10,
+                                /* augment length */ 0x0});
+
+  std::vector<uint8_t> data{/* augment length */ 0x80, 0x3};
+  SetFde32(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0x10, &data);
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+  ASSERT_TRUE(fde != nullptr);
+  ASSERT_TRUE(fde->cie != nullptr);
+  EXPECT_EQ(4U, fde->cie->version);
+  EXPECT_EQ(0x5000U, fde->cie_offset);
+  EXPECT_EQ(0x53a2U, fde->cfa_instructions_offset);
+  EXPECT_EQ(0x5504U, fde->cfa_instructions_end);
+  EXPECT_EQ(0x4300U, fde->pc_start);
+  EXPECT_EQ(0x4600U, fde->pc_end);
+  EXPECT_EQ(0U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset64_augment) {
+  SetCie64(&this->memory_, 0x5000, 0xfc,
+           std::vector<uint8_t>{/* version */ 4,
+                                /* augment string */ 'z', '\0',
+                                /* address size */ 8,
+                                /* segment size */ 0x10,
+                                /* code alignment factor */ 16,
+                                /* data alignment factor */ 32,
+                                /* return address register */ 10,
+                                /* augment length */ 0x0});
+
+  std::vector<uint8_t> data{/* augment length */ 0x80, 0x3};
+  SetFde64(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0x10, &data);
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+  ASSERT_TRUE(fde != nullptr);
+  ASSERT_TRUE(fde->cie != nullptr);
+  EXPECT_EQ(4U, fde->cie->version);
+  EXPECT_EQ(0x5000U, fde->cie_offset);
+  EXPECT_EQ(0x53b6U, fde->cfa_instructions_offset);
+  EXPECT_EQ(0x550cU, fde->cfa_instructions_end);
+  EXPECT_EQ(0x4300U, fde->pc_start);
+  EXPECT_EQ(0x4600U, fde->pc_end);
+  EXPECT_EQ(0U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset32_lsda_address) {
+  SetCie32(&this->memory_, 0x5000, 0xfc,
+           std::vector<uint8_t>{/* version */ 1,
+                                /* augment string */ 'z', 'L', '\0',
+                                /* address size */ 8,
+                                /* code alignment factor */ 16,
+                                /* data alignment factor */ 32,
+                                /* return address register */ 10,
+                                /* augment length */ 0x2,
+                                /* L data */ DW_EH_PE_udata2});
+
+  std::vector<uint8_t> data{/* augment length */ 0x80, 0x3,
+                            /* lsda address */ 0x20, 0x45};
+  SetFde32(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0, &data);
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+  ASSERT_TRUE(fde != nullptr);
+  ASSERT_TRUE(fde->cie != nullptr);
+  EXPECT_EQ(1U, fde->cie->version);
+  EXPECT_EQ(0x5000U, fde->cie_offset);
+  EXPECT_EQ(0x5392U, fde->cfa_instructions_offset);
+  EXPECT_EQ(0x5504U, fde->cfa_instructions_end);
+  EXPECT_EQ(0x4300U, fde->pc_start);
+  EXPECT_EQ(0x4600U, fde->pc_end);
+  EXPECT_EQ(0x4520U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset64_lsda_address) {
+  SetCie64(&this->memory_, 0x5000, 0xfc,
+           std::vector<uint8_t>{/* version */ 1,
+                                /* augment string */ 'z', 'L', '\0',
+                                /* address size */ 8,
+                                /* code alignment factor */ 16,
+                                /* data alignment factor */ 32,
+                                /* return address register */ 10,
+                                /* augment length */ 0x2,
+                                /* L data */ DW_EH_PE_udata2});
+
+  std::vector<uint8_t> data{/* augment length */ 0x80, 0x3,
+                            /* lsda address */ 0x20, 0x45};
+  SetFde64(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0, &data);
+
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+  ASSERT_TRUE(fde != nullptr);
+  ASSERT_TRUE(fde->cie != nullptr);
+  EXPECT_EQ(1U, fde->cie->version);
+  EXPECT_EQ(0x5000U, fde->cie_offset);
+  EXPECT_EQ(0x53a6U, fde->cfa_instructions_offset);
+  EXPECT_EQ(0x550cU, fde->cfa_instructions_end);
+  EXPECT_EQ(0x4300U, fde->pc_start);
+  EXPECT_EQ(0x4600U, fde->pc_end);
+  EXPECT_EQ(0x4520U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc_interleaved) {
+  SetCie32(&this->memory_, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
+
+  // FDE 0 (0x100 - 0x200)
+  SetFde32(&this->memory_, 0x5100, 0xfc, 0, 0x100, 0x100);
+  // FDE 1 (0x300 - 0x500)
+  SetFde32(&this->memory_, 0x5200, 0xfc, 0, 0x300, 0x200);
+  // FDE 2 (0x700 - 0x800)
+  SetFde32(&this->memory_, 0x5300, 0xfc, 0, 0x700, 0x100);
+  // FDE 3 (0xa00 - 0xb00)
+  SetFde32(&this->memory_, 0x5400, 0xfc, 0, 0xa00, 0x100);
+  // FDE 4 (0x100 - 0xb00)
+  SetFde32(&this->memory_, 0x5500, 0xfc, 0, 0x150, 0xa00);
+  // FDE 5 (0x0 - 0x50)
+  SetFde32(&this->memory_, 0x5600, 0xfc, 0, 0, 0x50);
+
+  this->debug_frame_->Init(0x5000, 0x700, 0);
+
+  // Force reading all entries so no entries are found.
+  const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0xfffff);
+  ASSERT_TRUE(fde == nullptr);
+
+  //   0x0   - 0x50   FDE 5
+  fde = this->debug_frame_->GetFdeFromPc(0x10);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0U, fde->pc_start);
+  EXPECT_EQ(0x50U, fde->pc_end);
+
+  //   0x100 - 0x200  FDE 0
+  fde = this->debug_frame_->GetFdeFromPc(0x170);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x100U, fde->pc_start);
+  EXPECT_EQ(0x200U, fde->pc_end);
+
+  //   0x200 - 0x300  FDE 4
+  fde = this->debug_frame_->GetFdeFromPc(0x210);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x150U, fde->pc_start);
+  EXPECT_EQ(0xb50U, fde->pc_end);
+
+  //   0x300 - 0x500  FDE 1
+  fde = this->debug_frame_->GetFdeFromPc(0x310);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x300U, fde->pc_start);
+  EXPECT_EQ(0x500U, fde->pc_end);
+
+  //   0x700 - 0x800  FDE 2
+  fde = this->debug_frame_->GetFdeFromPc(0x790);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x700U, fde->pc_start);
+  EXPECT_EQ(0x800U, fde->pc_end);
+
+  //   0x800 - 0x900  FDE 4
+  fde = this->debug_frame_->GetFdeFromPc(0x850);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x150U, fde->pc_start);
+  EXPECT_EQ(0xb50U, fde->pc_end);
+
+  //   0xa00 - 0xb00  FDE 3
+  fde = this->debug_frame_->GetFdeFromPc(0xa35);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0xa00U, fde->pc_start);
+  EXPECT_EQ(0xb00U, fde->pc_end);
+
+  //   0xb00 - 0xb50  FDE 4
+  fde = this->debug_frame_->GetFdeFromPc(0xb20);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x150U, fde->pc_start);
+  EXPECT_EQ(0xb50U, fde->pc_end);
+}
+
+REGISTER_TYPED_TEST_CASE_P(
+    DwarfDebugFrameTest, GetFdes32, GetFdes32_after_GetFdeFromPc, GetFdes32_not_in_section,
+    GetFdeFromPc32, GetFdeFromPc32_reverse, GetFdeFromPc32_not_in_section, GetFdes64,
+    GetFdes64_after_GetFdeFromPc, GetFdes64_not_in_section, GetFdeFromPc64, GetFdeFromPc64_reverse,
+    GetFdeFromPc64_not_in_section, GetCieFde32, GetCieFde64, GetCieFromOffset32_cie_cached,
+    GetCieFromOffset64_cie_cached, GetCieFromOffset32_version1, GetCieFromOffset64_version1,
+    GetCieFromOffset32_version3, GetCieFromOffset64_version3, GetCieFromOffset32_version4,
+    GetCieFromOffset64_version4, GetCieFromOffset_version_invalid, GetCieFromOffset32_augment,
+    GetCieFromOffset64_augment, GetFdeFromOffset32_augment, GetFdeFromOffset64_augment,
+    GetFdeFromOffset32_lsda_address, GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index e8d53e6..9cac6e8 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -16,7 +16,6 @@
 
 #include <stdint.h>
 
-#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <unwindstack/DwarfError.h>
@@ -30,50 +29,32 @@
 namespace unwindstack {
 
 template <typename TypeParam>
-class MockDwarfEhFrame : public DwarfEhFrame<TypeParam> {
- public:
-  MockDwarfEhFrame(Memory* memory) : DwarfEhFrame<TypeParam>(memory) {}
-  ~MockDwarfEhFrame() = default;
-
-  void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
-  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);
-  }
-
-  uint64_t TestGetFdeCount() { return this->fde_count_; }
-  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>
 class DwarfEhFrameTest : public ::testing::Test {
  protected:
   void SetUp() override {
     memory_.Clear();
-    eh_frame_ = new MockDwarfEhFrame<TypeParam>(&memory_);
+    eh_frame_ = new DwarfEhFrame<TypeParam>(&memory_);
     ResetLogs();
   }
 
   void TearDown() override { delete eh_frame_; }
 
   MemoryFake memory_;
-  MockDwarfEhFrame<TypeParam>* eh_frame_ = nullptr;
+  DwarfEhFrame<TypeParam>* eh_frame_ = nullptr;
 };
 TYPED_TEST_CASE_P(DwarfEhFrameTest);
 
 // NOTE: All test class variables need to be referenced as this->.
 
-TYPED_TEST_P(DwarfEhFrameTest, Init32) {
+// Only verify different cie/fde format. All other DwarfSection corner
+// cases are tested in DwarfDebugFrameTest.cpp.
+
+TYPED_TEST_P(DwarfEhFrameTest, GetFdeCieFromOffset32) {
   // CIE 32 information.
   this->memory_.SetData32(0x5000, 0xfc);
+  // Indicates this is a cie for eh_frame.
   this->memory_.SetData32(0x5004, 0);
-  this->memory_.SetData8(0x5008, 1);
-  this->memory_.SetData8(0x5009, '\0');
+  this->memory_.SetMemory(0x5008, std::vector<uint8_t>{1, '\0', 16, 32, 1});
 
   // FDE 32 information.
   this->memory_.SetData32(0x5100, 0xfc);
@@ -81,415 +62,70 @@
   this->memory_.SetData32(0x5108, 0x1500);
   this->memory_.SetData32(0x510c, 0x200);
 
-  this->memory_.SetData32(0x5200, 0xfc);
-  this->memory_.SetData32(0x5204, 0x204);
-  this->memory_.SetData32(0x5208, 0x2500);
-  this->memory_.SetData32(0x520c, 0x300);
+  const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x5100);
+  ASSERT_TRUE(fde != nullptr);
+  EXPECT_EQ(0x5000U, fde->cie_offset);
+  EXPECT_EQ(0x5110U, fde->cfa_instructions_offset);
+  EXPECT_EQ(0x5200U, fde->cfa_instructions_end);
+  EXPECT_EQ(0x6608U, fde->pc_start);
+  EXPECT_EQ(0x6808U, fde->pc_end);
+  EXPECT_EQ(0U, fde->lsda_address);
 
-  // CIE 32 information.
-  this->memory_.SetData32(0x5300, 0xfc);
-  this->memory_.SetData32(0x5304, 0);
-  this->memory_.SetData8(0x5308, 1);
-  this->memory_.SetData8(0x5309, '\0');
-
-  // FDE 32 information.
-  this->memory_.SetData32(0x5400, 0xfc);
-  this->memory_.SetData32(0x5404, 0x104);
-  this->memory_.SetData32(0x5408, 0x3500);
-  this->memory_.SetData32(0x540c, 0x400);
-
-  this->memory_.SetData32(0x5500, 0xfc);
-  this->memory_.SetData32(0x5504, 0x204);
-  this->memory_.SetData32(0x5508, 0x4500);
-  this->memory_.SetData32(0x550c, 0x500);
-
-  ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600, 0));
-  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(0x6608U, info.start);
-  EXPECT_EQ(0x6808U, info.end);
-
-  this->eh_frame_->TestGetFdeInfo(1, &info);
-  EXPECT_EQ(0x5200U, info.offset);
-  EXPECT_EQ(0x7708U, info.start);
-  EXPECT_EQ(0x7a08U, info.end);
-
-  this->eh_frame_->TestGetFdeInfo(2, &info);
-  EXPECT_EQ(0x5400U, info.offset);
-  EXPECT_EQ(0x8908U, info.start);
-  EXPECT_EQ(0x8d08U, info.end);
-
-  this->eh_frame_->TestGetFdeInfo(3, &info);
-  EXPECT_EQ(0x5500U, info.offset);
-  EXPECT_EQ(0x9a08U, info.start);
-  EXPECT_EQ(0x9f08U, info.end);
+  const DwarfCie* cie = fde->cie;
+  ASSERT_TRUE(cie != nullptr);
+  EXPECT_EQ(1U, cie->version);
+  EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
+  EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+  EXPECT_EQ(0U, cie->segment_size);
+  EXPECT_EQ('\0', cie->augmentation_string[0]);
+  EXPECT_EQ(0U, cie->personality_handler);
+  EXPECT_EQ(0x500dU, cie->cfa_instructions_offset);
+  EXPECT_EQ(0x5100U, cie->cfa_instructions_end);
+  EXPECT_EQ(16U, cie->code_alignment_factor);
+  EXPECT_EQ(32U, cie->data_alignment_factor);
+  EXPECT_EQ(1U, cie->return_address_register);
 }
 
-TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) {
-  // CIE 32 information.
-  this->memory_.SetData32(0x5000, 0xfc);
-  this->memory_.SetData32(0x5004, 0);
-  this->memory_.SetData8(0x5008, 1);
-  this->memory_.SetData8(0x5009, '\0');
-
-  // FDE 32 information.
-  this->memory_.SetData32(0x5100, 0xfc);
-  this->memory_.SetData32(0x5104, 0x1000);
-  this->memory_.SetData32(0x5108, 0x1500);
-  this->memory_.SetData32(0x510c, 0x200);
-
-  ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600, 0));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init64) {
+TYPED_TEST_P(DwarfEhFrameTest, GetFdeCieFromOffset64) {
   // CIE 64 information.
   this->memory_.SetData32(0x5000, 0xffffffff);
-  this->memory_.SetData64(0x5004, 0xf4);
+  this->memory_.SetData64(0x5004, 0xfc);
+  // Indicates this is a cie for eh_frame.
   this->memory_.SetData64(0x500c, 0);
-  this->memory_.SetData8(0x5014, 1);
-  this->memory_.SetData8(0x5015, '\0');
+  this->memory_.SetMemory(0x5014, std::vector<uint8_t>{1, '\0', 16, 32, 1});
 
   // FDE 64 information.
   this->memory_.SetData32(0x5100, 0xffffffff);
-  this->memory_.SetData64(0x5104, 0xf4);
+  this->memory_.SetData64(0x5104, 0xfc);
   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);
-
-  // CIE 64 information.
-  this->memory_.SetData32(0x5300, 0xffffffff);
-  this->memory_.SetData64(0x5304, 0xf4);
-  this->memory_.SetData64(0x530c, 0);
-  this->memory_.SetData8(0x5314, 1);
-  this->memory_.SetData8(0x5315, '\0');
-
-  // FDE 64 information.
-  this->memory_.SetData32(0x5400, 0xffffffff);
-  this->memory_.SetData64(0x5404, 0xf4);
-  this->memory_.SetData64(0x540c, 0x10c);
-  this->memory_.SetData64(0x5414, 0x3500);
-  this->memory_.SetData64(0x541c, 0x400);
-
-  this->memory_.SetData32(0x5500, 0xffffffff);
-  this->memory_.SetData64(0x5504, 0xf4);
-  this->memory_.SetData64(0x550c, 0x20c);
-  this->memory_.SetData64(0x5514, 0x4500);
-  this->memory_.SetData64(0x551c, 0x500);
-
-  ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600, 0));
-  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(0x6618U, info.start);
-  EXPECT_EQ(0x6818U, info.end);
-
-  this->eh_frame_->TestGetFdeInfo(1, &info);
-  EXPECT_EQ(0x5200U, info.offset);
-  EXPECT_EQ(0x7718U, info.start);
-  EXPECT_EQ(0x7a18U, info.end);
-
-  this->eh_frame_->TestGetFdeInfo(2, &info);
-  EXPECT_EQ(0x5400U, info.offset);
-  EXPECT_EQ(0x8918U, info.start);
-  EXPECT_EQ(0x8d18U, info.end);
-
-  this->eh_frame_->TestGetFdeInfo(3, &info);
-  EXPECT_EQ(0x5500U, info.offset);
-  EXPECT_EQ(0x9a18U, info.start);
-  EXPECT_EQ(0x9f18U, info.end);
-}
-
-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');
-
-  // 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, 0));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init_non_zero_load_bias) {
-  // CIE 32 information.
-  this->memory_.SetData32(0x5000, 0xfc);
-  this->memory_.SetData32(0x5004, 0);
-  this->memory_.SetData8(0x5008, 1);
-  this->memory_.SetData8(0x5009, 'z');
-  this->memory_.SetData8(0x500a, 'R');
-  this->memory_.SetData8(0x500b, '\0');
-  this->memory_.SetData8(0x500c, 0);
-  this->memory_.SetData8(0x500d, 0);
-  this->memory_.SetData8(0x500e, 0);
-  this->memory_.SetData8(0x500f, 0);
-  this->memory_.SetData8(0x5010, 0x1b);
-
-  // FDE 32 information.
-  this->memory_.SetData32(0x5100, 0xfc);
-  this->memory_.SetData32(0x5104, 0x104);
-  this->memory_.SetData32(0x5108, 0x1500);
-  this->memory_.SetData32(0x510c, 0x200);
-  this->memory_.SetData8(0x5110, 0);
-  this->memory_.SetData8(0x5111, 0);
-
-  ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0x2000));
-  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(0x8608U, info.start);
-  EXPECT_EQ(0x8808U, info.end);
-
-  const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x8700);
+  const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x5100);
   ASSERT_TRUE(fde != nullptr);
-  EXPECT_EQ(0x8608U, fde->pc_start);
-  EXPECT_EQ(0x8808U, fde->pc_end);
-}
-
-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);
-
-  // 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, 0));
-  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(0x6606U, info.start);
-  EXPECT_EQ(0x6806U, 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, 0));
-  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(0x6606U, info.start);
-  EXPECT_EQ(0x6806U, 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_->TestPushFdeInfo(info);
-  }
-
-  this->eh_frame_->TestSetFdeCount(0);
-  uint64_t fde_offset;
-  ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
-
-  this->eh_frame_->TestSetFdeCount(9);
-  ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
-  // Odd number of elements.
-  for (size_t i = 0; i < 9; i++) {
-    TypeParam pc = 0x1000 * (i + 1);
-    ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
-        << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
-        << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
-  }
-
-  // Even number of elements.
-  this->eh_frame_->TestSetFdeCount(10);
-  info.start = 0xa000;
-  info.end = 0xaff0;
-  info.offset = 0x5120;
-  this->eh_frame_->TestPushFdeInfo(info);
-
-  for (size_t i = 0; i < 10; i++) {
-    TypeParam pc = 0x1000 * (i + 1);
-    ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
-        << "Failed at index " << i;
-    EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
-    ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
-        << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
-  }
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, GetCieFde32) {
-  this->eh_frame_->TestSetOffset(0x4000);
-
-  // 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(0x1d008U, fde->pc_start);
-  EXPECT_EQ(0x1d108U, fde->pc_end);
-  EXPECT_EQ(0xf000U, fde->cie_offset);
+  EXPECT_EQ(0x5000U, fde->cie_offset);
+  EXPECT_EQ(0x5124U, fde->cfa_instructions_offset);
+  EXPECT_EQ(0x5208U, fde->cfa_instructions_end);
+  EXPECT_EQ(0x6618U, fde->pc_start);
+  EXPECT_EQ(0x6818U, fde->pc_end);
   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);
+  const DwarfCie* cie = fde->cie;
+  ASSERT_TRUE(cie != nullptr);
+  EXPECT_EQ(1U, cie->version);
+  EXPECT_EQ(DW_EH_PE_sdata8, cie->fde_address_encoding);
+  EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+  EXPECT_EQ(0U, cie->segment_size);
+  EXPECT_EQ('\0', cie->augmentation_string[0]);
+  EXPECT_EQ(0U, cie->personality_handler);
+  EXPECT_EQ(0x5019U, cie->cfa_instructions_offset);
+  EXPECT_EQ(0x5108U, cie->cfa_instructions_end);
+  EXPECT_EQ(16U, cie->code_alignment_factor);
+  EXPECT_EQ(32U, cie->data_alignment_factor);
+  EXPECT_EQ(1U, cie->return_address_register);
 }
 
-TYPED_TEST_P(DwarfEhFrameTest, GetCieFde64) {
-  this->eh_frame_->TestSetOffset(0x2000);
-
-  // 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(0xd018U, fde->pc_start);
-  EXPECT_EQ(0xd318U, 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);
-}
-
-REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, Init32, Init32_fde_not_following_cie, Init64,
-                           Init64_fde_not_following_cie, Init_non_zero_load_bias, Init_version1,
-                           Init_version4, GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
+REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, GetFdeCieFromOffset32, GetFdeCieFromOffset64);
 
 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
index 19c7b98..910ae36 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -30,10 +30,10 @@
 namespace unwindstack {
 
 template <typename TypeParam>
-class MockDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
+class TestDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
  public:
-  MockDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr<TypeParam>(memory) {}
-  ~MockDwarfEhFrameWithHdr() = default;
+  TestDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr<TypeParam>(memory) {}
+  ~TestDwarfEhFrameWithHdr() = default;
 
   void TestSetTableEncoding(uint8_t encoding) { this->table_encoding_ = encoding; }
   void TestSetEntriesOffset(uint64_t offset) { this->entries_offset_ = offset; }
@@ -64,14 +64,14 @@
  protected:
   void SetUp() override {
     memory_.Clear();
-    eh_frame_ = new MockDwarfEhFrameWithHdr<TypeParam>(&memory_);
+    eh_frame_ = new TestDwarfEhFrameWithHdr<TypeParam>(&memory_);
     ResetLogs();
   }
 
   void TearDown() override { delete eh_frame_; }
 
   MemoryFake memory_;
-  MockDwarfEhFrameWithHdr<TypeParam>* eh_frame_ = nullptr;
+  TestDwarfEhFrameWithHdr<TypeParam>* eh_frame_ = nullptr;
 };
 TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest);
 
@@ -121,23 +121,14 @@
   // CIE 32 information.
   this->memory_.SetData32(0x1300, 0xfc);
   this->memory_.SetData32(0x1304, 0);
-  this->memory_.SetData8(0x1308, 1);
-  this->memory_.SetData8(0x1309, 'z');
-  this->memory_.SetData8(0x130a, 'R');
-  this->memory_.SetData8(0x130b, '\0');
-  this->memory_.SetData8(0x130c, 0);
-  this->memory_.SetData8(0x130d, 0);
-  this->memory_.SetData8(0x130e, 0);
-  this->memory_.SetData8(0x130f, 0);
-  this->memory_.SetData8(0x1310, 0x1b);
+  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, 0x10f8);
   this->memory_.SetData32(0x140c, 0x200);
-  this->memory_.SetData8(0x1410, 0);
-  this->memory_.SetData8(0x1411, 0);
+  this->memory_.SetData16(0x1410, 0);
 
   ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
   EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
@@ -157,6 +148,68 @@
   EXPECT_EQ(0x4700U, fde->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});
+  this->memory_.SetData16(0x1004, 0x500);
+  this->memory_.SetData32(0x1006, 4);
+
+  // Header information.
+  this->memory_.SetData32(0x100a, 0x4600);
+  this->memory_.SetData32(0x100e, 0x1500);
+  this->memory_.SetData32(0x1012, 0x5500);
+  this->memory_.SetData32(0x1016, 0x1400);
+  this->memory_.SetData32(0x101a, 0x6800);
+  this->memory_.SetData32(0x101e, 0x1700);
+  this->memory_.SetData32(0x1022, 0x7700);
+  this->memory_.SetData32(0x1026, 0x1600);
+
+  // CIE 32 information.
+  this->memory_.SetData32(0x1300, 0xfc);
+  this->memory_.SetData32(0x1304, 0);
+  this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, '\0', 0, 0, 0});
+
+  // FDE 32 information.
+  // pc 0x5500 - 0x5700
+  this->memory_.SetData32(0x1400, 0xfc);
+  this->memory_.SetData32(0x1404, 0x104);
+  this->memory_.SetData32(0x1408, 0x40f8);
+  this->memory_.SetData32(0x140c, 0x200);
+
+  // pc 0x4600 - 0x4800
+  this->memory_.SetData32(0x1500, 0xfc);
+  this->memory_.SetData32(0x1504, 0x204);
+  this->memory_.SetData32(0x1508, 0x30f8);
+  this->memory_.SetData32(0x150c, 0x200);
+
+  // pc 0x7700 - 0x7900
+  this->memory_.SetData32(0x1600, 0xfc);
+  this->memory_.SetData32(0x1604, 0x304);
+  this->memory_.SetData32(0x1608, 0x60f8);
+  this->memory_.SetData32(0x160c, 0x200);
+
+  // pc 0x6800 - 0x6a00
+  this->memory_.SetData32(0x1700, 0xfc);
+  this->memory_.SetData32(0x1704, 0x404);
+  this->memory_.SetData32(0x1708, 0x50f8);
+  this->memory_.SetData32(0x170c, 0x200);
+
+  ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
+
+  std::vector<const DwarfFde*> fdes;
+  this->eh_frame_->GetFdes(&fdes);
+  ASSERT_EQ(4U, fdes.size());
+
+  EXPECT_EQ(0x4600U, fdes[0]->pc_start);
+  EXPECT_EQ(0x4800U, fdes[0]->pc_end);
+  EXPECT_EQ(0x5500U, fdes[1]->pc_start);
+  EXPECT_EQ(0x5700U, fdes[1]->pc_end);
+  EXPECT_EQ(0x6800U, fdes[2]->pc_start);
+  EXPECT_EQ(0x6a00U, fdes[2]->pc_end);
+  EXPECT_EQ(0x7700U, fdes[3]->pc_start);
+  EXPECT_EQ(0x7900U, fdes[3]->pc_end);
+}
+
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
   this->eh_frame_->TestSetTableEntrySize(0x10);
   this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
@@ -388,11 +441,7 @@
   // 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);
+  this->memory_.SetMemory(0xf008, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
 
   // FDE 32 information.
   this->memory_.SetData32(0x14000, 0x20);
@@ -429,11 +478,7 @@
   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);
+  this->memory_.SetMemory(0x6014, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
 
   // FDE 64 information.
   this->memory_.SetData32(0x8000, 0xffffffff);
@@ -478,7 +523,7 @@
   ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
 }
 
-REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias,
+REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias, GetFdes,
                            GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
                            GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
                            GetFdeOffsetBinary_verify, GetFdeOffsetBinary_index_fail,
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index 414f2f2..46f555a 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -16,7 +16,6 @@
 
 #include <stdint.h>
 
-#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <unwindstack/DwarfError.h>
@@ -31,42 +30,27 @@
 namespace unwindstack {
 
 template <typename TypeParam>
-class MockDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
+class TestDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
  public:
-  MockDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
-  virtual ~MockDwarfSectionImpl() = default;
+  TestDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
+  virtual ~TestDwarfSectionImpl() = default;
 
-  MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
+  bool Init(uint64_t, uint64_t, uint64_t) override { return false; }
 
-  MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));
+  void GetFdes(std::vector<const DwarfFde*>*) override {}
 
-  MOCK_METHOD1(GetFdeFromIndex, const DwarfFde*(size_t));
+  const DwarfFde* GetFdeFromPc(uint64_t) override { return nullptr; }
 
-  MOCK_METHOD1(GetCieOffsetFromFde32, uint64_t(uint32_t));
+  uint64_t GetCieOffsetFromFde32(uint32_t) { return 0; }
 
-  MOCK_METHOD1(GetCieOffsetFromFde64, uint64_t(uint64_t));
+  uint64_t GetCieOffsetFromFde64(uint64_t) { return 0; }
 
-  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;
-  }
-  void TestClearCachedCieEntry() { this->cie_entries_.clear(); }
-
-  void TestSetCachedFdeEntry(uint64_t offset, const DwarfFde& fde) {
-    this->fde_entries_[offset] = fde;
-  }
-  void TestClearCachedFdeEntry() { this->fde_entries_.clear(); }
+  uint64_t AdjustPcFromFde(uint64_t) override { return 0; }
 
   void TestSetCachedCieLocRegs(uint64_t offset, const dwarf_loc_regs_t& loc_regs) {
     this->cie_loc_regs_[offset] = loc_regs;
   }
   void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); }
-
   void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
 };
 
@@ -75,21 +59,41 @@
  protected:
   void SetUp() override {
     memory_.Clear();
-    section_ = new MockDwarfSectionImpl<TypeParam>(&memory_);
+    section_ = new TestDwarfSectionImpl<TypeParam>(&memory_);
     ResetLogs();
-    section_->TestSetCie32Value(static_cast<uint32_t>(-1));
-    section_->TestSetCie64Value(static_cast<uint64_t>(-1));
   }
 
   void TearDown() override { delete section_; }
 
   MemoryFake memory_;
-  MockDwarfSectionImpl<TypeParam>* section_ = nullptr;
+  TestDwarfSectionImpl<TypeParam>* section_ = nullptr;
 };
 TYPED_TEST_CASE_P(DwarfSectionImplTest);
 
 // NOTE: All test class variables need to be referenced as this->.
 
+TYPED_TEST_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_not_cache) {
+  ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+
+  this->section_->TestClearError();
+  ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
+  ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+
+  this->section_->TestClearError();
+  ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+}
+
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) {
   DwarfCie cie{.version = 3, .return_address_register = 5};
   RegsImplFake<TypeParam> regs(10);
@@ -487,334 +491,6 @@
   EXPECT_EQ(0x80000000U, regs.pc());
 }
 
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_fail_should_not_cache) {
-  ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
-  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-  this->section_->TestClearError();
-  ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
-  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) {
-  this->memory_.SetData32(0x5000, 0x100);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 0x1);
-  this->memory_.SetData8(0x5009, '\0');
-  this->memory_.SetData8(0x500a, 4);
-  this->memory_.SetData8(0x500b, 8);
-  this->memory_.SetData8(0x500c, 0x20);
-
-  const DwarfCie* cie = this->section_->GetCie(0x5000);
-  ASSERT_TRUE(cie != nullptr);
-  EXPECT_EQ(1U, cie->version);
-  EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
-  EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
-  EXPECT_EQ(0U, cie->segment_size);
-  EXPECT_EQ(1U, cie->augmentation_string.size());
-  EXPECT_EQ('\0', cie->augmentation_string[0]);
-  EXPECT_EQ(0U, cie->personality_handler);
-  EXPECT_EQ(0x500dU, cie->cfa_instructions_offset);
-  EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
-  EXPECT_EQ(4U, cie->code_alignment_factor);
-  EXPECT_EQ(8, cie->data_alignment_factor);
-  EXPECT_EQ(0x20U, cie->return_address_register);
-  EXPECT_EQ(DWARF_ERROR_NONE, this->section_->LastErrorCode());
-
-  this->section_->TestClearCachedCieEntry();
-  // Set version to 0, 2, 5 and verify we fail.
-  this->memory_.SetData8(0x5008, 0x0);
-  this->section_->TestClearError();
-  ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-
-  this->memory_.SetData8(0x5008, 0x2);
-  this->section_->TestClearError();
-  ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-
-  this->memory_.SetData8(0x5008, 0x5);
-  this->section_->TestClearError();
-  ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) {
-  this->memory_.SetData32(0x5000, 0x100);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 0x1);
-  this->memory_.SetData8(0x5009, '\0');
-  this->memory_.SetData8(0x500a, 4);
-  this->memory_.SetMemory(0x500b, std::vector<uint8_t>{0xfc, 0xff, 0xff, 0xff, 0x7f});
-  this->memory_.SetData8(0x5010, 0x20);
-
-  const DwarfCie* cie = this->section_->GetCie(0x5000);
-  ASSERT_TRUE(cie != nullptr);
-  EXPECT_EQ(1U, cie->version);
-  EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
-  EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
-  EXPECT_EQ(0U, cie->segment_size);
-  EXPECT_EQ(1U, cie->augmentation_string.size());
-  EXPECT_EQ('\0', cie->augmentation_string[0]);
-  EXPECT_EQ(0U, cie->personality_handler);
-  EXPECT_EQ(0x5011U, cie->cfa_instructions_offset);
-  EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
-  EXPECT_EQ(4U, cie->code_alignment_factor);
-  EXPECT_EQ(-4, cie->data_alignment_factor);
-  EXPECT_EQ(0x20U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_64_no_augment) {
-  this->memory_.SetData32(0x8000, 0xffffffff);
-  this->memory_.SetData64(0x8004, 0x200);
-  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);
-
-  const DwarfCie* cie = this->section_->GetCie(0x8000);
-  ASSERT_TRUE(cie != nullptr);
-  EXPECT_EQ(1U, cie->version);
-  EXPECT_EQ(DW_EH_PE_sdata8, cie->fde_address_encoding);
-  EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
-  EXPECT_EQ(0U, cie->segment_size);
-  EXPECT_EQ(1U, cie->augmentation_string.size());
-  EXPECT_EQ('\0', cie->augmentation_string[0]);
-  EXPECT_EQ(0U, cie->personality_handler);
-  EXPECT_EQ(0x8019U, cie->cfa_instructions_offset);
-  EXPECT_EQ(0x820cU, cie->cfa_instructions_end);
-  EXPECT_EQ(4U, cie->code_alignment_factor);
-  EXPECT_EQ(8, cie->data_alignment_factor);
-  EXPECT_EQ(0x20U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_augment) {
-  this->memory_.SetData32(0x5000, 0x100);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 0x1);
-  this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'L', 'P', 'R', '\0'});
-  this->memory_.SetData8(0x500e, 4);
-  this->memory_.SetData8(0x500f, 8);
-  this->memory_.SetData8(0x5010, 0x10);
-  // Augment length.
-  this->memory_.SetData8(0x5011, 0xf);
-  // L data.
-  this->memory_.SetData8(0x5012, DW_EH_PE_textrel | DW_EH_PE_udata2);
-  // P data.
-  this->memory_.SetData8(0x5013, DW_EH_PE_udata4);
-  this->memory_.SetData32(0x5014, 0x12345678);
-  // R data.
-  this->memory_.SetData8(0x5018, DW_EH_PE_udata2);
-
-  const DwarfCie* cie = this->section_->GetCie(0x5000);
-  ASSERT_TRUE(cie != nullptr);
-  EXPECT_EQ(1U, cie->version);
-  EXPECT_EQ(DW_EH_PE_udata2, cie->fde_address_encoding);
-  EXPECT_EQ(DW_EH_PE_textrel | DW_EH_PE_udata2, cie->lsda_encoding);
-  EXPECT_EQ(0U, cie->segment_size);
-  EXPECT_EQ(5U, cie->augmentation_string.size());
-  EXPECT_EQ('z', cie->augmentation_string[0]);
-  EXPECT_EQ('L', cie->augmentation_string[1]);
-  EXPECT_EQ('P', cie->augmentation_string[2]);
-  EXPECT_EQ('R', cie->augmentation_string[3]);
-  EXPECT_EQ('\0', cie->augmentation_string[4]);
-  EXPECT_EQ(0x12345678U, cie->personality_handler);
-  EXPECT_EQ(0x5021U, cie->cfa_instructions_offset);
-  EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
-  EXPECT_EQ(4U, cie->code_alignment_factor);
-  EXPECT_EQ(8, cie->data_alignment_factor);
-  EXPECT_EQ(0x10U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_3) {
-  this->memory_.SetData32(0x5000, 0x100);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 0x3);
-  this->memory_.SetData8(0x5009, '\0');
-  this->memory_.SetData8(0x500a, 4);
-  this->memory_.SetData8(0x500b, 8);
-  this->memory_.SetMemory(0x500c, std::vector<uint8_t>{0x81, 0x03});
-
-  const DwarfCie* cie = this->section_->GetCie(0x5000);
-  ASSERT_TRUE(cie != nullptr);
-  EXPECT_EQ(3U, cie->version);
-  EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
-  EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
-  EXPECT_EQ(0U, cie->segment_size);
-  EXPECT_EQ(1U, cie->augmentation_string.size());
-  EXPECT_EQ('\0', cie->augmentation_string[0]);
-  EXPECT_EQ(0U, cie->personality_handler);
-  EXPECT_EQ(0x500eU, cie->cfa_instructions_offset);
-  EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
-  EXPECT_EQ(4U, cie->code_alignment_factor);
-  EXPECT_EQ(8, cie->data_alignment_factor);
-  EXPECT_EQ(0x181U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_4) {
-  this->memory_.SetData32(0x5000, 0x100);
-  this->memory_.SetData32(0x5004, 0xffffffff);
-  this->memory_.SetData8(0x5008, 0x4);
-  this->memory_.SetData8(0x5009, '\0');
-  this->memory_.SetData8(0x500a, 4);
-  this->memory_.SetData8(0x500b, 0x13);
-  this->memory_.SetData8(0x500c, 4);
-  this->memory_.SetData8(0x500d, 8);
-  this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x81, 0x03});
-
-  const DwarfCie* cie = this->section_->GetCie(0x5000);
-  ASSERT_TRUE(cie != nullptr);
-  EXPECT_EQ(4U, cie->version);
-  EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
-  EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
-  EXPECT_EQ(0x13U, cie->segment_size);
-  EXPECT_EQ(1U, cie->augmentation_string.size());
-  EXPECT_EQ('\0', cie->augmentation_string[0]);
-  EXPECT_EQ(0U, cie->personality_handler);
-  EXPECT_EQ(0x5010U, cie->cfa_instructions_offset);
-  EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
-  EXPECT_EQ(4U, cie->code_alignment_factor);
-  EXPECT_EQ(8, cie->data_alignment_factor);
-  EXPECT_EQ(0x181U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
-  ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
-  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-  this->section_->TestClearError();
-  ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
-  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment) {
-  this->memory_.SetData32(0x4000, 0x20);
-  this->memory_.SetData32(0x4004, 0x8000);
-  this->memory_.SetData32(0x4008, 0x5000);
-  this->memory_.SetData32(0x400c, 0x100);
-
-  EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
-  DwarfCie cie{};
-  cie.fde_address_encoding = DW_EH_PE_udata4;
-  this->section_->TestSetCachedCieEntry(0x8000, cie);
-  EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
-  const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
-  ASSERT_TRUE(fde != nullptr);
-  ASSERT_TRUE(fde->cie != nullptr);
-  EXPECT_EQ(0x4010U, fde->cfa_instructions_offset);
-  EXPECT_EQ(0x4024U, fde->cfa_instructions_end);
-  EXPECT_EQ(0x5000U, fde->pc_start);
-  EXPECT_EQ(0x5100U, fde->pc_end);
-  EXPECT_EQ(0x8000U, fde->cie_offset);
-  EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment_non_zero_segment_size) {
-  this->memory_.SetData32(0x4000, 0x30);
-  this->memory_.SetData32(0x4004, 0x8000);
-  this->memory_.SetData32(0x4018, 0x5000);
-  this->memory_.SetData32(0x401c, 0x100);
-
-  EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
-  DwarfCie cie{};
-  cie.fde_address_encoding = DW_EH_PE_udata4;
-  cie.segment_size = 0x10;
-  this->section_->TestSetCachedCieEntry(0x8000, cie);
-  EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
-  const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
-  ASSERT_TRUE(fde != nullptr);
-  ASSERT_TRUE(fde->cie != nullptr);
-  EXPECT_EQ(0x4020U, fde->cfa_instructions_offset);
-  EXPECT_EQ(0x4034U, fde->cfa_instructions_end);
-  EXPECT_EQ(0x5000U, fde->pc_start);
-  EXPECT_EQ(0x5100U, fde->pc_end);
-  EXPECT_EQ(0x8000U, fde->cie_offset);
-  EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_augment) {
-  this->memory_.SetData32(0x4000, 0x100);
-  this->memory_.SetData32(0x4004, 0x8000);
-  this->memory_.SetData32(0x4008, 0x5000);
-  this->memory_.SetData32(0x400c, 0x100);
-  this->memory_.SetMemory(0x4010, std::vector<uint8_t>{0x82, 0x01});
-  this->memory_.SetData16(0x4012, 0x1234);
-
-  EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
-  DwarfCie cie{};
-  cie.fde_address_encoding = DW_EH_PE_udata4;
-  cie.augmentation_string.push_back('z');
-  cie.lsda_encoding = DW_EH_PE_udata2;
-  this->section_->TestSetCachedCieEntry(0x8000, cie);
-  EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
-  const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
-  ASSERT_TRUE(fde != nullptr);
-  ASSERT_TRUE(fde->cie != nullptr);
-  EXPECT_EQ(0x4094U, fde->cfa_instructions_offset);
-  EXPECT_EQ(0x4104U, fde->cfa_instructions_end);
-  EXPECT_EQ(0x5000U, fde->pc_start);
-  EXPECT_EQ(0x5100U, fde->pc_end);
-  EXPECT_EQ(0x8000U, fde->cie_offset);
-  EXPECT_EQ(0x1234U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_64_no_augment) {
-  this->memory_.SetData32(0x4000, 0xffffffff);
-  this->memory_.SetData64(0x4004, 0x100);
-  this->memory_.SetData64(0x400c, 0x12345678);
-  this->memory_.SetData32(0x4014, 0x5000);
-  this->memory_.SetData32(0x4018, 0x100);
-
-  EXPECT_CALL(*this->section_, GetCieOffsetFromFde64(0x12345678))
-      .WillOnce(::testing::Return(0x12345678));
-  DwarfCie cie{};
-  cie.fde_address_encoding = DW_EH_PE_udata4;
-  this->section_->TestSetCachedCieEntry(0x12345678, cie);
-  EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
-  const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
-  ASSERT_TRUE(fde != nullptr);
-  ASSERT_TRUE(fde->cie != nullptr);
-  EXPECT_EQ(0x401cU, fde->cfa_instructions_offset);
-  EXPECT_EQ(0x410cU, fde->cfa_instructions_end);
-  EXPECT_EQ(0x5000U, fde->pc_start);
-  EXPECT_EQ(0x5100U, fde->pc_end);
-  EXPECT_EQ(0x12345678U, fde->cie_offset);
-  EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_cached) {
-  DwarfCie cie{};
-  cie.fde_address_encoding = DW_EH_PE_udata4;
-  cie.augmentation_string.push_back('z');
-  cie.lsda_encoding = DW_EH_PE_udata2;
-
-  DwarfFde fde_cached{};
-  fde_cached.cfa_instructions_offset = 0x1000;
-  fde_cached.cfa_instructions_end = 0x1100;
-  fde_cached.pc_start = 0x9000;
-  fde_cached.pc_end = 0x9400;
-  fde_cached.cie_offset = 0x30000;
-  fde_cached.cie = &cie;
-  this->section_->TestSetCachedFdeEntry(0x6000, fde_cached);
-
-  const DwarfFde* fde = this->section_->GetFdeFromOffset(0x6000);
-  ASSERT_TRUE(fde != nullptr);
-  ASSERT_EQ(&cie, fde->cie);
-  EXPECT_EQ(0x1000U, fde->cfa_instructions_offset);
-  EXPECT_EQ(0x1100U, fde->cfa_instructions_end);
-  EXPECT_EQ(0x9000U, fde->pc_start);
-  EXPECT_EQ(0x9400U, fde->pc_end);
-  EXPECT_EQ(0x30000U, fde->cie_offset);
-}
-
 TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_not_cached) {
   DwarfCie cie{};
   cie.cfa_instructions_offset = 0x3000;
@@ -895,18 +571,16 @@
   ASSERT_EQ("", GetFakeLogBuf());
 }
 
-REGISTER_TYPED_TEST_CASE_P(
-    DwarfSectionImplTest, Eval_cfa_expr_eval_fail, Eval_cfa_expr_no_stack,
-    Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
-    Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
-    Eval_register_reference_chain, Eval_dex_pc, Eval_invalid_register, Eval_different_reg_locations,
-    Eval_return_address_undefined, Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc,
-    Eval_reg_expr, Eval_reg_val_expr, GetCie_fail_should_not_cache, GetCie_32_version_check,
-    GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
-    GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
-    GetFdeFromOffset_32_no_augment_non_zero_segment_size, GetFdeFromOffset_32_augment,
-    GetFdeFromOffset_64_no_augment, GetFdeFromOffset_cached, GetCfaLocationInfo_cie_not_cached,
-    GetCfaLocationInfo_cie_cached, Log);
+REGISTER_TYPED_TEST_CASE_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_not_cache,
+                           GetFdeFromOffset_fail_should_not_cache, Eval_cfa_expr_eval_fail,
+                           Eval_cfa_expr_no_stack, Eval_cfa_expr_is_register, Eval_cfa_expr,
+                           Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa, Eval_cfa_bad,
+                           Eval_cfa_register_prev, Eval_cfa_register_from_value,
+                           Eval_double_indirection, Eval_register_reference_chain, Eval_dex_pc,
+                           Eval_invalid_register, Eval_different_reg_locations,
+                           Eval_return_address_undefined, Eval_pc_zero, Eval_return_address,
+                           Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+                           GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(, DwarfSectionImplTest, DwarfSectionImplTestTypes);
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index 2c6c879..d754fcc 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -30,24 +30,18 @@
   MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
   virtual ~MockDwarfSection() = default;
 
-  MOCK_METHOD3(Log, bool(uint8_t, uint64_t, const DwarfFde*));
+  MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
 
   MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*));
 
+  MOCK_METHOD3(Log, bool(uint8_t, uint64_t, const DwarfFde*));
+
+  MOCK_METHOD1(GetFdes, void(std::vector<const DwarfFde*>*));
+
+  MOCK_METHOD1(GetFdeFromPc, const DwarfFde*(uint64_t));
+
   MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*));
 
-  MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
-
-  MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));
-
-  MOCK_METHOD1(GetFdeFromOffset, const DwarfFde*(uint64_t));
-
-  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));
@@ -57,112 +51,60 @@
 
 class DwarfSectionTest : public ::testing::Test {
  protected:
+  void SetUp() override { section_.reset(new MockDwarfSection(&memory_)); }
+
   MemoryFake memory_;
+  std::unique_ptr<MockDwarfSection> section_;
 };
 
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_from_pc) {
-  MockDwarfSection mock_section(&memory_);
-
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(false));
-
-  // Verify nullptr when GetFdeOffsetFromPc fails.
-  ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr);
-}
-
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_fde_pc_end) {
-  MockDwarfSection mock_section(&memory_);
-
-  DwarfFde fde{};
-  fde.pc_end = 0x500;
-
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(true));
-  EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
-  // Verify nullptr when GetFdeOffsetFromPc fails.
-  ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr);
-}
-
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_pass) {
-  MockDwarfSection mock_section(&memory_);
-
-  DwarfFde fde{};
-  fde.pc_end = 0x2000;
-
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(true));
-  EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
-  // Verify nullptr when GetFdeOffsetFromPc fails.
-  ASSERT_EQ(&fde, mock_section.GetFdeFromPc(0x1000));
-}
-
 TEST_F(DwarfSectionTest, Step_fail_fde) {
-  MockDwarfSection mock_section(&memory_);
-
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(false));
+  EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(nullptr));
 
   bool finished;
-  ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+  ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
 }
 
 TEST_F(DwarfSectionTest, Step_fail_cie_null) {
-  MockDwarfSection mock_section(&memory_);
-
   DwarfFde fde{};
   fde.pc_end = 0x2000;
   fde.cie = nullptr;
 
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(true));
-  EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
+  EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
 
   bool finished;
-  ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+  ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
 }
 
 TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
-  MockDwarfSection mock_section(&memory_);
-
   DwarfCie cie{};
   DwarfFde fde{};
   fde.pc_end = 0x2000;
   fde.cie = &cie;
 
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(true));
-  EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
-  EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+  EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
       .WillOnce(::testing::Return(false));
 
   bool finished;
-  ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+  ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
 }
 
 TEST_F(DwarfSectionTest, Step_pass) {
-  MockDwarfSection mock_section(&memory_);
-
   DwarfCie cie{};
   DwarfFde fde{};
   fde.pc_end = 0x2000;
   fde.cie = &cie;
 
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(true));
-  EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
-  EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+  EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
       .WillOnce(::testing::Return(true));
 
   MemoryFake process;
-  EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
       .WillOnce(::testing::Return(true));
 
   bool finished;
-  ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
 }
 
 static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde,
@@ -173,64 +115,53 @@
 }
 
 TEST_F(DwarfSectionTest, Step_cache) {
-  MockDwarfSection mock_section(&memory_);
-
   DwarfCie cie{};
   DwarfFde fde{};
   fde.pc_start = 0x500;
   fde.pc_end = 0x2000;
   fde.cie = &cie;
 
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(true));
-  EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
-  EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+  EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
 
   MemoryFake process;
-  EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
       .WillRepeatedly(::testing::Return(true));
 
   bool finished;
-  ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
-  ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
-  ASSERT_TRUE(mock_section.Step(0x1500, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1500, nullptr, &process, &finished));
 }
 
 TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
-  MockDwarfSection mock_section(&memory_);
-
   DwarfCie cie{};
   DwarfFde fde0{};
   fde0.pc_start = 0x1000;
   fde0.pc_end = 0x2000;
   fde0.cie = &cie;
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
-      .WillOnce(::testing::Return(true));
-  EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde0));
-  EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde0, ::testing::_))
+  EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde0));
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_))
       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
 
   MemoryFake process;
-  EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
       .WillRepeatedly(::testing::Return(true));
 
   bool finished;
-  ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
 
   DwarfFde fde1{};
   fde1.pc_start = 0x500;
   fde1.pc_end = 0x800;
   fde1.cie = &cie;
-  EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x600, ::testing::_))
-      .WillOnce(::testing::Return(true));
-  EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde1));
-  EXPECT_CALL(mock_section, GetCfaLocationInfo(0x600, &fde1, ::testing::_))
+  EXPECT_CALL(*section_, GetFdeFromPc(0x600)).WillOnce(::testing::Return(&fde1));
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_))
       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
 
-  ASSERT_TRUE(mock_section.Step(0x600, nullptr, &process, &finished));
-  ASSERT_TRUE(mock_section.Step(0x700, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x600, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x700, nullptr, &process, &finished));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 487d39c..aa6df84 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -656,8 +656,7 @@
 
   memory_.SetData32(0x5000, 0xfc);
   memory_.SetData32(0x5004, 0xffffffff);
-  memory_.SetData8(0x5008, 1);
-  memory_.SetData8(0x5009, '\0');
+  memory_.SetMemory(0x5008, std::vector<uint8_t>{1, '\0', 4, 8, 2});
 
   memory_.SetData32(0x5100, 0xfc);
   memory_.SetData32(0x5104, 0);
@@ -678,56 +677,6 @@
   InitHeadersDebugFrame<ElfInterface64Fake>();
 }
 
-template <typename ElfType>
-void ElfInterfaceTest::InitHeadersEhFrameFail() {
-  ElfType elf(&memory_);
-
-  elf.FakeSetEhFrameOffset(0x1000);
-  elf.FakeSetEhFrameSize(0x100);
-  elf.FakeSetDebugFrameOffset(0);
-  elf.FakeSetDebugFrameSize(0);
-
-  elf.InitHeaders(0);
-
-  EXPECT_TRUE(elf.eh_frame() == nullptr);
-  EXPECT_EQ(0U, elf.eh_frame_offset());
-  EXPECT_EQ(static_cast<uint64_t>(-1), elf.eh_frame_size());
-  EXPECT_TRUE(elf.debug_frame() == nullptr);
-}
-
-TEST_F(ElfInterfaceTest, init_headers_eh_frame32_fail) {
-  InitHeadersEhFrameFail<ElfInterface32Fake>();
-}
-
-TEST_F(ElfInterfaceTest, init_headers_eh_frame64_fail) {
-  InitHeadersEhFrameFail<ElfInterface64Fake>();
-}
-
-template <typename ElfType>
-void ElfInterfaceTest::InitHeadersDebugFrameFail() {
-  ElfType elf(&memory_);
-
-  elf.FakeSetEhFrameOffset(0);
-  elf.FakeSetEhFrameSize(0);
-  elf.FakeSetDebugFrameOffset(0x1000);
-  elf.FakeSetDebugFrameSize(0x100);
-
-  elf.InitHeaders(0);
-
-  EXPECT_TRUE(elf.eh_frame() == nullptr);
-  EXPECT_TRUE(elf.debug_frame() == nullptr);
-  EXPECT_EQ(0U, elf.debug_frame_offset());
-  EXPECT_EQ(static_cast<uint64_t>(-1), elf.debug_frame_size());
-}
-
-TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) {
-  InitHeadersDebugFrameFail<ElfInterface32Fake>();
-}
-
-TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) {
-  InitHeadersDebugFrameFail<ElfInterface64Fake>();
-}
-
 template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
 void ElfInterfaceTest::InitSectionHeadersMalformed() {
   std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -1024,11 +973,7 @@
   // CIE 32.
   memory_.SetData32(0x600, 0xfc);
   memory_.SetData32(0x604, 0xffffffff);
-  memory_.SetData8(0x608, 1);
-  memory_.SetData8(0x609, '\0');
-  memory_.SetData8(0x60a, 0x4);
-  memory_.SetData8(0x60b, 0x4);
-  memory_.SetData8(0x60c, 0x1);
+  memory_.SetMemory(0x608, std::vector<uint8_t>{1, '\0', 4, 4, 1});
 
   // FDE 32.
   memory_.SetData32(0x700, 0xfc);
@@ -1085,11 +1030,7 @@
   // CIE 32.
   memory_.SetData32(0x600, 0xfc);
   memory_.SetData32(0x604, 0);
-  memory_.SetData8(0x608, 1);
-  memory_.SetData8(0x609, '\0');
-  memory_.SetData8(0x60a, 0x4);
-  memory_.SetData8(0x60b, 0x4);
-  memory_.SetData8(0x60c, 0x1);
+  memory_.SetMemory(0x608, std::vector<uint8_t>{1, '\0', 4, 4, 1});
 
   // FDE 32.
   memory_.SetData32(0x700, 0xfc);