[DWARFv5] Read and dump multiple .debug_info sections.
Type units go in .debug_info comdats, not .debug_types, in v5. Differential Revision: https://reviews.llvm.org/D53907 llvm-svn: 346360
This commit is contained in:
parent
85e71733ed
commit
746c22389c
|
@ -11,6 +11,7 @@
|
|||
#define LLD_ELF_DWARF_H
|
||||
|
||||
#include "InputFiles.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
|
||||
|
@ -27,8 +28,9 @@ template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
|
|||
public:
|
||||
explicit LLDDwarfObj(ObjFile<ELFT> *Obj);
|
||||
|
||||
const llvm::DWARFSection &getInfoSection() const override {
|
||||
return InfoSection;
|
||||
void forEachInfoSections(
|
||||
llvm::function_ref<void(const llvm::DWARFSection &)> F) const override {
|
||||
F(InfoSection);
|
||||
}
|
||||
|
||||
const llvm::DWARFSection &getRangeSection() const override {
|
||||
|
|
|
@ -33,7 +33,8 @@ public:
|
|||
virtual ArrayRef<SectionName> getSectionNames() const { return {}; }
|
||||
virtual bool isLittleEndian() const = 0;
|
||||
virtual uint8_t getAddressSize() const { llvm_unreachable("unimplemented"); }
|
||||
virtual const DWARFSection &getInfoSection() const { return Dummy; }
|
||||
virtual void
|
||||
forEachInfoSections(function_ref<void(const DWARFSection &)> F) const {}
|
||||
virtual void
|
||||
forEachTypesSections(function_ref<void(const DWARFSection &)> F) const {}
|
||||
virtual StringRef getAbbrevSection() const { return ""; }
|
||||
|
@ -53,7 +54,8 @@ public:
|
|||
virtual StringRef getGnuPubNamesSection() const { return ""; }
|
||||
virtual StringRef getGnuPubTypesSection() const { return ""; }
|
||||
virtual const DWARFSection &getStringOffsetSection() const { return Dummy; }
|
||||
virtual const DWARFSection &getInfoDWOSection() const { return Dummy; }
|
||||
virtual void
|
||||
forEachInfoDWOSections(function_ref<void(const DWARFSection &)> F) const {}
|
||||
virtual void
|
||||
forEachTypesDWOSections(function_ref<void(const DWARFSection &)> F) const {}
|
||||
virtual StringRef getAbbrevDWOSection() const { return ""; }
|
||||
|
|
|
@ -351,20 +351,22 @@ void DWARFContext::dump(
|
|||
DObj->getAbbrevDWOSection()))
|
||||
getDebugAbbrevDWO()->dump(OS);
|
||||
|
||||
auto dumpDebugInfo = [&](unit_iterator_range Units) {
|
||||
if (DumpOffset)
|
||||
getDIEForOffset(DumpOffset.getValue())
|
||||
.dump(OS, 0, DumpOpts.noImplicitRecursion());
|
||||
auto dumpDebugInfo = [&](const char *Name, unit_iterator_range Units) {
|
||||
OS << '\n' << Name << " contents:\n";
|
||||
if (DumpOffset = DumpOffsets[DIDT_ID_DebugInfo])
|
||||
for (const auto &U : Units)
|
||||
U->getDIEForOffset(DumpOffset.getValue())
|
||||
.dump(OS, 0, DumpOpts.noImplicitRecursion());
|
||||
else
|
||||
for (const auto &U : Units)
|
||||
U->dump(OS, DumpOpts);
|
||||
};
|
||||
if (shouldDump(Explicit, ".debug_info", DIDT_ID_DebugInfo,
|
||||
DObj->getInfoSection().Data))
|
||||
dumpDebugInfo(info_section_units());
|
||||
if (shouldDump(ExplicitDWO, ".debug_info.dwo", DIDT_ID_DebugInfo,
|
||||
DObj->getInfoDWOSection().Data))
|
||||
dumpDebugInfo(dwo_info_section_units());
|
||||
if ((DumpType & DIDT_DebugInfo)) {
|
||||
if (Explicit || getNumCompileUnits())
|
||||
dumpDebugInfo(".debug_info", info_section_units());
|
||||
if (ExplicitDWO || getNumDWOCompileUnits())
|
||||
dumpDebugInfo(".debug_info.dwo", dwo_info_section_units());
|
||||
}
|
||||
|
||||
auto dumpDebugType = [&](const char *Name, unit_iterator_range Units) {
|
||||
OS << '\n' << Name << " contents:\n";
|
||||
|
@ -872,7 +874,9 @@ Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit(
|
|||
void DWARFContext::parseNormalUnits() {
|
||||
if (!NormalUnits.empty())
|
||||
return;
|
||||
NormalUnits.addUnitsForSection(*this, DObj->getInfoSection(), DW_SECT_INFO);
|
||||
DObj->forEachInfoSections([&](const DWARFSection &S) {
|
||||
NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO);
|
||||
});
|
||||
NormalUnits.finishedInfoUnits();
|
||||
DObj->forEachTypesSections([&](const DWARFSection &S) {
|
||||
NormalUnits.addUnitsForSection(*this, S, DW_SECT_TYPES);
|
||||
|
@ -882,8 +886,9 @@ void DWARFContext::parseNormalUnits() {
|
|||
void DWARFContext::parseDWOUnits(bool Lazy) {
|
||||
if (!DWOUnits.empty())
|
||||
return;
|
||||
DWOUnits.addUnitsForDWOSection(*this, DObj->getInfoDWOSection(), DW_SECT_INFO,
|
||||
Lazy);
|
||||
DObj->forEachInfoDWOSections([&](const DWARFSection &S) {
|
||||
DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy);
|
||||
});
|
||||
DWOUnits.finishedInfoUnits();
|
||||
DObj->forEachTypesDWOSections([&](const DWARFSection &S) {
|
||||
DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_TYPES, Lazy);
|
||||
|
@ -1235,20 +1240,20 @@ class DWARFObjInMemory final : public DWARFObject {
|
|||
const object::ObjectFile *Obj = nullptr;
|
||||
std::vector<SectionName> SectionNames;
|
||||
|
||||
using TypeSectionMap = MapVector<object::SectionRef, DWARFSectionMap,
|
||||
using InfoSectionMap = MapVector<object::SectionRef, DWARFSectionMap,
|
||||
std::map<object::SectionRef, unsigned>>;
|
||||
|
||||
TypeSectionMap TypesSections;
|
||||
TypeSectionMap TypesDWOSections;
|
||||
InfoSectionMap InfoSections;
|
||||
InfoSectionMap TypesSections;
|
||||
InfoSectionMap InfoDWOSections;
|
||||
InfoSectionMap TypesDWOSections;
|
||||
|
||||
DWARFSectionMap InfoSection;
|
||||
DWARFSectionMap LocSection;
|
||||
DWARFSectionMap LocListsSection;
|
||||
DWARFSectionMap LineSection;
|
||||
DWARFSectionMap RangeSection;
|
||||
DWARFSectionMap RnglistsSection;
|
||||
DWARFSectionMap StringOffsetSection;
|
||||
DWARFSectionMap InfoDWOSection;
|
||||
DWARFSectionMap LineDWOSection;
|
||||
DWARFSectionMap LocDWOSection;
|
||||
DWARFSectionMap StringOffsetDWOSection;
|
||||
|
@ -1263,14 +1268,12 @@ class DWARFObjInMemory final : public DWARFObject {
|
|||
|
||||
DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
|
||||
return StringSwitch<DWARFSectionMap *>(Name)
|
||||
.Case("debug_info", &InfoSection)
|
||||
.Case("debug_loc", &LocSection)
|
||||
.Case("debug_loclists", &LocListsSection)
|
||||
.Case("debug_line", &LineSection)
|
||||
.Case("debug_str_offsets", &StringOffsetSection)
|
||||
.Case("debug_ranges", &RangeSection)
|
||||
.Case("debug_rnglists", &RnglistsSection)
|
||||
.Case("debug_info.dwo", &InfoDWOSection)
|
||||
.Case("debug_loc.dwo", &LocDWOSection)
|
||||
.Case("debug_line.dwo", &LineDWOSection)
|
||||
.Case("debug_names", &DebugNamesSection)
|
||||
|
@ -1359,6 +1362,16 @@ public:
|
|||
for (const auto &SecIt : Sections) {
|
||||
if (StringRef *SectionData = mapSectionToMember(SecIt.first()))
|
||||
*SectionData = SecIt.second->getBuffer();
|
||||
else if (SecIt.first() == "debug_info")
|
||||
// Find debug_info and debug_types data by section rather than name as
|
||||
// there are multiple, comdat grouped, of these sections.
|
||||
InfoSections[SectionRef()].Data = SecIt.second->getBuffer();
|
||||
else if (SecIt.first() == "debug_info.dwo")
|
||||
InfoDWOSections[SectionRef()].Data = SecIt.second->getBuffer();
|
||||
else if (SecIt.first() == "debug_types")
|
||||
TypesSections[SectionRef()].Data = SecIt.second->getBuffer();
|
||||
else if (SecIt.first() == "debug_types.dwo")
|
||||
TypesDWOSections[SectionRef()].Data = SecIt.second->getBuffer();
|
||||
}
|
||||
}
|
||||
DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
|
||||
|
@ -1413,9 +1426,13 @@ public:
|
|||
// FIXME: Use the other dwo range section when we emit it.
|
||||
RangeDWOSection.Data = Data;
|
||||
}
|
||||
} else if (Name == "debug_info") {
|
||||
// Find debug_info and debug_types data by section rather than name as
|
||||
// there are multiple, comdat grouped, of these sections.
|
||||
InfoSections[Section].Data = Data;
|
||||
} else if (Name == "debug_info.dwo") {
|
||||
InfoDWOSections[Section].Data = Data;
|
||||
} else if (Name == "debug_types") {
|
||||
// Find debug_types data by section rather than name as there are
|
||||
// multiple, comdat grouped, debug_types sections.
|
||||
TypesSections[Section].Data = Data;
|
||||
} else if (Name == "debug_types.dwo") {
|
||||
TypesDWOSections[Section].Data = Data;
|
||||
|
@ -1450,9 +1467,16 @@ public:
|
|||
DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName);
|
||||
RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr;
|
||||
if (!Map) {
|
||||
// Find debug_types relocs by section rather than name as there are
|
||||
// multiple, comdat grouped, debug_types sections.
|
||||
if (RelSecName == "debug_types")
|
||||
// Find debug_info and debug_types relocs by section rather than name
|
||||
// as there are multiple, comdat grouped, of these sections.
|
||||
if (RelSecName == "debug_info")
|
||||
Map = &static_cast<DWARFSectionMap &>(InfoSections[*RelocatedSection])
|
||||
.Relocs;
|
||||
else if (RelSecName == "debug_info.dwo")
|
||||
Map = &static_cast<DWARFSectionMap &>(
|
||||
InfoDWOSections[*RelocatedSection])
|
||||
.Relocs;
|
||||
else if (RelSecName == "debug_types")
|
||||
Map =
|
||||
&static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection])
|
||||
.Relocs;
|
||||
|
@ -1550,8 +1574,10 @@ public:
|
|||
StringRef getLineStringSection() const override { return LineStringSection; }
|
||||
|
||||
// Sections for DWARF5 split dwarf proposal.
|
||||
const DWARFSection &getInfoDWOSection() const override {
|
||||
return InfoDWOSection;
|
||||
void forEachInfoDWOSections(
|
||||
function_ref<void(const DWARFSection &)> F) const override {
|
||||
for (auto &P : InfoDWOSections)
|
||||
F(P.second);
|
||||
}
|
||||
void forEachTypesDWOSections(
|
||||
function_ref<void(const DWARFSection &)> F) const override {
|
||||
|
@ -1598,7 +1624,11 @@ public:
|
|||
|
||||
StringRef getFileName() const override { return FileName; }
|
||||
uint8_t getAddressSize() const override { return AddressSize; }
|
||||
const DWARFSection &getInfoSection() const override { return InfoSection; }
|
||||
void forEachInfoSections(
|
||||
function_ref<void(const DWARFSection &)> F) const override {
|
||||
for (auto &P : InfoSections)
|
||||
F(P.second);
|
||||
}
|
||||
void forEachTypesSections(
|
||||
function_ref<void(const DWARFSection &)> F) const override {
|
||||
for (auto &P : TypesSections)
|
||||
|
|
|
@ -364,15 +364,18 @@ unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S,
|
|||
|
||||
bool DWARFVerifier::handleDebugInfo() {
|
||||
const DWARFObject &DObj = DCtx.getDWARFObj();
|
||||
unsigned NumErrors = 0;
|
||||
|
||||
OS << "Verifying .debug_info Unit Header Chain...\n";
|
||||
unsigned result = verifyUnitSection(DObj.getInfoSection(), DW_SECT_INFO);
|
||||
DObj.forEachInfoSections([&](const DWARFSection &S) {
|
||||
NumErrors += verifyUnitSection(S, DW_SECT_INFO);
|
||||
});
|
||||
|
||||
OS << "Verifying .debug_types Unit Header Chain...\n";
|
||||
DObj.forEachTypesSections([&](const DWARFSection &S) {
|
||||
result += verifyUnitSection(S, DW_SECT_TYPES);
|
||||
NumErrors += verifyUnitSection(S, DW_SECT_TYPES);
|
||||
});
|
||||
return result == 0;
|
||||
return NumErrors == 0;
|
||||
}
|
||||
|
||||
unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
|
||||
|
@ -551,6 +554,7 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
|
|||
unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
|
||||
DWARFAttribute &AttrValue) {
|
||||
const DWARFObject &DObj = DCtx.getDWARFObj();
|
||||
auto DieCU = Die.getDwarfUnit();
|
||||
unsigned NumErrors = 0;
|
||||
const auto Form = AttrValue.Value.getForm();
|
||||
switch (Form) {
|
||||
|
@ -563,7 +567,6 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
|
|||
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||
assert(RefVal);
|
||||
if (RefVal) {
|
||||
auto DieCU = Die.getDwarfUnit();
|
||||
auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
|
||||
auto CUOffset = AttrValue.Value.getRawUValue();
|
||||
if (CUOffset >= CUSize) {
|
||||
|
@ -588,7 +591,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
|
|||
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||
assert(RefVal);
|
||||
if (RefVal) {
|
||||
if (*RefVal >= DObj.getInfoSection().Data.size()) {
|
||||
if (*RefVal >= DieCU->getInfoSection().Data.size()) {
|
||||
++NumErrors;
|
||||
error() << "DW_FORM_ref_addr offset beyond .debug_info "
|
||||
"bounds:\n";
|
||||
|
|
|
@ -152,6 +152,38 @@ CU_split_5_end:
|
|||
# CHECK-NEXT: DW_AT_producer {{.*}} "Handmade DWO producer"
|
||||
# CHECK-NEXT: DW_AT_name {{.*}} "V5_dwo_compile_unit"
|
||||
|
||||
# Now a DWARF v5 type unit, which goes in a .debug_info.dwo comdat.
|
||||
# Note there will not be another ".debug_info.dwo contents:" line, even though
|
||||
# there is a separate ELF section header; it's dumped along with the previous
|
||||
# unit as if they were in a single section.
|
||||
|
||||
.section .debug_info.dwo,"G",@progbits,5555,comdat
|
||||
# CHECK-NOT: .debug_info.dwo
|
||||
|
||||
# DWARF v5 split type unit header.
|
||||
TU_split_5_start:
|
||||
.long TU_split_5_end-TU_split_5_version # Length of Unit
|
||||
TU_split_5_version:
|
||||
.short 5 # DWARF version number
|
||||
.byte 6 # DWARF Unit Type
|
||||
.byte 8 # Address Size (in bytes)
|
||||
.long .debug_abbrev.dwo # Offset Into Abbrev. Section
|
||||
.quad 0x8899aabbccddeeff # Type Signature
|
||||
.long TU_split_5_type-TU_split_5_start # Type offset
|
||||
# The type-unit DIE, which has a name.
|
||||
.byte 2
|
||||
.long dwo_TU_5
|
||||
# The type DIE, which has a name.
|
||||
TU_split_5_type:
|
||||
.byte 3
|
||||
.long dwo_TU_5
|
||||
.byte 0 # NULL
|
||||
.byte 0 # NULL
|
||||
TU_split_5_end:
|
||||
|
||||
# CHECK: 0x00000000: Type Unit: length = 0x00000020 version = 0x0005 unit_type = DW_UT_split_type abbr_offset = 0x0000 addr_size = 0x08 name = 'V5_split_type_unit' type_signature = 0x8899aabbccddeeff type_offset = 0x001d (next unit at 0x00000024)
|
||||
# CHECK: 0x00000018: DW_TAG_type_unit
|
||||
|
||||
.section .debug_types,"",@progbits
|
||||
# CHECK-LABEL: .debug_types contents:
|
||||
|
||||
|
@ -178,34 +210,6 @@ TU_4_end:
|
|||
# CHECK: 0x00000000: Type Unit: length = 0x0000001f version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 name = 'V4_type_unit' type_signature = 0x0011223344556677 type_offset = 0x001c (next unit at 0x00000023)
|
||||
# CHECK: 0x00000017: DW_TAG_type_unit
|
||||
|
||||
.section .debug_types.dwo,"",@progbits
|
||||
# FIXME: DWARF v5 wants type units in .debug_info[.dwo] not .debug_types[.dwo].
|
||||
# CHECK: .debug_types.dwo contents:
|
||||
|
||||
# DWARF v5 split type unit header.
|
||||
TU_split_5_start:
|
||||
.long TU_split_5_end-TU_split_5_version # Length of Unit
|
||||
TU_split_5_version:
|
||||
.short 5 # DWARF version number
|
||||
.byte 6 # DWARF Unit Type
|
||||
.byte 8 # Address Size (in bytes)
|
||||
.long .debug_abbrev.dwo # Offset Into Abbrev. Section
|
||||
.quad 0x8899aabbccddeeff # Type Signature
|
||||
.long TU_split_5_type-TU_split_5_start # Type offset
|
||||
# The type-unit DIE, which has a name.
|
||||
.byte 2
|
||||
.long dwo_TU_5
|
||||
# The type DIE, which has a name.
|
||||
TU_split_5_type:
|
||||
.byte 3
|
||||
.long dwo_TU_5
|
||||
.byte 0 # NULL
|
||||
.byte 0 # NULL
|
||||
TU_split_5_end:
|
||||
|
||||
# CHECK: 0x00000000: Type Unit: length = 0x00000020 version = 0x0005 unit_type = DW_UT_split_type abbr_offset = 0x0000 addr_size = 0x08 name = 'V5_split_type_unit' type_signature = 0x8899aabbccddeeff type_offset = 0x001d (next unit at 0x00000024)
|
||||
# CHECK: 0x00000018: DW_TAG_type_unit
|
||||
|
||||
.section .debug_line,"",@progbits
|
||||
# CHECK-LABEL: .debug_line contents:
|
||||
|
||||
|
|
Loading…
Reference in New Issue