/// The table consists of a header followed by an array of address values from
/// .debug_addr section.
class DWARFDebugAddrTable {
-public:
- struct Header {
- /// The total length of the entries for this table, not including the length
- /// field itself.
- uint32_t Length = 0;
- /// The DWARF version number.
- uint16_t Version = 5;
- /// The size in bytes of an address on the target architecture. For
- /// segmented addressing, this is the size of the offset portion of the
- /// address.
- uint8_t AddrSize;
- /// The size in bytes of a segment selector on the target architecture.
- /// If the target system uses a flat address space, this value is 0.
- uint8_t SegSize = 0;
- };
-
-private:
dwarf::DwarfFormat Format;
- uint64_t HeaderOffset;
- Header HeaderData;
- uint32_t DataSize = 0;
+ uint64_t Offset;
+ /// The total length of the entries for this table, not including the length
+ /// field itself.
+ uint32_t Length = 0;
+ /// The DWARF version number.
+ uint16_t Version;
+ /// The size in bytes of an address on the target architecture. For
+ /// segmented addressing, this is the size of the offset portion of the
+ /// address.
+ uint8_t AddrSize;
+ /// The size in bytes of a segment selector on the target architecture.
+ /// If the target system uses a flat address space, this value is 0.
+ uint8_t SegSize;
std::vector<uint64_t> Addrs;
+ /// Invalidate Length field to stop further processing.
+ void invalidateLength() { Length = 0; }
+
+ Error extractAddresses(const DWARFDataExtractor &Data, uint64_t *OffsetPtr,
+ uint64_t EndOffset);
+
public:
- void clear();
- /// Extract an entire table, including all addresses.
- Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr,
- uint16_t Version, uint8_t AddrSize,
+ /// Extract the entire table, including all addresses.
+ Error extract(const DWARFDataExtractor &Data, uint64_t *OffsetPtr,
+ uint16_t CUVersion, uint8_t CUAddrSize,
std::function<void(Error)> WarnCallback);
- uint64_t getHeaderOffset() const { return HeaderOffset; }
- uint8_t getAddrSize() const { return HeaderData.AddrSize; }
+ /// Extract a DWARFv5 address table.
+ Error extractV5(const DWARFDataExtractor &Data, uint64_t *OffsetPtr,
+ uint8_t CUAddrSize, std::function<void(Error)> WarnCallback);
+
+ /// Extract a pre-DWARFv5 address table. Such tables do not have a header
+ /// and consist only of a series of addresses.
+ /// See https://gcc.gnu.org/wiki/DebugFission for details.
+ Error extractPreStandard(const DWARFDataExtractor &Data, uint64_t *OffsetPtr,
+ uint16_t CUVersion, uint8_t CUAddrSize);
+
void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
/// Return the address based on a given index.
Expected<uint64_t> getAddrEntry(uint32_t Index) const;
- /// Return the size of the table header including the length
- /// but not including the addresses.
- uint8_t getHeaderSize() const {
- switch (Format) {
- case dwarf::DwarfFormat::DWARF32:
- return 8; // 4 + 2 + 1 + 1
- case dwarf::DwarfFormat::DWARF64:
- return 16; // 12 + 2 + 1 + 1
- }
- llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64)");
- }
-
- /// Returns the length of this table, including the length field, or 0 if the
- /// length has not been determined (e.g. because the table has not yet been
- /// parsed, or there was a problem in parsing).
- uint32_t getLength() const;
-
- /// Verify that the given length is valid for this table.
- bool hasValidLength() const { return getLength() != 0; }
-
- /// Invalidate Length field to stop further processing.
- void invalidateLength() { HeaderData.Length = 0; }
-
- /// Returns the length of the array of addresses.
- uint32_t getDataSize() const;
+ /// Return the full length of this table, including the length field.
+ /// Return None if the length cannot be identified reliably.
+ Optional<uint64_t> getFullLength() const;
};
} // end namespace llvm
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;
+ // Check that we can read the unit length field.
+ if (!Data.isValidOffsetForDataOfSize(Offset, 4))
return createStringError(errc::invalid_argument,
- "section is not large enough to contain an "
- "address 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;
- }
+ "section is not large enough to contain an "
+ "address table length at offset 0x%" PRIx64,
+ Offset);
// 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 = HeaderData.Length;
- invalidateLength();
- return createStringError(errc::invalid_argument,
- "address table at offset 0x%" PRIx64
- " has a unit_length value of 0x%" PRIx32
- ", which is too small to contain a complete header",
- HeaderOffset, TmpLength);
- }
- uint64_t End = HeaderOffset + getLength();
- if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
- uint32_t TmpLength = HeaderData.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%" PRIx32,
- HeaderOffset, TmpLength);
- }
-
- 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();
+ Length = Data.getU32(OffsetPtr);
+ if (Length == dwarf::DW_LENGTH_DWARF64) {
+ invalidateLength();
+ return createStringError(
+ errc::not_supported,
+ "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx64, Offset);
+ }
+
+ if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
+ uint32_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%" PRIx32,
+ Offset, DiagnosticLength);
+ }
+ uint64_t EndOffset = *OffsetPtr + Length;
+ // Ensure that we can read the remaining header fields.
+ if (Length < 4) {
+ uint32_t DiagnosticLength = Length;
+ invalidateLength();
+ return createStringError(
+ errc::invalid_argument,
+ "address table at offset 0x%" PRIx64
+ " has a unit_length value of 0x%" PRIx32
+ ", 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) {
+ // Perform a basic validation of the header fields.
+ if (Version != 5)
return createStringError(errc::not_supported,
"address table at offset 0x%" PRIx64
" has unsupported version %" PRIu16,
- HeaderOffset, HeaderData.Version);
- }
- // 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,
- "address 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)
+ Offset, Version);
+ // TODO: add support for non-zero segment selector size.
+ if (SegSize != 0)
return createStringError(errc::not_supported,
- "address table at offset 0x%" PRIx64
- " has unsupported address size %" PRIu8
- " (4 and 8 are supported)",
- HeaderOffset, HeaderData.AddrSize);
- if (HeaderData.AddrSize != AddrSize && AddrSize != 0)
+ "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,
- HeaderOffset, HeaderData.AddrSize, AddrSize));
-
- // TODO: add support for non-zero segment selector size.
- if (HeaderData.SegSize != 0)
- return createStringError(errc::not_supported,
- "address 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,
- "address table at offset 0x%" PRIx64
- " contains data of size %" PRIu32
- " which is not a multiple of addr size %" PRIu8,
- HeaderOffset, DataSize, HeaderData.AddrSize);
+ Offset, AddrSize, CUAddrSize));
}
- Data.setAddressSize(HeaderData.AddrSize);
- uint32_t AddrCount = DataSize / HeaderData.AddrSize;
- for (uint32_t I = 0; I < AddrCount; ++I)
- Addrs.push_back(Data.getRelocatedAddress(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);
- if (HeaderData.Length)
+ OS << format("0x%8.8" PRIx32 ": ", Offset);
+ if (Length)
OS << format("Address table header: 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);
+ ", version = 0x%4.4" PRIx16 ", addr_size = 0x%2.2" PRIx8
+ ", seg_size = 0x%2.2" PRIx8 "\n",
+ Length, Version, AddrSize, SegSize);
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);
if (Index < Addrs.size())
return Addrs[Index];
return createStringError(errc::invalid_argument,
- "Index %" PRIu32 " is out of range in the "
+ "Index %" PRIu32 " is out of range of the "
"address table at offset 0x%" PRIx64,
- Index, HeaderOffset);
+ Index, Offset);
}
-uint32_t DWARFDebugAddrTable::getLength() const {
- if (HeaderData.Length == 0)
- return 0;
+Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
+ if (Length == 0)
+ return None;
// TODO: DWARF64 support.
- return HeaderData.Length + sizeof(uint32_t);
+ return Length + sizeof(uint32_t);
}
-uint32_t DWARFDebugAddrTable::getDataSize() const {
- if (DataSize != 0)
- return DataSize;
- if (getLength() == 0)
- return 0;
- return getLength() - getHeaderSize();
-}