Refactor the DwarfSection classes.

Modify the code for the no header sections because it turns out that
it is not okay to assume that the fdes are non-overlapping. It's necessary
to read the fdes in order and match as you go.

Modify the code so that it only reads until it finds the given pc rather than
reading all of the cie/fde entries at once.

Rewrote the tests to verify the new behavior.

Bug: 68998033
Bug: 110235461

Test: Ran libbacktrace/libunwindstack unit tests.
Test: Unwind the mediaserver process on a walleye and verify it
Test: unwinds properly.

Change-Id: I7bb59d1db72c13fa34caa9735ec34c1a60e20ed2
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);