Skip to content

Commit 3661eb1

Browse files
authored
Add support for parsing type unit entries in .debug_names. (#72952)
This is a follow up patch after .debug_names can now emit local type unit entries when we compile with type units + DWARF5 + .debug_names. The pull request that added this functionality was: #70515 This patch makes sure that the DebugNamesDWARFIndex in LLDB will not manually need to parse type units if they have a valid index. It also fixes the index to be able to correctly extract name entries that reference type unit DIEs. Added a test to verify things work as expected.
1 parent 8327f4a commit 3661eb1

File tree

4 files changed

+98
-7
lines changed

4 files changed

+98
-7
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp

+15-5
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,29 @@ llvm::DenseSet<dw_offset_t>
3737
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
3838
llvm::DenseSet<dw_offset_t> result;
3939
for (const DebugNames::NameIndex &ni : debug_names) {
40-
for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
40+
const uint32_t num_cus = ni.getCUCount();
41+
for (uint32_t cu = 0; cu < num_cus; ++cu)
4142
result.insert(ni.getCUOffset(cu));
43+
const uint32_t num_tus = ni.getLocalTUCount();
44+
for (uint32_t tu = 0; tu < num_tus; ++tu)
45+
result.insert(ni.getLocalTUOffset(tu));
4246
}
4347
return result;
4448
}
4549

4650
std::optional<DIERef>
4751
DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
48-
std::optional<uint64_t> cu_offset = entry.getCUOffset();
49-
if (!cu_offset)
50-
return std::nullopt;
52+
// Look for a DWARF unit offset (CU offset or local TU offset) as they are
53+
// both offsets into the .debug_info section.
54+
std::optional<uint64_t> unit_offset = entry.getCUOffset();
55+
if (!unit_offset) {
56+
unit_offset = entry.getLocalTUOffset();
57+
if (!unit_offset)
58+
return std::nullopt;
59+
}
5160

52-
DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
61+
DWARFUnit *cu =
62+
m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset);
5363
if (!cu)
5464
return std::nullopt;
5565

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Test that we can use .debug_names to lookup a type that is only referenced
2+
// from within a type unit. In the code below the type named "stype" is only
3+
// referenced within the type unit itself and when we enable .debug_names, we
4+
// expect the have an entry for this and to be able to find this type when
5+
// we do a lookup.
6+
7+
// REQUIRES: lld
8+
9+
// RUN: %clang %s -target x86_64-pc-linux -gdwarf-5 -fdebug-types-section \
10+
// RUN: -gpubnames -fno-limit-debug-info -c -o %t.o
11+
// RUN: ld.lld %t.o -o %t
12+
// RUN: %lldb %t -o "type lookup stype" -b | FileCheck %s --check-prefix=BASE
13+
// RUN: %lldb %t -o "type lookup bar::stype" -b | FileCheck %s --check-prefix=PART
14+
// RUN: %lldb %t -o "type lookup foo::bar::stype" -b | FileCheck %s --check-prefix=FULL
15+
16+
// BASE: (lldb) type lookup stype
17+
// BASE-NEXT: int
18+
19+
// PART: (lldb) type lookup bar::stype
20+
// PART-NEXT: int
21+
22+
// FULL: (lldb) type lookup foo::bar::stype
23+
// FULL-NEXT: int
24+
25+
namespace foo {
26+
class bar {
27+
public:
28+
typedef unsigned utype;
29+
// This type is only referenced from within the type unit and we need to
30+
// make sure we can find it with the new type unit support in .debug_names.
31+
typedef int stype;
32+
33+
private:
34+
utype m_unsigned;
35+
36+
public:
37+
bar(utype u) : m_unsigned(u) {}
38+
39+
utype get() const { return m_unsigned; }
40+
void set(utype u) { m_unsigned = u; }
41+
stype gets() const { return (stype)m_unsigned; }
42+
};
43+
} // namespace foo
44+
45+
int main() {
46+
foo::bar b(12);
47+
return 0;
48+
}

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

+18-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ class DWARFAcceleratorTable {
5656
/// recorded in this Accelerator Entry.
5757
virtual std::optional<uint64_t> getCUOffset() const = 0;
5858

59+
/// Returns the Offset of the Type Unit associated with this
60+
/// Accelerator Entry or std::nullopt if the Type Unit offset is not
61+
/// recorded in this Accelerator Entry.
62+
virtual std::optional<uint64_t> getLocalTUOffset() const {
63+
// Default return for accelerator tables that don't support type units.
64+
return std::nullopt;
65+
}
66+
5967
/// Returns the Tag of the Debug Info Entry associated with this
6068
/// Accelerator Entry or std::nullopt if the Tag is not recorded in this
6169
/// Accelerator Entry.
@@ -424,6 +432,7 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
424432

425433
public:
426434
std::optional<uint64_t> getCUOffset() const override;
435+
std::optional<uint64_t> getLocalTUOffset() const override;
427436
std::optional<dwarf::Tag> getTag() const override { return tag(); }
428437

429438
/// Returns the Index into the Compilation Unit list of the owning Name
@@ -433,9 +442,17 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
433442
/// which will handle that check itself). Note that entries in NameIndexes
434443
/// which index just a single Compilation Unit are implicitly associated
435444
/// with that unit, so this function will return 0 even without an explicit
436-
/// DW_IDX_compile_unit attribute.
445+
/// DW_IDX_compile_unit attribute, unless there is a DW_IDX_type_unit
446+
/// attribute.
437447
std::optional<uint64_t> getCUIndex() const;
438448

449+
/// Returns the Index into the Local Type Unit list of the owning Name
450+
/// Index or std::nullopt if this Accelerator Entry does not have an
451+
/// associated Type Unit. It is up to the user to verify that the
452+
/// returned Index is valid in the owning NameIndex (or use
453+
/// getLocalTUOffset(), which will handle that check itself).
454+
std::optional<uint64_t> getLocalTUIndex() const;
455+
439456
/// .debug_names-specific getter, which always succeeds (DWARF v5 index
440457
/// entries always have a tag).
441458
dwarf::Tag tag() const { return Abbr->Tag; }

llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,10 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
621621
if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
622622
return Off->getAsUnsignedConstant();
623623
// In a per-CU index, the entries without a DW_IDX_compile_unit attribute
624-
// implicitly refer to the single CU.
624+
// implicitly refer to the single CU, but only if we don't have a
625+
// DW_IDX_type_unit.
626+
if (lookup(dwarf::DW_IDX_type_unit).has_value())
627+
return std::nullopt;
625628
if (NameIdx->getCUCount() == 1)
626629
return 0;
627630
return std::nullopt;
@@ -634,6 +637,19 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
634637
return NameIdx->getCUOffset(*Index);
635638
}
636639

640+
std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUOffset() const {
641+
std::optional<uint64_t> Index = getLocalTUIndex();
642+
if (!Index || *Index >= NameIdx->getLocalTUCount())
643+
return std::nullopt;
644+
return NameIdx->getLocalTUOffset(*Index);
645+
}
646+
647+
std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const {
648+
if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_type_unit))
649+
return Off->getAsUnsignedConstant();
650+
return std::nullopt;
651+
}
652+
637653
void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
638654
W.startLine() << formatv("Abbrev: {0:x}\n", Abbr->Code);
639655
W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);

0 commit comments

Comments
 (0)