Index: include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h +++ include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h @@ -10,20 +10,36 @@ #ifndef LLVM_LIB_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H #define LLVM_LIB_DEBUGINFO_DWARFABBREVIATIONDECLARATION_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.h" +#include namespace llvm { +class DWARFUnit; +class DWARFFormValue; class raw_ostream; class DWARFAbbreviationDeclaration { public: struct AttributeSpec { - AttributeSpec(dwarf::Attribute A, dwarf::Form F) : Attr(A), Form(F) {} + AttributeSpec(dwarf::Attribute A, dwarf::Form F, Optional S) + : Attr(A), Form(F), ByteSize(S) {} dwarf::Attribute Attr; dwarf::Form Form; + /// If ByteSize has a value, then it contains the fixed size in bytes for + /// the Form in this object. If ByteSize doesn't have a value, then the + /// byte size of Form either varies according to the DWARFUnit that it is + /// contained in or the value size varies and must be decoded from the + /// debug information in order to determine its size. + Optional ByteSize; + /// Get the fixed byte size of this Form if possible. This function might use + /// the DWARFUnit to calculate the size of the Form, like for DW_AT_address + /// and DW_AT_ref_addr, so this isn't just an accessor for the ByteSize + /// member. + Optional getByteSize(const DWARFUnit *U) const; }; typedef SmallVector AttributeSpecVector; @@ -46,18 +62,48 @@ return dwarf::Form(0); } - uint32_t findAttributeIndex(dwarf::Attribute attr) const; + Optional findAttributeIndex(dwarf::Attribute attr) const; + // Efficiently extract an attribute value for a DWARFUnit given the DIE offset + // and the attribute. Returns true if the attribute was successfully extracted + // into FormValue. + bool getAttributeValue(const uint32_t DIEOffset, const dwarf::Attribute Attr, + const DWARFUnit *U, DWARFFormValue &FormValue) const; bool extract(DataExtractor Data, uint32_t* OffsetPtr); void dump(raw_ostream &OS) const; + // Return an optioanl byte size of all attribute data in this abbreviation + // if a constant size can be calculated given a DWARFUnit. This allows DWARF + // parsing to be faster as many DWARF DIEs have a fixed byte size. + Optional getFixedAttributesByteSize(const DWARFUnit *U) const; + private: void clear(); + // A helper structure that can quickly determine the size in bytes of an + // abbreviation declaration. + struct FixedSizeInfo { + /// The fixed byte size for fixed size forms. + uint16_t NumBytes; + /// Number of DW_FORM_address forms in this abbrevation declaration. + uint8_t NumAddrs; + /// Number of DW_FORM_ref_addr forms in this abbrevation declaration. + uint8_t NumRefAddrs; + // Constructor + FixedSizeInfo() : NumBytes(0), NumAddrs(0), NumRefAddrs(0) {} + // Calculate the fixed size in bytes given a DWARFUnit. + size_t getByteSize(const DWARFUnit *U) const; + }; + uint32_t Code; dwarf::Tag Tag; + uint8_t CodeByteSize; bool HasChildren; - AttributeSpecVector AttributeSpecs; + // Keep a map of attributes to attribute index for quick attribute lookups. + std::map AttributeMap; + // If this abbreviation has a fixed byte size then \a FixedAttributeSize + // will have a value. + Optional FixedAttributeSize; }; } Index: include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFContext.h +++ include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -284,6 +284,9 @@ public: DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr); + DWARFContextInMemory(bool IsLittleEndian, uint8_t AddrSize, + StringRef DebugAbbrev, StringRef DebugInfo, + StringRef DebugStr); bool isLittleEndian() const override { return IsLittleEndian; } uint8_t getAddressSize() const override { return AddressSize; } const DWARFSection &getInfoSection() override { return InfoSection; } Index: include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h @@ -48,6 +48,10 @@ /// starting at a given offset. If DIE can't be extracted, returns false and /// doesn't change OffsetPtr. bool extractFast(const DWARFUnit *U, uint32_t *OffsetPtr); + /// High performance DWARFDebugInfoEntry should use this call. + bool extractFast(const DWARFUnit *U, uint32_t *OffsetPtr, + const DataExtractor &DebugInfoData, + uint32_t UEndOffset); uint32_t getTag() const { return AbbrevDecl ? AbbrevDecl->getTag() : 0; } bool isNULL() const { return AbbrevDecl == nullptr; } @@ -98,6 +102,10 @@ dwarf::Attribute Attr, uint64_t FailValue) const; + int64_t getAttributeValueAsSignedConstant(const DWARFUnit *U, + dwarf::Attribute Attr, + int64_t FailValue) const; + uint64_t getAttributeValueAsUnsignedConstant(const DWARFUnit *U, dwarf::Attribute Attr, uint64_t FailValue) const; Index: include/llvm/DebugInfo/DWARF/DWARFFormValue.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -56,6 +56,7 @@ public: DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F), U(nullptr) {} dwarf::Form getForm() const { return Form; } + void setForm(dwarf::Form F) { Form = F; } bool isFormClass(FormClass FC) const; const DWARFUnit *getUnit() const { return U; } void dump(raw_ostream &OS) const; @@ -81,7 +82,41 @@ Optional getAsAddress() const; Optional getAsSectionOffset() const; Optional> getAsBlock() const; - + /// Get the fixed byte size for a given form. + /// + /// If the form always has a fixed valid byte size that doesn't depend on a + /// DWARFUnit, then an Optional with a value will be returned. If the form + /// can vary in size depending on the DWARFUnit (DWARF version, address byte + /// size, or DWARF 32/64) and the DWARFUnit is valid, then an Optional with a + /// valid value is returned. If the form is always encoded using a variable + /// length storage format (ULEB or SLEB numbers or blocks) or the size + /// depends on a DWARFUnit and the DWARFUnit is NULL, then None will be + /// returned. + /// @param Form The DWARF form to get the fixed byte size for + /// @param U The DWARFUnit that can be used to help determine the byte size. + /// @return Optional value with the fixed byte size or None if + /// \a Form doesn't have a fixed byte size or a DWARFUnit wasn't supplied + /// and was needed to calculate the byte size. + static Optional getFixedByteSize(dwarf::Form Form, + const DWARFUnit *U = nullptr); + // Get the fixed byte size for a given form. If the form is always encoded + // using a variable length storage format (ULEB/SLEB numbers or blocks) then + // an Optional with no value will be returned. + + /// Get the fixed byte size for a given form. + /// + /// If the form has a fixed byte size given a valid DWARF version and address + /// byte size, then an Optional with a valid value is returned. If the form + /// is always encoded using a variable length storage format (ULEB or SLEB + /// numbers or blocks) then None will be returned. + /// + /// @param Form DWARF form to get the fixed byte size for + /// @param Version DWARF version number. + /// @param AddrSize size of an address in bytes. + /// @return Optional value with the fixed byte size or None if + /// \a Form doesn't have a fixed byte size. + static Optional getFixedByteSize(dwarf::Form Form, uint16_t Version, + uint8_t AddrSize); bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFUnit *U) const; static bool skipValue(dwarf::Form form, DataExtractor debug_info_data, @@ -89,9 +124,6 @@ static bool skipValue(dwarf::Form form, DataExtractor debug_info_data, uint32_t *offset_ptr, uint16_t Version, uint8_t AddrSize); - - static ArrayRef getFixedFormSizes(uint8_t AddrSize, - uint16_t Version); private: void dumpString(raw_ostream &OS) const; }; Index: include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -191,6 +191,7 @@ uint32_t getNextUnitOffset() const { return Offset + Length + 4; } uint32_t getLength() const { return Length; } uint16_t getVersion() const { return Version; } + bool getIsDwarf64() const { return false; } // FIXME: Support DWARF64. const DWARFAbbreviationDeclarationSet *getAbbreviations() const { return Abbrevs; } @@ -199,6 +200,11 @@ // FIXME: Support DWARF64. return (Version == 2) ? AddrSize : 4; } + uint8_t getDwarfOffsetByteSize() const { + if (getIsDwarf64()) + return 8; + return 4; + } uint64_t getBaseAddress() const { return BaseAddr; } void setBaseAddress(uint64_t base_addr) { Index: lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -17,8 +19,11 @@ void DWARFAbbreviationDeclaration::clear() { Code = 0; Tag = DW_TAG_null; + CodeByteSize = 0; HasChildren = false; AttributeSpecs.clear(); + AttributeMap.clear(); + FixedAttributeSize.reset(); } DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() { @@ -29,10 +34,12 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, uint32_t* OffsetPtr) { clear(); + const uint32_t Offset = *OffsetPtr; Code = Data.getULEB128(OffsetPtr); if (Code == 0) { return false; } + CodeByteSize = *OffsetPtr - Offset; Tag = static_cast(Data.getULEB128(OffsetPtr)); if (Tag == DW_TAG_null) { clear(); @@ -40,12 +47,34 @@ } uint8_t ChildrenByte = Data.getU8(OffsetPtr); HasChildren = (ChildrenByte == DW_CHILDREN_yes); + // Assign a value to our optional FixedAttributeSize member variable. If + // this member variable still has a value after the while loop below, then + // this abbreviation declaration has a fixed byte size. + FixedAttributeSize = FixedSizeInfo(); + // Read all of the abbreviation attributes and forms. while (true) { auto A = static_cast(Data.getULEB128(OffsetPtr)); auto F = static_cast
(Data.getULEB128(OffsetPtr)); if (A && F) { - AttributeSpecs.push_back(AttributeSpec(A, F)); + auto FixedFormByteSize = DWARFFormValue::getFixedByteSize(F); + AttributeSpecs.push_back(AttributeSpec(A, F, FixedFormByteSize)); + // If this abbrevation still has a fixed byte size, then update the + // FixedAttributeSize + if (FixedAttributeSize.hasValue()) { + if (FixedFormByteSize.hasValue()) + FixedAttributeSize->NumBytes += FixedFormByteSize.getValue(); + else if (F == DW_FORM_addr) + ++FixedAttributeSize->NumAddrs; + else if (F == DW_FORM_ref_addr) + ++FixedAttributeSize->NumRefAddrs; + else { + // Indicate we no longer have a fixed byte size for this abbreviation + // by clearing the FixedAttributeSize optional value so it doesn't + // have a value. + FixedAttributeSize.reset(); + } + } } else if (A == 0 && F == 0) { // We successfully reached the end of this abbreviation declaration // since both attribute and form are zero. @@ -59,6 +88,12 @@ return false; } } + + // Make an attribute to index lookup table to make findAttributeIndex fast + uint32_t AttrIndex = 0; + for (const AttributeSpec &Spec : AttributeSpecs) { + AttributeMap[Spec.Attr] = AttrIndex++; + } return true; } @@ -88,11 +123,67 @@ OS << '\n'; } -uint32_t -DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute attr) const { - for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) { - if (AttributeSpecs[i].Attr == attr) - return i; +Optional +DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const { + const auto Iter = AttributeMap.find(Attr); + if (Iter != AttributeMap.end()) + return Iter->second; + return Optional(); +} + +bool DWARFAbbreviationDeclaration::getAttributeValue( + const uint32_t DIEOffset, const dwarf::Attribute Attr, const DWARFUnit *U, + DWARFFormValue &FormValue) const { + Optional MatchAttrIndex = findAttributeIndex(Attr); + if (!MatchAttrIndex.hasValue()) + return false; + + auto DebugInfoData = U->getDebugInfoExtractor(); + + // Add the byte size of ULEB that for the abbrev Code so we can start skipping + // the attribute data. + uint32_t Offset = DIEOffset + CodeByteSize; + uint32_t AttrIndex = 0; + for (const auto &Spec : AttributeSpecs) { + if (*MatchAttrIndex == AttrIndex) { + // We have arrived at the attribute to extract, extract if from Offset. + FormValue.setForm(Spec.Form); + return FormValue.extractValue(DebugInfoData, &Offset, U); + } + // March Offset along until we get to the attribute we want. + Optional AttrSize = Spec.getByteSize(U); + if (AttrSize.hasValue()) + Offset += AttrSize.getValue(); + else + DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, U); + ++AttrIndex; } - return -1U; + return false; } + +size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize( + const DWARFUnit *U) const { + assert(U); + size_t ByteSize = NumBytes; + if (NumAddrs > 0) + ByteSize += NumAddrs * U->getAddressByteSize(); + if (NumRefAddrs > 0) + ByteSize += NumRefAddrs * U->getRefAddrByteSize(); + return ByteSize; +} + +// Get the fixed byte size of this Form if the Form is fixed in byte size. +Optional DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( + const DWARFUnit *U) const { + if (ByteSize.hasValue()) + return ByteSize; + assert(U); + return DWARFFormValue::getFixedByteSize(Form, U); +} + +Optional DWARFAbbreviationDeclaration::getFixedAttributesByteSize( + const DWARFUnit *U) const { + if (FixedAttributeSize.hasValue()) + return FixedAttributeSize->getByteSize(U); + return None; +} Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -901,4 +901,13 @@ } } +DWARFContextInMemory::DWARFContextInMemory(bool LittleEndian, uint8_t AddrSize, + StringRef DebugAbbrev, + StringRef DebugInfo, + StringRef DebugStr) + : IsLittleEndian(LittleEndian), AddressSize(AddrSize), + AbbrevSection(DebugAbbrev), StringSection(DebugStr) { + InfoSection.Data = DebugInfo; +} + void DWARFContextInMemory::anchor() { } Index: lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -185,9 +185,15 @@ bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFUnit *U, uint32_t *OffsetPtr) { + DataExtractor DebugInfoData = U->getDebugInfoExtractor(); + const uint32_t UEndOffset = U->getNextUnitOffset(); + return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset); +} +bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFUnit *U, + uint32_t *OffsetPtr, + const DataExtractor &DebugInfoData, + uint32_t UEndOffset) { Offset = *OffsetPtr; - DataExtractor DebugInfoData = U->getDebugInfoExtractor(); - uint32_t UEndOffset = U->getNextUnitOffset(); if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset)) return false; uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr); @@ -202,19 +208,20 @@ *OffsetPtr = Offset; return false; } - ArrayRef FixedFormSizes = DWARFFormValue::getFixedFormSizes( - U->getAddressByteSize(), U->getVersion()); - assert(FixedFormSizes.size() > 0); - - // Skip all data in the .debug_info for the attributes + // See if this DIE has attributes that all have fixed byte sizes. If so, we + // can just add these to the offset to get to the next DIE + Optional FixedDIESize = AbbrevDecl->getFixedAttributesByteSize(U); + if (FixedDIESize.hasValue()) { + *OffsetPtr += *FixedDIESize; + return true; + } + // Skip all data in the .debug_info for the each of the attribute's forms. for (const auto &AttrSpec : AbbrevDecl->attributes()) { - auto Form = AttrSpec.Form; - - uint8_t FixedFormSize = - (Form < FixedFormSizes.size()) ? FixedFormSizes[Form] : 0; - if (FixedFormSize) - *OffsetPtr += FixedFormSize; - else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U)) { + Optional FixedFormSize = AttrSpec.getByteSize(U); + if (FixedFormSize.hasValue()) { + *OffsetPtr += FixedFormSize.getValue(); + } else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData, + OffsetPtr, U)) { // Restore the original offset. *OffsetPtr = Offset; return false; @@ -235,27 +242,9 @@ bool DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFUnit *U, dwarf::Attribute Attr, DWARFFormValue &FormValue) const { - if (!AbbrevDecl) + if (!AbbrevDecl || !U) return false; - - uint32_t AttrIdx = AbbrevDecl->findAttributeIndex(Attr); - if (AttrIdx == -1U) - return false; - - DataExtractor DebugInfoData = U->getDebugInfoExtractor(); - uint32_t DebugInfoOffset = getOffset(); - - // Skip the abbreviation code so we are at the data for the attributes - DebugInfoData.getULEB128(&DebugInfoOffset); - - // Skip preceding attribute values. - for (uint32_t i = 0; i < AttrIdx; ++i) { - DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(i), - DebugInfoData, &DebugInfoOffset, U); - } - - FormValue = DWARFFormValue(AbbrevDecl->getFormByIndex(AttrIdx)); - return FormValue.extractValue(DebugInfoData, &DebugInfoOffset, U); + return AbbrevDecl->getAttributeValue(Offset, Attr, U, FormValue); } const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString( @@ -288,6 +277,15 @@ return Result.hasValue() ? Result.getValue() : FailValue; } +int64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsSignedConstant( + const DWARFUnit *U, dwarf::Attribute Attr, int64_t FailValue) const { + DWARFFormValue FormValue; + if (!getAttributeValue(U, Attr, FormValue)) + return FailValue; + Optional Result = FormValue.getAsSignedConstant(); + return Result.hasValue() ? Result.getValue() : FailValue; +} + uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsReference( const DWARFUnit *U, dwarf::Attribute Attr, uint64_t FailValue) const { Index: lib/DebugInfo/DWARF/DWARFFormValue.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -29,54 +29,8 @@ return (Version == 2) ? AddrSize : 4; } -template -ArrayRef makeFixedFormSizesArrayRef() { - static const uint8_t sizes[] = { - 0, // 0x00 unused - AddrSize, // 0x01 DW_FORM_addr - 0, // 0x02 unused - 0, // 0x03 DW_FORM_block2 - 0, // 0x04 DW_FORM_block4 - 2, // 0x05 DW_FORM_data2 - 4, // 0x06 DW_FORM_data4 - 8, // 0x07 DW_FORM_data8 - 0, // 0x08 DW_FORM_string - 0, // 0x09 DW_FORM_block - 0, // 0x0a DW_FORM_block1 - 1, // 0x0b DW_FORM_data1 - 1, // 0x0c DW_FORM_flag - 0, // 0x0d DW_FORM_sdata - 4, // 0x0e DW_FORM_strp - 0, // 0x0f DW_FORM_udata - RefAddrSize, // 0x10 DW_FORM_ref_addr - 1, // 0x11 DW_FORM_ref1 - 2, // 0x12 DW_FORM_ref2 - 4, // 0x13 DW_FORM_ref4 - 8, // 0x14 DW_FORM_ref8 - 0, // 0x15 DW_FORM_ref_udata - 0, // 0x16 DW_FORM_indirect - 4, // 0x17 DW_FORM_sec_offset - 0, // 0x18 DW_FORM_exprloc - 0, // 0x19 DW_FORM_flag_present - }; - return makeArrayRef(sizes); } -} -ArrayRef DWARFFormValue::getFixedFormSizes(uint8_t AddrSize, - uint16_t Version) { - uint8_t RefAddrSize = getRefAddrSize(AddrSize, Version); - if (AddrSize == 4 && RefAddrSize == 4) - return makeFixedFormSizesArrayRef<4, 4>(); - if (AddrSize == 4 && RefAddrSize == 8) - return makeFixedFormSizesArrayRef<4, 8>(); - if (AddrSize == 8 && RefAddrSize == 4) - return makeFixedFormSizesArrayRef<8, 4>(); - if (AddrSize == 8 && RefAddrSize == 8) - return makeFixedFormSizesArrayRef<8, 8>(); - return None; -} - static const DWARFFormValue::FormClass DWARF4FormClasses[] = { DWARFFormValue::FC_Unknown, // 0x0 DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr @@ -108,6 +62,159 @@ DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present }; +Optional DWARFFormValue::getFixedByteSize(dwarf::Form form, + const DWARFUnit *U) { + switch (form) { + case DW_FORM_addr: + if (U) + return U->getAddressByteSize(); + return None; + + case DW_FORM_block: // ULEB128 length L followed by L bytes. + case DW_FORM_block1: // 1 byte length L followed by L bytes. + case DW_FORM_block2: // 2 byte length L followed by L bytes. + case DW_FORM_block4: // 4 byte length L followed by L bytes. + case DW_FORM_string: // C-string with null terminator. + case DW_FORM_sdata: // SLEB128. + case DW_FORM_udata: // ULEB128. + case DW_FORM_ref_udata: // ULEB128. + case DW_FORM_indirect: // ULEB128. + case DW_FORM_exprloc: // ULEB128 length L followed by L bytes. + case DW_FORM_strx: // ULEB128. + case DW_FORM_addrx: // ULEB128. + case DW_FORM_loclistx: // ULEB128. + case DW_FORM_rnglistx: // ULEB128. + case DW_FORM_GNU_addr_index: // ULEB128. + case DW_FORM_GNU_str_index: // ULEB128. + return None; + + case DW_FORM_ref_addr: + if (U) + return U->getRefAddrByteSize(); + return None; + + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_ref1: + return 1; + + case DW_FORM_data2: + case DW_FORM_ref2: + return 2; + + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_strp: + return 4; + + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: + case DW_FORM_strp_sup: + case DW_FORM_ref_sup: + // 4 bytes in DWARF 32, 8 bytes in DWARF 64. + if (U) + return U->getDwarfOffsetByteSize(); + return None; + + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + return 8; + + case DW_FORM_flag_present: + return 0; + + case DW_FORM_data16: + return 16; + + case DW_FORM_implicit_const: + // The implicit value is stored in the abbreviation as a ULEB128, any + // there no data in debug info. + return 0; + + default: + assert(!"Handle this form in this switch statement"); + return None; + } + return None; +} + +Optional DWARFFormValue::getFixedByteSize(dwarf::Form form, + uint16_t Version, + uint8_t AddrSize) { + switch (form) { + case DW_FORM_addr: + return AddrSize; + + case DW_FORM_block: // ULEB128 length L followed by L bytes. + case DW_FORM_block1: // 1 byte length L followed by L bytes. + case DW_FORM_block2: // 2 byte length L followed by L bytes. + case DW_FORM_block4: // 4 byte length L followed by L bytes. + case DW_FORM_string: // C-string with null terminator. + case DW_FORM_sdata: // SLEB128. + case DW_FORM_udata: // ULEB128. + case DW_FORM_ref_udata: // ULEB128. + case DW_FORM_indirect: // ULEB128. + case DW_FORM_exprloc: // ULEB128 length L followed by L bytes. + case DW_FORM_strx: // ULEB128. + case DW_FORM_addrx: // ULEB128. + case DW_FORM_loclistx: // ULEB128. + case DW_FORM_rnglistx: // ULEB128. + case DW_FORM_GNU_addr_index: // ULEB128. + case DW_FORM_GNU_str_index: // ULEB128. + return None; + + case DW_FORM_ref_addr: + return (Version == 2) ? AddrSize : 4; + + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_ref1: + return 1; + + case DW_FORM_data2: + case DW_FORM_ref2: + return 2; + + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_strp: + return 4; + + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: + case DW_FORM_strp_sup: + case DW_FORM_ref_sup: + // 4 bytes in DWARF 32, 8 in DWARF 64. + return 4; // FIXME: This DWARF parser currently only handles DWARF 32. + + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + return 8; + + case DW_FORM_flag_present: + return 0; + + case DW_FORM_data16: + return 16; + + case DW_FORM_implicit_const: + // The implicit value is stored in the abbreviation as a ULEB128, any + // there no data in debug info. + return 0; + + default: + assert(!"Handle this form in this switch statement"); + return None; + } + return None; +} + bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { // First, check DWARF4 form classes. if (Form < makeArrayRef(DWARF4FormClasses).size() && @@ -256,22 +363,9 @@ return true; } -bool -DWARFFormValue::skipValue(DataExtractor debug_info_data, uint32_t* offset_ptr, - const DWARFUnit *U) const { - return DWARFFormValue::skipValue(Form, debug_info_data, offset_ptr, U); -} - -bool -DWARFFormValue::skipValue(dwarf::Form form, DataExtractor debug_info_data, - uint32_t *offset_ptr, const DWARFUnit *cu) { - return skipValue(form, debug_info_data, offset_ptr, cu->getVersion(), - cu->getAddressByteSize()); -} -bool -DWARFFormValue::skipValue(dwarf::Form form, DataExtractor debug_info_data, - uint32_t *offset_ptr, uint16_t Version, - uint8_t AddrSize) { +bool skipVariableLengthValue(dwarf::Form form, + const DataExtractor &debug_info_data, + uint32_t *offset_ptr, const DWARFUnit *U) { bool indirect = false; do { switch (form) { @@ -304,51 +398,48 @@ debug_info_data.getCStr(offset_ptr); return true; - // Compile unit address sized values case DW_FORM_addr: - *offset_ptr += AddrSize; - return true; case DW_FORM_ref_addr: - *offset_ptr += getRefAddrSize(AddrSize, Version); - return true; - - // 0 byte values - implied from the form. case DW_FORM_flag_present: - return true; - - // 1 byte values case DW_FORM_data1: case DW_FORM_flag: case DW_FORM_ref1: - *offset_ptr += 1; - return true; - - // 2 byte values case DW_FORM_data2: case DW_FORM_ref2: - *offset_ptr += 2; - return true; - - // 4 byte values case DW_FORM_data4: case DW_FORM_ref4: - *offset_ptr += 4; - return true; - - // 8 byte values case DW_FORM_data8: case DW_FORM_ref8: case DW_FORM_ref_sig8: - *offset_ptr += 8; - return true; + case DW_FORM_sec_offset: + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + if (indirect) { + Optional FixedByteSize = + DWARFFormValue::getFixedByteSize(form, U); + if (FixedByteSize.hasValue()) { + *offset_ptr += FixedByteSize.getValue(); + return true; + } + } else { + assert(!"only variable length Form can be passed to this function"); + } + return false; // signed or unsigned LEB 128 values - // case DW_FORM_APPLE_db_str: case DW_FORM_sdata: + debug_info_data.getSLEB128(offset_ptr); + return true; + case DW_FORM_udata: case DW_FORM_ref_udata: + case DW_FORM_strx: + case DW_FORM_addrx: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: - case DW_FORM_GNU_addr_index: debug_info_data.getULEB128(offset_ptr); return true; @@ -357,14 +448,6 @@ form = static_cast(debug_info_data.getULEB128(offset_ptr)); break; - // FIXME: 4 for DWARF32, 8 for DWARF64. - case DW_FORM_sec_offset: - case DW_FORM_strp: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: - *offset_ptr += 4; - return true; - default: return false; } @@ -372,6 +455,38 @@ return true; } +bool DWARFFormValue::skipValue(DataExtractor debug_info_data, + uint32_t *offset_ptr, const DWARFUnit *U) const { + return DWARFFormValue::skipValue(Form, debug_info_data, offset_ptr, U); +} + +bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor debug_info_data, + uint32_t *offset_ptr, const DWARFUnit *U) { + Optional FixedByteSize = getFixedByteSize(form, U); + if (FixedByteSize.hasValue()) { + *offset_ptr += FixedByteSize.getValue(); + return true; + } + return skipVariableLengthValue(form, debug_info_data, offset_ptr, U); +} + +bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor debug_info_data, + uint32_t *offset_ptr, uint16_t Version, + uint8_t AddrSize) { + Optional FixedByteSize = getFixedByteSize(form, nullptr); + if (FixedByteSize.hasValue()) { + *offset_ptr += FixedByteSize.getValue(); + return true; + } else if (form == DW_FORM_addr) { + *offset_ptr += AddrSize; + return true; + } else if (form == DW_FORM_ref_addr) { + *offset_ptr += getRefAddrSize(AddrSize, Version); + return true; + } + return skipVariableLengthValue(form, debug_info_data, offset_ptr, nullptr); +} + void DWARFFormValue::dump(raw_ostream &OS) const { uint64_t uvalue = Value.uval; @@ -556,8 +671,9 @@ return None; return Value.uval + U->getOffset(); case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: + case DW_FORM_GNU_ref_alt: return Value.uval; - // FIXME: Add proper support for DW_FORM_ref_sig8 and DW_FORM_GNU_ref_alt. default: return None; } Index: lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFUnit.cpp +++ lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -196,10 +196,11 @@ uint32_t DIEOffset = Offset + getHeaderSize(); uint32_t NextCUOffset = getNextUnitOffset(); DWARFDebugInfoEntryMinimal DIE; + DataExtractor DebugInfoData = getDebugInfoExtractor(); uint32_t Depth = 0; bool IsCUDie = true; - while (DIEOffset < NextCUOffset && DIE.extractFast(this, &DIEOffset)) { + while (DIE.extractFast(this, &DIEOffset, DebugInfoData, NextCUOffset)) { if (IsCUDie) { if (AppendCUDie) Dies.push_back(DIE); Index: tools/dsymutil/DwarfLinker.cpp =================================================================== --- tools/dsymutil/DwarfLinker.cpp +++ tools/dsymutil/DwarfLinker.cpp @@ -2082,20 +2082,20 @@ // Global variables with constant value can always be kept. if (!(Flags & TF_InFunctionScope) && - Abbrev->findAttributeIndex(dwarf::DW_AT_const_value) != -1U) { + Abbrev->findAttributeIndex(dwarf::DW_AT_const_value).hasValue()) { MyInfo.InDebugMap = true; return Flags | TF_Keep; } - uint32_t LocationIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_location); - if (LocationIdx == -1U) + Optional LocationIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_location); + if (!LocationIdx.hasValue()) return Flags; uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode()); const DWARFUnit &OrigUnit = Unit.getOrigUnit(); uint32_t LocationOffset, LocationEndOffset; std::tie(LocationOffset, LocationEndOffset) = - getAttributeOffsets(Abbrev, LocationIdx, Offset, OrigUnit); + getAttributeOffsets(Abbrev, *LocationIdx, Offset, OrigUnit); // See if there is a relocation to a valid debug map entry inside // this variable's location. The order is important here. We want to @@ -2122,15 +2122,15 @@ Flags |= TF_InFunctionScope; - uint32_t LowPcIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc); - if (LowPcIdx == -1U) + Optional LowPcIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc); + if (!LowPcIdx.hasValue()) return Flags; uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode()); const DWARFUnit &OrigUnit = Unit.getOrigUnit(); uint32_t LowPcOffset, LowPcEndOffset; std::tie(LowPcOffset, LowPcEndOffset) = - getAttributeOffsets(Abbrev, LowPcIdx, Offset, OrigUnit); + getAttributeOffsets(Abbrev, *LowPcIdx, Offset, OrigUnit); uint64_t LowPc = DIE.getAttributeValueAsAddress(&OrigUnit, dwarf::DW_AT_low_pc, -1ULL); Index: unittests/DebugInfo/DWARF/CMakeLists.txt =================================================================== --- unittests/DebugInfo/DWARF/CMakeLists.txt +++ unittests/DebugInfo/DWARF/CMakeLists.txt @@ -3,6 +3,8 @@ ) set(DebugInfoSources + DWARFGenerator.cpp + DWARFDebugInfoTest.cpp DWARFFormValueTest.cpp ) Index: unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp +++ unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp @@ -20,19 +20,6 @@ namespace { -TEST(DWARFFormValue, FixedFormSizes) { - // Size of DW_FORM_addr and DW_FORM_ref_addr are equal in DWARF2, - // DW_FORM_ref_addr is always 4 bytes in DWARF32 starting from DWARF3. - ArrayRef sizes = DWARFFormValue::getFixedFormSizes(4, 2); - EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]); - sizes = DWARFFormValue::getFixedFormSizes(8, 2); - EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]); - sizes = DWARFFormValue::getFixedFormSizes(8, 3); - EXPECT_EQ(4, sizes[DW_FORM_ref_addr]); - // Check that we don't have fixed form sizes for weird address sizes. - EXPECT_EQ(0U, DWARFFormValue::getFixedFormSizes(16, 2).size()); -} - bool isFormClass(dwarf::Form Form, DWARFFormValue::FormClass FC) { return DWARFFormValue(Form).isFormClass(FC); }