120 changes: 105 additions & 15 deletions llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,98 @@

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 {
Expand All @@ -49,6 +132,10 @@ bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {
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))
Expand All @@ -58,6 +145,7 @@ bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {
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)
Expand All @@ -76,7 +164,8 @@ bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {

// 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;
Expand Down Expand Up @@ -105,20 +194,21 @@ bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {
}

StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) {
#define CASE(DS) \
case DW_SECT_##DS: \
return #DS;
switch (DS) {
CASE(INFO);
CASE(TYPES);
CASE(ABBREV);
CASE(LINE);
CASE(LOC);
CASE(STR_OFFSETS);
CASE(MACINFO);
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 {
Expand All @@ -133,7 +223,7 @@ 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)
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ bool DWARFVerifier::handleDebugInfo() {

OS << "Verifying .debug_types Unit Header Chain...\n";
DObj.forEachTypesSections([&](const DWARFSection &S) {
NumErrors += verifyUnitSection(S, DW_SECT_TYPES);
NumErrors += verifyUnitSection(S, DW_SECT_EXT_TYPES);
});
return NumErrors == 0;
}
Expand Down
51 changes: 51 additions & 0 deletions llvm/test/DebugInfo/X86/dwp-v2-cu-index.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
## 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
94 changes: 94 additions & 0 deletions llvm/test/DebugInfo/X86/dwp-v2-loc.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
## The test checks that pre-v5 compile units in package files read their
## location tables from .debug_loc.dwo sections.
## See dwp-v5-loclists.s for v5 units.

# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
# RUN: llvm-dwarfdump -debug-info -debug-loc - | \
# RUN: FileCheck %s

# CHECK: .debug_info.dwo contents:
# CHECK: DW_TAG_compile_unit
# CHECK-NEXT: DW_AT_GNU_dwo_id (0x1100001122222222)
# CHECK: DW_TAG_variable
# CHECK-NEXT: DW_AT_name ("a")
# CHECK-NEXT: DW_AT_location (0x00000000:
# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000001, 0x0000000000000010): DW_OP_reg5 RDI)

# CHECK: .debug_loc.dwo contents:
# CHECK: 0x00000013:
# CHECK-NEXT: DW_LLE_startx_length (0x00000001, 0x00000010): DW_OP_reg5 RDI

.section .debug_abbrev.dwo, "e", @progbits
.LAbbrevBegin:
.uleb128 1 # Abbreviation Code
.uleb128 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.uleb128 0x2131 # DW_AT_GNU_dwo_id
.uleb128 7 # DW_FORM_data8
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.uleb128 2 # Abbreviation Code
.uleb128 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.uleb128 3 # DW_AT_name
.uleb128 8 # DW_FORM_string
.uleb128 2 # DW_AT_location
.uleb128 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.LAbbrevEnd:

.section .debug_info.dwo, "e", @progbits
.LCUBegin:
.long .LCUEnd-.LCUVersion # Length of Unit
.LCUVersion:
.short 4 # Version
.long 0 # Abbrev offset
.byte 8 # Address size
.uleb128 1 # Abbrev [1] DW_TAG_compile_unit
.quad 0x1100001122222222 # DW_AT_GNU_dwo_id
.uleb128 2 # Abbrev [2] DW_TAG_variable
.asciz "a" # DW_AT_name
.long 0 # DW_AT_location
.byte 0 # End Of Children Mark
.LCUEnd:

.section .debug_loc.dwo, "e", @progbits
## Start the section with a number of dummy DW_LLE_end_of_list entries to check
## that the reading offset is correctly adjusted.
.zero 0x13
.LLocBegin:
.byte 3 # DW_LLE_startx_length
.uleb128 1 # Index
.long 0x10 # Length
.short 1 # Loc expr size
.byte 85 # DW_OP_reg5
.byte 0 # DW_LLE_end_of_list
.LLocEnd:

.section .debug_cu_index, "", @progbits
## Header:
.long 2 # Version
.long 3 # 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 5 # DW_SECT_LOC
## Row 1:
.long 0 # Offset in .debug_info.dwo
.long 0 # Offset in .debug_abbrev.dwo
.long .LLocBegin-.debug_loc.dwo # Offset in .debug_loc.dwo
## Table of Section Sizes:
.long .LCUEnd-.LCUBegin # Size in .debug_info.dwo
.long .LAbbrevEnd-.LAbbrevBegin # Size in .debug_abbrev.dwo
.long .LLocEnd-.LLocBegin # Size in .debug_loc.dwo
42 changes: 42 additions & 0 deletions llvm/test/DebugInfo/X86/dwp-v2-tu-index.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## 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
52 changes: 52 additions & 0 deletions llvm/test/DebugInfo/X86/dwp-v5-cu-index.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## 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
140 changes: 140 additions & 0 deletions llvm/test/DebugInfo/X86/dwp-v5-loclists.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
## The test checks that v5 compile units in package files read their
## location tables from .debug_loclists.dwo sections.
## See dwp-v2-loc.s for pre-v5 units.

# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
# RUN: llvm-dwarfdump -debug-info -debug-loclists - | \
# RUN: FileCheck %s

# CHECK: .debug_info.dwo contents:
# CHECK: DW_TAG_compile_unit
# CHECK: DW_TAG_variable
# CHECK-NEXT: DW_AT_name ("a")
# CHECK-NEXT: DW_AT_location (0x{{[0-9a-f]+}}:
# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000001, 0x0000000000000010): DW_OP_reg5 RDI)
# CHECK: DW_TAG_variable
# CHECK-NEXT: DW_AT_name ("b")
# CHECK-NEXT: DW_AT_location (indexed (0x1) loclist = 0x{{[0-9a-f]+}}:
# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000005, 0x0000000000000020): DW_OP_regx RDI)

# CHECK: .debug_loclists.dwo contents:
# CHECK: locations list header:
# CHECK: locations list header:
# CHECK: offsets:
# CHECK: 0x{{[0-9a-f]+}}:
# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000001, 0x0000000000000010): DW_OP_reg5 RDI
# CHECK: 0x{{[0-9a-f]+}}:
# CHECK-NEXT: DW_LLE_startx_length (0x0000000000000005, 0x0000000000000020): DW_OP_regx RDI

.section .debug_abbrev.dwo, "e", @progbits
.LAbbrevBegin:
.uleb128 1 # Abbreviation Code
.uleb128 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.uleb128 2 # Abbreviation Code
.uleb128 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.uleb128 3 # DW_AT_name
.uleb128 8 # DW_FORM_string
.uleb128 2 # DW_AT_location
.uleb128 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.uleb128 3 # Abbreviation Code
.uleb128 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.uleb128 3 # DW_AT_name
.uleb128 8 # DW_FORM_string
.uleb128 2 # DW_AT_location
.uleb128 34 # DW_FORM_loclistx
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.LAbbrevEnd:

.section .debug_info.dwo, "e", @progbits
.LCUBegin:
.long .LCUEnd-.LCUVersion # Length of Unit
.LCUVersion:
.short 5 # Version
.byte 5 # DW_UT_split_compile
.byte 8 # Address size
.long 0 # Abbrev offset
.quad 0x1100001122222222 # DWO id
.uleb128 1 # Abbrev [1] DW_TAG_compile_unit
.uleb128 2 # Abbrev [2] DW_TAG_variable
.asciz "a" # DW_AT_name
.long .LLL0-.LLLBegin # DW_AT_location (DW_FORM_sec_offset)
.uleb128 3 # Abbrev [3] DW_TAG_variable
.asciz "b" # DW_AT_name
.uleb128 1 # DW_AT_location (DW_FORM_loclistx)
.byte 0 # End Of Children Mark
.LCUEnd:

.section .debug_loclists.dwo, "e", @progbits
## Start the section with an unused table to check that the reading offset
## of the real table is correctly adjusted.
.long .LLLDummyEnd-.LLLDummyVersion # Length of Unit
.LLLDummyVersion:
.short 5 # Version
.byte 8 # Address size
.byte 0 # Segment selector size
.long 0 # Offset entry count
.byte 0 # DW_LLE_end_of_list
.LLLDummyEnd:

.LLLBegin:
.long .LLLEnd-.LLLVersion # Length of Unit
.LLLVersion:
.short 5 # Version
.byte 8 # Address size
.byte 0 # Segment selector size
.long 2 # Offset entry count
.LLLBase:
.long .LLL0-.LLLBase
.long .LLL1-.LLLBase
.LLL0:
.byte 3 # DW_LLE_startx_length
.uleb128 1 # Index
.uleb128 0x10 # Length
.uleb128 1 # Loc expr size
.byte 85 # DW_OP_reg5
.byte 0 # DW_LLE_end_of_list
.LLL1:
.byte 3 # DW_LLE_startx_length
.uleb128 5 # Index
.uleb128 0x20 # Length
.uleb128 2 # Loc expr size
.byte 144 # DW_OP_regx
.uleb128 5 # RDI
.byte 0 # DW_LLE_end_of_list
.LLLEnd:

.section .debug_cu_index, "", @progbits
## Header:
.short 5 # Version
.space 2 # Padding
.long 3 # 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 5 # DW_SECT_LOCLISTS
## Row 1:
.long 0 # Offset in .debug_info.dwo
.long 0 # Offset in .debug_abbrev.dwo
.long .LLLBegin-.debug_loclists.dwo # Offset in .debug_loclists.dwo
## Table of Section Sizes:
.long .LCUEnd-.LCUBegin # Size in .debug_info.dwo
.long .LAbbrevEnd-.LAbbrevBegin # Size in .debug_abbrev.dwo
.long .LLLEnd-.LLLBegin # Size in .debug_loclists.dwo
107 changes: 107 additions & 0 deletions llvm/test/DebugInfo/X86/dwp-v5-rnglists.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
## The test checks that ranges for compile units in package files are read
## correctly, i.e. the base offset in the index section is taken into account.

# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
# RUN: llvm-dwarfdump -v -debug-info -debug-rnglists - | \
# RUN: FileCheck %s

# CHECK: .debug_info.dwo contents:
# CHECK: Compile Unit:
# CHECK: DW_TAG_compile_unit [1]
# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000022
# CHECK-NEXT: [0x00000005, 0x0000000f))

# CHECK: .debug_rnglists.dwo contents:
# CHECK: 0x00000000: range list header:
# CHECK: 0x0000000d: range list header:
# CHECK-NEXT: offsets: [
# CHECK-NEXT: 0x00000008 => 0x00000021
# CHECK-NEXT: 0x00000009 => 0x00000022
# CHECK-NEXT: ]
# CHECK-NEXT: ranges:
# CHECK-NEXT: 0x00000021: [DW_RLE_end_of_list]
# CHECK-NEXT: 0x00000022: [DW_RLE_offset_pair]: 0x00000005, 0x0000000f => [0x00000005, 0x0000000f)
# CHECK-NEXT: 0x00000025: [DW_RLE_end_of_list]

.section .debug_abbrev.dwo, "e", @progbits
.LAbbrev:
.byte 0x01 # Abbrev code
.byte 0x11 # DW_TAG_compile_unit
.byte 0x00 # DW_CHILDREN_no
.byte 0x55 # DW_AT_ranges
.byte 0x23 # DW_FORM_rnglistx
.byte 0x00 # EOM(1)
.byte 0x00 # EOM(2)
.byte 0x00 # EOM(3)
.LAbbrevEnd:

.section .debug_info.dwo, "e", @progbits
.LCU:
.long .LCUEnd-.LCUVersion # Length
.LCUVersion:
.short 5 # Version
.byte 5 # DW_UT_split_compile
.byte 4 # Address Size (in bytes)
.long 0 # Offset Into Abbrev Section
.quad 0x1100001122222222 # DWO id
.uleb128 1 # Abbrev [1] DW_TAG_compile_unit
.uleb128 1 # DW_AT_ranges (DW_FORM_rnglistx)
.LCUEnd:

.section .debug_rnglists.dwo,"e",@progbits
.LRLT0:
.long .LRLT0End-.LRLT0Version # Length
.LRLT0Version:
.short 5
.byte 4
.byte 0
.long 0
.LRLT0List0:
.byte 0 # DW_RLE_end_of_list
.LRLT0End:

.LRLT1:
.long .LRLT1End-.LRLT1Version
.LRLT1Version:
.short 5 # Version
.byte 4 # Address size
.byte 0 # Segment selector size
.long 2 # Offset entry count
.LRLT1Base:
.long .LRLT1List0-.LRLT1Base
.long .LRLT1List1-.LRLT1Base
.LRLT1List0:
.byte 0 # DW_RLE_end_of_list
.LRLT1List1:
.byte 4 # DW_RLE_offset_pair
.uleb128 5 # Starting offset
.uleb128 15 # Ending offset
.byte 0 # DW_RLE_end_of_list
.LRLT1End:

.section .debug_cu_index, "", @progbits
## Header:
.short 5 # Version
.space 2 # Padding
.long 3 # 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 8 # DW_SECT_RNGLISTS
## Row 1:
.long 0 # Offset in .debug_info.dwo
.long 0 # Offset in .debug_abbrev.dwo
.long .LRLT1-.debug_rnglists.dwo # Offset in .debug_rnglists.dwo
## Table of Section Sizes:
.long .LCUEnd-.LCU # Size in .debug_info.dwo
.long .LAbbrevEnd-.LAbbrev # Size in .debug_abbrev.dwo
.long .LRLT1End-.LRLT1 # Size in .debug_rnglists.dwo
43 changes: 43 additions & 0 deletions llvm/test/DebugInfo/X86/dwp-v5-tu-index.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## 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
50 changes: 33 additions & 17 deletions llvm/tools/llvm-dwp/llvm-dwp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,20 @@ struct UnitIndexEntry {
StringRef DWPName;
};

// Convert an internal section identifier into the index to use with
// UnitIndexEntry::Contributions.
static unsigned getContributionIndex(DWARFSectionKind Kind) {
// 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
// value of the section identifier.
static unsigned getOnDiskSectionId(unsigned Index) {
return Index + DW_SECT_INFO;
}

static StringRef getSubsection(StringRef Section,
const DWARFUnitIndex::Entry &Entry,
DWARFSectionKind Kind) {
Expand All @@ -241,15 +255,15 @@ static void addAllTypesFromDWP(
// Zero out the debug_info contribution
Entry.Contributions[0] = {};
for (auto Kind : TUIndex.getColumnKinds()) {
auto &C = Entry.Contributions[Kind - DW_SECT_INFO];
auto &C = Entry.Contributions[getContributionIndex(Kind)];
C.Offset += I->Offset;
C.Length = I->Length;
++I;
}
auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO];
unsigned TypesIndex = getContributionIndex(DW_SECT_EXT_TYPES);
auto &C = Entry.Contributions[TypesIndex];
Out.emitBytes(Types.substr(
C.Offset - TUEntry.Contributions[DW_SECT_TYPES - DW_SECT_INFO].Offset,
C.Length));
C.Offset - TUEntry.Contributions[TypesIndex].Offset, C.Length));
C.Offset = TypesOffset;
TypesOffset += C.Length;
}
Expand All @@ -268,7 +282,7 @@ static void addAllTypes(MCStreamer &Out,
UnitIndexEntry Entry = CUEntry;
// Zero out the debug_info contribution
Entry.Contributions[0] = {};
auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO];
auto &C = Entry.Contributions[getContributionIndex(DW_SECT_EXT_TYPES)];
C.Offset = TypesOffset;
auto PrevOffset = Offset;
// Length of the unit, including the 4 byte length field.
Expand Down Expand Up @@ -345,7 +359,7 @@ writeIndex(MCStreamer &Out, MCSection *Section,
// Write the column headers (which sections will appear in the table)
for (size_t i = 0; i != ContributionOffsets.size(); ++i)
if (ContributionOffsets[i])
Out.emitIntValue(i + DW_SECT_INFO, 4);
Out.emitIntValue(getOnDiskSectionId(i), 4);

// Write the offsets.
writeIndexTable(Out, ContributionOffsets, IndexEntries,
Expand Down Expand Up @@ -438,8 +452,8 @@ static Error handleSection(
return Error::success();

if (DWARFSectionKind Kind = SectionPair->second.second) {
auto Index = Kind - DW_SECT_INFO;
if (Kind != DW_SECT_TYPES) {
auto Index = getContributionIndex(Kind);
if (Kind != DW_SECT_EXT_TYPES) {
CurEntry.Contributions[Index].Offset = ContributionOffsets[Index];
ContributionOffsets[Index] +=
(CurEntry.Contributions[Index].Length = Contents.size());
Expand Down Expand Up @@ -523,10 +537,10 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection();
const StringMap<std::pair<MCSection *, DWARFSectionKind>> KnownSections = {
{"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}},
{"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_TYPES}},
{"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}},
{"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}},
{"debug_str.dwo", {StrSection, static_cast<DWARFSectionKind>(0)}},
{"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_LOC}},
{"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}},
{"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}},
{"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}},
{"debug_cu_index", {CUIndexSection, static_cast<DWARFSectionKind>(0)}},
Expand Down Expand Up @@ -589,7 +603,8 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
P.first->second.Name = ID.Name;
P.first->second.DWOName = ID.DWOName;
addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection,
CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]);
CurEntry,
ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)]);
continue;
}

Expand Down Expand Up @@ -618,7 +633,7 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
NewEntry.DWOName = ID.DWOName;
NewEntry.DWPName = Input;
for (auto Kind : CUIndex.getColumnKinds()) {
auto &C = NewEntry.Contributions[Kind - DW_SECT_INFO];
auto &C = NewEntry.Contributions[getContributionIndex(Kind)];
C.Offset += I->Offset;
C.Length = I->Length;
++I;
Expand All @@ -628,13 +643,14 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
if (!CurTypesSection.empty()) {
if (CurTypesSection.size() != 1)
return make_error<DWPError>("multiple type unit sections in .dwp file");
DWARFUnitIndex TUIndex(DW_SECT_TYPES);
DWARFUnitIndex TUIndex(DW_SECT_EXT_TYPES);
DataExtractor TUIndexData(CurTUIndexSection, Obj.isLittleEndian(), 0);
if (!TUIndex.parse(TUIndexData))
return make_error<DWPError>("failed to parse tu_index");
addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, TypesSection,
CurTypesSection.front(), CurEntry,
ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]);
addAllTypesFromDWP(
Out, TypeIndexEntries, TUIndex, TypesSection, CurTypesSection.front(),
CurEntry,
ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)]);
}
}

Expand All @@ -645,7 +661,7 @@ static Error write(MCStreamer &Out, ArrayRef<std::string> Inputs) {
TypeIndexEntries);

// Lie about the type contribution
ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO] = 0;
ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES)] = 0;
// Unlie about the info contribution
ContributionOffsets[0] = 1;

Expand Down