Skip to content

Commit 3b5b814

Browse files
Add support for using foreign type units in .debug_names. (#87740)
This patch adds support for the new foreign type unit support in .debug_names. Features include: - don't manually index foreign TUs if we have info for them - only use the type unit entries that match the .dwo files when we have a .dwp file - fix type unit lookups for .dwo files - fix crashers that happen due to PeekDIEName() using wrong offsets where an entry had DW_IDX_comp_unit and DW_IDX_type_unit entries and when we had no type unit support, it would cause us to think it was a normal DIE in .debug_info from the main executable. --------- Co-authored-by: paperchalice <[email protected]>
1 parent 9ab292d commit 3b5b814

File tree

13 files changed

+350
-43
lines changed

13 files changed

+350
-43
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section,
232232
return result;
233233
}
234234

235+
const std::shared_ptr<SymbolFileDWARFDwo> &DWARFDebugInfo::GetDwpSymbolFile() {
236+
return m_dwarf.GetDwpSymbolFile();
237+
}
238+
235239
DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) {
236240
auto pos = llvm::lower_bound(m_type_hash_to_unit_index,
237241
std::make_pair(hash, 0u), llvm::less_first());

lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class DWARFDebugInfo {
5252

5353
const DWARFDebugAranges &GetCompileUnitAranges();
5454

55+
const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile();
56+
5557
protected:
5658
typedef std::vector<DWARFUnitSP> UnitColl;
5759

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

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
1111
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
1212
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
13+
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
1314
#include "lldb/Core/Module.h"
1415
#include "lldb/Utility/RegularExpression.h"
1516
#include "lldb/Utility/Stream.h"
@@ -34,6 +35,17 @@ DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
3435
module, std::move(index_up), debug_names, debug_str, dwarf));
3536
}
3637

38+
llvm::DenseSet<uint64_t>
39+
DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) {
40+
llvm::DenseSet<uint64_t> result;
41+
for (const DebugNames::NameIndex &ni : debug_names) {
42+
const uint32_t num_tus = ni.getForeignTUCount();
43+
for (uint32_t tu = 0; tu < num_tus; ++tu)
44+
result.insert(ni.getForeignTUSignature(tu));
45+
}
46+
return result;
47+
}
48+
3749
llvm::DenseSet<dw_offset_t>
3850
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
3951
llvm::DenseSet<dw_offset_t> result;
@@ -48,20 +60,80 @@ DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
4860
return result;
4961
}
5062

63+
std::optional<DWARFTypeUnit *>
64+
DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const {
65+
std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature();
66+
if (!type_sig.has_value())
67+
return std::nullopt;
68+
69+
// Ask the entry for the skeleton compile unit offset and fetch the .dwo
70+
// file from it and get the type unit by signature from there. If we find
71+
// the type unit in the .dwo file, we don't need to check that the
72+
// DW_AT_dwo_name matches because each .dwo file can have its own type unit.
73+
std::optional<uint64_t> cu_offset = entry.getRelatedCUOffset();
74+
if (!cu_offset)
75+
return nullptr; // Return NULL, this is a type unit, but couldn't find it.
76+
77+
DWARFUnit *cu =
78+
m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
79+
if (!cu)
80+
return nullptr; // Return NULL, this is a type unit, but couldn't find it.
81+
82+
auto dwp_sp = m_debug_info.GetDwpSymbolFile();
83+
if (!dwp_sp) {
84+
// No .dwp file, we need to load the .dwo file.
85+
DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit();
86+
// We don't need the check if the type unit matches the .dwo file if we have
87+
// a .dwo file (not a .dwp), so we can just return the value here.
88+
if (!dwo_cu.IsDWOUnit())
89+
return nullptr; // We weren't able to load the .dwo file.
90+
return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(
91+
*type_sig);
92+
}
93+
// We have a .dwp file, just get the type unit from there. We need to verify
94+
// that the type unit that ended up in the final .dwp file is the right type
95+
// unit. Type units have signatures which are the same across multiple .dwo
96+
// files, but only one of those type units will end up in the .dwp file. The
97+
// contents of type units for the same type can be different in different .dwo
98+
// files, which means the DIE offsets might not be the same between two
99+
// different type units. So we need to determine if this accelerator table
100+
// matches the type unit that ended up in the .dwp file. If it doesn't match,
101+
// then we need to ignore this accelerator table entry as the type unit that
102+
// is in the .dwp file will have its own index. In order to determine if the
103+
// type unit that ended up in a .dwp file matches this DebugNames::Entry, we
104+
// need to find the skeleton compile unit for this entry.
105+
DWARFTypeUnit *foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig);
106+
if (!foreign_tu)
107+
return nullptr; // Return NULL, this is a type unit, but couldn't find it.
108+
109+
DWARFBaseDIE cu_die = cu->GetUnitDIEOnly();
110+
DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly();
111+
llvm::StringRef cu_dwo_name =
112+
cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
113+
llvm::StringRef tu_dwo_name =
114+
tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
115+
if (cu_dwo_name == tu_dwo_name)
116+
return foreign_tu; // We found a match!
117+
return nullptr; // Return NULL, this is a type unit, but couldn't find it.
118+
}
119+
51120
DWARFUnit *
52121
DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const {
122+
123+
if (std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry))
124+
return foreign_tu.value();
125+
53126
// Look for a DWARF unit offset (CU offset or local TU offset) as they are
54127
// both offsets into the .debug_info section.
55128
std::optional<uint64_t> unit_offset = entry.getCUOffset();
56-
if (!unit_offset) {
129+
if (!unit_offset)
57130
unit_offset = entry.getLocalTUOffset();
58-
if (!unit_offset)
59-
return nullptr;
131+
if (unit_offset) {
132+
if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo,
133+
*unit_offset))
134+
return &cu->GetNonSkeletonUnit();
60135
}
61-
62-
DWARFUnit *cu =
63-
m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset);
64-
return cu ? &cu->GetNonSkeletonUnit() : nullptr;
136+
return nullptr;
65137
}
66138

67139
DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const {
@@ -274,6 +346,13 @@ void DebugNamesDWARFIndex::GetFullyQualifiedType(
274346
if (!isType(entry.tag()))
275347
continue;
276348

349+
// If we get a NULL foreign_tu back, the entry doesn't match the type unit
350+
// in the .dwp file, or we were not able to load the .dwo file or the DWO ID
351+
// didn't match.
352+
std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
353+
if (foreign_tu && foreign_tu.value() == nullptr)
354+
continue;
355+
277356
// Grab at most one extra parent, subsequent parents are not necessary to
278357
// test equality.
279358
std::optional<llvm::SmallVector<Entry, 4>> parent_chain =

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ class DebugNamesDWARFIndex : public DWARFIndex {
7070
: DWARFIndex(module), m_debug_info(dwarf.DebugInfo()),
7171
m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data),
7272
m_debug_names_up(std::move(debug_names_up)),
73-
m_fallback(module, dwarf, GetUnits(*m_debug_names_up)) {}
73+
m_fallback(module, dwarf, GetUnits(*m_debug_names_up),
74+
GetTypeUnitSignatures(*m_debug_names_up)) {}
7475

7576
DWARFDebugInfo &m_debug_info;
7677

@@ -85,6 +86,31 @@ class DebugNamesDWARFIndex : public DWARFIndex {
8586

8687
DWARFUnit *GetNonSkeletonUnit(const DebugNames::Entry &entry) const;
8788
DWARFDIE GetDIE(const DebugNames::Entry &entry) const;
89+
90+
/// Checks if an entry is a foreign TU and fetch the type unit.
91+
///
92+
/// This function checks if the DebugNames::Entry refers to a foreign TU and
93+
/// returns an optional with a value of the \a entry is a foreign type unit
94+
/// entry. A valid pointer will be returned if this entry is from a .dwo file
95+
/// or if it is from a .dwp file and it matches the type unit's originating
96+
/// .dwo file by verifying that the DW_TAG_type_unit DIE has a DW_AT_dwo_name
97+
/// that matches the DWO name from the originating skeleton compile unit.
98+
///
99+
/// \param[in] entry
100+
/// The accelerator table entry to check.
101+
///
102+
/// \returns
103+
/// A std::optional that has a value if this entry represents a foreign type
104+
/// unit. If the pointer is valid, then we were able to find and match the
105+
/// entry to the type unit in the .dwo or .dwp file. The returned value can
106+
/// have a valid, yet contain NULL in the following cases:
107+
/// - we were not able to load the .dwo file (missing or DWO ID mismatch)
108+
/// - we were able to load the .dwp file, but the type units DWO name
109+
/// doesn't match the originating skeleton compile unit's entry
110+
/// Returns std::nullopt if this entry is not a foreign type unit entry.
111+
std::optional<DWARFTypeUnit *>
112+
GetForeignTypeUnit(const DebugNames::Entry &entry) const;
113+
88114
bool ProcessEntry(const DebugNames::Entry &entry,
89115
llvm::function_ref<bool(DWARFDIE die)> callback);
90116

@@ -97,6 +123,8 @@ class DebugNamesDWARFIndex : public DWARFIndex {
97123
llvm::StringRef name);
98124

99125
static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names);
126+
static llvm::DenseSet<uint64_t>
127+
GetTypeUnitSignatures(const DebugNames &debug_names);
100128
};
101129

102130
} // namespace dwarf

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ void ManualDWARFIndex::Index() {
6060
}
6161
if (dwp_info && dwp_info->ContainsTypeUnits()) {
6262
for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {
63-
if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U)))
64-
units_to_index.push_back(tu);
63+
if (auto *tu =
64+
llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) {
65+
if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash()))
66+
units_to_index.push_back(tu);
67+
}
6568
}
6669
}
6770

lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ class SymbolFileDWARFDwo;
2121
class ManualDWARFIndex : public DWARFIndex {
2222
public:
2323
ManualDWARFIndex(Module &module, SymbolFileDWARF &dwarf,
24-
llvm::DenseSet<dw_offset_t> units_to_avoid = {})
24+
llvm::DenseSet<dw_offset_t> units_to_avoid = {},
25+
llvm::DenseSet<uint64_t> type_sigs_to_avoid = {})
2526
: DWARFIndex(module), m_dwarf(&dwarf),
26-
m_units_to_avoid(std::move(units_to_avoid)) {}
27+
m_units_to_avoid(std::move(units_to_avoid)),
28+
m_type_sigs_to_avoid(std::move(type_sigs_to_avoid)) {}
2729

2830
void Preload() override { Index(); }
2931

@@ -170,6 +172,7 @@ class ManualDWARFIndex : public DWARFIndex {
170172
SymbolFileDWARF *m_dwarf;
171173
/// Which dwarf units should we skip while building the index.
172174
llvm::DenseSet<dw_offset_t> m_units_to_avoid;
175+
llvm::DenseSet<uint64_t> m_type_sigs_to_avoid;
173176

174177
IndexSet m_set;
175178
bool m_indexed = false;

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

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,45 +1727,52 @@ lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) {
17271727
return pos->second;
17281728
}
17291729

1730-
DWARFDIE
1731-
SymbolFileDWARF::GetDIE(const DIERef &die_ref) {
1732-
// This method can be called without going through the symbol vendor so we
1733-
// need to lock the module.
1734-
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
1735-
1736-
SymbolFileDWARF *symbol_file = nullptr;
1737-
1730+
SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) {
17381731
// Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we
17391732
// must make sure we use the correct DWARF file when resolving things. On
17401733
// MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple
17411734
// SymbolFileDWARF classes, one for each .o file. We can often end up with
17421735
// references to other DWARF objects and we must be ready to receive a
17431736
// "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF
17441737
// instance.
1738+
17451739
std::optional<uint32_t> file_index = die_ref.file_index();
1746-
if (file_index) {
1747-
if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile()) {
1748-
symbol_file = debug_map->GetSymbolFileByOSOIndex(*file_index); // OSO case
1749-
if (symbol_file)
1750-
return symbol_file->DebugInfo().GetDIE(die_ref.section(),
1751-
die_ref.die_offset());
1752-
return DWARFDIE();
1753-
}
17541740

1741+
// If the file index matches, then we have the right SymbolFileDWARF already.
1742+
// This will work for both .dwo file and DWARF in .o files for mac. Also if
1743+
// both the file indexes are invalid, then we have a match.
1744+
if (GetFileIndex() == file_index)
1745+
return this;
1746+
1747+
if (file_index) {
1748+
// We have a SymbolFileDWARFDebugMap, so let it find the right file
1749+
\ if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile())
1750+
return debug_map->GetSymbolFileByOSOIndex(*file_index);
1751+
1752+
// Handle the .dwp file case correctly
17551753
if (*file_index == DIERef::k_file_index_mask)
1756-
symbol_file = GetDwpSymbolFile().get(); // DWP case
1757-
else
1758-
symbol_file = this->DebugInfo()
1759-
.GetUnitAtIndex(*die_ref.file_index())
1760-
->GetDwoSymbolFile(); // DWO case
1761-
} else if (die_ref.die_offset() == DW_INVALID_OFFSET) {
1762-
return DWARFDIE();
1754+
return GetDwpSymbolFile().get(); // DWP case
1755+
1756+
// Handle the .dwo file case correctly
1757+
return DebugInfo().GetUnitAtIndex(*die_ref.file_index())
1758+
->GetDwoSymbolFile(); // DWO case
17631759
}
1760+
return this;
1761+
}
17641762

1765-
if (symbol_file)
1766-
return symbol_file->GetDIE(die_ref);
1763+
DWARFDIE
1764+
SymbolFileDWARF::GetDIE(const DIERef &die_ref) {
1765+
if (die_ref.die_offset() == DW_INVALID_OFFSET)
1766+
return DWARFDIE();
17671767

1768-
return DebugInfo().GetDIE(die_ref.section(), die_ref.die_offset());
1768+
// This method can be called without going through the symbol vendor so we
1769+
// need to lock the module.
1770+
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
1771+
SymbolFileDWARF *symbol_file = GetDIERefSymbolFile(die_ref);
1772+
if (symbol_file)
1773+
return symbol_file->DebugInfo().GetDIE(die_ref.section(),
1774+
die_ref.die_offset());
1775+
return DWARFDIE();
17691776
}
17701777

17711778
/// Return the DW_AT_(GNU_)dwo_id.

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,15 @@ class SymbolFileDWARF : public SymbolFileCommon {
241241
return m_external_type_modules;
242242
}
243243

244+
/// Given a DIERef, find the correct SymbolFileDWARF.
245+
///
246+
/// A DIERef contains a file index that can uniquely identify a N_OSO file for
247+
/// DWARF in .o files on mac, or a .dwo or .dwp file index for split DWARF.
248+
/// Calling this function will find the correct symbol file to use so that
249+
/// further lookups can be done on the correct symbol file so that the DIE
250+
/// offset makes sense in the DIERef.
251+
virtual SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref);
252+
244253
virtual DWARFDIE GetDIE(const DIERef &die_ref);
245254

246255
DWARFDIE GetDIE(lldb::user_id_t uid);

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,8 @@ bool SymbolFileDWARFDwo::GetDebugInfoHadFrameVariableErrors() const {
174174
void SymbolFileDWARFDwo::SetDebugInfoHadFrameVariableErrors() {
175175
return GetBaseSymbolFile().SetDebugInfoHadFrameVariableErrors();
176176
}
177+
178+
SymbolFileDWARF *
179+
SymbolFileDWARFDwo::GetDIERefSymbolFile(const DIERef &die_ref) {
180+
return GetBaseSymbolFile().GetDIERefSymbolFile(die_ref);
181+
}

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF {
6767
bool GetDebugInfoHadFrameVariableErrors() const override;
6868
void SetDebugInfoHadFrameVariableErrors() override;
6969

70+
SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref) override;
71+
7072
protected:
7173
DIEToTypePtr &GetDIEToType() override;
7274

0 commit comments

Comments
 (0)