(defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \
defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \
defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX || \
- defined HANDLE_DW_END)
+ defined HANDLE_DW_END || defined HANDLE_DW_SECT)
#error "Missing macro definition of HANDLE_DW*"
#endif
#define HANDLE_DW_END(ID, NAME)
#endif
+#ifndef HANDLE_DW_SECT
+#define HANDLE_DW_SECT(ID, NAME)
+#endif
+
HANDLE_DW_TAG(0x0000, null, 2, DWARF, DW_KIND_NONE)
HANDLE_DW_TAG(0x0001, array_type, 2, DWARF, DW_KIND_TYPE)
HANDLE_DW_TAG(0x0002, class_type, 2, DWARF, DW_KIND_TYPE)
HANDLE_DW_IDX(0x04, parent)
HANDLE_DW_IDX(0x05, type_hash)
+// DWARF package file section identifiers.
+// DWARFv5, section 7.3.5.3, table 7.1.
+HANDLE_DW_SECT(1, INFO)
+HANDLE_DW_SECT(3, ABBREV)
+HANDLE_DW_SECT(4, LINE)
+HANDLE_DW_SECT(5, LOCLISTS)
+HANDLE_DW_SECT(6, STR_OFFSETS)
+HANDLE_DW_SECT(7, MACRO)
+HANDLE_DW_SECT(8, RNGLISTS)
#undef HANDLE_DW_TAG
#undef HANDLE_DW_AT
#undef HANDLE_DWARF_SECTION
#undef HANDLE_DW_IDX
#undef HANDLE_DW_END
+#undef HANDLE_DW_SECT
class raw_ostream;
+/// The enum of section identifiers to be used in internal interfaces.
+///
+/// Pre-standard implementation of package files defined a number of section
+/// identifiers with values that clash definitions in the DWARFv5 standard.
+/// See https://gcc.gnu.org/wiki/DebugFissionDWP and Section 7.3.5.3 in DWARFv5.
+///
+/// The following identifiers are the same in the proposal and in DWARFv5:
+/// - DW_SECT_INFO = 1 (.debug_info.dwo)
+/// - DW_SECT_ABBREV = 3 (.debug_abbrev.dwo)
+/// - DW_SECT_LINE = 4 (.debug_line.dwo)
+/// - DW_SECT_STR_OFFSETS = 6 (.debug_str_offsets.dwo)
+///
+/// The following identifiers are defined only in DWARFv5:
+/// - DW_SECT_LOCLISTS = 5 (.debug_loclists.dwo)
+/// - DW_SECT_RNGLISTS = 8 (.debug_rnglists.dwo)
+///
+/// The following identifiers are defined only in the GNU proposal:
+/// - DW_SECT_TYPES = 2 (.debug_types.dwo)
+/// - DW_SECT_LOC = 5 (.debug_loc.dwo)
+/// - DW_SECT_MACINFO = 7 (.debug_macinfo.dwo)
+///
+/// DW_SECT_MACRO for the .debug_macro.dwo section is defined in both standards,
+/// but with different values, 8 in GNU and 7 in DWARFv5.
+///
+/// This enum defines constants to represent the identifiers of both sets.
+/// For DWARFv5 ones, the values are the same as defined in the standard.
+/// For pre-standard ones that correspond to sections being deprecated in
+/// DWARFv5, the values are chosen arbitrary and a tag "_EXT_" is added to
+/// the names.
+///
+/// The enum is for internal use only. The user should not expect the values
+/// to correspond to any input/output constants. Special conversion functions,
+/// serializeSectionKind() and deserializeSectionKind(), should be used for
+/// the translation.
enum DWARFSectionKind {
- DW_SECT_INFO = 1,
- DW_SECT_EXT_TYPES,
- DW_SECT_ABBREV,
- DW_SECT_LINE,
- DW_SECT_EXT_LOC,
- DW_SECT_STR_OFFSETS,
- DW_SECT_EXT_MACINFO,
- DW_SECT_MACRO,
+ /// Denotes a value read from an index section that does not correspond
+ /// to any of the supported standards.
+ DW_SECT_EXT_unknown = 0,
+#define HANDLE_DW_SECT(ID, NAME) DW_SECT_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+ DW_SECT_EXT_TYPES = 2,
+ DW_SECT_EXT_LOC = 9,
+ DW_SECT_EXT_MACINFO = 10,
};
+/// Convert the internal value for a section kind to an on-disk value.
+///
+/// The conversion depends on the version of the index section.
+/// IndexVersion is expected to be either 2 for pre-standard GNU proposal
+/// or 5 for DWARFv5 package file.
+uint32_t serializeSectionKind(DWARFSectionKind Kind, unsigned IndexVersion);
+
+/// Convert a value read from an index section to the internal representation.
+///
+/// The conversion depends on the index section version, which is expected
+/// to be either 2 for pre-standard GNU proposal or 5 for DWARFv5 package file.
+DWARFSectionKind deserializeSectionKind(uint32_t Value, unsigned IndexVersion);
+
class DWARFUnitIndex {
struct Header {
uint32_t Version;
DWARFSectionKind InfoColumnKind;
int InfoColumn = -1;
std::unique_ptr<DWARFSectionKind[]> ColumnKinds;
+ // This is a parallel array of section identifiers as they read from the input
+ // file. The mapping from raw values to DWARFSectionKind is not revertable in
+ // case of unknown identifiers, so we keep them here.
+ std::unique_ptr<uint32_t[]> RawSectionIds;
std::unique_ptr<Entry[]> Rows;
mutable std::vector<Entry *> OffsetLookup;
using namespace llvm;
+namespace {
+
+enum class DWARFSectionKindV2 {
+ DW_SECT_INFO = 1,
+ DW_SECT_TYPES = 2,
+ DW_SECT_ABBREV = 3,
+ DW_SECT_LINE = 4,
+ DW_SECT_LOC = 5,
+ DW_SECT_STR_OFFSETS = 6,
+ DW_SECT_MACINFO = 7,
+ DW_SECT_MACRO = 8,
+};
+
+} // namespace
+
+// Return true if the section identifier is defined in the DWARFv5 standard.
+constexpr bool isKnownV5SectionID(uint32_t ID) {
+ return ID >= DW_SECT_INFO && ID <= DW_SECT_RNGLISTS &&
+ ID != DW_SECT_EXT_TYPES;
+}
+
+uint32_t llvm::serializeSectionKind(DWARFSectionKind Kind,
+ unsigned IndexVersion) {
+ if (IndexVersion == 5) {
+ assert(isKnownV5SectionID(Kind));
+ return static_cast<uint32_t>(Kind);
+ }
+ assert(IndexVersion == 2);
+ switch (Kind) {
+#define CASE(S,T) \
+ case DW_SECT_##S: \
+ return static_cast<uint32_t>(DWARFSectionKindV2::DW_SECT_##T)
+ CASE(INFO, INFO);
+ CASE(EXT_TYPES, TYPES);
+ CASE(ABBREV, ABBREV);
+ CASE(LINE, LINE);
+ CASE(EXT_LOC, LOC);
+ CASE(STR_OFFSETS, STR_OFFSETS);
+ CASE(EXT_MACINFO, MACINFO);
+ CASE(MACRO, MACRO);
+#undef CASE
+ default:
+ // All other section kinds have no corresponding values in v2 indexes.
+ llvm_unreachable("Invalid DWARFSectionKind");
+ }
+}
+
+DWARFSectionKind llvm::deserializeSectionKind(uint32_t Value,
+ unsigned IndexVersion) {
+ if (IndexVersion == 5)
+ return isKnownV5SectionID(Value)
+ ? static_cast<DWARFSectionKind>(Value)
+ : DW_SECT_EXT_unknown;
+ assert(IndexVersion == 2);
+ switch (static_cast<DWARFSectionKindV2>(Value)) {
+#define CASE(S,T) \
+ case DWARFSectionKindV2::DW_SECT_##S: \
+ return DW_SECT_##T
+ CASE(INFO, INFO);
+ CASE(TYPES, EXT_TYPES);
+ CASE(ABBREV, ABBREV);
+ CASE(LINE, LINE);
+ CASE(LOC, EXT_LOC);
+ CASE(STR_OFFSETS, STR_OFFSETS);
+ CASE(MACINFO, EXT_MACINFO);
+ CASE(MACRO, MACRO);
+#undef CASE
+ }
+ return DW_SECT_EXT_unknown;
+}
+
bool DWARFUnitIndex::Header::parse(DataExtractor IndexData,
uint64_t *OffsetPtr) {
+ const uint64_t BeginOffset = *OffsetPtr;
if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16))
return false;
+ // GCC Debug Fission defines the version as an unsigned 32-bit field
+ // with value of 2, https://gcc.gnu.org/wiki/DebugFissionDWP.
+ // DWARFv5 defines the same space as an uhalf version field with value of 5
+ // and a 2 bytes long padding, see Section 7.3.5.3.
Version = IndexData.getU32(OffsetPtr);
+ if (Version != 2) {
+ *OffsetPtr = BeginOffset;
+ Version = IndexData.getU16(OffsetPtr);
+ if (Version != 5)
+ return false;
+ *OffsetPtr += 2; // Skip padding.
+ }
NumColumns = IndexData.getU32(OffsetPtr);
NumUnits = IndexData.getU32(OffsetPtr);
NumBuckets = IndexData.getU32(OffsetPtr);
- return Version <= 2;
+ return true;
}
void DWARFUnitIndex::Header::dump(raw_ostream &OS) const {
if (!Header.parse(IndexData, &Offset))
return false;
+ // Fix InfoColumnKind: in DWARFv5, type units are in .debug_info.dwo.
+ if (Header.Version == 5)
+ InfoColumnKind = DW_SECT_INFO;
+
if (!IndexData.isValidOffsetForDataOfSize(
Offset, Header.NumBuckets * (8 + 4) +
(2 * Header.NumUnits + 1) * 4 * Header.NumColumns))
auto Contribs =
std::make_unique<Entry::SectionContribution *[]>(Header.NumUnits);
ColumnKinds = std::make_unique<DWARFSectionKind[]>(Header.NumColumns);
+ RawSectionIds = std::make_unique<uint32_t[]>(Header.NumColumns);
// Read Hash Table of Signatures
for (unsigned i = 0; i != Header.NumBuckets; ++i)
// Read the Column Headers
for (unsigned i = 0; i != Header.NumColumns; ++i) {
- ColumnKinds[i] = static_cast<DWARFSectionKind>(IndexData.getU32(&Offset));
+ RawSectionIds[i] = IndexData.getU32(&Offset);
+ ColumnKinds[i] = deserializeSectionKind(RawSectionIds[i], Header.Version);
if (ColumnKinds[i] == InfoColumnKind) {
if (InfoColumn != -1)
return false;
}
StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) {
-#define CASE(DS) \
- case DW_SECT_##DS: \
- return #DS;
switch (DS) {
- CASE(INFO);
- CASE(ABBREV);
- CASE(LINE);
- CASE(STR_OFFSETS);
- CASE(MACRO);
+#define HANDLE_DW_SECT(ID, NAME) \
+ case DW_SECT_##NAME: \
+ return #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
case DW_SECT_EXT_TYPES:
return "TYPES";
case DW_SECT_EXT_LOC:
return "LOC";
case DW_SECT_EXT_MACINFO:
return "MACINFO";
+ case DW_SECT_EXT_unknown:
+ return StringRef();
}
- return StringRef();
+ llvm_unreachable("Unknown DWARFSectionKind");
}
void DWARFUnitIndex::dump(raw_ostream &OS) const {
if (!Name.empty())
OS << ' ' << left_justify(Name, 24);
else
- OS << format(" Unknown: %-15u", static_cast<unsigned>(Kind));
+ OS << format(" Unknown: %-15" PRIu32, RawSectionIds[i]);
}
OS << "\n----- ------------------";
for (unsigned i = 0; i != Header.NumColumns; ++i)
--- /dev/null
+## The test checks that we can parse and dump a pre-standard CU index section.
+## See https://gcc.gnu.org/wiki/DebugFissionDWP for the proposal.
+
+# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
+# RUN: llvm-dwarfdump -debug-cu-index - | \
+# RUN: FileCheck %s
+
+# CHECK: .debug_cu_index contents:
+# CHECK-NEXT: version = 2 slots = 2
+# CHECK-EMPTY:
+# CHECK-NEXT: Index Signature INFO ABBREV LINE LOC STR_OFFSETS MACINFO MACRO
+# CHECK-NEXT: ----- ------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------
+# CHECK-NEXT: 1 0x1100001122222222 [0x00001000, 0x00001010) [0x00002000, 0x00002020) [0x00003000, 0x00003030) [0x00004000, 0x00004040) [0x00005000, 0x00005050) [0x00006000, 0x00006060) [0x00007000, 0x00007070)
+
+ .section .debug_cu_index, "", @progbits
+## Header:
+ .long 2 # Version
+ .long 7 # Section count
+ .long 1 # Unit count
+ .long 2 # Slot count
+## Hash Table of Signatures:
+ .quad 0x1100001122222222
+ .quad 0
+## Parallel Table of Indexes:
+ .long 1
+ .long 0
+## Table of Section Offsets:
+## Row 0:
+ .long 1 # DW_SECT_INFO
+ .long 3 # DW_SECT_ABBREV
+ .long 4 # DW_SECT_LINE
+ .long 5 # DW_SECT_LOC
+ .long 6 # DW_SECT_STR_OFFSETS
+ .long 7 # DW_SECT_MACINFO
+ .long 8 # DW_SECT_MACRO
+## Row 1:
+ .long 0x1000 # Offset in .debug_info.dwo
+ .long 0x2000 # Offset in .debug_abbrev.dwo
+ .long 0x3000 # Offset in .debug_line.dwo
+ .long 0x4000 # Offset in .debug_loc.dwo
+ .long 0x5000 # Offset in .debug_str_offsets.dwo
+ .long 0x6000 # Offset in .debug_macinfo.dwo
+ .long 0x7000 # Offset in .debug_macro.dwo
+## Table of Section Sizes:
+ .long 0x10 # Size in .debug_info.dwo
+ .long 0x20 # Size in .debug_abbrev.dwo
+ .long 0x30 # Size in .debug_line.dwo
+ .long 0x40 # Size in .debug_loc.dwo
+ .long 0x50 # Size in .debug_str_offsets.dwo
+ .long 0x60 # Size in .debug_macinfo.dwo
+ .long 0x70 # Size in .debug_macro.dwo
--- /dev/null
+## The test checks that we can parse and dump a pre-standard TU index section.
+## See https://gcc.gnu.org/wiki/DebugFissionDWP for the proposal.
+
+# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
+# RUN: llvm-dwarfdump -debug-tu-index - | \
+# RUN: FileCheck %s
+
+# CHECK: .debug_tu_index contents:
+# CHECK-NEXT: version = 2 slots = 2
+# CHECK-EMPTY:
+# CHECK-NEXT: Index Signature TYPES ABBREV LINE STR_OFFSETS
+# CHECK-NEXT: ----- ------------------ ------------------------ ------------------------ ------------------------ ------------------------
+# CHECK-NEXT: 1 0x1100001122222222 [0x00001000, 0x00001010) [0x00002000, 0x00002020) [0x00003000, 0x00003030) [0x00004000, 0x00004040)
+
+ .section .debug_tu_index, "", @progbits
+## Header:
+ .long 2 # Version
+ .long 4 # Section count
+ .long 1 # Unit count
+ .long 2 # Slot count
+## Hash Table of Signatures:
+ .quad 0x1100001122222222
+ .quad 0
+## Parallel Table of Indexes:
+ .long 1
+ .long 0
+## Table of Section Offsets:
+## Row 0:
+ .long 2 # DW_SECT_TYPES
+ .long 3 # DW_SECT_ABBREV
+ .long 4 # DW_SECT_LINE
+ .long 6 # DW_SECT_STR_OFFSETS
+## Row 1:
+ .long 0x1000 # Offset in .debug_types.dwo
+ .long 0x2000 # Offset in .debug_abbrev.dwo
+ .long 0x3000 # Offset in .debug_line.dwo
+ .long 0x4000 # Offset in .debug_str_offsets.dwo
+## Table of Section Sizes:
+ .long 0x10 # Size in .debug_types.dwo
+ .long 0x20 # Size in .debug_abbrev.dwo
+ .long 0x30 # Size in .debug_line.dwo
+ .long 0x40 # Size in .debug_str_offsets.dwo
--- /dev/null
+## The test checks that we can parse and dump a CU index section that is
+## compliant to the DWARFv5 standard.
+
+# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
+# RUN: llvm-dwarfdump -debug-cu-index - | \
+# RUN: FileCheck %s
+
+# CHECK: .debug_cu_index contents:
+# CHECK-NEXT: version = 5 slots = 2
+# CHECK-EMPTY:
+# CHECK-NEXT: Index Signature INFO ABBREV LINE LOCLISTS STR_OFFSETS MACRO RNGLISTS
+# CHECK-NEXT: ----- ------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------ ------------------------
+# CHECK-NEXT: 1 0x1100001122222222 [0x00001000, 0x00001010) [0x00002000, 0x00002020) [0x00003000, 0x00003030) [0x00004000, 0x00004040) [0x00005000, 0x00005050) [0x00006000, 0x00006060) [0x00007000, 0x00007070)
+
+ .section .debug_cu_index, "", @progbits
+## Header:
+ .short 5 # Version
+ .space 2 # Padding
+ .long 7 # Section count
+ .long 1 # Unit count
+ .long 2 # Slot count
+## Hash Table of Signatures:
+ .quad 0x1100001122222222
+ .quad 0
+## Parallel Table of Indexes:
+ .long 1
+ .long 0
+## Table of Section Offsets:
+## Row 0:
+ .long 1 # DW_SECT_INFO
+ .long 3 # DW_SECT_ABBREV
+ .long 4 # DW_SECT_LINE
+ .long 5 # DW_SECT_LOCLISTS
+ .long 6 # DW_SECT_STR_OFFSETS
+ .long 7 # DW_SECT_MACRO
+ .long 8 # DW_SECT_RNGLISTS
+## Row 1:
+ .long 0x1000 # Offset in .debug_info.dwo
+ .long 0x2000 # Offset in .debug_abbrev.dwo
+ .long 0x3000 # Offset in .debug_line.dwo
+ .long 0x4000 # Offset in .debug_loclists.dwo
+ .long 0x5000 # Offset in .debug_str_offsets.dwo
+ .long 0x6000 # Offset in .debug_macro.dwo
+ .long 0x7000 # Offset in .debug_rnglists.dwo
+## Table of Section Sizes:
+ .long 0x10 # Size in .debug_info.dwo
+ .long 0x20 # Size in .debug_abbrev.dwo
+ .long 0x30 # Size in .debug_line.dwo
+ .long 0x40 # Size in .debug_loclists.dwo
+ .long 0x50 # Size in .debug_str_offsets.dwo
+ .long 0x60 # Size in .debug_macro.dwo
+ .long 0x70 # Size in .debug_rnglists.dwo
--- /dev/null
+## The test checks that we can parse and dump a TU index section that is
+## compliant to the DWARFv5 standard.
+
+# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
+# RUN: llvm-dwarfdump -debug-tu-index - | \
+# RUN: FileCheck %s
+
+# CHECK: .debug_tu_index contents:
+# CHECK-NEXT: version = 5 slots = 2
+# CHECK-EMPTY:
+# CHECK-NEXT: Index Signature INFO ABBREV LINE STR_OFFSETS
+# CHECK-NEXT: ----- ------------------ ------------------------ ------------------------ ------------------------ ------------------------
+# CHECK-NEXT: 1 0x1100001122222222 [0x00001000, 0x00001010) [0x00002000, 0x00002020) [0x00003000, 0x00003030) [0x00004000, 0x00004040)
+
+ .section .debug_tu_index, "", @progbits
+## Header:
+ .short 5 # Version
+ .space 2 # Padding
+ .long 4 # Section count
+ .long 1 # Unit count
+ .long 2 # Slot count
+## Hash Table of Signatures:
+ .quad 0x1100001122222222
+ .quad 0
+## Parallel Table of Indexes:
+ .long 1
+ .long 0
+## Table of Section Offsets:
+## Row 0:
+ .long 1 # DW_SECT_INFO
+ .long 3 # DW_SECT_ABBREV
+ .long 4 # DW_SECT_LINE
+ .long 6 # DW_SECT_STR_OFFSETS
+## Row 1:
+ .long 0x1000 # Offset in .debug_info.dwo
+ .long 0x2000 # Offset in .debug_abbrev.dwo
+ .long 0x3000 # Offset in .debug_line.dwo
+ .long 0x4000 # Offset in .debug_str_offsets.dwo
+## Table of Section Sizes:
+ .long 0x10 # Size in .debug_info.dwo
+ .long 0x20 # Size in .debug_abbrev.dwo
+ .long 0x30 # Size in .debug_line.dwo
+ .long 0x40 # Size in .debug_str_offsets.dwo
StringRef DWPName;
};
-// Convert a section identifier into the index to use with
+// Convert an internal section identifier into the index to use with
// UnitIndexEntry::Contributions.
static unsigned getContributionIndex(DWARFSectionKind Kind) {
- assert(Kind >= DW_SECT_INFO);
- return Kind - DW_SECT_INFO;
+ // Assuming the pre-standard DWP format.
+ assert(serializeSectionKind(Kind, 2) >= DW_SECT_INFO);
+ return serializeSectionKind(Kind, 2) - DW_SECT_INFO;
}
// Convert a UnitIndexEntry::Contributions index to the corresponding on-disk