Skip to content

Commit

Permalink
Add support for parsing type unit entries in .debug_names. (llvm#72952)
Browse files Browse the repository at this point in the history
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:

llvm#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.
  • Loading branch information
clayborg authored Nov 28, 2023
1 parent 8327f4a commit 3661eb1
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 7 deletions.
20 changes: 15 additions & 5 deletions lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,29 @@ llvm::DenseSet<dw_offset_t>
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
llvm::DenseSet<dw_offset_t> result;
for (const DebugNames::NameIndex &ni : debug_names) {
for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
const uint32_t num_cus = ni.getCUCount();
for (uint32_t cu = 0; cu < num_cus; ++cu)
result.insert(ni.getCUOffset(cu));
const uint32_t num_tus = ni.getLocalTUCount();
for (uint32_t tu = 0; tu < num_tus; ++tu)
result.insert(ni.getLocalTUOffset(tu));
}
return result;
}

std::optional<DIERef>
DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
std::optional<uint64_t> cu_offset = entry.getCUOffset();
if (!cu_offset)
return std::nullopt;
// Look for a DWARF unit offset (CU offset or local TU offset) as they are
// both offsets into the .debug_info section.
std::optional<uint64_t> unit_offset = entry.getCUOffset();
if (!unit_offset) {
unit_offset = entry.getLocalTUOffset();
if (!unit_offset)
return std::nullopt;
}

DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
DWARFUnit *cu =
m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset);
if (!cu)
return std::nullopt;

Expand Down
48 changes: 48 additions & 0 deletions lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-debug-names.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Test that we can use .debug_names to lookup a type that is only referenced
// from within a type unit. In the code below the type named "stype" is only
// referenced within the type unit itself and when we enable .debug_names, we
// expect the have an entry for this and to be able to find this type when
// we do a lookup.

// REQUIRES: lld

// RUN: %clang %s -target x86_64-pc-linux -gdwarf-5 -fdebug-types-section \
// RUN: -gpubnames -fno-limit-debug-info -c -o %t.o
// RUN: ld.lld %t.o -o %t
// RUN: %lldb %t -o "type lookup stype" -b | FileCheck %s --check-prefix=BASE
// RUN: %lldb %t -o "type lookup bar::stype" -b | FileCheck %s --check-prefix=PART
// RUN: %lldb %t -o "type lookup foo::bar::stype" -b | FileCheck %s --check-prefix=FULL

// BASE: (lldb) type lookup stype
// BASE-NEXT: int

// PART: (lldb) type lookup bar::stype
// PART-NEXT: int

// FULL: (lldb) type lookup foo::bar::stype
// FULL-NEXT: int

namespace foo {
class bar {
public:
typedef unsigned utype;
// This type is only referenced from within the type unit and we need to
// make sure we can find it with the new type unit support in .debug_names.
typedef int stype;

private:
utype m_unsigned;

public:
bar(utype u) : m_unsigned(u) {}

utype get() const { return m_unsigned; }
void set(utype u) { m_unsigned = u; }
stype gets() const { return (stype)m_unsigned; }
};
} // namespace foo

int main() {
foo::bar b(12);
return 0;
}
19 changes: 18 additions & 1 deletion llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ class DWARFAcceleratorTable {
/// recorded in this Accelerator Entry.
virtual std::optional<uint64_t> getCUOffset() const = 0;

/// Returns the Offset of the Type Unit associated with this
/// Accelerator Entry or std::nullopt if the Type Unit offset is not
/// recorded in this Accelerator Entry.
virtual std::optional<uint64_t> getLocalTUOffset() const {
// Default return for accelerator tables that don't support type units.
return std::nullopt;
}

/// Returns the Tag of the Debug Info Entry associated with this
/// Accelerator Entry or std::nullopt if the Tag is not recorded in this
/// Accelerator Entry.
Expand Down Expand Up @@ -424,6 +432,7 @@ class DWARFDebugNames : public DWARFAcceleratorTable {

public:
std::optional<uint64_t> getCUOffset() const override;
std::optional<uint64_t> getLocalTUOffset() const override;
std::optional<dwarf::Tag> getTag() const override { return tag(); }

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

/// Returns the Index into the Local Type Unit list of the owning Name
/// Index or std::nullopt if this Accelerator Entry does not have an
/// associated Type Unit. It is up to the user to verify that the
/// returned Index is valid in the owning NameIndex (or use
/// getLocalTUOffset(), which will handle that check itself).
std::optional<uint64_t> getLocalTUIndex() const;

/// .debug_names-specific getter, which always succeeds (DWARF v5 index
/// entries always have a tag).
dwarf::Tag tag() const { return Abbr->Tag; }
Expand Down
18 changes: 17 additions & 1 deletion llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,10 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
return Off->getAsUnsignedConstant();
// In a per-CU index, the entries without a DW_IDX_compile_unit attribute
// implicitly refer to the single CU.
// implicitly refer to the single CU, but only if we don't have a
// DW_IDX_type_unit.
if (lookup(dwarf::DW_IDX_type_unit).has_value())
return std::nullopt;
if (NameIdx->getCUCount() == 1)
return 0;
return std::nullopt;
Expand All @@ -634,6 +637,19 @@ std::optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
return NameIdx->getCUOffset(*Index);
}

std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUOffset() const {
std::optional<uint64_t> Index = getLocalTUIndex();
if (!Index || *Index >= NameIdx->getLocalTUCount())
return std::nullopt;
return NameIdx->getLocalTUOffset(*Index);
}

std::optional<uint64_t> DWARFDebugNames::Entry::getLocalTUIndex() const {
if (std::optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_type_unit))
return Off->getAsUnsignedConstant();
return std::nullopt;
}

void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
W.startLine() << formatv("Abbrev: {0:x}\n", Abbr->Code);
W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);
Expand Down

0 comments on commit 3661eb1

Please sign in to comment.