Skip to content

Commit 13cc94e

Browse files
authored
Add support for verifying .debug_names in split DWARF for CUs and TUs. (#101775)
This patch fixes .debug_names verification for split DWARF with no type units. It will print out an error for any name entries where we can't locate the .dwo file. It finds the non skeleton unit and correctly figures out the DIE offset in the .dwo file. If the non skeleton unit is found and yet the skeleton unit has a DWO ID, an error will be emitted showing we couldn't access the non-skeleton compile unit.
1 parent 7f1f3af commit 13cc94e

File tree

7 files changed

+241
-7
lines changed

7 files changed

+241
-7
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ class DWARFContext : public DIContext {
264264
DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash);
265265
DWARFTypeUnit *getTypeUnitForHash(uint16_t Version, uint64_t Hash, bool IsDWO);
266266

267+
/// Return the DWARF unit that includes an offset (relative to .debug_info).
268+
DWARFUnit *getUnitForOffset(uint64_t Offset);
269+
267270
/// Return the compile unit that includes an offset (relative to .debug_info).
268271
DWARFCompileUnit *getCompileUnitForOffset(uint64_t Offset);
269272

llvm/lib/DebugInfo/DWARF/DWARFContext.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,9 +1510,12 @@ DWARFUnitVector &DWARFContext::getDWOUnits(bool Lazy) {
15101510
return State->getDWOUnits(Lazy);
15111511
}
15121512

1513+
DWARFUnit *DWARFContext::getUnitForOffset(uint64_t Offset) {
1514+
return State->getNormalUnits().getUnitForOffset(Offset);
1515+
}
1516+
15131517
DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) {
1514-
return dyn_cast_or_null<DWARFCompileUnit>(
1515-
State->getNormalUnits().getUnitForOffset(Offset));
1518+
return dyn_cast_or_null<DWARFCompileUnit>(getUnitForOffset(Offset));
15161519
}
15171520

15181521
DWARFCompileUnit *DWARFContext::getCompileUnitForCodeAddress(uint64_t Address) {

llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,8 +1626,63 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
16261626
UnitOffset = NI.getCUOffset(*CUIndex);
16271627
if (!UnitOffset)
16281628
continue;
1629-
uint64_t DIEOffset = *UnitOffset + *EntryOr->getDIEUnitOffset();
1630-
DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset);
1629+
// For split DWARF entries we need to make sure we find the non skeleton
1630+
// DWARF unit that is needed and use that's DWARF unit offset as the
1631+
// DIE offset to add the DW_IDX_die_offset to.
1632+
DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset);
1633+
if (DU == nullptr || DU->getOffset() != *UnitOffset) {
1634+
// If we didn't find a DWARF Unit from the UnitOffset, or if the offset
1635+
// of the unit doesn't match exactly, report an error.
1636+
ErrorCategory.Report(
1637+
"Name Index entry contains invalid CU or TU offset", [&]() {
1638+
error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
1639+
"invalid CU or TU offset {1:x}.\n",
1640+
NI.getUnitOffset(), EntryID, *UnitOffset);
1641+
});
1642+
++NumErrors;
1643+
continue;
1644+
}
1645+
// This function will try to get the non skeleton unit DIE, but if it is
1646+
// unable to load the .dwo file from the .dwo or .dwp, it will return the
1647+
// unit DIE of the DWARFUnit in "DU". So we need to check if the DWARFUnit
1648+
// has a .dwo file, but we couldn't load it.
1649+
1650+
// FIXME: Need a follow up patch to fix usage of
1651+
// DWARFUnit::getNonSkeletonUnitDIE() so that it returns an empty DWARFDie
1652+
// if the .dwo file isn't available and clean up other uses of this function
1653+
// call to properly deal with it. It isn't clear that getNonSkeletonUnitDIE
1654+
// will return the unit DIE of DU if we aren't able to get the .dwo file,
1655+
// but that is what the function currently does.
1656+
DWARFDie NonSkeletonUnitDie = DU->getNonSkeletonUnitDIE();
1657+
if (DU->getDWOId() && DU->getUnitDIE() == NonSkeletonUnitDie) {
1658+
ErrorCategory.Report("Unable to get load .dwo file", [&]() {
1659+
error() << formatv("Name Index @ {0:x}: Entry @ {1:x} unable to load "
1660+
".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
1661+
NI.getUnitOffset(), EntryID,
1662+
dwarf::toString(DU->getUnitDIE().find(
1663+
{DW_AT_dwo_name, DW_AT_GNU_dwo_name})),
1664+
*UnitOffset);
1665+
});
1666+
++NumErrors;
1667+
continue;
1668+
}
1669+
DWARFUnit *NonSkeletonUnit = NonSkeletonUnitDie.getDwarfUnit();
1670+
uint64_t DIEOffset =
1671+
NonSkeletonUnit->getOffset() + *EntryOr->getDIEUnitOffset();
1672+
const uint64_t NextUnitOffset = NonSkeletonUnit->getNextUnitOffset();
1673+
// DIE offsets are relative to the specified CU or TU. Make sure the DIE
1674+
// offsets is a valid relative offset.
1675+
if (DIEOffset >= NextUnitOffset) {
1676+
ErrorCategory.Report("NameIndex relative DIE offset too large", [&]() {
1677+
error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "
1678+
"DIE @ {2:x} when CU or TU ends at {3:x}.\n",
1679+
NI.getUnitOffset(), EntryID, DIEOffset,
1680+
NextUnitOffset);
1681+
});
1682+
continue;
1683+
}
1684+
DWARFDie DIE = NonSkeletonUnit->getDIEForOffset(DIEOffset);
1685+
16311686
if (!DIE) {
16321687
ErrorCategory.Report("NameIndex references nonexistent DIE", [&]() {
16331688
error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "
@@ -1637,7 +1692,12 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
16371692
++NumErrors;
16381693
continue;
16391694
}
1640-
if (DIE.getDwarfUnit()->getOffset() != *UnitOffset) {
1695+
// Only compare the DIE we found's DWARFUnit offset if the DIE lives in
1696+
// the DWARFUnit from the DW_IDX_comp_unit or DW_IDX_type_unit. If we are
1697+
// using split DWARF, then the DIE's DWARFUnit doesn't need to match the
1698+
// skeleton unit.
1699+
if (DIE.getDwarfUnit() == DU &&
1700+
DIE.getDwarfUnit()->getOffset() != *UnitOffset) {
16411701
ErrorCategory.Report("Name index contains mismatched CU of DIE", [&]() {
16421702
error() << formatv(
16431703
"Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
--- !ELF
2+
FileHeader:
3+
Class: ELFCLASS64
4+
Data: ELFDATA2LSB
5+
Type: ET_EXEC
6+
Machine: EM_X86_64
7+
ProgramHeaders:
8+
- Type: PT_PHDR
9+
Flags: [ PF_R ]
10+
VAddr: 0x200040
11+
Align: 0x8
12+
Offset: 0x40
13+
- Type: PT_LOAD
14+
Flags: [ PF_R ]
15+
FirstSec: .eh_frame
16+
LastSec: .eh_frame
17+
VAddr: 0x200000
18+
Align: 0x1000
19+
Offset: 0x0
20+
- Type: PT_LOAD
21+
Flags: [ PF_X, PF_R ]
22+
FirstSec: .text
23+
LastSec: .text
24+
VAddr: 0x201160
25+
Align: 0x1000
26+
Offset: 0x160
27+
- Type: PT_GNU_STACK
28+
Flags: [ PF_W, PF_R ]
29+
Align: 0x0
30+
Offset: 0x0
31+
Sections:
32+
- Name: .eh_frame
33+
Type: SHT_PROGBITS
34+
Flags: [ SHF_ALLOC ]
35+
Address: 0x200120
36+
AddressAlign: 0x8
37+
Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000201000000F00000000410E108602430D064A0C070800000000000000
38+
- Name: .text
39+
Type: SHT_PROGBITS
40+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
41+
Address: 0x201160
42+
AddressAlign: 0x10
43+
Content: 554889E5C745FC0000000031C05DC3
44+
- Name: .debug_abbrev
45+
Type: SHT_PROGBITS
46+
AddressAlign: 0x1
47+
Content: 014A00101772171B257625111B12067317000000
48+
- Name: .debug_info
49+
Type: SHT_PROGBITS
50+
AddressAlign: 0x1
51+
Content: 24000000050004080000000048DE180E7C9CA7750100000000080000000001000F00000008000000
52+
- Name: .debug_str_offsets
53+
Type: SHT_PROGBITS
54+
AddressAlign: 0x1
55+
Content: 0C000000050000000900000000000000
56+
- Name: .debug_names
57+
Type: SHT_PROGBITS
58+
AddressAlign: 0x4
59+
Content: 8800000005000000010000000000000000000000030000000300000019000000080000004C4C564D30373030000000000100000002000000030000008973880B6A7F9A7C3080880B140000000B0000001000000000000000060000000C0000000113031304190000022E031304190000032403130419000000013900000000021A0000000003350000000000
60+
- Name: .comment
61+
Type: SHT_PROGBITS
62+
Flags: [ SHF_MERGE, SHF_STRINGS ]
63+
AddressAlign: 0x1
64+
EntSize: 0x1
65+
Content: 004C696E6B65723A204C4C442031392E302E30202868747470733A2F2F6769746875622E636F6D2F636C6179626F72672F6C6C766D2D70726F6A6563742E67697420353562313431303839356236396438653435313766366132613239373862343134623465636163332900636C616E672076657273696F6E2031392E302E30676974202868747470733A2F2F6769746875622E636F6D2F636C6179626F72672F6C6C766D2D70726F6A6563742E67697420353562313431303839356236396438653435313766366132613239373862343134623465636163332900
66+
- Name: .debug_line
67+
Type: SHT_PROGBITS
68+
AddressAlign: 0x1
69+
Content: 590000000500080037000000010101FB0E0D00010101010000000100000101011F010000000003011F020F051E0102000000006A7F8D4D5A8D13A0F16154AB8A56B134040000090260112000000000001605030AAE060B2E0202000101
70+
- Name: .debug_line_str
71+
Type: SHT_PROGBITS
72+
Flags: [ SHF_MERGE, SHF_STRINGS ]
73+
AddressAlign: 0x1
74+
EntSize: 0x1
75+
Content: 2E006D61696E2E63707000
76+
Symbols:
77+
- Name: main.cpp
78+
Type: STT_FILE
79+
Index: SHN_ABS
80+
- Name: main
81+
Type: STT_FUNC
82+
Section: .text
83+
Binding: STB_GLOBAL
84+
Value: 0x201160
85+
Size: 0xF
86+
DWARF:
87+
debug_str:
88+
- main.dwo
89+
- .
90+
- main
91+
- int
92+
- Foo
93+
debug_addr:
94+
- Length: 0xC
95+
Version: 0x5
96+
AddressSize: 0x8
97+
Entries:
98+
- Address: 0x201160
99+
...
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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_str_offsets.dwo
10+
Type: SHT_PROGBITS
11+
Flags: [ SHF_EXCLUDE ]
12+
AddressAlign: 0x1
13+
Content: 24000000050000000000000005000000090000000B0000000D00000011000000810000008A000000
14+
- Name: .debug_str.dwo
15+
Type: SHT_PROGBITS
16+
Flags: [ SHF_EXCLUDE, SHF_MERGE, SHF_STRINGS ]
17+
AddressAlign: 0x1
18+
EntSize: 0x1
19+
Content: 6D61696E00696E740066007800466F6F00636C616E672076657273696F6E2031392E302E30676974202868747470733A2F2F6769746875622E636F6D2F636C6179626F72672F6C6C766D2D70726F6A6563742E676974203535623134313038393562363964386534353137663661326132393738623431346234656361633329006D61696E2E637070006D61696E2E64776F00
20+
- Name: .debug_info.dwo
21+
Type: SHT_PROGBITS
22+
Flags: [ SHF_EXCLUDE ]
23+
AddressAlign: 0x1
24+
Content: 46000000050005080000000048DE180E7C9CA77501052100060702000F000000015600000535000000030291780200063900000000040105040505040400010603350000000002000000
25+
- Name: .debug_abbrev.dwo
26+
Type: SHT_PROGBITS
27+
Flags: [ SHF_EXCLUDE ]
28+
AddressAlign: 0x1
29+
Content: 01110125251305032576250000022E01111B1206401803253A0B3B0B49133F190000033400021803253A0B3B0B4913000004240003253E0B0B0B0000051301360B03250B0B3A0B3B0B0000060D00032549133A0B3B0B380B000000
30+
- Type: SectionHeaderTable
31+
Sections:
32+
- Name: .strtab
33+
- Name: .debug_str_offsets.dwo
34+
- Name: .debug_str.dwo
35+
- Name: .debug_info.dwo
36+
- Name: .debug_abbrev.dwo
37+
...

llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-entries.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
# CHECK: error: Name Index @ 0x0: Unable to get string associated with name 1.
44
# CHECK: error: Name Index @ 0x0: Entry @ 0x73 contains an invalid CU index (47).
5-
# CHECK: error: Name Index @ 0x0: Entry @ 0x79 references a non-existing DIE @ 0x3fa.
6-
# CHECK: error: Name Index @ 0x0: Entry @ 0x85: mismatched CU of DIE @ 0x30: index - 0x0; debug_info - 0x1e.
5+
# CHECK: error: Name Index @ 0x0: Entry @ 0x79 references a DIE @ 0x3fa when CU or TU ends at 0x1e.
6+
# CHECK: error: Name Index @ 0x0: Entry @ 0x85 references a DIE @ 0x30 when CU or TU ends at 0x1e.
77
# CHECK: error: Name Index @ 0x0: Entry @ 0x8b: mismatched Tag of DIE @ 0x17: index - DW_TAG_subprogram; debug_info - DW_TAG_variable.
88
# CHECK: error: Name Index @ 0x0: Entry @ 0x91: mismatched Name of DIE @ 0x35: index - foo; debug_info - bar, _Z3bar.
99
# CHECK: error: Name Index @ 0x0: Name 2 (foo): Incorrectly terminated entry list.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Verify we can successfully verify .debug_names with split DWARF.
2+
#
3+
# RUN: rm -rf %t1/
4+
# RUN: mkdir %t1
5+
# RUN: yaml2obj %p/Inputs/verify_split_dwarf_debug_names_exe.yaml > %t1/a.out
6+
# RUN: yaml2obj %p/Inputs/verify_split_dwarf_debug_names_main_dwo.yaml > %t1/main.dwo
7+
# RUN: cd %t1
8+
# RUN: llvm-dwarfdump --verify %t1/a.out | FileCheck %s
9+
10+
# CHECK: Verifying unit: 1 / 1
11+
# CHECK: Verifying dwo Units...
12+
# CHECK: Verifying .debug_line...
13+
# CHECK: Verifying .debug_str_offsets...
14+
# CHECK: Verifying .debug_names...
15+
# CHECK: No errors.
16+
17+
# Now verify if we remove the "main.dwo" file that we get an error letting us
18+
# know that the .dwo file was not able to be found.
19+
# RUN: rm %t1/main.dwo
20+
# RUN: not llvm-dwarfdump --verify %t1/a.out | FileCheck --check-prefix=NODWO %s
21+
22+
# NODWO: Verifying unit: 1 / 1
23+
# NODWO: Verifying dwo Units...
24+
# NODWO: Verifying .debug_line...
25+
# NODWO: Verifying .debug_str_offsets...
26+
# NODWO: Verifying .debug_names...
27+
# NODWO: error: Name Index @ 0x0: Entry @ 0x79 unable to load .dwo file "main.dwo" for DWARF unit @ 0x0.
28+
# NODWO: error: Name Index @ 0x0: Entry @ 0x7f unable to load .dwo file "main.dwo" for DWARF unit @ 0x0.
29+
# NODWO: error: Name Index @ 0x0: Entry @ 0x85 unable to load .dwo file "main.dwo" for DWARF unit @ 0x0.
30+
# NODWO: error: Aggregated error counts:
31+
# NODWO: error: Unable to get load .dwo file occurred 3 time(s).
32+
# NODWO: Errors detected.

0 commit comments

Comments
 (0)