diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFContext.cpp | 20 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp | 182 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/PDB/PDBContext.cpp | 3 |
3 files changed, 186 insertions, 19 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index a4195b75c47..6aa4675630f 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -72,7 +72,7 @@ static void dumpAccelSection(raw_ostream &OS, StringRef Name, Accel.dump(OS); } -void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { +void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) { if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { OS << ".debug_abbrev contents:\n"; getDebugAbbrev()->dump(OS); @@ -125,6 +125,10 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { if (DumpType == DIDT_All || DumpType == DIDT_Frames) { OS << "\n.debug_frame contents:\n"; getDebugFrame()->dump(OS); + if (DumpEH) { + OS << "\n.eh_frame contents:\n"; + getEHFrame()->dump(OS); + } } if (DumpType == DIDT_All || DumpType == DIDT_Macro) { @@ -355,7 +359,18 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() { // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html DataExtractor debugFrameData(getDebugFrameSection(), isLittleEndian(), getAddressSize()); - DebugFrame.reset(new DWARFDebugFrame()); + DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */)); + DebugFrame->parse(debugFrameData); + return DebugFrame.get(); +} + +const DWARFDebugFrame *DWARFContext::getEHFrame() { + if (EHFrame) + return EHFrame.get(); + + DataExtractor debugFrameData(getEHFrameSection(), isLittleEndian(), + getAddressSize()); + DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */)); DebugFrame->parse(debugFrameData); return DebugFrame.get(); } @@ -641,6 +656,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, .Case("debug_line", &LineSection.Data) .Case("debug_aranges", &ARangeSection) .Case("debug_frame", &DebugFrameSection) + .Case("eh_frame", &EHFrameSection) .Case("debug_str", &StringSection) .Case("debug_ranges", &RangeSection) .Case("debug_macinfo", &MacinfoSection) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index 72dc95e977a..366fad411a9 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DataTypes.h" @@ -199,19 +200,31 @@ public: CIE(uint64_t Offset, uint64_t Length, uint8_t Version, SmallString<8> Augmentation, uint8_t AddressSize, uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor, - int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister) + int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister, + SmallString<8> AugmentationData, Optional<uint32_t> FDEPointerEncoding, + Optional<uint32_t> LSDAPointerEncoding) : FrameEntry(FK_CIE, Offset, Length), Version(Version), Augmentation(std::move(Augmentation)), AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize), CodeAlignmentFactor(CodeAlignmentFactor), DataAlignmentFactor(DataAlignmentFactor), - ReturnAddressRegister(ReturnAddressRegister) {} + ReturnAddressRegister(ReturnAddressRegister), + AugmentationData(AugmentationData), + FDEPointerEncoding(FDEPointerEncoding), + LSDAPointerEncoding(LSDAPointerEncoding) { } ~CIE() override {} + StringRef getAugmentationString() const { return Augmentation; } uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; } int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; } + Optional<uint32_t> getFDEPointerEncoding() const { + return FDEPointerEncoding; + } + Optional<uint32_t> getLSDAPointerEncoding() const { + return LSDAPointerEncoding; + } void dumpHeader(raw_ostream &OS) const override { OS << format("%08x %08x %08x CIE", @@ -231,6 +244,8 @@ public: (int32_t)DataAlignmentFactor); OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister); + if (!AugmentationData.empty()) + OS << " Augmentation data: " << AugmentationData << "\n"; OS << "\n"; } @@ -247,6 +262,11 @@ private: uint64_t CodeAlignmentFactor; int64_t DataAlignmentFactor; uint64_t ReturnAddressRegister; + + // The following are used when the CIE represents an EH frame entry. + SmallString<8> AugmentationData; + Optional<uint32_t> FDEPointerEncoding; + Optional<uint32_t> LSDAPointerEncoding; }; @@ -431,7 +451,7 @@ void FrameEntry::dumpInstructions(raw_ostream &OS) const { } } -DWARFDebugFrame::DWARFDebugFrame() { +DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) { } DWARFDebugFrame::~DWARFDebugFrame() { @@ -447,6 +467,39 @@ static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data, errs() << "\n"; } +static unsigned getSizeForEncoding(const DataExtractor &Data, + unsigned symbolEncoding) { + unsigned format = symbolEncoding & 0x0f; + switch (format) { + default: llvm_unreachable("Unknown Encoding"); + case dwarf::DW_EH_PE_absptr: + case dwarf::DW_EH_PE_signed: + return Data.getAddressSize(); + case dwarf::DW_EH_PE_udata2: + case dwarf::DW_EH_PE_sdata2: + return 2; + case dwarf::DW_EH_PE_udata4: + case dwarf::DW_EH_PE_sdata4: + return 4; + case dwarf::DW_EH_PE_udata8: + case dwarf::DW_EH_PE_sdata8: + return 8; + } +} + +static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset, + unsigned Encoding) { + switch (getSizeForEncoding(Data, Encoding)) { + case 2: + return Data.getU16(&Offset); + case 4: + return Data.getU32(&Offset); + case 8: + return Data.getU64(&Offset); + default: + llvm_unreachable("Illegal data size"); + } +} void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; @@ -455,6 +508,14 @@ void DWARFDebugFrame::parse(DataExtractor Data) { 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; @@ -473,47 +534,136 @@ void DWARFDebugFrame::parse(DataExtractor Data) { // 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 ? 8 : 4); - bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID); + 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); - uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&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; + Optional<uint32_t> FDEPointerEncoding; + Optional<uint32_t> LSDAPointerEncoding; + if (IsEH) { + Optional<uint32_t> PersonalityEncoding; + Optional<uint64_t> Personality; + + uint64_t AugmentationLength = 0; + uint32_t StartAugmentationOffset = 0; + uint32_t EndAugmentationOffset = 0; + + // 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': + if (LSDAPointerEncoding) + ReportError("Duplicate LSDA encoding in entry at %lx"); + 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': + if (FDEPointerEncoding) + ReportError("Duplicate FDE encoding in entry at %lx"); + 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 (Offset != EndAugmentationOffset) + ReportError("Parsing augmentation data at %lx failed"); + + AugmentationData = Data.getData().slice(StartAugmentationOffset, + EndAugmentationOffset); + } + auto Cie = make_unique<CIE>(StartOffset, Length, Version, StringRef(Augmentation), AddressSize, SegmentDescriptorSize, CodeAlignmentFactor, - DataAlignmentFactor, ReturnAddressRegister); + DataAlignmentFactor, ReturnAddressRegister, + AugmentationData, FDEPointerEncoding, + LSDAPointerEncoding); CIEs[StartOffset] = Cie.get(); Entries.emplace_back(std::move(Cie)); } else { // FDE uint64_t CIEPointer = Id; - uint64_t InitialLocation = Data.getAddress(&Offset); - uint64_t AddressRange = Data.getAddress(&Offset); + 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"); + + Optional<uint32_t> FDEPointerEncoding = Cie->getFDEPointerEncoding(); + if (!FDEPointerEncoding) + ReportError("Parsing at %lx failed due to missing pointer encoding"); + + InitialLocation = readPointer(Data, Offset, *FDEPointerEncoding); + AddressRange = readPointer(Data, Offset, *FDEPointerEncoding); + 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. + uint64_t LSDA = 0; + if (Optional<uint32_t> Encoding = Cie->getLSDAPointerEncoding()) + LSDA = readPointer(Data, Offset, *Encoding); + + 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, - CIEs[CIEPointer])); + Cie)); } Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset); - if (Offset != EndStructureOffset) { - std::string Str; - raw_string_ostream OS(Str); - OS << format("Parsing entry instructions at %lx failed", StartOffset); - report_fatal_error(Str); - } + if (Offset != EndStructureOffset) + ReportError("Parsing entry instructions at %lx failed"); } } diff --git a/llvm/lib/DebugInfo/PDB/PDBContext.cpp b/llvm/lib/DebugInfo/PDB/PDBContext.cpp index ca2ae6665ce..561a91ea08b 100644 --- a/llvm/lib/DebugInfo/PDB/PDBContext.cpp +++ b/llvm/lib/DebugInfo/PDB/PDBContext.cpp @@ -28,7 +28,8 @@ PDBContext::PDBContext(const COFFObjectFile &Object, Session->setLoadAddress(ImageBase.get()); } -void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType) {} +void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType, + bool DumpEH) {} DILineInfo PDBContext::getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { |