diff options
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp | 258 |
1 files changed, 125 insertions, 133 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp index f71543799e286..dcf2aefeb39f6 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp @@ -12,144 +12,144 @@ using namespace llvm; -void DWARFDebugAddrTable::clear() { - HeaderData = {}; +Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, + uint64_t EndOffset) { + assert(EndOffset >= *OffsetPtr); + uint64_t DataSize = EndOffset - *OffsetPtr; + assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize)); + if (AddrSize != 4 && AddrSize != 8) + return createStringError(errc::not_supported, + "address table at offset 0x%" PRIx64 + " has unsupported address size %" PRIu8 + " (4 and 8 are supported)", + Offset, AddrSize); + if (DataSize % AddrSize != 0) { + invalidateLength(); + return createStringError(errc::invalid_argument, + "address table at offset 0x%" PRIx64 + " contains data of size 0x%" PRIx64 + " which is not a multiple of addr size %" PRIu8, + Offset, DataSize, AddrSize); + } Addrs.clear(); - invalidateLength(); + size_t Count = DataSize / AddrSize; + Addrs.reserve(Count); + while (Count--) + Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr)); + return Error::success(); } -Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data, - uint64_t *OffsetPtr, - uint16_t Version, - uint8_t AddrSize, - std::function<void(Error)> WarnCallback) { - clear(); - HeaderOffset = *OffsetPtr; - // Read and verify the length field. - if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) +Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, uint8_t CUAddrSize, + std::function<void(Error)> WarnCallback) { + Offset = *OffsetPtr; + llvm::Error Err = Error::success(); + std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err); + if (Err) { + invalidateLength(); return createStringError(errc::invalid_argument, - "section is not large enough to contain a " - ".debug_addr table length at offset 0x%" - PRIx64, *OffsetPtr); - uint16_t UnitVersion; - if (Version == 0) { - WarnCallback(createStringError(errc::invalid_argument, - "DWARF version is not defined in CU," - " assuming version 5")); - UnitVersion = 5; - } else { - UnitVersion = Version; + "parsing address table at offset 0x%" PRIx64 + ": %s", + Offset, toString(std::move(Err)).c_str()); + } + + if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) { + uint64_t DiagnosticLength = Length; + invalidateLength(); + return createStringError( + errc::invalid_argument, + "section is not large enough to contain an address table " + "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64, + Offset, DiagnosticLength); } - // TODO: Add support for DWARF64. - Format = dwarf::DwarfFormat::DWARF32; - if (UnitVersion >= 5) { - HeaderData.Length = Data.getU32(OffsetPtr); - if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) { - invalidateLength(); - return createStringError(errc::not_supported, - "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64, - HeaderOffset); - } - if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) { - uint32_t TmpLength = getLength(); - invalidateLength(); - return createStringError(errc::invalid_argument, - ".debug_addr table at offset 0x%" PRIx64 - " has too small length (0x%" PRIx32 - ") to contain a complete header", - HeaderOffset, TmpLength); - } - uint64_t End = HeaderOffset + getLength(); - if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) { - uint32_t TmpLength = getLength(); - invalidateLength(); - return createStringError(errc::invalid_argument, - "section is not large enough to contain a .debug_addr table " - "of length 0x%" PRIx32 " at offset 0x%" PRIx64, - TmpLength, HeaderOffset); - } - - HeaderData.Version = Data.getU16(OffsetPtr); - HeaderData.AddrSize = Data.getU8(OffsetPtr); - HeaderData.SegSize = Data.getU8(OffsetPtr); - DataSize = getDataSize(); - } else { - HeaderData.Version = UnitVersion; - HeaderData.AddrSize = AddrSize; - // TODO: Support for non-zero SegSize. - HeaderData.SegSize = 0; - DataSize = Data.size(); + uint64_t EndOffset = *OffsetPtr + Length; + // Ensure that we can read the remaining header fields. + if (Length < 4) { + uint64_t DiagnosticLength = Length; + invalidateLength(); + return createStringError( + errc::invalid_argument, + "address table at offset 0x%" PRIx64 + " has a unit_length value of 0x%" PRIx64 + ", which is too small to contain a complete header", + Offset, DiagnosticLength); } - // Perform basic validation of the remaining header fields. + Version = Data.getU16(OffsetPtr); + AddrSize = Data.getU8(OffsetPtr); + SegSize = Data.getU8(OffsetPtr); - // We support DWARF version 5 for now as well as pre-DWARF5 - // implementations of .debug_addr table, which doesn't contain a header - // and consists only of a series of addresses. - if (HeaderData.Version > 5) { - return createStringError(errc::not_supported, "version %" PRIu16 - " of .debug_addr section at offset 0x%" PRIx64 " is not supported", - HeaderData.Version, HeaderOffset); - } - // FIXME: For now we just treat version mismatch as an error, - // however the correct way to associate a .debug_addr table - // with a .debug_info table is to look at the DW_AT_addr_base - // attribute in the info table. - if (HeaderData.Version != UnitVersion) - return createStringError(errc::invalid_argument, - ".debug_addr table at offset 0x%" PRIx64 - " has version %" PRIu16 - " which is different from the version suggested" - " by the DWARF unit header: %" PRIu16, - HeaderOffset, HeaderData.Version, UnitVersion); - if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) + // Perform a basic validation of the header fields. + if (Version != 5) return createStringError(errc::not_supported, - ".debug_addr table at offset 0x%" PRIx64 - " has unsupported address size %" PRIu8, - HeaderOffset, HeaderData.AddrSize); - if (HeaderData.AddrSize != AddrSize && AddrSize != 0) - return createStringError(errc::invalid_argument, - ".debug_addr table at offset 0x%" PRIx64 - " has address size %" PRIu8 - " which is different from CU address size %" PRIu8, - HeaderOffset, HeaderData.AddrSize, AddrSize); - + "address table at offset 0x%" PRIx64 + " has unsupported version %" PRIu16, + Offset, Version); // TODO: add support for non-zero segment selector size. - if (HeaderData.SegSize != 0) + if (SegSize != 0) return createStringError(errc::not_supported, - ".debug_addr table at offset 0x%" PRIx64 - " has unsupported segment selector size %" PRIu8, - HeaderOffset, HeaderData.SegSize); - if (DataSize % HeaderData.AddrSize != 0) { - invalidateLength(); - return createStringError(errc::invalid_argument, - ".debug_addr table at offset 0x%" PRIx64 - " contains data of size %" PRIu32 - " which is not a multiple of addr size %" PRIu8, - HeaderOffset, DataSize, HeaderData.AddrSize); + "address table at offset 0x%" PRIx64 + " has unsupported segment selector size %" PRIu8, + Offset, SegSize); + + if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset)) + return Err; + if (CUAddrSize && AddrSize != CUAddrSize) { + WarnCallback(createStringError( + errc::invalid_argument, + "address table at offset 0x%" PRIx64 " has address size %" PRIu8 + " which is different from CU address size %" PRIu8, + Offset, AddrSize, CUAddrSize)); } - Data.setAddressSize(HeaderData.AddrSize); - uint32_t AddrCount = DataSize / HeaderData.AddrSize; - for (uint32_t I = 0; I < AddrCount; ++I) - if (HeaderData.AddrSize == 4) - Addrs.push_back(Data.getU32(OffsetPtr)); - else - Addrs.push_back(Data.getU64(OffsetPtr)); return Error::success(); } +Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, + uint16_t CUVersion, + uint8_t CUAddrSize) { + assert(CUVersion > 0 && CUVersion < 5); + + Offset = *OffsetPtr; + Length = 0; + Version = CUVersion; + AddrSize = CUAddrSize; + SegSize = 0; + + return extractAddresses(Data, OffsetPtr, Data.size()); +} + +Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, + uint16_t CUVersion, + uint8_t CUAddrSize, + std::function<void(Error)> WarnCallback) { + if (CUVersion > 0 && CUVersion < 5) + return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize); + if (CUVersion == 0) + WarnCallback(createStringError(errc::invalid_argument, + "DWARF version is not defined in CU," + " assuming version 5")); + return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback); +} + void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { if (DumpOpts.Verbose) - OS << format("0x%8.8" PRIx32 ": ", HeaderOffset); - OS << format("Addr Section: length = 0x%8.8" PRIx32 - ", version = 0x%4.4" PRIx16 ", " - "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n", - HeaderData.Length, HeaderData.Version, HeaderData.AddrSize, - HeaderData.SegSize); + OS << format("0x%8.8" PRIx64 ": ", Offset); + if (Length) { + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); + OS << "Address table header: " + << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length) + << ", format = " << dwarf::FormatString(Format) + << format(", version = 0x%4.4" PRIx16, Version) + << format(", addr_size = 0x%2.2" PRIx8, AddrSize) + << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n"; + } if (Addrs.size() > 0) { - const char *AddrFmt = (HeaderData.AddrSize == 4) ? "0x%8.8" PRIx64 "\n" - : "0x%16.16" PRIx64 "\n"; + const char *AddrFmt = + (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n"; OS << "Addrs: [\n"; for (uint64_t Addr : Addrs) OS << format(AddrFmt, Addr); @@ -162,21 +162,13 @@ Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { return Addrs[Index]; return createStringError(errc::invalid_argument, "Index %" PRIu32 " is out of range of the " - ".debug_addr table at offset 0x%" PRIx64, - Index, HeaderOffset); + "address table at offset 0x%" PRIx64, + Index, Offset); } -uint32_t DWARFDebugAddrTable::getLength() const { - if (HeaderData.Length == 0) - return 0; - // TODO: DWARF64 support. - return HeaderData.Length + sizeof(uint32_t); +Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const { + if (Length == 0) + return None; + return Length + dwarf::getUnitLengthFieldByteSize(Format); } -uint32_t DWARFDebugAddrTable::getDataSize() const { - if (DataSize != 0) - return DataSize; - if (getLength() == 0) - return 0; - return getLength() - getHeaderSize(); -} |