Index: include/llvm/DebugInfo/DWARF/DWARFFormValue.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -81,17 +81,78 @@ 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. + /// + /// \returns Optional value with the fixed byte size or None if + /// \p 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 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. + /// \param Format enum value from llvm::dwarf::DwarfFormat. + /// \returns Optional value with the fixed byte size or None if + /// \p Form doesn't have a fixed byte size. + static Optional getFixedByteSize(dwarf::Form Form, uint16_t Version, + uint8_t AddrSize, + llvm::dwarf::DwarfFormat Format); + /// Skip a form in \p debug_info_data at offset specified by \p offset_ptr. + /// + /// Skips the bytes for this form in the debug info and updates the offset. + /// + /// \param debug_info_data the .debug_info data to use to skip the value. + /// \param offset_ptr a reference to the offset that will be updated. + /// \param U the DWARFUnit to use when skipping the form in case the form + /// size differs according to data in the DWARFUnit. + /// \returns true on success, false if the form was not skipped. bool skipValue(DataExtractor debug_info_data, uint32_t *offset_ptr, const DWARFUnit *U) const; + /// Skip a form in \p debug_info_data at offset specified by \p offset_ptr. + /// + /// Skips the bytes for this form in the debug info and updates the offset. + /// + /// \param form the DW_FORM enumeration that indicates the form to skip. + /// \param debug_info_data the .debug_info data to use to skip the value. + /// \param offset_ptr a reference to the offset that will be updated. + /// \param U the DWARFUnit to use when skipping the form in case the form + /// size differs according to data in the DWARFUnit. + /// \returns true on success, false if the form was not skipped. static bool skipValue(dwarf::Form form, DataExtractor debug_info_data, - uint32_t *offset_ptr, const DWARFUnit *u); + uint32_t *offset_ptr, const DWARFUnit *U); + /// Skip a form in \p debug_info_data at offset specified by \p offset_ptr. + /// + /// Skips the bytes for this form in the debug info and updates the offset. + /// + /// \param form the DW_FORM enumeration that indicates the form to skip. + /// \param debug_info_data the .debug_info data to use to skip the value. + /// \param offset_ptr a reference to the offset that will be updated. + /// \param Version DWARF version number. + /// \param AddrSize size of an address in bytes. + /// \param Format enum value from llvm::dwarf::DwarfFormat. + /// \returns true on success, false if the form was not skipped. 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); + uint8_t AddrSize, llvm::dwarf::DwarfFormat Format); 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,14 +191,23 @@ uint32_t getNextUnitOffset() const { return Offset + Length + 4; } uint32_t getLength() const { return Length; } uint16_t getVersion() const { return Version; } + llvm::dwarf::DwarfFormat getFormat() const { + return llvm::dwarf::DwarfFormat::Dwarf32; // FIXME: Support DWARF64. + } const DWARFAbbreviationDeclarationSet *getAbbreviations() const { return Abbrevs; } uint8_t getAddressByteSize() const { return AddrSize; } uint8_t getRefAddrByteSize() const { - // FIXME: Support DWARF64. - return (Version == 2) ? AddrSize : 4; + if (Version == 2) + return AddrSize; + return getDwarfOffsetByteSize(); } + uint8_t getDwarfOffsetByteSize() const { + if (getFormat() == llvm::dwarf::DwarfFormat::Dwarf32) + return 4; + return 8; + } uint64_t getBaseAddress() const { return BaseAddr; } void setBaseAddress(uint64_t base_addr) { Index: include/llvm/Support/Dwarf.h =================================================================== --- include/llvm/Support/Dwarf.h +++ include/llvm/Support/Dwarf.h @@ -433,6 +433,12 @@ }; }; +// Constants that define the DWARF format as 32 or 64 bit. +enum DwarfFormat { + Dwarf32, + Dwarf64 +}; + } // End of namespace dwarf } // End of namespace llvm Index: lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -202,18 +202,13 @@ *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 for (const auto &AttrSpec : AbbrevDecl->attributes()) { auto Form = AttrSpec.Form; - uint8_t FixedFormSize = - (Form < FixedFormSizes.size()) ? FixedFormSizes[Form] : 0; - if (FixedFormSize) - *OffsetPtr += FixedFormSize; + if (Optional FixedSize = DWARFFormValue::getFixedByteSize(Form, U)) + *OffsetPtr += *FixedSize; else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U)) { // Restore the original offset. *OffsetPtr = Offset; Index: lib/DebugInfo/DWARF/DWARFFormValue.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -23,60 +23,6 @@ using namespace dwarf; using namespace syntax; -namespace { -uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) { - // FIXME: Support DWARF64. - 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 +54,162 @@ 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: + llvm_unreachable("Handle this form in this switch statement"); + return None; + } + return None; +} + +Optional DWARFFormValue::getFixedByteSize(dwarf::Form form, uint16_t Version, uint8_t AddrSize, llvm::dwarf::DwarfFormat Format) { + 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: + if (Version == 2) + return AddrSize; + if (Format == Dwarf32) + return 4; + return 8; + + 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: + if (Format == Dwarf32) + return 4; + return 8; + + 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: + llvm_unreachable("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 +358,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 +393,47 @@ 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) { + if (Optional FixedSize = + DWARFFormValue::getFixedByteSize(form, U)) { + *offset_ptr += *FixedSize; + return true; + } + } else { + llvm_unreachable("Form must be variable length"); + } + 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 +442,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 +449,32 @@ 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) { + if (Optional FixedSize = getFixedByteSize(form, U)) { + *offset_ptr += *FixedSize; + 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, + llvm::dwarf::DwarfFormat Format) { + if (Optional FixedSize = getFixedByteSize(form, Version, AddrSize, + Format)) { + *offset_ptr += *FixedSize; + 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 +659,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: tools/llvm-dwp/llvm-dwp.cpp =================================================================== --- tools/llvm-dwp/llvm-dwp.cpp +++ tools/llvm-dwp/llvm-dwp.cpp @@ -133,7 +133,14 @@ StringRef Str) { uint32_t Offset = 0; DataExtractor InfoData(Info, true, 0); - InfoData.getU32(&Offset); // Length + llvm::dwarf::DwarfFormat Format = llvm::dwarf::DwarfFormat::Dwarf32; + uint64_t Length = InfoData.getU32(&Offset); + // If the length is 0xffffffff, then this indictes that this is a DWARF 64 + // stream and the length is actually encoded into a 64 bit value that follows. + if (Length == 0xffffffffU) { + Format = llvm::dwarf::DwarfFormat::Dwarf64; + Length = InfoData.getU64(&Offset); + } uint16_t Version = InfoData.getU16(&Offset); InfoData.getU32(&Offset); // Abbrev offset (should be zero) uint8_t AddrSize = InfoData.getU8(&Offset); @@ -174,7 +181,8 @@ ID.Signature = InfoData.getU64(&Offset); break; default: - DWARFFormValue::skipValue(Form, InfoData, &Offset, Version, AddrSize); + DWARFFormValue::skipValue(Form, InfoData, &Offset, Version, AddrSize, + Format); } } return ID; Index: unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp +++ unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp @@ -22,15 +22,47 @@ 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()); + Optional RefSize; + Optional AddrSize; + // Test 32 bit DWARF version 2 with 4 byte addresses + RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 2, 4, Dwarf32); + AddrSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 2, 4, Dwarf32); + EXPECT_TRUE(RefSize.hasValue()); + EXPECT_TRUE(AddrSize.hasValue()); + EXPECT_EQ(*RefSize, *AddrSize); + + // Test 32 bit DWARF version 2 with 8 byte addresses + RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 2, 8, Dwarf32); + AddrSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 2, 8, Dwarf32); + EXPECT_TRUE(RefSize.hasValue()); + EXPECT_TRUE(AddrSize.hasValue()); + EXPECT_EQ(*RefSize, *AddrSize); + + // DW_FORM_ref_addr is 4 bytes in DWARF 32 in DWARF version 3 and beyond. + RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 3, 4, Dwarf32); + EXPECT_TRUE(RefSize.hasValue()); + EXPECT_EQ(*RefSize, 4); + + RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 4, 4, Dwarf32); + EXPECT_TRUE(RefSize.hasValue()); + EXPECT_EQ(*RefSize, 4); + + RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 5, 4, Dwarf32); + EXPECT_TRUE(RefSize.hasValue()); + EXPECT_EQ(*RefSize, 4); + + // DW_FORM_ref_addr is 8 bytes in DWARF 64 in DWARF version 3 and beyond. + RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 3, 8, Dwarf64); + EXPECT_TRUE(RefSize.hasValue()); + EXPECT_EQ(*RefSize, 8); + + RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 4, 8, Dwarf64); + EXPECT_TRUE(RefSize.hasValue()); + EXPECT_EQ(*RefSize, 8); + + RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, 5, 8, Dwarf64); + EXPECT_TRUE(RefSize.hasValue()); + EXPECT_EQ(*RefSize, 8); } bool isFormClass(dwarf::Form Form, DWARFFormValue::FormClass FC) {