Skip to content

Commit dc5c044

Browse files
authored
Add verification support for .debug_names with foreign type units. (#109011)
This commit enables 'llvm-dwarfdump --veriy' to verify the DWARF in foreign type units when using split DWARF for the .debug_names section.
1 parent 470a599 commit dc5c044

File tree

9 files changed

+322
-58
lines changed

9 files changed

+322
-58
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
447447
std::optional<uint64_t> getForeignTUTypeSignature() const override;
448448
std::optional<dwarf::Tag> getTag() const override { return tag(); }
449449

450-
// Special function that will return the related CU offset needed type
450+
// Special function that will return the related CU offset needed type
451451
// units. This gets used to find the .dwo file that originated the entries
452452
// for a given type unit.
453453
std::optional<uint64_t> getRelatedCUOffset() const;
@@ -468,12 +468,13 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
468468
/// index for an entry that is a type unit.
469469
std::optional<uint64_t> getRelatedCUIndex() const;
470470

471-
/// Returns the Index into the Local Type Unit list of the owning Name
471+
/// Returns the index of the Type Unit of the owning
472+
/// Name
472473
/// Index or std::nullopt if this Accelerator Entry does not have an
473474
/// associated Type Unit. It is up to the user to verify that the
474-
/// returned Index is valid in the owning NameIndex (or use
475+
/// returned Index is a valid index in the owning NameIndex (or use
475476
/// getLocalTUOffset(), which will handle that check itself).
476-
std::optional<uint64_t> getLocalTUIndex() const;
477+
std::optional<uint64_t> getTUIndex() const;
477478

478479
/// .debug_names-specific getter, which always succeeds (DWARF v5 index
479480
/// entries always have a tag).
@@ -803,7 +804,7 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
803804

804805
private:
805806
SmallVector<NameIndex, 0> NameIndices;
806-
DenseMap<uint64_t, const NameIndex *> CUToNameIndex;
807+
DenseMap<uint64_t, const NameIndex *> UnitOffsetToNameIndex;
807808

808809
public:
809810
DWARFDebugNames(const DWARFDataExtractor &AccelSection,
@@ -820,9 +821,9 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
820821
const_iterator begin() const { return NameIndices.begin(); }
821822
const_iterator end() const { return NameIndices.end(); }
822823

823-
/// Return the Name Index covering the compile unit at CUOffset, or nullptr if
824-
/// there is no Name Index covering that unit.
825-
const NameIndex *getCUNameIndex(uint64_t CUOffset);
824+
/// Return the Name Index covering the compile unit or local type unit at
825+
/// UnitOffset, or nullptr if there is no Name Index covering that unit.
826+
const NameIndex *getCUOrTUNameIndex(uint64_t UnitOffset);
826827
};
827828

828829
/// Calculates the starting offsets for various sections within the

llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ class DWARFContext : public DIContext {
209209
return State->getDWOUnits();
210210
}
211211

212+
/// Return true of this DWARF context is a DWP file.
213+
bool isDWP() const;
214+
212215
/// Get units from .debug_types.dwo in the DWO context.
213216
unit_iterator_range dwo_types_section_units() {
214217
DWARFUnitVector &DWOUnits = State->getDWOUnits();
@@ -262,7 +265,7 @@ class DWARFContext : public DIContext {
262265
}
263266

264267
DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash);
265-
DWARFTypeUnit *getTypeUnitForHash(uint16_t Version, uint64_t Hash, bool IsDWO);
268+
DWARFTypeUnit *getTypeUnitForHash(uint64_t Hash, bool IsDWO);
266269

267270
/// Return the DWARF unit that includes an offset (relative to .debug_info).
268271
DWARFUnit *getUnitForOffset(uint64_t Offset);

llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getRelatedCUIndex() const {
635635
if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
636636
return Off->getAsUnsignedConstant();
637637
// In a per-CU index, the entries without a DW_IDX_compile_unit attribute
638-
// implicitly refer to the single CU.
638+
// implicitly refer to the single CU.
639639
if (NameIdx->getCUCount() == 1)
640640
return 0;
641641
return std::nullopt;
@@ -665,15 +665,15 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getRelatedCUOffset() const {
665665
}
666666

667667
std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUOffset() const {
668-
std::optional<uint64_t> Index = getLocalTUIndex();
668+
std::optional<uint64_t> Index = getTUIndex();
669669
if (!Index || *Index >= NameIdx->getLocalTUCount())
670670
return std::nullopt;
671671
return NameIdx->getLocalTUOffset(*Index);
672672
}
673673

674674
std::optional<uint64_t>
675675
DWARFDebugNames::Entry::getForeignTUTypeSignature() const {
676-
std::optional<uint64_t> Index = getLocalTUIndex();
676+
std::optional<uint64_t> Index = getTUIndex();
677677
const uint32_t NumLocalTUs = NameIdx->getLocalTUCount();
678678
if (!Index || *Index < NumLocalTUs)
679679
return std::nullopt; // Invalid TU index or TU index is for a local TU
@@ -684,7 +684,7 @@ DWARFDebugNames::Entry::getForeignTUTypeSignature() const {
684684
return NameIdx->getForeignTUSignature(ForeignTUIndex);
685685
}
686686

687-
std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const {
687+
std::optional<uint64_t> DWARFDebugNames::Entry::getTUIndex() const {
688688
if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_type_unit))
689689
return Off->getAsUnsignedConstant();
690690
return std::nullopt;
@@ -1061,14 +1061,16 @@ DWARFDebugNames::equal_range(StringRef Key) const {
10611061
}
10621062

10631063
const DWARFDebugNames::NameIndex *
1064-
DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) {
1065-
if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) {
1064+
DWARFDebugNames::getCUOrTUNameIndex(uint64_t UnitOffset) {
1065+
if (UnitOffsetToNameIndex.size() == 0 && NameIndices.size() > 0) {
10661066
for (const auto &NI : *this) {
10671067
for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU)
1068-
CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI);
1068+
UnitOffsetToNameIndex.try_emplace(NI.getCUOffset(CU), &NI);
1069+
for (uint32_t TU = 0; TU < NI.getLocalTUCount(); ++TU)
1070+
UnitOffsetToNameIndex.try_emplace(NI.getLocalTUOffset(TU), &NI);
10691071
}
10701072
}
1071-
return CUToNameIndex.lookup(CUOffset);
1073+
return UnitOffsetToNameIndex.lookup(UnitOffset);
10721074
}
10731075

10741076
static bool isObjCSelector(StringRef Name) {

llvm/lib/DebugInfo/DWARF/DWARFContext.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,8 +1345,7 @@ void DWARFContext::dump(
13451345
getDebugNames().dump(OS);
13461346
}
13471347

1348-
DWARFTypeUnit *DWARFContext::getTypeUnitForHash(uint16_t Version, uint64_t Hash,
1349-
bool IsDWO) {
1348+
DWARFTypeUnit *DWARFContext::getTypeUnitForHash(uint64_t Hash, bool IsDWO) {
13501349
DWARFUnitVector &DWOUnits = State->getDWOUnits();
13511350
if (const auto &TUI = getTUIndex()) {
13521351
if (const auto *R = TUI.getFromHash(Hash))
@@ -2478,3 +2477,5 @@ uint8_t DWARFContext::getCUAddrSize() {
24782477
auto CUs = compile_units();
24792478
return CUs.empty() ? 0 : (*CUs.begin())->getAddressByteSize();
24802479
}
2480+
2481+
bool DWARFContext::isDWP() const { return !DObj->getCUIndexSection().empty(); }

llvm/lib/DebugInfo/DWARF/DWARFDie.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,8 @@ DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const {
319319
if (DWARFUnit *SpecUnit = U->getUnitVector().getUnitForOffset(*Offset))
320320
Result = SpecUnit->getDIEForOffset(*Offset);
321321
} else if (std::optional<uint64_t> Sig = V.getAsSignatureReference()) {
322-
if (DWARFTypeUnit *TU = U->getContext().getTypeUnitForHash(
323-
U->getVersion(), *Sig, U->isDWOUnit()))
322+
if (DWARFTypeUnit *TU =
323+
U->getContext().getTypeUnitForHash(*Sig, U->isDWOUnit()))
324324
Result = TU->getDIEForOffset(TU->getTypeOffset() + TU->getOffset());
325325
}
326326
return Result;
@@ -329,8 +329,8 @@ DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const {
329329
DWARFDie DWARFDie::resolveTypeUnitReference() const {
330330
if (auto Attr = find(DW_AT_signature)) {
331331
if (std::optional<uint64_t> Sig = Attr->getAsReferenceUVal()) {
332-
if (DWARFTypeUnit *TU = U->getContext().getTypeUnitForHash(
333-
U->getVersion(), *Sig, U->isDWOUnit()))
332+
if (DWARFTypeUnit *TU =
333+
U->getContext().getTypeUnitForHash(*Sig, U->isDWOUnit()))
334334
return TU->getDIEForOffset(TU->getTypeOffset() + TU->getOffset());
335335
}
336336
}

llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp

Lines changed: 103 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
2525
#include "llvm/DebugInfo/DWARF/DWARFObject.h"
2626
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
27+
#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
2728
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
2829
#include "llvm/Object/Error.h"
2930
#include "llvm/Support/DJB.h"
@@ -1479,13 +1480,6 @@ unsigned DWARFVerifier::verifyNameIndexAttribute(
14791480

14801481
unsigned
14811482
DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
1482-
if (NI.getForeignTUCount() > 0) {
1483-
warn() << formatv("Name Index @ {0:x}: Verifying indexes of foreign type "
1484-
"units is not currently supported.\n",
1485-
NI.getUnitOffset());
1486-
return 0;
1487-
}
1488-
14891483
unsigned NumErrors = 0;
14901484
for (const auto &Abbrev : NI.getAbbrevs()) {
14911485
StringRef TagName = dwarf::TagString(Abbrev.Tag);
@@ -1573,10 +1567,6 @@ static SmallVector<std::string, 3> getNames(const DWARFDie &DIE,
15731567
unsigned DWARFVerifier::verifyNameIndexEntries(
15741568
const DWARFDebugNames::NameIndex &NI,
15751569
const DWARFDebugNames::NameTableEntry &NTE) {
1576-
// Verifying foreign type unit indexes not supported.
1577-
if (NI.getForeignTUCount() > 0)
1578-
return 0;
1579-
15801570
const char *CStr = NTE.getString();
15811571
if (!CStr) {
15821572
ErrorCategory.Report("Unable to get string associated with name", [&]() {
@@ -1596,8 +1586,8 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
15961586
for (; EntryOr; ++NumEntries, EntryID = NextEntryID,
15971587
EntryOr = NI.getEntry(&NextEntryID)) {
15981588

1599-
std::optional<uint64_t> CUIndex = EntryOr->getCUIndex();
1600-
std::optional<uint64_t> TUIndex = EntryOr->getLocalTUIndex();
1589+
std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex();
1590+
std::optional<uint64_t> TUIndex = EntryOr->getTUIndex();
16011591
if (CUIndex && *CUIndex >= NI.getCUCount()) {
16021592
ErrorCategory.Report("Name Index entry contains invalid CU index", [&]() {
16031593
error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
@@ -1607,7 +1597,9 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
16071597
++NumErrors;
16081598
continue;
16091599
}
1610-
if (TUIndex && *TUIndex >= NI.getLocalTUCount()) {
1600+
const uint32_t NumLocalTUs = NI.getLocalTUCount();
1601+
const uint32_t NumForeignTUs = NI.getForeignTUCount();
1602+
if (TUIndex && *TUIndex >= (NumLocalTUs + NumForeignTUs)) {
16111603
ErrorCategory.Report("Name Index entry contains invalid TU index", [&]() {
16121604
error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
16131605
"invalid TU index ({2}).\n",
@@ -1617,11 +1609,44 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
16171609
continue;
16181610
}
16191611
std::optional<uint64_t> UnitOffset;
1620-
if (TUIndex)
1621-
UnitOffset = NI.getLocalTUOffset(*TUIndex);
1622-
else if (CUIndex)
1612+
if (TUIndex) {
1613+
// We have a local or foreign type unit.
1614+
if (*TUIndex >= NumLocalTUs) {
1615+
// This is a foreign type unit, we will find the right type unit by
1616+
// type unit signature later in this function.
1617+
1618+
// Foreign type units must have a valid CU index, either from a
1619+
// DW_IDX_comp_unit attribute value or from the .debug_names table only
1620+
// having a single compile unit. We need the originating compile unit
1621+
// because foreign type units can come from any .dwo file, yet only one
1622+
// copy of the type unit will end up in the .dwp file.
1623+
if (CUIndex) {
1624+
// We need the local skeleton unit offset for the code below.
1625+
UnitOffset = NI.getCUOffset(*CUIndex);
1626+
} else {
1627+
ErrorCategory.Report(
1628+
"Name Index entry contains foreign TU index with invalid CU "
1629+
"index",
1630+
[&]() {
1631+
error() << formatv(
1632+
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1633+
"foreign TU index ({2}) with no CU index.\n",
1634+
NI.getUnitOffset(), EntryID, *TUIndex);
1635+
});
1636+
++NumErrors;
1637+
continue;
1638+
}
1639+
} else {
1640+
// Local type unit, get the DWARF unit offset for the type unit.
1641+
UnitOffset = NI.getLocalTUOffset(*TUIndex);
1642+
}
1643+
} else if (CUIndex) {
1644+
// Local CU entry, get the DWARF unit offset for the CU.
16231645
UnitOffset = NI.getCUOffset(*CUIndex);
1624-
if (!UnitOffset)
1646+
}
1647+
1648+
// Watch for tombstoned type unit entries.
1649+
if (!UnitOffset || UnitOffset == UINT32_MAX)
16251650
continue;
16261651
// For split DWARF entries we need to make sure we find the non skeleton
16271652
// DWARF unit that is needed and use that's DWARF unit offset as the
@@ -1633,7 +1658,7 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
16331658
ErrorCategory.Report(
16341659
"Name Index entry contains invalid CU or TU offset", [&]() {
16351660
error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
1636-
"invalid CU or TU offset {1:x}.\n",
1661+
"invalid CU or TU offset {2:x}.\n",
16371662
NI.getUnitOffset(), EntryID, *UnitOffset);
16381663
});
16391664
++NumErrors;
@@ -1650,20 +1675,52 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
16501675
// call to properly deal with it. It isn't clear that getNonSkeletonUnitDIE
16511676
// will return the unit DIE of DU if we aren't able to get the .dwo file,
16521677
// but that is what the function currently does.
1678+
DWARFDie UnitDie = DU->getUnitDIE();
16531679
DWARFDie NonSkeletonUnitDie = DU->getNonSkeletonUnitDIE();
1654-
if (DU->getDWOId() && DU->getUnitDIE() == NonSkeletonUnitDie) {
1680+
if (DU->getDWOId() && UnitDie == NonSkeletonUnitDie) {
16551681
ErrorCategory.Report("Unable to get load .dwo file", [&]() {
1656-
error() << formatv("Name Index @ {0:x}: Entry @ {1:x} unable to load "
1657-
".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1658-
NI.getUnitOffset(), EntryID,
1659-
dwarf::toString(DU->getUnitDIE().find(
1660-
{DW_AT_dwo_name, DW_AT_GNU_dwo_name})),
1661-
*UnitOffset);
1682+
error() << formatv(
1683+
"Name Index @ {0:x}: Entry @ {1:x} unable to load "
1684+
".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1685+
NI.getUnitOffset(), EntryID,
1686+
dwarf::toString(UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name})),
1687+
*UnitOffset);
16621688
});
16631689
++NumErrors;
16641690
continue;
16651691
}
1666-
DWARFUnit *NonSkeletonUnit = NonSkeletonUnitDie.getDwarfUnit();
1692+
DWARFUnit *NonSkeletonUnit = nullptr;
1693+
if (TUIndex && *TUIndex >= NumLocalTUs) {
1694+
// We have a foreign TU index, which either means we have a .dwo file
1695+
// that has one or more type units, or we have a .dwp file with one or
1696+
// more type units. We need to get the type unit from the DWARFContext
1697+
// of the .dwo. We got the NonSkeletonUnitDie above that has the .dwo
1698+
// or .dwp DWARF context, so we have to get the type unit from that file.
1699+
// We have also verified that NonSkeletonUnitDie points to a DWO file
1700+
// above, so we know we have the right file.
1701+
const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;
1702+
const uint64_t TypeSig = NI.getForeignTUSignature(ForeignTUIdx);
1703+
llvm::DWARFContext &SkeletonDCtx =
1704+
NonSkeletonUnitDie.getDwarfUnit()->getContext();
1705+
// Now find the type unit from the type signature and then update the
1706+
// NonSkeletonUnitDie to point to the actual type unit in the .dwo/.dwp.
1707+
NonSkeletonUnit =
1708+
SkeletonDCtx.getTypeUnitForHash(TypeSig, /*IsDWO=*/true);
1709+
NonSkeletonUnitDie = NonSkeletonUnit->getUnitDIE(true);
1710+
// If we have foreign type unit in a DWP file, then we need to ignore
1711+
// any entries from type units that don't match the one that made it into
1712+
// the .dwp file.
1713+
if (SkeletonDCtx.isDWP()) {
1714+
StringRef DUDwoName = dwarf::toStringRef(
1715+
UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1716+
StringRef TUDwoName = dwarf::toStringRef(
1717+
NonSkeletonUnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1718+
if (DUDwoName != TUDwoName)
1719+
continue; // Skip this TU, it isn't the one in the .dwp file.
1720+
}
1721+
} else {
1722+
NonSkeletonUnit = NonSkeletonUnitDie.getDwarfUnit();
1723+
}
16671724
uint64_t DIEOffset =
16681725
NonSkeletonUnit->getOffset() + *EntryOr->getDIEUnitOffset();
16691726
const uint64_t NextUnitOffset = NonSkeletonUnit->getNextUnitOffset();
@@ -1920,15 +1977,26 @@ unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
19201977
for (const DWARFDebugNames::NameTableEntry &NTE : NI)
19211978
NumErrors += verifyNameIndexEntries(NI, NTE);
19221979

1923-
if (NumErrors > 0)
1924-
return NumErrors;
1925-
1926-
for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units()) {
1980+
for (const std::unique_ptr<DWARFUnit> &U : DCtx.info_section_units()) {
19271981
if (const DWARFDebugNames::NameIndex *NI =
1928-
AccelTable.getCUNameIndex(U->getOffset())) {
1929-
auto *CU = cast<DWARFCompileUnit>(U.get());
1930-
for (const DWARFDebugInfoEntry &Die : CU->dies())
1931-
NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI);
1982+
AccelTable.getCUOrTUNameIndex(U->getOffset())) {
1983+
DWARFCompileUnit *CU = dyn_cast<DWARFCompileUnit>(U.get());
1984+
if (CU) {
1985+
if (CU->getDWOId()) {
1986+
DWARFDie CUDie = CU->getUnitDIE(true);
1987+
DWARFDie NonSkeletonUnitDie =
1988+
CUDie.getDwarfUnit()->getNonSkeletonUnitDIE(false);
1989+
if (CUDie != NonSkeletonUnitDie) {
1990+
for (const DWARFDebugInfoEntry &Die :
1991+
NonSkeletonUnitDie.getDwarfUnit()->dies())
1992+
NumErrors += verifyNameIndexCompleteness(
1993+
DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), *NI);
1994+
}
1995+
} else {
1996+
for (const DWARFDebugInfoEntry &Die : CU->dies())
1997+
NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI);
1998+
}
1999+
}
19322000
}
19332001
}
19342002
return NumErrors;

0 commit comments

Comments
 (0)