Index: include/llvm/DebugInfo/DWARF/DWARFFormValue.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -81,17 +81,79 @@ 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); + uint8_t AddrSize, llvm::dwarf::DwarfFormat Format); - 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,14 +191,26 @@ uint32_t getNextUnitOffset() const { return Offset + Length + 4; } uint32_t getLength() const { return Length; } uint16_t getVersion() const { return Version; } + dwarf::DwarfFormat getFormat() const { + return 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 { + switch (getFormat()) { + case dwarf::DwarfFormat::DWARF32: + return 4; + case dwarf::DwarfFormat::DWARF64: + 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,9 @@ }; }; +/// 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,214 @@ DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present }; +namespace { + +/// A helper class that can be used in DWARFFormValue.cpp functions that need +/// to know the byte size of DW_FORM values that vary in size depending on the +/// DWARF version, address byte size, or DWARF32 or DWARF64. +class FormSizeHelper { + uint16_t Version; + uint8_t AddrSize; + llvm::dwarf::DwarfFormat Format; + +public: + FormSizeHelper(uint16_t V, uint8_t A, llvm::dwarf::DwarfFormat F) + : Version(V), AddrSize(A), Format(F) {} + uint8_t getAddressByteSize() const { return AddrSize; } + uint8_t getRefAddrByteSize() const { + if (Version == 2) + return AddrSize; + return getDwarfOffsetByteSize(); + } + uint8_t getDwarfOffsetByteSize() const { + switch (Format) { + case dwarf::DwarfFormat::DWARF32: + return 4; + case dwarf::DwarfFormat::DWARF64: + return 8; + } + llvm_unreachable("Invalid Format value"); + } +}; + +} // end anonymous namespace + +template +static Optional getFixedByteSize(dwarf::Form Form, const T *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: + 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; +} + +template +static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, + uint32_t *OffsetPtr, const T *U) { + bool Indirect = false; + do { + switch (Form) { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info. + case DW_FORM_exprloc: + case DW_FORM_block: { + uint64_t size = DebugInfoData.getULEB128(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block1: { + uint8_t size = DebugInfoData.getU8(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block2: { + uint16_t size = DebugInfoData.getU16(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block4: { + uint32_t size = DebugInfoData.getU32(OffsetPtr); + *OffsetPtr += size; + return true; + } + + // Inlined NULL terminated C-strings. + case DW_FORM_string: + DebugInfoData.getCStr(OffsetPtr); + return true; + + case DW_FORM_addr: + case DW_FORM_ref_addr: + case DW_FORM_flag_present: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_flag: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + case DW_FORM_sec_offset: + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + if (Optional FixedSize = ::getFixedByteSize(Form, U)) { + *OffsetPtr += *FixedSize; + return true; + } + return false; + + // signed or unsigned LEB 128 values. + case DW_FORM_sdata: + DebugInfoData.getSLEB128(OffsetPtr); + 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: + DebugInfoData.getULEB128(OffsetPtr); + return true; + + case DW_FORM_indirect: + Indirect = true; + Form = static_cast(DebugInfoData.getULEB128(OffsetPtr)); + break; + + default: + return false; + } + } while (Indirect); + return true; +} + +Optional DWARFFormValue::getFixedByteSize(dwarf::Form Form, + const DWARFUnit *U) { + return ::getFixedByteSize(Form, U); +} + +Optional +DWARFFormValue::getFixedByteSize(dwarf::Form Form, uint16_t Version, + uint8_t AddrSize, + llvm::dwarf::DwarfFormat Format) { + FormSizeHelper FSH(Version, AddrSize, Format); + return ::getFixedByteSize(Form, &FSH); +} + bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { // First, check DWARF4 form classes. if (Form < makeArrayRef(DWARF4FormClasses).size() && @@ -155,8 +309,7 @@ : U->getRefAddrByteSize(); RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); if (AI != U->getRelocMap()->end()) { - const std::pair &R = AI->second; - Value.uval = data.getUnsigned(offset_ptr, AddrSize) + R.second; + Value.uval = data.getUnsigned(offset_ptr, AddrSize) + AI->second.second; } else Value.uval = data.getUnsigned(offset_ptr, AddrSize); break; @@ -188,7 +341,8 @@ Value.uval = data.getU16(offset_ptr); break; case DW_FORM_data4: - case DW_FORM_ref4: { + case DW_FORM_ref4: + case DW_FORM_strp: { Value.uval = data.getU32(offset_ptr); if (!U) break; @@ -216,15 +370,16 @@ indirect = true; break; case DW_FORM_sec_offset: - case DW_FORM_strp: case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: { - // FIXME: This is 64-bit for DWARF64. - Value.uval = data.getU32(offset_ptr); + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_strp_sup: + case DW_FORM_ref_sup: { if (!U) - break; - RelocAddrMap::const_iterator AI = - U->getRelocMap()->find(*offset_ptr - 4); + return false; + RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); + uint8_t Size = U->getDwarfOffsetByteSize(); + Value.uval = data.getUnsigned(offset_ptr, Size); if (AI != U->getRelocMap()->end()) Value.uval += AI->second.second; break; @@ -256,120 +411,22 @@ 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(DataExtractor DebugInfoData, + uint32_t *offset_ptr, const DWARFUnit *U) const { + return DWARFFormValue::skipValue(Form, DebugInfoData, 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 DebugInfoData, + uint32_t *offset_ptr, const DWARFUnit *U) { + return skipFormValue(form, DebugInfoData, offset_ptr, U); } -bool -DWARFFormValue::skipValue(dwarf::Form form, DataExtractor debug_info_data, - uint32_t *offset_ptr, uint16_t Version, - uint8_t AddrSize) { - bool indirect = false; - do { - switch (form) { - // Blocks if inlined data that have a length field and the data bytes - // inlined in the .debug_info - case DW_FORM_exprloc: - case DW_FORM_block: { - uint64_t size = debug_info_data.getULEB128(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block1: { - uint8_t size = debug_info_data.getU8(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block2: { - uint16_t size = debug_info_data.getU16(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block4: { - uint32_t size = debug_info_data.getU32(offset_ptr); - *offset_ptr += size; - return true; - } - // Inlined NULL terminated C-strings - case DW_FORM_string: - 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; - - // signed or unsigned LEB 128 values - // case DW_FORM_APPLE_db_str: - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_GNU_str_index: - case DW_FORM_GNU_addr_index: - debug_info_data.getULEB128(offset_ptr); - return true; - - case DW_FORM_indirect: - indirect = true; - 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; - } - } while (indirect); - return true; +bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor DebugInfoData, + uint32_t *offset_ptr, uint16_t Version, + uint8_t AddrSize, + llvm::dwarf::DwarfFormat Format) { + FormSizeHelper FSH(Version, AddrSize, Format); + return skipFormValue(form, DebugInfoData, offset_ptr, &FSH); } void @@ -556,8 +613,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 + dwarf::DwarfFormat Format = 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 = 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 @@ -21,16 +21,47 @@ 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()); + 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) {