Index: include/llvm/DebugInfo/DIContext.h =================================================================== --- include/llvm/DebugInfo/DIContext.h +++ include/llvm/DebugInfo/DIContext.h @@ -140,7 +140,8 @@ DIContext(DIContextKind K) : Kind(K) {} virtual ~DIContext() {} - virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) = 0; + virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) = 0; virtual DILineInfo getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; Index: include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFContext.h +++ include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -48,6 +48,7 @@ std::unique_ptr Aranges; std::unique_ptr Line; std::unique_ptr DebugFrame; + std::unique_ptr DebugEHFrame; std::unique_ptr Macro; DWARFUnitSection DWOCUs; @@ -81,7 +82,8 @@ return DICtx->getKind() == CK_DWARF; } - void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override; + void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) override; typedef DWARFUnitSection::iterator_range cu_iterator_range; typedef DWARFUnitSection::iterator_range tu_iterator_range; @@ -168,6 +170,9 @@ /// Get a pointer to the parsed frame information object. const DWARFDebugFrame *getDebugFrame(); + /// Get a pointer to the parsed eh frame information object. + const DWARFDebugFrame *getDebugEHFrame(); + /// Get a pointer to the parsed DebugMacro object. const DWARFDebugMacro *getDebugMacro(); @@ -191,6 +196,7 @@ virtual const DWARFSection &getLocSection() = 0; virtual StringRef getARangeSection() = 0; virtual StringRef getDebugFrameSection() = 0; + virtual StringRef getDebugEHFrameSection() = 0; virtual const DWARFSection &getLineSection() = 0; virtual StringRef getStringSection() = 0; virtual StringRef getRangeSection() = 0; @@ -242,6 +248,7 @@ DWARFSection LocSection; StringRef ARangeSection; StringRef DebugFrameSection; + StringRef DebugEHFrameSection; DWARFSection LineSection; StringRef StringSection; StringRef RangeSection; @@ -281,6 +288,7 @@ const DWARFSection &getLocSection() override { return LocSection; } StringRef getARangeSection() override { return ARangeSection; } StringRef getDebugFrameSection() override { return DebugFrameSection; } + StringRef getDebugEHFrameSection() override { return DebugEHFrameSection; } const DWARFSection &getLineSection() override { return LineSection; } StringRef getStringSection() override { return StringSection; } StringRef getRangeSection() override { return RangeSection; } Index: include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -19,11 +19,13 @@ class FrameEntry; -/// \brief A parsed .debug_frame section + /// \brief A parsed .debug_frame or .eh_frame section /// class DWARFDebugFrame { + // True if this is parsing an eh_frame section. + bool IsEH; public: - DWARFDebugFrame(); + DWARFDebugFrame(bool IsEH); ~DWARFDebugFrame(); /// \brief Dump the section data into the given stream. Index: include/llvm/DebugInfo/PDB/PDBContext.h =================================================================== --- include/llvm/DebugInfo/PDB/PDBContext.h +++ include/llvm/DebugInfo/PDB/PDBContext.h @@ -38,7 +38,8 @@ return DICtx->getKind() == CK_PDB; } - void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override; + void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) override; DILineInfo getLineInfoForAddress( uint64_t Address, Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -72,7 +72,7 @@ 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 @@ if (DumpType == DIDT_All || DumpType == DIDT_Frames) { OS << "\n.debug_frame contents:\n"; getDebugFrame()->dump(OS); + if (DumpEH) { + OS << "\n.eh_frame contents:\n"; + getDebugEHFrame()->dump(OS); + } } if (DumpType == DIDT_All || DumpType == DIDT_Macro) { @@ -355,7 +359,27 @@ // 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::getDebugEHFrame() { + if (DebugEHFrame) + return DebugEHFrame.get(); + + // There's a "bug" in the DWARFv3 standard with respect to the target address + // size within debug frame sections. While DWARF is supposed to be independent + // of its container, FDEs have fields with size being "target address size", + // which isn't specified in DWARF in general. It's only specified for CUs, but + // .eh_frame can appear without a .debug_info section. Follow the example of + // other tools (libdwarf) and extract this from the container (ObjectFile + // provides this information). This problem is fixed in DWARFv4 + // See this dwarf-discuss discussion for more details: + // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html + DataExtractor debugFrameData(getDebugEHFrameSection(), isLittleEndian(), + getAddressSize()); + DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */)); DebugFrame->parse(debugFrameData); return DebugFrame.get(); } @@ -641,6 +665,7 @@ .Case("debug_line", &LineSection.Data) .Case("debug_aranges", &ARangeSection) .Case("debug_frame", &DebugFrameSection) + .Case("eh_frame", &DebugEHFrameSection) .Case("debug_str", &StringSection) .Case("debug_ranges", &RangeSection) .Case("debug_macinfo", &MacinfoSection) Index: lib/DebugInfo/DWARF/DWARFDebugFrame.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ 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" @@ -191,19 +192,31 @@ 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 FDEPointerEncoding, + Optional 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 getFDEPointerEncoding() const { + return FDEPointerEncoding; + } + Optional getLSDAPointerEncoding() const { + return LSDAPointerEncoding; + } void dumpHeader(raw_ostream &OS) const override { OS << format("%08x %08x %08x CIE", @@ -223,6 +236,8 @@ (int32_t)DataAlignmentFactor); OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister); + if (!AugmentationData.empty()) + OS << " Augmentation data: " << AugmentationData << "\n"; OS << "\n"; } @@ -239,6 +254,11 @@ 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 FDEPointerEncoding; + Optional LSDAPointerEncoding; }; @@ -423,7 +443,7 @@ } } -DWARFDebugFrame::DWARFDebugFrame() { +DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) { } DWARFDebugFrame::~DWARFDebugFrame() { @@ -439,6 +459,39 @@ 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; @@ -447,6 +500,14 @@ 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; @@ -465,15 +526,22 @@ // 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(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); + StringRef AugmentationString(Augmentation ? Augmentation : ""); + uint64_t EHData = 0; + if (AugmentationString.count("eh")) + EHData = Data.getAddress(&Offset); uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : Data.getU8(&Offset); Data.setAddressSize(AddressSize); uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset); @@ -481,31 +549,122 @@ int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); + // Parse the augmentation data for EH CIEs + StringRef AugmentationData; + Optional FDEPointerEncoding; + Optional LSDAPointerEncoding; + if (IsEH && StringRef(Augmentation).startswith("z")) { + Optional PersonalityEncoding; + Optional Personality; + + uint64_t AugmentationLength = Data.getULEB128(&Offset); + + uint32_t StartAugmentationOffset = Offset; + uint32_t EndAugmentationOffset = + Offset + static_cast(AugmentationLength); + + // Walk the augmentation string to get all the augmentation data. + for (unsigned i = 1, e = AugmentationString.size(); i != e; ++i) { + char Char = AugmentationString[i]; + switch (Char) { + case 'e': + if ((i + 1) == e || AugmentationString[i + 1] != 'h') + ReportError( + "Expected 'eh' in augmentation string in entry at %lx"); + // Skip the 'h'. + ++i; + break; + 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': + ReportError( + "'z' must be first in the augmentation string in entry at %lx"); + } + } + + if (Offset != EndAugmentationOffset) + ReportError("Parsing augmentation data at %lx failed"); + + AugmentationData = Data.getData().slice(StartAugmentationOffset, + EndAugmentationOffset); + } + auto Cie = make_unique(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 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.count('z')) { + // Parse the augmentation length and data for this FDE. + uint64_t AugmentationLength = Data.getULEB128(&Offset); + + uint32_t EndAugmentationOffset = + Offset + static_cast(AugmentationLength); + + // Decode the LSDA if the CIE augmentation string said we should. + uint64_t LSDA = 0; + if (AugmentationString.count('L')) { + Optional Encoding = Cie->getLSDAPointerEncoding(); + if (!Encoding) + ReportError("Parsing at %lx failed " + "due to missing pointer encoding"); + 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"); } } Index: lib/DebugInfo/PDB/PDBContext.cpp =================================================================== --- lib/DebugInfo/PDB/PDBContext.cpp +++ lib/DebugInfo/PDB/PDBContext.cpp @@ -28,7 +28,8 @@ 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) { Index: test/tools/llvm-objdump/eh_frame-arm64.test =================================================================== --- test/tools/llvm-objdump/eh_frame-arm64.test +++ test/tools/llvm-objdump/eh_frame-arm64.test @@ -1,23 +1,23 @@ # RUN: llvm-objdump -unwind-info %p/Inputs/eh_frame.macho-arm64 2>/dev/null | FileCheck %s -# CHECK: Contents of __eh_frame section: -# CHECK: CIE: -# CHECK: Length: 16 -# CHECK: CIE ID: 0 -# CHECK: Version: 1 -# CHECK: Augmentation String: zR -# CHECK: Code Alignment Factor: 1 -# CHECK: Data Alignment Factor: -8 -# CHECK: Return Address Register: 30 -# CHECK: Augmentation Data Length: 1 -# CHECK: FDE Address Pointer Encoding: 16 -# CHECK: Instructions: -# CHECK: 0c 1f 00 -# CHECK: FDE: -# CHECK: Length: 32 -# CHECK: CIE Offset: 0 -# CHECK: PC Begin: ffffffffffffffe4 -# CHECK: PC Range: 0000000000000020 -# CHECK: Augmentation Data Length: 0 -# CHECK: Instructions: -# CHECK: 48 0e 10 9e 01 9d 02 00 00 00 00 +# CHECK: .eh_frame contents: + +# CHECK: 00000000 00000010 ffffffff CIE +# CHECK: Version: 1 +# CHECK: Augmentation: "zR" +# CHECK: Code alignment factor: 1 +# CHECK: Data alignment factor: -8 +# CHECK: Return address column: 30 +# CHECK: Augmentation data: + +# CHECK: DW_CFA_def_cfa: reg31 +0 + +# CHECK: 00000014 00000020 00000018 FDE cie=00000018 pc=ffffffe4...00000004 +# CHECK: DW_CFA_advance_loc: 8 +# CHECK: DW_CFA_def_cfa_offset: +16 +# CHECK: DW_CFA_offset: reg30 -8 +# CHECK: DW_CFA_offset: reg29 -16 +# CHECK: DW_CFA_nop: +# CHECK: DW_CFA_nop: +# CHECK: DW_CFA_nop: +# CHECK: DW_CFA_nop: Index: tools/llvm-objdump/MachODump.cpp =================================================================== --- tools/llvm-objdump/MachODump.cpp +++ tools/llvm-objdump/MachODump.cpp @@ -1213,6 +1213,12 @@ printLazyBindTable(MachOOF); if (WeakBind) printWeakBindTable(MachOOF); + + if (DwarfDumpType != DIDT_Null) { + std::unique_ptr DICtx(new DWARFContextInMemory(*MachOOF)); + // Dump the complete DWARF structure. + DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */); + } } // printUnknownCPUType() helps print_fat_headers for unknown CPU's. @@ -6751,262 +6757,6 @@ } } -static unsigned getSizeForEncoding(bool is64Bit, - 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 is64Bit ? 8 : 4; - 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 char *&Pos, bool is64Bit, unsigned Encoding) { - switch (getSizeForEncoding(is64Bit, Encoding)) { - case 2: - return readNext(Pos); - break; - case 4: - return readNext(Pos); - break; - case 8: - return readNext(Pos); - break; - default: - llvm_unreachable("Illegal data size"); - } -} - -static void printMachOEHFrameSection(const MachOObjectFile *Obj, - std::map &Symbols, - const SectionRef &EHFrame) { - if (!Obj->isLittleEndian()) { - outs() << "warning: cannot handle big endian __eh_frame section\n"; - return; - } - - bool is64Bit = Obj->is64Bit(); - - outs() << "Contents of __eh_frame section:\n"; - - StringRef Contents; - EHFrame.getContents(Contents); - - /// A few fields of the CIE are used when decoding the FDE's. This struct - /// will cache those fields we need so that we don't have to decode it - /// repeatedly for each FDE that references it. - struct DecodedCIE { - Optional FDEPointerEncoding; - Optional LSDAPointerEncoding; - bool hasAugmentationLength; - }; - - // Map from the start offset of the CIE to the cached data for that CIE. - DenseMap CachedCIEs; - - for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) { - - const char *EntryStartPos = Pos; - - uint64_t Length = readNext(Pos); - if (Length == 0xffffffff) - Length = readNext(Pos); - - // Save the Pos so that we can check the length we encoded against what we - // end up decoding. - const char *PosAfterLength = Pos; - const char *EntryEndPos = PosAfterLength + Length; - - assert(EntryEndPos <= End && - "__eh_frame entry length exceeds section size"); - - uint32_t ID = readNext(Pos); - if (ID == 0) { - // This is a CIE. - - uint32_t Version = readNext(Pos); - - // Parse a null terminated augmentation string - SmallString<8> AugmentationString; - for (uint8_t Char = readNext(Pos); Char; - Char = readNext(Pos)) - AugmentationString.push_back(Char); - - // Optionally parse the EH data if the augmentation string says it's there. - Optional EHData; - if (StringRef(AugmentationString).count("eh")) - EHData = is64Bit ? readNext(Pos) : readNext(Pos); - - unsigned ULEBByteCount; - uint64_t CodeAlignmentFactor = decodeULEB128((const uint8_t *)Pos, - &ULEBByteCount); - Pos += ULEBByteCount; - - int64_t DataAlignmentFactor = decodeSLEB128((const uint8_t *)Pos, - &ULEBByteCount); - Pos += ULEBByteCount; - - uint32_t ReturnAddressRegister = readNext(Pos); - - Optional AugmentationLength; - Optional LSDAPointerEncoding; - Optional PersonalityEncoding; - Optional Personality; - Optional FDEPointerEncoding; - if (!AugmentationString.empty() && AugmentationString.front() == 'z') { - AugmentationLength = decodeULEB128((const uint8_t *)Pos, - &ULEBByteCount); - Pos += ULEBByteCount; - - // Walk the augmentation string to get all the augmentation data. - for (unsigned i = 1, e = AugmentationString.size(); i != e; ++i) { - char Char = AugmentationString[i]; - switch (Char) { - case 'e': - assert((i + 1) != e && AugmentationString[i + 1] == 'h' && - "Expected 'eh' in augmentation string"); - break; - case 'L': - assert(!LSDAPointerEncoding && "Duplicate LSDA encoding"); - LSDAPointerEncoding = readNext(Pos); - break; - case 'P': { - assert(!Personality && "Duplicate personality"); - PersonalityEncoding = readNext(Pos); - Personality = readPointer(Pos, is64Bit, *PersonalityEncoding); - break; - } - case 'R': - assert(!FDEPointerEncoding && "Duplicate FDE encoding"); - FDEPointerEncoding = readNext(Pos); - break; - case 'z': - llvm_unreachable("'z' must be first in the augmentation string"); - } - } - } - - outs() << "CIE:\n"; - outs() << " Length: " << Length << "\n"; - outs() << " CIE ID: " << ID << "\n"; - outs() << " Version: " << Version << "\n"; - outs() << " Augmentation String: " << AugmentationString << "\n"; - if (EHData) - outs() << " EHData: " << *EHData << "\n"; - outs() << " Code Alignment Factor: " << CodeAlignmentFactor << "\n"; - outs() << " Data Alignment Factor: " << DataAlignmentFactor << "\n"; - outs() << " Return Address Register: " << ReturnAddressRegister << "\n"; - if (AugmentationLength) { - outs() << " Augmentation Data Length: " << *AugmentationLength << "\n"; - if (LSDAPointerEncoding) { - outs() << " FDE LSDA Pointer Encoding: " - << *LSDAPointerEncoding << "\n"; - } - if (Personality) { - outs() << " Personality Encoding: " << *PersonalityEncoding << "\n"; - outs() << " Personality: " << *Personality << "\n"; - } - if (FDEPointerEncoding) { - outs() << " FDE Address Pointer Encoding: " - << *FDEPointerEncoding << "\n"; - } - } - // FIXME: Handle instructions. - // For now just emit some bytes - outs() << " Instructions:\n "; - dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos), - outs()); - outs() << "\n"; - Pos = EntryEndPos; - - // Cache this entry. - uint64_t Offset = EntryStartPos - Contents.data(); - CachedCIEs[Offset] = { FDEPointerEncoding, LSDAPointerEncoding, - AugmentationLength.hasValue() }; - continue; - } - - // This is an FDE. - // The CIE pointer for an FDE is the same location as the ID which we - // already read. - uint32_t CIEPointer = ID; - - const char *CIEStart = PosAfterLength - CIEPointer; - assert(CIEStart >= Contents.data() && - "FDE points to CIE before the __eh_frame start"); - - uint64_t CIEOffset = CIEStart - Contents.data(); - auto CIEIt = CachedCIEs.find(CIEOffset); - if (CIEIt == CachedCIEs.end()) - llvm_unreachable("Couldn't find CIE at offset in to __eh_frame section"); - - const DecodedCIE &CIE = CIEIt->getSecond(); - assert(CIE.FDEPointerEncoding && - "FDE references CIE which did not set pointer encoding"); - - uint64_t PCPointerSize = getSizeForEncoding(is64Bit, - *CIE.FDEPointerEncoding); - - uint64_t PCBegin = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding); - uint64_t PCRange = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding); - - Optional AugmentationLength; - uint32_t LSDAPointerSize; - Optional LSDAPointer; - if (CIE.hasAugmentationLength) { - unsigned ULEBByteCount; - AugmentationLength = decodeULEB128((const uint8_t *)Pos, - &ULEBByteCount); - Pos += ULEBByteCount; - - // Decode the LSDA if the CIE augmentation string said we should. - if (CIE.LSDAPointerEncoding) { - LSDAPointerSize = getSizeForEncoding(is64Bit, *CIE.LSDAPointerEncoding); - LSDAPointer = readPointer(Pos, is64Bit, *CIE.LSDAPointerEncoding); - } - } - - outs() << "FDE:\n"; - outs() << " Length: " << Length << "\n"; - outs() << " CIE Offset: " << CIEOffset << "\n"; - - if (PCPointerSize == 8) { - outs() << format(" PC Begin: %016" PRIx64, PCBegin) << "\n"; - outs() << format(" PC Range: %016" PRIx64, PCRange) << "\n"; - } else { - outs() << format(" PC Begin: %08" PRIx64, PCBegin) << "\n"; - outs() << format(" PC Range: %08" PRIx64, PCRange) << "\n"; - } - if (AugmentationLength) { - outs() << " Augmentation Data Length: " << *AugmentationLength << "\n"; - if (LSDAPointer) { - if (LSDAPointerSize == 8) - outs() << format(" LSDA Pointer: %016\n" PRIx64, *LSDAPointer); - else - outs() << format(" LSDA Pointer: %08\n" PRIx64, *LSDAPointer); - } - } - - // FIXME: Handle instructions. - // For now just emit some bytes - outs() << " Instructions:\n "; - dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos), - outs()); - outs() << "\n"; - Pos = EntryEndPos; - } -} - void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) { std::map Symbols; for (const SymbolRef &SymRef : Obj->symbols()) { @@ -7027,8 +6777,15 @@ printMachOCompactUnwindSection(Obj, Symbols, Section); else if (SectName == "__unwind_info") printMachOUnwindInfoSection(Obj, Symbols, Section); - else if (SectName == "__eh_frame") - printMachOEHFrameSection(Obj, Symbols, Section); + else if (SectName == "__eh_frame") { + // If the Dwarf dump type is not going to dump the debug info, then + // we'll just print it from here. + if (DwarfDumpType != DIDT_Frames) { + std::unique_ptr DICtx(new DWARFContextInMemory(*Obj)); + // Dump the frames DWARF structure. + DICtx->dump(outs(), DIDT_Frames, true /* DumpEH */); + } + } } } Index: tools/llvm-objdump/llvm-objdump.h =================================================================== --- tools/llvm-objdump/llvm-objdump.h +++ tools/llvm-objdump/llvm-objdump.h @@ -10,6 +10,7 @@ #define LLVM_TOOLS_LLVM_OBJDUMP_LLVM_OBJDUMP_H #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DataTypes.h" @@ -53,6 +54,7 @@ extern cl::opt SymbolTable; extern cl::opt UnwindInfo; extern cl::opt PrintImmHex; +extern cl::opt DwarfDumpType; // Various helper functions. void error(std::error_code ec); Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -22,6 +22,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/CodeGen/FaultMaps.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" @@ -176,6 +177,40 @@ cl::opt PrintFaultMaps("fault-map-section", cl::desc("Display contents of faultmap section")); +cl::opt llvm::DwarfDumpType( + "dwarf", cl::init(DIDT_Null), cl::desc("Dump of dwarf debug sections:"), + cl::values( + clEnumValN(DIDT_All, "all", "Dump all debug sections"), + clEnumValN(DIDT_Abbrev, "abbrev", ".debug_abbrev"), + clEnumValN(DIDT_AbbrevDwo, "abbrev.dwo", ".debug_abbrev.dwo"), + clEnumValN(DIDT_AppleNames, "apple_names", ".apple_names"), + clEnumValN(DIDT_AppleTypes, "apple_types", ".apple_types"), + clEnumValN(DIDT_AppleNamespaces, "apple_namespaces", + ".apple_namespaces"), + clEnumValN(DIDT_AppleObjC, "apple_objc", ".apple_objc"), + clEnumValN(DIDT_Aranges, "aranges", ".debug_aranges"), + clEnumValN(DIDT_Info, "info", ".debug_info"), + clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"), + clEnumValN(DIDT_Types, "types", ".debug_types"), + clEnumValN(DIDT_TypesDwo, "types.dwo", ".debug_types.dwo"), + clEnumValN(DIDT_Line, "line", ".debug_line"), + clEnumValN(DIDT_LineDwo, "line.dwo", ".debug_line.dwo"), + clEnumValN(DIDT_Loc, "loc", ".debug_loc"), + clEnumValN(DIDT_LocDwo, "loc.dwo", ".debug_loc.dwo"), + clEnumValN(DIDT_Frames, "frames", ".debug_frame"), + clEnumValN(DIDT_Macro, "macro", ".debug_macinfo"), + clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"), + clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"), + clEnumValN(DIDT_Pubtypes, "pubtypes", ".debug_pubtypes"), + clEnumValN(DIDT_GnuPubnames, "gnu_pubnames", ".debug_gnu_pubnames"), + clEnumValN(DIDT_GnuPubtypes, "gnu_pubtypes", ".debug_gnu_pubtypes"), + clEnumValN(DIDT_Str, "str", ".debug_str"), + clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"), + clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", + ".debug_str_offsets.dwo"), + clEnumValN(DIDT_CUIndex, "cu_index", ".debug_cu_index"), + clEnumValN(DIDT_TUIndex, "tu_index", ".debug_tu_index"), clEnumValEnd)); + static StringRef ToolName; namespace { @@ -1588,6 +1623,11 @@ printRawClangAST(o); if (PrintFaultMaps) printFaultMaps(o); + if (DwarfDumpType != DIDT_Null) { + std::unique_ptr DICtx(new DWARFContextInMemory(*o)); + // Dump the complete DWARF structure. + DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */); + } } /// @brief Dump each object file in \a a; @@ -1680,7 +1720,8 @@ && !(DylibId && MachOOpt) && !(ObjcMetaData && MachOOpt) && !(FilterSections.size() != 0 && MachOOpt) - && !PrintFaultMaps) { + && !PrintFaultMaps + && DwarfDumpType == DIDT_Null) { cl::PrintHelpMessage(); return 2; }