diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h index 635cefdf2..388ab0a4f 100644 --- a/libunwindstack/DwarfDebugFrame.h +++ b/libunwindstack/DwarfDebugFrame.h @@ -26,9 +26,9 @@ namespace unwindstack { template -class DwarfDebugFrame : public DwarfSectionImpl { +class DwarfDebugFrame : public DwarfSectionImplNoHdr { public: - DwarfDebugFrame(Memory* memory) : DwarfSectionImpl(memory) { + DwarfDebugFrame(Memory* memory) : DwarfSectionImplNoHdr(memory) { this->cie32_value_ = static_cast(-1); this->cie64_value_ = static_cast(-1); } diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h index 7a41e4550..df441fb52 100644 --- a/libunwindstack/DwarfEhFrame.h +++ b/libunwindstack/DwarfEhFrame.h @@ -25,9 +25,9 @@ namespace unwindstack { template -class DwarfEhFrame : public DwarfSectionImpl { +class DwarfEhFrame : public DwarfSectionImplNoHdr { public: - DwarfEhFrame(Memory* memory) : DwarfSectionImpl(memory) {} + DwarfEhFrame(Memory* memory) : DwarfSectionImplNoHdr(memory) {} virtual ~DwarfEhFrame() = default; uint64_t GetCieOffsetFromFde32(uint32_t pointer) override { diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp index fd6a457ef..668527a4d 100644 --- a/libunwindstack/DwarfEhFrameWithHdr.cpp +++ b/libunwindstack/DwarfEhFrameWithHdr.cpp @@ -39,6 +39,7 @@ bool DwarfEhFrameWithHdr::Init(uint64_t offset, uint64_t size, uint 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 @@ bool DwarfEhFrameWithHdr::Init(uint64_t offset, uint64_t size, uint } template -const DwarfFde* DwarfEhFrameWithHdr::GetFdeFromIndex(size_t index) { - const FdeInfo* info = GetFdeInfoFromIndex(index); - if (info == nullptr) { +const DwarfFde* DwarfEhFrameWithHdr::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 @@ -241,6 +252,21 @@ bool DwarfEhFrameWithHdr::GetFdeOffsetFromPc(uint64_t pc, uint64_t* } } +template +void DwarfEhFrameWithHdr::GetFdes(std::vector* 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; template class DwarfEhFrameWithHdr; diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h index d16dd1006..e3e9ca885 100644 --- a/libunwindstack/DwarfEhFrameWithHdr.h +++ b/libunwindstack/DwarfEhFrameWithHdr.h @@ -21,7 +21,7 @@ #include -#include "DwarfEhFrame.h" +#include namespace unwindstack { @@ -29,12 +29,12 @@ namespace unwindstack { class Memory; template -class DwarfEhFrameWithHdr : public DwarfEhFrame { +class DwarfEhFrameWithHdr : public DwarfSectionImpl { public: // Add these so that the protected members of DwarfSectionImpl // can be accessed without needing a this->. using DwarfSectionImpl::memory_; - using DwarfSectionImpl::fde_count_; + using DwarfSectionImpl::pc_offset_; using DwarfSectionImpl::entries_offset_; using DwarfSectionImpl::entries_end_; using DwarfSectionImpl::last_error_; @@ -45,14 +45,27 @@ class DwarfEhFrameWithHdr : public DwarfEhFrame { uint64_t offset; }; - DwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrame(memory) {} + DwarfEhFrameWithHdr(Memory* memory) : DwarfSectionImpl(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 @@ class DwarfEhFrameWithHdr : public DwarfEhFrame { bool GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, uint64_t total_entries); + void GetFdes(std::vector* fdes) override; + protected: uint8_t version_; uint8_t ptr_encoding_; @@ -71,6 +86,7 @@ class DwarfEhFrameWithHdr : public DwarfEhFrame { uint64_t entries_data_offset_; uint64_t cur_entries_offset_ = 0; + uint64_t fde_count_; std::unordered_map fde_info_; }; diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index eb8394989..6061f6137 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -36,24 +36,6 @@ namespace unwindstack { 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); @@ -80,6 +62,314 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f return Eval(it->second.cie, process_memory, it->second, regs, finished); } +template +const DwarfCie* DwarfSectionImpl::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 +bool DwarfSectionImpl::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(-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 +bool DwarfSectionImpl::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(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 +const DwarfFde* DwarfSectionImpl::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 +bool DwarfSectionImpl::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(-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 +bool DwarfSectionImpl::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(cie->fde_address_encoding, &fde->pc_start); + fde->pc_start = AdjustPcFromFde(fde->pc_start); + + memory_.set_pc_offset(0); + if (!valid || !memory_.ReadEncodedValue(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(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 bool DwarfSectionImpl::EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value, @@ -259,307 +549,6 @@ bool DwarfSectionImpl::Eval(const DwarfCie* cie, Memory* regular_me return true; } -template -const DwarfCie* DwarfSectionImpl::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 -bool DwarfSectionImpl::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(-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(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 -const DwarfFde* DwarfSectionImpl::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 -bool DwarfSectionImpl::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(-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(cie->fde_address_encoding, &fde->pc_start); - fde->pc_start = AdjustPcFromFde(fde->pc_start); - - memory_.set_pc_offset(0); - if (!valid || !memory_.ReadEncodedValue(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(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 bool DwarfSectionImpl::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) { @@ -601,9 +590,10 @@ bool DwarfSectionImpl::Log(uint8_t indent, uint64_t pc, const Dwarf } template -bool DwarfSectionImpl::Init(uint64_t offset, uint64_t size, uint64_t load_bias) { +bool DwarfSectionImplNoHdr::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 @@ bool DwarfSectionImpl::Init(uint64_t offset, uint64_t size, uint64_ memory_.set_data_offset(offset); pc_offset_ = offset; - return CreateSortedFdeList(); -} - -template -bool DwarfSectionImpl::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 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(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 -bool DwarfSectionImpl::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(encoding, &start); - start = AdjustPcFromFde(start); - - uint64_t length; - memory_.set_pc_offset(0); - if (!valid || !memory_.template ReadEncodedValue(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 -bool DwarfSectionImpl::CreateSortedFdeList() { - memory_.set_cur_offset(entries_offset_); +void DwarfSectionImplNoHdr::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 +bool DwarfSectionImplNoHdr::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(-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(-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 -bool DwarfSectionImpl::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::GetFdes(std::vector* 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); + } + } + + 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; } } - return false; } template -const DwarfFde* DwarfSectionImpl::GetFdeFromIndex(size_t index) { - if (index >= fdes_.size()) { - return nullptr; +const DwarfFde* DwarfSectionImplNoHdr::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; template class DwarfSectionImpl; +// Explicitly instantiate DwarfSectionImplNoHdr +template class DwarfSectionImplNoHdr; +template class DwarfSectionImplNoHdr; + // Explicitly instantiate DwarfDebugFrame template class DwarfDebugFrame; template class DwarfDebugFrame; diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h index 847f382ed..e9942decd 100644 --- a/libunwindstack/include/unwindstack/DwarfSection.h +++ b/libunwindstack/include/unwindstack/DwarfSection.h @@ -43,7 +43,12 @@ class DwarfSection { class iterator : public std::iterator { 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(-1)) { + index_ = fdes_.size(); + } + } iterator& operator++() { index_++; @@ -65,15 +70,18 @@ class DwarfSection { 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 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(-1)); } DwarfErrorCode LastErrorCode() { return last_error_.code; } uint64_t LastErrorAddress() { return last_error_.address; } @@ -82,15 +90,11 @@ class DwarfSection { 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* 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 @@ class DwarfSection { uint32_t cie32_value_ = 0; uint64_t cie64_value_ = 0; - uint64_t fde_count_ = 0; std::unordered_map fde_entries_; std::unordered_map cie_entries_; std::unordered_map cie_loc_regs_; @@ -119,55 +122,73 @@ class DwarfSection { template 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* 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 fdes_; - uint64_t entries_offset_; - uint64_t entries_end_; +template +class DwarfSectionImplNoHdr : public DwarfSectionImpl { + public: + // Add these so that the protected members of DwarfSectionImpl + // can be accessed without needing a this->. + using DwarfSectionImpl::memory_; + using DwarfSectionImpl::pc_offset_; + using DwarfSectionImpl::entries_offset_; + using DwarfSectionImpl::entries_end_; + using DwarfSectionImpl::last_error_; + using DwarfSectionImpl::load_bias_; + using DwarfSectionImpl::cie_entries_; + using DwarfSectionImpl::fde_entries_; + using DwarfSectionImpl::cie32_value_; + using DwarfSectionImpl::cie64_value_; + + DwarfSectionImplNoHdr(Memory* memory) : DwarfSectionImpl(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* fdes) override; + + protected: + bool GetNextCieOrFde(DwarfFde** fde_entry); + + void InsertFde(const DwarfFde* fde); + + uint64_t next_entries_offset_ = 0; + + std::map> fdes_; }; } // namespace unwindstack diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp index 3a5204463..d62093404 100644 --- a/libunwindstack/tests/DwarfDebugFrameTest.cpp +++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp @@ -16,7 +16,8 @@ #include -#include +#include + #include #include @@ -29,481 +30,378 @@ namespace unwindstack { -template -class MockDwarfDebugFrame : public DwarfDebugFrame { - public: - MockDwarfDebugFrame(Memory* memory) : DwarfDebugFrame(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::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::FdeInfo* info) { - *info = this->fdes_[index]; - } -}; - template class DwarfDebugFrameTest : public ::testing::Test { protected: void SetUp() override { memory_.Clear(); - debug_frame_ = new MockDwarfDebugFrame(&memory_); + debug_frame_ = new DwarfDebugFrame(&memory_); ResetLogs(); } void TearDown() override { delete debug_frame_; } MemoryFake memory_; - MockDwarfDebugFrame* debug_frame_ = nullptr; + DwarfDebugFrame* 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 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 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* 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* 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{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{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); - - this->memory_.SetData32(0x5500, 0xfc); - this->memory_.SetData32(0x5504, 0x300); - this->memory_.SetData32(0x5508, 0x4500); - this->memory_.SetData32(0x550c, 0x500); + SetFde32(memory, 0x5400, 0xfc, 0x300, 0x3500, 0x400); + SetFde32(memory, 0x5500, 0xfc, 0x300, 0x4500, 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::FdeInfo info(0, 0, 0); + std::vector 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 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 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); - - // 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); + ASSERT_EQ(3U, fdes.size()); +} +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::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::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{'z', 'R', 'P', 'L', '\0'}); - // Code alignment factor. - this->memory_.SetMemory(0x500e, std::vector{0x80, 0x00}); - // Data alignment factor. - this->memory_.SetMemory(0x5010, std::vector{0x81, 0x80, 0x80, 0x00}); - // Return address register - this->memory_.SetData8(0x5014, 0x84); - // Augmentation length - this->memory_.SetMemory(0x5015, std::vector{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::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{'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{0x80, 0x00}); - // Data alignment factor. - this->memory_.SetMemory(0x5012, std::vector{0x81, 0x80, 0x80, 0x00}); - // Return address register - this->memory_.SetMemory(0x5016, std::vector{0x85, 0x10}); - // Augmentation length - this->memory_.SetMemory(0x5018, std::vector{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::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::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{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{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 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 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 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{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, GetCieFde32) { } 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{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 @@ TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde64) { 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{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 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{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 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{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{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{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{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{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{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{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{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{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{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{/* 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{/* 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{/* 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 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{/* 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 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{/* 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 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{/* 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 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{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 DwarfDebugFrameTestTypes; INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes); diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp index e8d53e647..9cac6e8ee 100644 --- a/libunwindstack/tests/DwarfEhFrameTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameTest.cpp @@ -16,7 +16,6 @@ #include -#include #include #include @@ -29,51 +28,33 @@ namespace unwindstack { -template -class MockDwarfEhFrame : public DwarfEhFrame { - public: - MockDwarfEhFrame(Memory* memory) : DwarfEhFrame(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::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::FdeInfo* info) { - *info = this->fdes_[index]; - } -}; - template class DwarfEhFrameTest : public ::testing::Test { protected: void SetUp() override { memory_.Clear(); - eh_frame_ = new MockDwarfEhFrame(&memory_); + eh_frame_ = new DwarfEhFrame(&memory_); ResetLogs(); } void TearDown() override { delete eh_frame_; } MemoryFake memory_; - MockDwarfEhFrame* eh_frame_ = nullptr; + DwarfEhFrame* 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{1, '\0', 16, 32, 1}); // FDE 32 information. this->memory_.SetData32(0x5100, 0xfc); @@ -81,415 +62,70 @@ TYPED_TEST_P(DwarfEhFrameTest, Init32) { 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::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{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::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::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{'z', 'R', 'P', 'L', '\0'}); - // Code alignment factor. - this->memory_.SetMemory(0x500e, std::vector{0x80, 0x00}); - // Data alignment factor. - this->memory_.SetMemory(0x5010, std::vector{0x81, 0x80, 0x80, 0x00}); - // Return address register - this->memory_.SetData8(0x5014, 0x84); - // Augmentation length - this->memory_.SetMemory(0x5015, std::vector{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::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{'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{0x80, 0x00}); - // Data alignment factor. - this->memory_.SetMemory(0x5012, std::vector{0x81, 0x80, 0x80, 0x00}); - // Return address register - this->memory_.SetMemory(0x5016, std::vector{0x85, 0x10}); - // Augmentation length - this->memory_.SetMemory(0x5018, std::vector{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::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::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 DwarfEhFrameTestTypes; INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes); diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp index 19c7b98a2..910ae363b 100644 --- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp +++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp @@ -30,10 +30,10 @@ namespace unwindstack { template -class MockDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr { +class TestDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr { public: - MockDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr(memory) {} - ~MockDwarfEhFrameWithHdr() = default; + TestDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr(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 @@ class DwarfEhFrameWithHdrTest : public ::testing::Test { protected: void SetUp() override { memory_.Clear(); - eh_frame_ = new MockDwarfEhFrameWithHdr(&memory_); + eh_frame_ = new TestDwarfEhFrameWithHdr(&memory_); ResetLogs(); } void TearDown() override { delete eh_frame_; } MemoryFake memory_; - MockDwarfEhFrameWithHdr* eh_frame_ = nullptr; + TestDwarfEhFrameWithHdr* eh_frame_ = nullptr; }; TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest); @@ -121,23 +121,14 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias) { // 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{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 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias) { EXPECT_EQ(0x4700U, fde->pc_end); } +TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes) { + this->memory_.SetMemory( + 0x1000, std::vector{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{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 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 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde32) { // CIE 32 information. this->memory_.SetData32(0xf000, 0x100); this->memory_.SetData32(0xf004, 0); - this->memory_.SetData8(0xf008, 0x1); - this->memory_.SetData8(0xf009, '\0'); - this->memory_.SetData8(0xf00a, 4); - this->memory_.SetData8(0xf00b, 8); - this->memory_.SetData8(0xf00c, 0x20); + this->memory_.SetMemory(0xf008, std::vector{1, '\0', 4, 8, 0x20}); // FDE 32 information. this->memory_.SetData32(0x14000, 0x20); @@ -429,11 +478,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde64) { 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{1, '\0', 4, 8, 0x20}); // FDE 64 information. this->memory_.SetData32(0x8000, 0xffffffff); @@ -478,7 +523,7 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeFromPc_fde_not_found) { 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 414f2f248..46f555a6f 100644 --- a/libunwindstack/tests/DwarfSectionImplTest.cpp +++ b/libunwindstack/tests/DwarfSectionImplTest.cpp @@ -16,7 +16,6 @@ #include -#include #include #include @@ -31,42 +30,27 @@ namespace unwindstack { template -class MockDwarfSectionImpl : public DwarfSectionImpl { +class TestDwarfSectionImpl : public DwarfSectionImpl { public: - MockDwarfSectionImpl(Memory* memory) : DwarfSectionImpl(memory) {} - virtual ~MockDwarfSectionImpl() = default; + TestDwarfSectionImpl(Memory* memory) : DwarfSectionImpl(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*) 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 @@ class DwarfSectionImplTest : public ::testing::Test { protected: void SetUp() override { memory_.Clear(); - section_ = new MockDwarfSectionImpl(&memory_); + section_ = new TestDwarfSectionImpl(&memory_); ResetLogs(); - section_->TestSetCie32Value(static_cast(-1)); - section_->TestSetCie64Value(static_cast(-1)); } void TearDown() override { delete section_; } MemoryFake memory_; - MockDwarfSectionImpl* section_ = nullptr; + TestDwarfSectionImpl* 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 regs(10); @@ -487,334 +491,6 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) { 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{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{'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{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{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{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 @@ TYPED_TEST_P(DwarfSectionImplTest, Log) { 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 DwarfSectionImplTestTypes; INSTANTIATE_TYPED_TEST_CASE_P(, DwarfSectionImplTest, DwarfSectionImplTestTypes); diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp index 2c6c8790a..d754fcc50 100644 --- a/libunwindstack/tests/DwarfSectionTest.cpp +++ b/libunwindstack/tests/DwarfSectionTest.cpp @@ -30,24 +30,18 @@ class MockDwarfSection : public DwarfSection { 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*)); + + 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 MockDwarfSection : public DwarfSection { class DwarfSectionTest : public ::testing::Test { protected: + void SetUp() override { section_.reset(new MockDwarfSection(&memory_)); } + MemoryFake memory_; + std::unique_ptr 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 @@ static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde, } 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 487d39c87..aa6df8412 100644 --- a/libunwindstack/tests/ElfInterfaceTest.cpp +++ b/libunwindstack/tests/ElfInterfaceTest.cpp @@ -656,8 +656,7 @@ void ElfInterfaceTest::InitHeadersDebugFrame() { memory_.SetData32(0x5000, 0xfc); memory_.SetData32(0x5004, 0xffffffff); - memory_.SetData8(0x5008, 1); - memory_.SetData8(0x5009, '\0'); + memory_.SetMemory(0x5008, std::vector{1, '\0', 4, 8, 2}); memory_.SetData32(0x5100, 0xfc); memory_.SetData32(0x5104, 0); @@ -678,56 +677,6 @@ TEST_F(ElfInterfaceTest, init_headers_debug_frame64) { InitHeadersDebugFrame(); } -template -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(-1), elf.eh_frame_size()); - EXPECT_TRUE(elf.debug_frame() == nullptr); -} - -TEST_F(ElfInterfaceTest, init_headers_eh_frame32_fail) { - InitHeadersEhFrameFail(); -} - -TEST_F(ElfInterfaceTest, init_headers_eh_frame64_fail) { - InitHeadersEhFrameFail(); -} - -template -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(-1), elf.debug_frame_size()); -} - -TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) { - InitHeadersDebugFrameFail(); -} - -TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) { - InitHeadersDebugFrameFail(); -} - template void ElfInterfaceTest::InitSectionHeadersMalformed() { std::unique_ptr elf(new ElfInterfaceType(&memory_)); @@ -1024,11 +973,7 @@ TEST_F(ElfInterfaceTest, is_valid_pc_from_debug_frame) { // 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{1, '\0', 4, 4, 1}); // FDE 32. memory_.SetData32(0x700, 0xfc); @@ -1085,11 +1030,7 @@ TEST_F(ElfInterfaceTest, is_valid_pc_from_eh_frame) { // 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{1, '\0', 4, 4, 1}); // FDE 32. memory_.SetData32(0x700, 0xfc);