Skip to content

Commit 3301f3d

Browse files
committed
Add verification support for .debug_names with foreign type units.
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 6558e56 commit 3301f3d

File tree

9 files changed

+294
-48
lines changed

9 files changed

+294
-48
lines changed

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

Lines changed: 5 additions & 5 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;
@@ -803,7 +803,7 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
803803

804804
private:
805805
SmallVector<NameIndex, 0> NameIndices;
806-
DenseMap<uint64_t, const NameIndex *> CUToNameIndex;
806+
DenseMap<uint64_t, const NameIndex *> UnitOffsetToNameIndex;
807807

808808
public:
809809
DWARFDebugNames(const DWARFDataExtractor &AccelSection,
@@ -820,9 +820,9 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
820820
const_iterator begin() const { return NameIndices.begin(); }
821821
const_iterator end() const { return NameIndices.end(); }
822822

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);
823+
/// Return the Name Index covering the compile unit or local type unit at
824+
/// UnitOffset, or nullptr if there is no Name Index covering that unit.
825+
const NameIndex *getCUOrTUNameIndex(uint64_t UnitOffset);
826826
};
827827

828828
/// 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: 7 additions & 5 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;
@@ -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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const {
320320
Result = SpecUnit->getDIEForOffset(*Offset);
321321
} else if (std::optional<uint64_t> Sig = V.getAsSignatureReference()) {
322322
if (DWARFTypeUnit *TU = U->getContext().getTypeUnitForHash(
323-
U->getVersion(), *Sig, U->isDWOUnit()))
323+
*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: 83 additions & 32 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,7 +1586,7 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
15961586
for (; EntryOr; ++NumEntries, EntryID = NextEntryID,
15971587
EntryOr = NI.getEntry(&NextEntryID)) {
15981588

1599-
std::optional<uint64_t> CUIndex = EntryOr->getCUIndex();
1589+
std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex();
16001590
std::optional<uint64_t> TUIndex = EntryOr->getLocalTUIndex();
16011591
if (CUIndex && *CUIndex >= NI.getCUCount()) {
16021592
ErrorCategory.Report("Name Index entry contains invalid CU index", [&]() {
@@ -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,10 +1609,28 @@ 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 (CUIndex)
16231613
UnitOffset = NI.getCUOffset(*CUIndex);
1614+
else if (TUIndex) {
1615+
if (*TUIndex >= NumLocalTUs) {
1616+
// Foreign type units must have a valid CU index, either from a
1617+
// DW_IDX_comp_unit attribute value or from the .debug_names table only
1618+
// having a single compile unit. We need the originating compile unit
1619+
// because foreign type units can come from any .dwo file, yet only one
1620+
// copy of the type unit will end up in the .dwp file.
1621+
ErrorCategory.Report(
1622+
"Name Index entry contains foreign TU index with invalid CU index",
1623+
[&]() {
1624+
error() << formatv(
1625+
"Name Index @ {0:x}: Entry @ {1:x} contains an "
1626+
"foreign TU index ({2}) with no CU index.\n",
1627+
NI.getUnitOffset(), EntryID, *TUIndex);
1628+
});
1629+
++NumErrors;
1630+
continue;
1631+
}
1632+
UnitOffset = NI.getLocalTUOffset(*TUIndex);
1633+
}
16241634
if (!UnitOffset)
16251635
continue;
16261636
// For split DWARF entries we need to make sure we find the non skeleton
@@ -1650,20 +1660,52 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
16501660
// call to properly deal with it. It isn't clear that getNonSkeletonUnitDIE
16511661
// will return the unit DIE of DU if we aren't able to get the .dwo file,
16521662
// but that is what the function currently does.
1663+
DWARFDie UnitDie = DU->getUnitDIE();
16531664
DWARFDie NonSkeletonUnitDie = DU->getNonSkeletonUnitDIE();
1654-
if (DU->getDWOId() && DU->getUnitDIE() == NonSkeletonUnitDie) {
1665+
if (DU->getDWOId() && UnitDie == NonSkeletonUnitDie) {
16551666
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);
1667+
error() << formatv(
1668+
"Name Index @ {0:x}: Entry @ {1:x} unable to load "
1669+
".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1670+
NI.getUnitOffset(), EntryID,
1671+
dwarf::toString(UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name})),
1672+
*UnitOffset);
16621673
});
16631674
++NumErrors;
16641675
continue;
16651676
}
1666-
DWARFUnit *NonSkeletonUnit = NonSkeletonUnitDie.getDwarfUnit();
1677+
DWARFUnit *NonSkeletonUnit = nullptr;
1678+
if (TUIndex && *TUIndex >= NumLocalTUs) {
1679+
// We have a foreign TU index, which either means we have a .dwo file
1680+
// that has one or more type units, or we have a .dwp file with on or
1681+
// more type units. We need to get the type unit from the DWARFContext
1682+
// of the .dwo. We got the NonSkeletonUnitDie above that has the .dwo
1683+
// or .dwp DWARF context, so we have to get the type unit from that file.
1684+
// We have also verified that NonSkeletonUnitDie points to a DWO file
1685+
// above, so we know we have the right file.
1686+
const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs;
1687+
const uint64_t TypeSig = NI.getForeignTUSignature(ForeignTUIdx);
1688+
llvm::DWARFContext &SkeletonDCtx =
1689+
NonSkeletonUnitDie.getDwarfUnit()->getContext();
1690+
// Now find the type unit from the type signature and then update the
1691+
// NonSkeletonUnitDie to point to the actual type unit in the .dwo/.dwp.
1692+
NonSkeletonUnit =
1693+
SkeletonDCtx.getTypeUnitForHash(TypeSig, /*IsDWO=*/true);
1694+
NonSkeletonUnitDie = NonSkeletonUnit->getUnitDIE(true);
1695+
// If we have foreign type unit in a DWP file, then we need to ignore
1696+
// any entries from type units that don't match the one that made it into
1697+
// the .dwp file.
1698+
if (SkeletonDCtx.isDWP()) {
1699+
StringRef DUDwoName = dwarf::toStringRef(
1700+
UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1701+
StringRef TUDwoName = dwarf::toStringRef(
1702+
NonSkeletonUnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name}));
1703+
if (DUDwoName != TUDwoName)
1704+
continue; // Skip this TU, it isn't the one in the .dwp file.
1705+
}
1706+
} else {
1707+
NonSkeletonUnit = NonSkeletonUnitDie.getDwarfUnit();
1708+
}
16671709
uint64_t DIEOffset =
16681710
NonSkeletonUnit->getOffset() + *EntryOr->getDIEUnitOffset();
16691711
const uint64_t NextUnitOffset = NonSkeletonUnit->getNextUnitOffset();
@@ -1920,15 +1962,24 @@ unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
19201962
for (const DWARFDebugNames::NameTableEntry &NTE : NI)
19211963
NumErrors += verifyNameIndexEntries(NI, NTE);
19221964

1923-
if (NumErrors > 0)
1924-
return NumErrors;
1925-
1926-
for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units()) {
1965+
for (const std::unique_ptr<DWARFUnit> &U : DCtx.info_section_units()) {
19271966
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);
1967+
AccelTable.getCUOrTUNameIndex(U->getOffset())) {
1968+
DWARFCompileUnit *CU = cast<DWARFCompileUnit>(U.get());
1969+
if (CU && CU->getDWOId()) {
1970+
DWARFDie CUDie = CU->getUnitDIE(true);
1971+
DWARFDie NonSkeletonUnitDie =
1972+
CUDie.getDwarfUnit()->getNonSkeletonUnitDIE(false);
1973+
if (CUDie != NonSkeletonUnitDie) {
1974+
for (const DWARFDebugInfoEntry &Die :
1975+
NonSkeletonUnitDie.getDwarfUnit()->dies())
1976+
NumErrors += verifyNameIndexCompleteness(
1977+
DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), *NI);
1978+
}
1979+
} else {
1980+
for (const DWARFDebugInfoEntry &Die : CU->dies())
1981+
NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI);
1982+
}
19321983
}
19331984
}
19341985
return NumErrors;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--- !ELF
2+
FileHeader:
3+
Class: ELFCLASS64
4+
Data: ELFDATA2LSB
5+
Type: ET_REL
6+
Machine: EM_X86_64
7+
SectionHeaderStringTable: .strtab
8+
Sections:
9+
- Name: .debug_info.dwo
10+
Type: SHT_PROGBITS
11+
Flags: [ SHF_EXCLUDE ]
12+
AddressAlign: 0x1
13+
Content: 3A0000000500060800000000F25C0974DC2049EF210000000121000304000000000205070400020305300000000004000439000000060003000501050400320000000500060800000000F111DEDB09E62F8A2100000001210003040000000002050A0400070309310000000008000005010504005300000005000508000000004F3AF08A9CD57502060B21000C04070021000000015600000B400000000802917802000C440000000802917408000D4D000000000501050409F25C0974DC2049EF09F111DEDB09E62F8A00
14+
- Name: .debug_str_offsets.dwo
15+
Type: SHT_PROGBITS
16+
Flags: [ SHF_EXCLUDE ]
17+
AddressAlign: 0x1
18+
Content: 38000000050000000000000005000000090000000B0000000D0000001600000018000000240000002F00000034000000360000003F000000AF000000
19+
- Name: .debug_str.dwo
20+
Type: SHT_PROGBITS
21+
Flags: [ SHF_EXCLUDE, SHF_MERGE, SHF_STRINGS ]
22+
AddressAlign: 0x1
23+
EntSize: 0x1
24+
Content: 6D61696E00696E740063002E006D61696E2E64776F007800496E74656765725479706500437573746F6D547970650063617270006100436172705479706500636C616E672076657273696F6E2032302E302E30676974202868747470733A2F2F6769746875622E636F6D2F636C6179626F72672F6C6C766D2D70726F6A6563742E676974203937383833363863333763333139623131656239613331616630663130616163363262613466373229006D61696E2E63707000
25+
- Name: .debug_abbrev.dwo
26+
Type: SHT_PROGBITS
27+
Flags: [ SHF_EXCLUDE ]
28+
AddressAlign: 0x1
29+
Content: 01410113051B25762510170000021301360B03250B0B3A0B3B0B0000030D00032549133A0B3B0B380B0000041600491303253A0B3B0B000005240003253E0B0B0B000006110125251305032576250000072E01111B1206401803253A0B3B0B49133F190000083400021803253A0B3B0B491300000913003C196920000000
30+
- Name: .debug_line.dwo
31+
Type: SHT_PROGBITS
32+
Flags: [ SHF_EXCLUDE ]
33+
AddressAlign: 0x1
34+
Content: 36000000050008002E000000010101FB0E01010108012E00030108020F051E016D61696E2E6370700000D76E37CBD0032FAB59BE5997238B5EB3
35+
- Type: SectionHeaderTable
36+
Sections:
37+
- Name: .strtab
38+
- Name: .debug_info.dwo
39+
- Name: .debug_str_offsets.dwo
40+
- Name: .debug_str.dwo
41+
- Name: .debug_abbrev.dwo
42+
- Name: .debug_line.dwo
43+
...
44+

0 commit comments

Comments
 (0)