Fix potential bad info in eh_frame_hdr.

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

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

Add new unit tests to verify this functionality.

Bug: 142483624

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