Index: include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -10,13 +10,13 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H +#include "llvm/ADT/SmallString.h" #include "llvm/Support/DataExtractor.h" #include #include namespace llvm { -class FrameEntry; class raw_ostream; /// \brief A parsed .debug_frame or .eh_frame section @@ -26,6 +26,159 @@ bool IsEH; public: + /// \brief Abstract frame entry defining the common interface concrete + /// entries implement. + class FrameEntry { + public: + enum FrameKind { FK_CIE, FK_FDE }; + + FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length) + : Kind(K), Offset(Offset), Length(Length) {} + + virtual ~FrameEntry() = default; + + FrameKind getKind() const { return Kind; } + virtual uint64_t getOffset() const { return Offset; } + uint64_t getLength() const { return Length; } + + /// \brief Parse and store a sequence of CFI instructions from Data, + /// starting at *Offset and ending at EndOffset. If everything + /// goes well, *Offset should be equal to EndOffset when this method + /// returns. Otherwise, an error occurred. + virtual void parseInstructions(DataExtractor Data, uint32_t *Offset, + uint32_t EndOffset); + + /// \brief Dump the entry header to the given output stream. + virtual void dumpHeader(raw_ostream &OS) const = 0; + + /// \brief Dump the entry's instructions to the given output stream. + virtual void dumpInstructions(raw_ostream &OS) const; + + protected: + const FrameKind Kind; + + /// \brief Offset of this entry in the section. + uint64_t Offset; + + /// \brief Entry length as specified in DWARF. + uint64_t Length; + + /// An entry may contain CFI instructions. An instruction consists of an + /// opcode and an optional sequence of operands. + using Operands = std::vector; + struct Instruction { + Instruction(uint8_t Opcode) : Opcode(Opcode) {} + + uint8_t Opcode; + Operands Ops; + }; + + std::vector Instructions; + + /// Convenience methods to add a new instruction with the given opcode and + /// operands to the Instructions vector. + void addInstruction(uint8_t Opcode) { + Instructions.push_back(Instruction(Opcode)); + } + + void addInstruction(uint8_t Opcode, uint64_t Operand1) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + } + + void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { + Instructions.push_back(Instruction(Opcode)); + Instructions.back().Ops.push_back(Operand1); + Instructions.back().Ops.push_back(Operand2); + } + }; + + /// \brief DWARF Common Information Entry (CIE) + class CIE : public FrameEntry { + public: + // CIEs (and FDEs) are simply container classes, so the only sensible way to + // create them is by providing the full parsed contents in the constructor. + 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, + SmallString<8> AugmentationData, uint32_t FDEPointerEncoding, + uint32_t LSDAPointerEncoding) + : FrameEntry(DWARFDebugFrame::FrameEntry::FK_CIE, Offset, Length), + Version(Version), Augmentation(std::move(Augmentation)), + AddressSize(AddressSize), + SegmentDescriptorSize(SegmentDescriptorSize), + CodeAlignmentFactor(CodeAlignmentFactor), + DataAlignmentFactor(DataAlignmentFactor), + ReturnAddressRegister(ReturnAddressRegister), + AugmentationData(std::move(AugmentationData)), + FDEPointerEncoding(FDEPointerEncoding), + LSDAPointerEncoding(LSDAPointerEncoding) {} + + ~CIE() override = default; + + StringRef getAugmentationString() const { return Augmentation; } + uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; } + int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; } + + uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; } + + uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; } + + void dumpHeader(raw_ostream &OS) const override; + + static bool classof(const DWARFDebugFrame::FrameEntry *FE) { + return FE->getKind() == DWARFDebugFrame::FrameEntry::FK_CIE; + } + + private: + /// The following fields are defined in section 6.4.1 of the DWARF standard + /// v4 + uint8_t Version; + SmallString<8> Augmentation; + uint8_t AddressSize; + uint8_t SegmentDescriptorSize; + uint64_t CodeAlignmentFactor; + int64_t DataAlignmentFactor; + uint64_t ReturnAddressRegister; + + // The following are used when the CIE represents an EH frame entry. + SmallString<8> AugmentationData; + uint32_t FDEPointerEncoding; + uint32_t LSDAPointerEncoding; + }; + + /// \brief DWARF Frame Description Entry (FDE) + class FDE : public FrameEntry { + public: + // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with + // an offset to the CIE (provided by parsing the FDE header). The CIE itself + // is obtained lazily once it's actually required. + FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset, + uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie) + : FrameEntry(DWARFDebugFrame::FrameEntry::FK_FDE, Offset, Length), + LinkedCIEOffset(LinkedCIEOffset), InitialLocation(InitialLocation), + AddressRange(AddressRange), LinkedCIE(Cie) {} + + ~FDE() override = default; + + CIE *getLinkedCIE() const { return LinkedCIE; } + + void dumpHeader(raw_ostream &OS) const override; + + static bool classof(const DWARFDebugFrame::FrameEntry *FE) { + return FE->getKind() == DWARFDebugFrame::FrameEntry::FK_FDE; + } + + private: + /// The following fields are defined in section 6.4.1 of the DWARF standard + /// v3 + uint64_t LinkedCIEOffset; + uint64_t InitialLocation; + uint64_t AddressRange; + CIE *LinkedCIE; + }; + DWARFDebugFrame(bool IsEH); ~DWARFDebugFrame(); @@ -36,8 +189,19 @@ /// data is assumed to be pointing to the beginning of the section. void parse(DataExtractor Data); + typedef std::vector> FrameEntryContainer; + typedef FrameEntryContainer::const_iterator const_iterator; + + iterator_range entries() const { + return make_range(begin(), end()); + } + + const_iterator begin() const { return Entries.begin(); } + + const_iterator end() const { return Entries.end(); } + private: - std::vector> Entries; + FrameEntryContainer Entries; }; } // end namespace llvm Index: lib/DebugInfo/DWARF/DWARFDebugFrame.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -12,7 +12,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -32,80 +31,13 @@ using namespace llvm; using namespace dwarf; -/// \brief Abstract frame entry defining the common interface concrete -/// entries implement. -class llvm::FrameEntry { -public: - enum FrameKind {FK_CIE, FK_FDE}; - - FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length) - : Kind(K), Offset(Offset), Length(Length) {} - - virtual ~FrameEntry() = default; - - FrameKind getKind() const { return Kind; } - virtual uint64_t getOffset() const { return Offset; } - - /// \brief Parse and store a sequence of CFI instructions from Data, - /// starting at *Offset and ending at EndOffset. If everything - /// goes well, *Offset should be equal to EndOffset when this method - /// returns. Otherwise, an error occurred. - virtual void parseInstructions(DataExtractor Data, uint32_t *Offset, - uint32_t EndOffset); - - /// \brief Dump the entry header to the given output stream. - virtual void dumpHeader(raw_ostream &OS) const = 0; - - /// \brief Dump the entry's instructions to the given output stream. - virtual void dumpInstructions(raw_ostream &OS) const; - -protected: - const FrameKind Kind; - - /// \brief Offset of this entry in the section. - uint64_t Offset; - - /// \brief Entry length as specified in DWARF. - uint64_t Length; - - /// An entry may contain CFI instructions. An instruction consists of an - /// opcode and an optional sequence of operands. - using Operands = std::vector; - struct Instruction { - Instruction(uint8_t Opcode) - : Opcode(Opcode) - {} - - uint8_t Opcode; - Operands Ops; - }; - - std::vector Instructions; - - /// Convenience methods to add a new instruction with the given opcode and - /// operands to the Instructions vector. - void addInstruction(uint8_t Opcode) { - Instructions.push_back(Instruction(Opcode)); - } - - void addInstruction(uint8_t Opcode, uint64_t Operand1) { - Instructions.push_back(Instruction(Opcode)); - Instructions.back().Ops.push_back(Operand1); - } - - void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { - Instructions.push_back(Instruction(Opcode)); - Instructions.back().Ops.push_back(Operand1); - Instructions.back().Ops.push_back(Operand2); - } -}; - // See DWARF standard v3, section 7.23 const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; -void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset, - uint32_t EndOffset) { +void DWARFDebugFrame::FrameEntry::parseInstructions(DataExtractor Data, + uint32_t *Offset, + uint32_t EndOffset) { while (*Offset < EndOffset) { uint8_t Opcode = Data.getU8(Offset); // Some instructions have a primary opcode encoded in the top bits. @@ -199,126 +131,6 @@ namespace { -/// \brief DWARF Common Information Entry (CIE) -class CIE : public FrameEntry { -public: - // CIEs (and FDEs) are simply container classes, so the only sensible way to - // create them is by providing the full parsed contents in the constructor. - 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, - SmallString<8> AugmentationData, uint32_t FDEPointerEncoding, - uint32_t LSDAPointerEncoding) - : FrameEntry(FK_CIE, Offset, Length), Version(Version), - Augmentation(std::move(Augmentation)), AddressSize(AddressSize), - SegmentDescriptorSize(SegmentDescriptorSize), - CodeAlignmentFactor(CodeAlignmentFactor), - DataAlignmentFactor(DataAlignmentFactor), - ReturnAddressRegister(ReturnAddressRegister), - AugmentationData(std::move(AugmentationData)), - FDEPointerEncoding(FDEPointerEncoding), - LSDAPointerEncoding(LSDAPointerEncoding) {} - - ~CIE() override = default; - - StringRef getAugmentationString() const { return Augmentation; } - uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; } - int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; } - - uint32_t getFDEPointerEncoding() const { - return FDEPointerEncoding; - } - - uint32_t getLSDAPointerEncoding() const { - return LSDAPointerEncoding; - } - - void dumpHeader(raw_ostream &OS) const override { - OS << format("%08x %08x %08x CIE", - (uint32_t)Offset, (uint32_t)Length, DW_CIE_ID) - << "\n"; - OS << format(" Version: %d\n", Version); - OS << " Augmentation: \"" << Augmentation << "\"\n"; - if (Version >= 4) { - OS << format(" Address size: %u\n", - (uint32_t)AddressSize); - OS << format(" Segment desc size: %u\n", - (uint32_t)SegmentDescriptorSize); - } - OS << format(" Code alignment factor: %u\n", - (uint32_t)CodeAlignmentFactor); - OS << format(" Data alignment factor: %d\n", - (int32_t)DataAlignmentFactor); - OS << format(" Return address column: %d\n", - (int32_t)ReturnAddressRegister); - if (!AugmentationData.empty()) { - OS << " Augmentation data: "; - for (uint8_t Byte : AugmentationData) - OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf); - OS << "\n"; - } - OS << "\n"; - } - - static bool classof(const FrameEntry *FE) { - return FE->getKind() == FK_CIE; - } - -private: - /// The following fields are defined in section 6.4.1 of the DWARF standard v4 - uint8_t Version; - SmallString<8> Augmentation; - uint8_t AddressSize; - uint8_t SegmentDescriptorSize; - uint64_t CodeAlignmentFactor; - int64_t DataAlignmentFactor; - uint64_t ReturnAddressRegister; - - // The following are used when the CIE represents an EH frame entry. - SmallString<8> AugmentationData; - uint32_t FDEPointerEncoding; - uint32_t LSDAPointerEncoding; -}; - -/// \brief DWARF Frame Description Entry (FDE) -class FDE : public FrameEntry { -public: - // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with - // an offset to the CIE (provided by parsing the FDE header). The CIE itself - // is obtained lazily once it's actually required. - FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset, - uint64_t InitialLocation, uint64_t AddressRange, - CIE *Cie) - : FrameEntry(FK_FDE, Offset, Length), LinkedCIEOffset(LinkedCIEOffset), - InitialLocation(InitialLocation), AddressRange(AddressRange), - LinkedCIE(Cie) {} - - ~FDE() override = default; - - CIE *getLinkedCIE() const { return LinkedCIE; } - - void dumpHeader(raw_ostream &OS) const override { - OS << format("%08x %08x %08x FDE ", - (uint32_t)Offset, (uint32_t)Length, (int32_t)LinkedCIEOffset); - OS << format("cie=%08x pc=%08x...%08x\n", - (int32_t)LinkedCIEOffset, - (uint32_t)InitialLocation, - (uint32_t)InitialLocation + (uint32_t)AddressRange); - } - - static bool classof(const FrameEntry *FE) { - return FE->getKind() == FK_FDE; - } - -private: - /// The following fields are defined in section 6.4.1 of the DWARF standard v3 - uint64_t LinkedCIEOffset; - uint64_t InitialLocation; - uint64_t AddressRange; - CIE *LinkedCIE; -}; - /// \brief Types of operands to CF instructions. enum OperandType { OT_Unset, @@ -441,13 +253,13 @@ } } -void FrameEntry::dumpInstructions(raw_ostream &OS) const { +void DWARFDebugFrame::FrameEntry::dumpInstructions(raw_ostream &OS) const { uint64_t CodeAlignmentFactor = 0; int64_t DataAlignmentFactor = 0; - const CIE *Cie = dyn_cast(this); + const auto *Cie = dyn_cast(this); if (!Cie) - Cie = cast(this)->getLinkedCIE(); + Cie = cast(this)->getLinkedCIE(); if (Cie) { CodeAlignmentFactor = Cie->getCodeAlignmentFactor(); DataAlignmentFactor = Cie->getDataAlignmentFactor(); @@ -528,7 +340,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; - DenseMap CIEs; + DenseMap CIEs; while (Data.isValidOffset(Offset)) { uint32_t StartOffset = Offset; @@ -641,7 +453,8 @@ uint64_t CIEPointer = Id; uint64_t InitialLocation = 0; uint64_t AddressRange = 0; - CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer]; + DWARFDebugFrame::CIE *Cie = + CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer]; if (IsEH) { // The address size is encoded in the CIE we reference. @@ -674,9 +487,8 @@ AddressRange = Data.getAddress(&Offset); } - Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer, - InitialLocation, AddressRange, - Cie)); + Entries.emplace_back(new DWARFDebugFrame::FDE( + StartOffset, Length, CIEPointer, InitialLocation, AddressRange, Cie)); } Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset); @@ -686,6 +498,37 @@ } } +void DWARFDebugFrame::CIE::dumpHeader(raw_ostream &OS) const { + OS << format("%08x %08x %08x CIE", (uint32_t)Offset, (uint32_t)Length, + DW_CIE_ID) + << "\n"; + OS << format(" Version: %d\n", Version); + OS << " Augmentation: \"" << Augmentation << "\"\n"; + if (Version >= 4) { + OS << format(" Address size: %u\n", (uint32_t)AddressSize); + OS << format(" Segment desc size: %u\n", + (uint32_t)SegmentDescriptorSize); + } + OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor); + OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor); + OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister); + if (!AugmentationData.empty()) { + OS << " Augmentation data: "; + for (uint8_t Byte : AugmentationData) + OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf); + OS << "\n"; + } + OS << "\n"; +} + +void DWARFDebugFrame::FDE::dumpHeader(raw_ostream &OS) const { + OS << format("%08x %08x %08x FDE ", (uint32_t)Offset, (uint32_t)Length, + (int32_t)LinkedCIEOffset); + OS << format("cie=%08x pc=%08x...%08x\n", (int32_t)LinkedCIEOffset, + (uint32_t)InitialLocation, + (uint32_t)InitialLocation + (uint32_t)AddressRange); +} + void DWARFDebugFrame::dump(raw_ostream &OS) const { OS << "\n"; for (const auto &Entry : Entries) {