Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ca98e18 authored by Christopher Ferris's avatar Christopher Ferris
Browse files

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
parent 85f5a444
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -26,9 +26,9 @@
namespace unwindstack {

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

template <typename AddressType>
class DwarfEhFrame : public DwarfSectionImplNoHdr<AddressType> {
class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
 public:
  DwarfEhFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {}
  DwarfEhFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
  virtual ~DwarfEhFrame() = default;

  uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
+36 −12
Original line number Diff line number Diff line
@@ -32,14 +32,19 @@ static inline bool IsEncodingRelative(uint8_t encoding) {
}

template <typename AddressType>
bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) {
  section_bias_ = section_bias;
bool DwarfEhFrameWithHdr<AddressType>::EhFrameInit(uint64_t offset, uint64_t size,
                                                   int64_t section_bias) {
  return DwarfSectionImpl<AddressType>::Init(offset, size, section_bias);
}

template <typename AddressType>
bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t, int64_t section_bias) {
  memory_.clear_func_offset();
  memory_.clear_text_offset();
  memory_.set_data_offset(offset);
  memory_.set_cur_offset(offset);
  pc_offset_ = offset;

  hdr_section_bias_ = section_bias;

  // Read the first four bytes all at once.
  uint8_t data[4];
@@ -56,7 +61,7 @@ bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int6
    return false;
  }

  ptr_encoding_ = data[1];
  uint8_t ptr_encoding = data[1];
  uint8_t fde_count_encoding = data[2];
  table_encoding_ = data[3];
  table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
@@ -70,7 +75,8 @@ bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int6
  }

  memory_.set_pc_offset(memory_.cur_offset());
  if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) {
  uint64_t ptr_offset;
  if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding, &ptr_offset)) {
    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
    last_error_.address = memory_.cur_offset();
    return false;
@@ -88,10 +94,8 @@ bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int6
    return false;
  }

  entries_offset_ = memory_.cur_offset();
  entries_end_ = offset + size;
  entries_data_offset_ = offset;
  cur_entries_offset_ = entries_offset_;
  hdr_entries_offset_ = memory_.cur_offset();
  hdr_entries_data_offset_ = offset;

  return true;
}
@@ -107,6 +111,16 @@ const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
    return nullptr;
  }

  // There is a possibility that this entry points to a zero length FDE
  // due to a bug. If this happens, try and find the non-zero length FDE
  // from eh_frame directly. See b/142483624.
  if (fde->pc_start == fde->pc_end) {
    fde = DwarfSectionImpl<AddressType>::GetFdeFromPc(pc);
    if (fde == nullptr) {
      return nullptr;
    }
  }

  // Guaranteed pc >= pc_start, need to check pc in the fde range.
  if (pc < fde->pc_end) {
    return fde;
@@ -124,8 +138,8 @@ DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
  }
  FdeInfo* info = &fde_info_[index];

  memory_.set_data_offset(entries_data_offset_);
  memory_.set_cur_offset(entries_offset_ + 2 * index * table_entry_size_);
  memory_.set_data_offset(hdr_entries_data_offset_);
  memory_.set_cur_offset(hdr_entries_offset_ + 2 * index * table_entry_size_);
  memory_.set_pc_offset(0);
  uint64_t value;
  if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
@@ -138,7 +152,7 @@ DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {

  // Relative encodings require adding in the load bias.
  if (IsEncodingRelative(table_encoding_)) {
    value += section_bias_;
    value += hdr_section_bias_;
  }
  info->pc = value;
  return info;
@@ -190,6 +204,16 @@ void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fde
    if (fde == nullptr) {
      break;
    }

    // There is a possibility that this entry points to a zero length FDE
    // due to a bug. If this happens, try and find the non-zero length FDE
    // from eh_frame directly. See b/142483624.
    if (fde->pc_start == fde->pc_end) {
      const DwarfFde* fde_real = DwarfSectionImpl<AddressType>::GetFdeFromPc(fde->pc_start);
      if (fde_real != nullptr) {
        fde = fde_real;
      }
    }
    fdes->push_back(fde);
  }
}
+11 −16
Original line number Diff line number Diff line
@@ -34,11 +34,7 @@ class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
  // Add these so that the protected members of DwarfSectionImpl
  // can be accessed without needing a this->.
  using DwarfSectionImpl<AddressType>::memory_;
  using DwarfSectionImpl<AddressType>::pc_offset_;
  using DwarfSectionImpl<AddressType>::entries_offset_;
  using DwarfSectionImpl<AddressType>::entries_end_;
  using DwarfSectionImpl<AddressType>::last_error_;
  using DwarfSectionImpl<AddressType>::section_bias_;

  struct FdeInfo {
    AddressType pc;
@@ -49,18 +45,19 @@ class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
  virtual ~DwarfEhFrameWithHdr() = default;

  uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
    return this->memory_.cur_offset() - pointer - 4;
    return memory_.cur_offset() - pointer - 4;
  }

  uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
    return this->memory_.cur_offset() - pointer - 8;
    return memory_.cur_offset() - pointer - 8;
  }

  uint64_t AdjustPcFromFde(uint64_t pc) override {
    // The eh_frame uses relative pcs.
    return pc + this->memory_.cur_offset() - 4;
    return pc + memory_.cur_offset() - 4;
  }

  bool EhFrameInit(uint64_t offset, uint64_t size, int64_t section_bias);
  bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;

  const DwarfFde* GetFdeFromPc(uint64_t pc) override;
@@ -72,17 +69,15 @@ class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
  void GetFdes(std::vector<const DwarfFde*>* fdes) override;

 protected:
  uint8_t version_;
  uint8_t ptr_encoding_;
  uint8_t table_encoding_;
  size_t table_entry_size_;
  uint8_t version_ = 0;
  uint8_t table_encoding_ = 0;
  size_t table_entry_size_ = 0;

  uint64_t ptr_offset_;
  uint64_t hdr_entries_offset_ = 0;
  uint64_t hdr_entries_data_offset_ = 0;
  uint64_t hdr_section_bias_ = 0;

  uint64_t entries_data_offset_;
  uint64_t cur_entries_offset_ = 0;

  uint64_t fde_count_;
  uint64_t fde_count_ = 0;
  std::unordered_map<uint64_t, FdeInfo> fde_info_;
};

+35 −30
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ const DwarfCie* DwarfSectionImpl<AddressType>::GetCieFromOffset(uint64_t offset)
    return &cie_entry->second;
  }
  DwarfCie* cie = &cie_entries_[offset];
  memory_.set_data_offset(entries_offset_);
  memory_.set_cur_offset(offset);
  if (!FillInCieHeader(cie) || !FillInCie(cie)) {
    // Erase the cached entry.
@@ -251,6 +252,7 @@ const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset)
    return &fde_entry->second;
  }
  DwarfFde* fde = &fde_entries_[offset];
  memory_.set_data_offset(entries_offset_);
  memory_.set_cur_offset(offset);
  if (!FillInFdeHeader(fde) || !FillInFde(fde)) {
    fde_entries_.erase(offset);
@@ -591,8 +593,7 @@ bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const Dwarf
}

template <typename AddressType>
bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size,
                                              int64_t section_bias) {
bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) {
  section_bias_ = section_bias;
  entries_offset_ = offset;
  next_entries_offset_ = offset;
@@ -601,7 +602,6 @@ bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size,
  memory_.clear_func_offset();
  memory_.clear_text_offset();
  memory_.set_cur_offset(offset);
  memory_.set_data_offset(offset);
  pc_offset_ = offset;

  return true;
@@ -617,7 +617,7 @@ bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size,
// and an fde has a start pc of 0x100 and end pc of 0x500, two new entries
// will be added: 0x200, 0x100 and 0x500, 0x400.
template <typename AddressType>
void DwarfSectionImplNoHdr<AddressType>::InsertFde(const DwarfFde* fde) {
void DwarfSectionImpl<AddressType>::InsertFde(const DwarfFde* fde) {
  uint64_t start = fde->pc_start;
  uint64_t end = fde->pc_end;
  auto it = fdes_.upper_bound(start);
@@ -654,9 +654,10 @@ void DwarfSectionImplNoHdr<AddressType>::InsertFde(const DwarfFde* fde) {
}

template <typename AddressType>
bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
bool DwarfSectionImpl<AddressType>::GetNextCieOrFde(const DwarfFde** fde_entry) {
  uint64_t start_offset = next_entries_offset_;

  memory_.set_data_offset(entries_offset_);
  memory_.set_cur_offset(next_entries_offset_);
  uint32_t value32;
  if (!memory_.ReadBytes(&value32, sizeof(value32))) {
@@ -689,7 +690,7 @@ bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
      entry_is_cie = true;
      cie_fde_encoding = DW_EH_PE_sdata8;
    } else {
      cie_offset = this->GetCieOffsetFromFde64(value64);
      cie_offset = GetCieOffsetFromFde64(value64);
    }
  } else {
    next_entries_offset_ = memory_.cur_offset() + value32;
@@ -705,37 +706,45 @@ bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
      entry_is_cie = true;
      cie_fde_encoding = DW_EH_PE_sdata4;
    } else {
      cie_offset = this->GetCieOffsetFromFde32(value32);
      cie_offset = GetCieOffsetFromFde32(value32);
    }
  }

  if (entry_is_cie) {
    auto entry = cie_entries_.find(start_offset);
    if (entry == cie_entries_.end()) {
      DwarfCie* cie = &cie_entries_[start_offset];
      cie->lsda_encoding = DW_EH_PE_omit;
      cie->cfa_instructions_end = next_entries_offset_;
      cie->fde_address_encoding = cie_fde_encoding;

    if (!this->FillInCie(cie)) {
      if (!FillInCie(cie)) {
        cie_entries_.erase(start_offset);
        return false;
      }
    }
    *fde_entry = nullptr;
  } else {
    auto entry = fde_entries_.find(start_offset);
    if (entry != fde_entries_.end()) {
      *fde_entry = &entry->second;
    } else {
      DwarfFde* fde = &fde_entries_[start_offset];
      fde->cfa_instructions_end = next_entries_offset_;
      fde->cie_offset = cie_offset;

    if (!this->FillInFde(fde)) {
      if (!FillInFde(fde)) {
        fde_entries_.erase(start_offset);
        return false;
      }
      *fde_entry = fde;
    }
  }
  return true;
}

template <typename AddressType>
void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
void DwarfSectionImpl<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
  // Loop through the already cached entries.
  uint64_t entry_offset = entries_offset_;
  while (entry_offset < next_entries_offset_) {
@@ -754,7 +763,7 @@ void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* f
  }

  while (next_entries_offset_ < entries_end_) {
    DwarfFde* fde;
    const DwarfFde* fde;
    if (!GetNextCieOrFde(&fde)) {
      break;
    }
@@ -771,7 +780,7 @@ void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* f
}

template <typename AddressType>
const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromPc(uint64_t pc) {
  // Search in the list of fdes we already have.
  auto it = fdes_.upper_bound(pc);
  if (it != fdes_.end()) {
@@ -784,7 +793,7 @@ const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
  // to do a linear search of the fdes by pc. As fdes are read, a cached
  // search map is created.
  while (next_entries_offset_ < entries_end_) {
    DwarfFde* fde;
    const DwarfFde* fde;
    if (!GetNextCieOrFde(&fde)) {
      return nullptr;
    }
@@ -807,10 +816,6 @@ const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
template class DwarfSectionImpl<uint32_t>;
template class DwarfSectionImpl<uint64_t>;

// Explicitly instantiate DwarfSectionImplNoHdr
template class DwarfSectionImplNoHdr<uint32_t>;
template class DwarfSectionImplNoHdr<uint64_t>;

// Explicitly instantiate DwarfDebugFrame
template class DwarfDebugFrame<uint32_t>;
template class DwarfDebugFrame<uint64_t>;
Loading