Skip to content

Commit

Permalink
[DWARF] Support DWARF64 in DWARFListTableHeader.
Browse files Browse the repository at this point in the history
This enables 64-bit DWARF support for parsing range and location list tables.

Differential Revision: https://reviews.llvm.org/D66643

llvm-svn: 371014
  • Loading branch information
igorkudrin committed Sep 5, 2019
1 parent e99dc4b commit 991f0fb
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 44 deletions.
35 changes: 21 additions & 14 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFListTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class DWARFListTableHeader {
struct Header {
/// The total length of the entries for this table, not including the length
/// field itself.
uint32_t Length = 0;
uint64_t Length = 0;
/// The DWARF version number.
uint16_t Version;
/// The size in bytes of an address on the target architecture. For
Expand All @@ -75,7 +75,7 @@ class DWARFListTableHeader {
/// The offset table, which contains offsets to the individual list entries.
/// It is used by forms such as DW_FORM_rnglistx.
/// FIXME: Generate the table and use the appropriate forms.
std::vector<uint32_t> Offsets;
std::vector<uint64_t> Offsets;
/// The table's format, either DWARF32 or DWARF64.
dwarf::DwarfFormat Format;
/// The offset at which the header (and hence the table) is located within
Expand All @@ -97,14 +97,26 @@ class DWARFListTableHeader {
}
uint64_t getHeaderOffset() const { return HeaderOffset; }
uint8_t getAddrSize() const { return HeaderData.AddrSize; }
uint32_t getLength() const { return HeaderData.Length; }
uint64_t getLength() const { return HeaderData.Length; }
uint16_t getVersion() const { return HeaderData.Version; }
StringRef getSectionName() const { return SectionName; }
StringRef getListTypeString() const { return ListTypeString; }
dwarf::DwarfFormat getFormat() const { return Format; }

/// Return the size of the table header including the length but not including
/// the offsets.
static uint8_t getHeaderSize(dwarf::DwarfFormat Format) {
switch (Format) {
case dwarf::DwarfFormat::DWARF32:
return 12;
case dwarf::DwarfFormat::DWARF64:
return 20;
}
llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
}

void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
Optional<uint64_t> getOffsetEntry(uint32_t Index) const {
if (Index < Offsets.size())
return Offsets[Index];
return None;
Expand All @@ -116,7 +128,7 @@ class DWARFListTableHeader {
/// Returns the length of the 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 length() const;
uint64_t length() const;
};

/// A class representing a table of lists as specified in the DWARF v5
Expand Down Expand Up @@ -155,30 +167,25 @@ template <typename DWARFListType> class DWARFListTableBase {

uint64_t getHeaderOffset() const { return Header.getHeaderOffset(); }
uint8_t getAddrSize() const { return Header.getAddrSize(); }
dwarf::DwarfFormat getFormat() const { return Header.getFormat(); }

void dump(raw_ostream &OS,
llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
LookupPooledAddress,
DIDumpOptions DumpOpts = {}) const;

/// Return the contents of the offset entry designated by a given index.
Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
Optional<uint64_t> getOffsetEntry(uint32_t Index) const {
return Header.getOffsetEntry(Index);
}
/// Return the size of the table header including the length but not including
/// the offsets. This is dependent on the table format, which is unambiguously
/// derived from parsing the table.
uint8_t getHeaderSize() const {
switch (Header.getFormat()) {
case dwarf::DwarfFormat::DWARF32:
return 12;
case dwarf::DwarfFormat::DWARF64:
return 20;
}
llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
return DWARFListTableHeader::getHeaderSize(getFormat());
}

uint32_t length() { return Header.length(); }
uint64_t length() { return Header.length(); }
};

template <typename DWARFListType>
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ class DWARFUnit {
/// Return a rangelist's offset based on an index. The index designates
/// an entry in the rangelist table's offset array and is supplied by
/// DW_FORM_rnglistx.
Optional<uint32_t> getRnglistOffset(uint32_t Index) {
Optional<uint64_t> getRnglistOffset(uint32_t Index) {
if (RngListTable)
return RngListTable->getOffsetEntry(Index);
return None;
Expand Down
52 changes: 30 additions & 22 deletions llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,34 @@ Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
"section is not large enough to contain a "
"%s table length at offset 0x%" PRIx64,
SectionName.data(), *OffsetPtr);
// TODO: Add support for DWARF64.
HeaderData.Length = Data.getRelocatedValue(4, OffsetPtr);
if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64)
return createStringError(errc::not_supported,
"DWARF64 is not supported in %s at offset 0x%" PRIx64,
SectionName.data(), HeaderOffset);
Format = dwarf::DwarfFormat::DWARF32;
if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
uint8_t OffsetByteSize = 4;
HeaderData.Length = Data.getRelocatedValue(4, OffsetPtr);
if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) {
Format = dwarf::DwarfFormat::DWARF64;
OffsetByteSize = 8;
HeaderData.Length = Data.getU64(OffsetPtr);
} else if (HeaderData.Length >= dwarf::DW_LENGTH_lo_reserved) {
return createStringError(errc::invalid_argument,
"%s table at offset 0x%" PRIx64
" has unsupported reserved unit length of value 0x%8.8" PRIx64,
SectionName.data(), HeaderOffset, HeaderData.Length);
}
uint64_t FullLength =
HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format);
assert(FullLength == length());
if (FullLength < getHeaderSize(Format))
return createStringError(errc::invalid_argument,
"%s table at offset 0x%" PRIx64
" has too small length (0x%" PRIx32
" has too small length (0x%" PRIx64
") to contain a complete header",
SectionName.data(), HeaderOffset, length());
uint64_t End = HeaderOffset + length();
if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset))
SectionName.data(), HeaderOffset, FullLength);
uint64_t End = HeaderOffset + FullLength;
if (!Data.isValidOffsetForDataOfSize(HeaderOffset, FullLength))
return createStringError(errc::invalid_argument,
"section is not large enough to contain a %s table "
"of length 0x%" PRIx32 " at offset 0x%" PRIx64,
SectionName.data(), length(), HeaderOffset);
"of length 0x%" PRIx64 " at offset 0x%" PRIx64,
SectionName.data(), FullLength, HeaderOffset);

HeaderData.Version = Data.getU16(OffsetPtr);
HeaderData.AddrSize = Data.getU8(OffsetPtr);
Expand All @@ -65,23 +74,23 @@ Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
"%s table at offset 0x%" PRIx64
" has unsupported segment selector size %" PRIu8,
SectionName.data(), HeaderOffset, HeaderData.SegSize);
if (End < HeaderOffset + sizeof(HeaderData) +
HeaderData.OffsetEntryCount * sizeof(uint32_t))
if (End < HeaderOffset + getHeaderSize(Format) +
HeaderData.OffsetEntryCount * OffsetByteSize)
return createStringError(errc::invalid_argument,
"%s table at offset 0x%" PRIx64 " has more offset entries (%" PRIu32
") than there is space for",
SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount);
Data.setAddressSize(HeaderData.AddrSize);
for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I)
Offsets.push_back(Data.getRelocatedValue(4, OffsetPtr));
Offsets.push_back(Data.getRelocatedValue(OffsetByteSize, OffsetPtr));
return Error::success();
}

void DWARFListTableHeader::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
if (DumpOpts.Verbose)
OS << format("0x%8.8" PRIx64 ": ", HeaderOffset);
OS << format(
"%s list header: length = 0x%8.8" PRIx32 ", version = 0x%4.4" PRIx16 ", "
"%s list header: length = 0x%8.8" PRIx64 ", version = 0x%4.4" PRIx16 ", "
"addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8
", offset_entry_count = "
"0x%8.8" PRIx32 "\n",
Expand All @@ -91,18 +100,17 @@ void DWARFListTableHeader::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
if (HeaderData.OffsetEntryCount > 0) {
OS << "offsets: [";
for (const auto &Off : Offsets) {
OS << format("\n0x%8.8" PRIx32, Off);
OS << format("\n0x%8.8" PRIx64, Off);
if (DumpOpts.Verbose)
OS << format(" => 0x%8.8" PRIx64,
Off + HeaderOffset + sizeof(HeaderData));
Off + HeaderOffset + getHeaderSize(Format));
}
OS << "\n]\n";
}
}

uint32_t DWARFListTableHeader::length() const {
uint64_t DWARFListTableHeader::length() const {
if (HeaderData.Length == 0)
return 0;
// TODO: DWARF64 support.
return HeaderData.Length + sizeof(uint32_t);
return HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format);
}

This file was deleted.

39 changes: 39 additions & 0 deletions llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_dwarf64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \
# RUN: llvm-dwarfdump -v --debug-rnglists - | \
# RUN: FileCheck %s

# CHECK: .debug_rnglists contents:
# CHECK-NEXT: 0x00000000: range list header:
# CHECK-SAME: length = 0x0000001a,
# CHECK-SAME: version = 0x0005,
# CHECK-SAME: addr_size = 0x08,
# CHECK-SAME: seg_size = 0x00,
# CHECK-SAME: offset_entry_count = 0x00000002
# CHECK-NEXT: offsets: [
# CHECK-NEXT: 0x00000010 => 0x00000024
# CHECK-NEXT: 0x00000011 => 0x00000025
# CHECK-NEXT: ]
# CHECK-NEXT: ranges:
# CHECK-NEXT: 0x00000024: [DW_RLE_end_of_list]
# CHECK-NEXT: 0x00000025: [DW_RLE_end_of_list]

.section .debug_rnglists,"",@progbits
.long 0xffffffff # DWARF64 mark
.quad .Lend - .Lversion # Table length
.Lversion:
.short 5 # Version
.byte 8 # Address size
.byte 0 # Segment selector size
.long 2 # Offset entry count

.Loffsets:
.quad .Ltable0 - .Loffsets
.quad .Ltable1 - .Loffsets

.Ltable0:
.byte 0 # DW_RLE_end_of_list

.Ltable1:
.byte 0 # DW_RLE_end_of_list

.Lend:
5 changes: 0 additions & 5 deletions llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@
# CHECK-NEXT: error: section is not large enough to contain a .debug_rnglists table of length 0x1f at offset 0xe5
# CHECK-NOT: error:

# RUN: llvm-mc %S/Inputs/debug_rnglists_DWARF64.s -filetype obj -triple x86_64-pc-linux -o - | \
# RUN: llvm-dwarfdump --debug-rnglists - 2>&1 | FileCheck %s --check-prefix=DWARF64

# DWARF64: DWARF64 is not supported in .debug_rnglists at offset 0x0

.section .debug_rnglists,"",@progbits

# Table 1 (good)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o - | \
# RUN: llvm-dwarfdump --debug-rnglists - 2>&1 | \
# RUN: FileCheck %s --implicit-check-not=error

# CHECK: error: .debug_rnglists table at offset 0x0 has unsupported reserved unit length of value 0xfffffff0

.section .debug_rnglists,"",@progbits
.long 0xfffffff0

0 comments on commit 991f0fb

Please sign in to comment.