void EhFrame::moveInputFragments(EhFrame& pInFrame, CIE& pInCIE, CIE* pOutCIE) { SectionData& in_sd = *pInFrame.getSectionData(); SectionData::FragmentListType& in_frag_list = in_sd.getFragmentList(); SectionData& out_sd = *getSectionData(); SectionData::FragmentListType& out_frag_list = out_sd.getFragmentList(); if (!pOutCIE) { // Newly inserted Fragment* frag = in_frag_list.remove(SectionData::iterator(pInCIE)); out_frag_list.push_back(frag); frag->setParent(&out_sd); for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i) { frag = in_frag_list.remove(SectionData::iterator(**i)); out_frag_list.push_back(frag); frag->setParent(&out_sd); } return; } SectionData::iterator cur_iter(*pOutCIE); assert (cur_iter != out_frag_list.end()); for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i) { Fragment* frag = in_frag_list.remove(SectionData::iterator(**i)); cur_iter = out_frag_list.insertAfter(cur_iter, frag); frag->setParent(&out_sd); } }
void EhFrame::setupAttributes(const LDSection* rel_sec) { for (cie_iterator i = cie_begin(), e = cie_end(); i != e; ++i) { CIE* cie = *i; removeDiscardedFDE(*cie, rel_sec); if (cie->getPersonalityName().size() == 0) { // There's no personality data encoding inside augmentation string. cie->setMergeable(); } else { if (!rel_sec) { // No relocation to eh_frame section assert (cie->getPersonalityName() != "" && "PR name should be a symbol address or offset"); continue; } const RelocData* reloc_data = rel_sec->getRelocData(); for (RelocData::const_iterator ri = reloc_data->begin(), re = reloc_data->end(); ri != re; ++ri) { const Relocation& rel = *ri; if (rel.targetRef().getOutputOffset() == cie->getOffset() + cie->getPersonalityOffset()) { cie->setMergeable(); cie->setPersonalityName(rel.symInfo()->outSymbol()->name()); cie->setRelocation(rel); break; } } assert (cie->getPersonalityName() != "" && "PR name should be a symbol address or offset"); } } }
void EhFrame::removeDiscardedFDE(CIE& pCIE, const LDSection* pRelocSect) { if (!pRelocSect) return; typedef std::vector<FDE*> FDERemoveList; FDERemoveList to_be_removed_fdes; const RelocData* reloc_data = pRelocSect->getRelocData(); for (fde_iterator i = pCIE.begin(), e = pCIE.end(); i != e; ++i) { FDE& fde = **i; for (RelocData::const_iterator ri = reloc_data->begin(), re = reloc_data->end(); ri != re; ++ri) { const Relocation& rel = *ri; if (rel.targetRef().getOutputOffset() == fde.getOffset() + getDataStartOffset<32>()) { bool has_section = rel.symInfo()->outSymbol()->hasFragRef(); if (!has_section) // The section was discarded, just ignore this FDE. // This may happen when redundant group section was read. to_be_removed_fdes.push_back(&fde); break; } } } for (FDERemoveList::iterator i = to_be_removed_fdes.begin(), e = to_be_removed_fdes.end(); i != e; ++i) { FDE& fde = **i; fde.getCIE().remove(fde); // FIXME: This traverses relocations from the beginning on each FDE, which // may cause performance degration. Actually relocations will be sequential // order, so we can bookkeep the previously found relocation for next use. // Note: We must ensure FDE order is ordered. for (RelocData::const_iterator ri = reloc_data->begin(), re = reloc_data->end(); ri != re;) { Relocation& rel = const_cast<Relocation&>(*ri++); if (rel.targetRef().getOutputOffset() >= fde.getOffset() && rel.targetRef().getOutputOffset() < fde.getOffset() + fde.size()) { const_cast<RelocData*>(reloc_data)->remove(rel); } } } }
void EhFrame::removeAndUpdateCIEForFDE(EhFrame& pInFrame, CIE& pInCIE, CIE& pOutCIE, const LDSection* rel_sect) { // Make this relocation to be ignored. Relocation* rel = const_cast<Relocation*>(pInCIE.getRelocation()); if (rel && rel_sect) const_cast<RelocData*>(rel_sect->getRelocData())->remove(*rel); // Update the CIE-pointed FDEs for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i) (*i)->setCIE(pOutCIE); // We cannot know whether there are references to this fragment, so just // keep it in input fragment list instead of memory deallocation pInCIE.clearFDEs(); }
void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; DenseMap<uint32_t, CIE *> CIEs; while (Data.isValidOffset(Offset)) { uint32_t StartOffset = Offset; auto ReportError = [StartOffset](const char *ErrorMsg) { std::string Str; raw_string_ostream OS(Str); OS << format(ErrorMsg, StartOffset); OS.flush(); report_fatal_error(Str); }; bool IsDWARF64 = false; uint64_t Length = Data.getU32(&Offset); uint64_t Id; if (Length == UINT32_MAX) { // DWARF-64 is distinguished by the first 32 bits of the initial length // field being 0xffffffff. Then, the next 64 bits are the actual entry // length. IsDWARF64 = true; Length = Data.getU64(&Offset); } // At this point, Offset points to the next field after Length. // Length is the structure size excluding itself. Compute an offset one // past the end of the structure (needed to know how many instructions to // read). // TODO: For honest DWARF64 support, DataExtractor will have to treat // offset_ptr as uint64_t* uint32_t StartStructureOffset = Offset; uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length); // The Id field's size depends on the DWARF format Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4); bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID || (IsEH && !Id)); if (IsCIE) { uint8_t Version = Data.getU8(&Offset); const char *Augmentation = Data.getCStr(&Offset); StringRef AugmentationString(Augmentation ? Augmentation : ""); uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset); Data.setAddressSize(AddressSize); uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset); uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); // Parse the augmentation data for EH CIEs StringRef AugmentationData(""); uint32_t FDEPointerEncoding = DW_EH_PE_omit; uint32_t LSDAPointerEncoding = DW_EH_PE_omit; if (IsEH) { Optional<uint32_t> PersonalityEncoding; Optional<uint64_t> Personality; Optional<uint64_t> AugmentationLength; uint32_t StartAugmentationOffset; uint32_t EndAugmentationOffset; // Walk the augmentation string to get all the augmentation data. for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) { switch (AugmentationString[i]) { default: ReportError("Unknown augmentation character in entry at %lx"); case 'L': LSDAPointerEncoding = Data.getU8(&Offset); break; case 'P': { if (Personality) ReportError("Duplicate personality in entry at %lx"); PersonalityEncoding = Data.getU8(&Offset); Personality = readPointer(Data, Offset, *PersonalityEncoding); break; } case 'R': FDEPointerEncoding = Data.getU8(&Offset); break; case 'z': if (i) ReportError("'z' must be the first character at %lx"); // Parse the augmentation length first. We only parse it if // the string contains a 'z'. AugmentationLength = Data.getULEB128(&Offset); StartAugmentationOffset = Offset; EndAugmentationOffset = Offset + static_cast<uint32_t>(*AugmentationLength); } } if (AugmentationLength.hasValue()) { if (Offset != EndAugmentationOffset) ReportError("Parsing augmentation data at %lx failed"); AugmentationData = Data.getData().slice(StartAugmentationOffset, EndAugmentationOffset); } } auto Cie = make_unique<CIE>(StartOffset, Length, Version, AugmentationString, AddressSize, SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor, ReturnAddressRegister, AugmentationData, FDEPointerEncoding, LSDAPointerEncoding); CIEs[StartOffset] = Cie.get(); Entries.emplace_back(std::move(Cie)); } else { // FDE uint64_t CIEPointer = Id; uint64_t InitialLocation = 0; uint64_t AddressRange = 0; CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer]; if (IsEH) { // The address size is encoded in the CIE we reference. if (!Cie) ReportError("Parsing FDE data at %lx failed due to missing CIE"); InitialLocation = readPointer(Data, Offset, Cie->getFDEPointerEncoding()); AddressRange = readPointer(Data, Offset, Cie->getFDEPointerEncoding()); StringRef AugmentationString = Cie->getAugmentationString(); if (!AugmentationString.empty()) { // Parse the augmentation length and data for this FDE. uint64_t AugmentationLength = Data.getULEB128(&Offset); uint32_t EndAugmentationOffset = Offset + static_cast<uint32_t>(AugmentationLength); // Decode the LSDA if the CIE augmentation string said we should. if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) readPointer(Data, Offset, Cie->getLSDAPointerEncoding()); if (Offset != EndAugmentationOffset) ReportError("Parsing augmentation data at %lx failed"); } } else { InitialLocation = Data.getAddress(&Offset); AddressRange = Data.getAddress(&Offset); } Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer, InitialLocation, AddressRange, Cie)); } Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset); if (Offset != EndStructureOffset) ReportError("Parsing entry instructions at %lx failed"); } }