Skip to content

Commit 4c72021

Browse files
author
jeffreytan81
committed
Improve type query using .debug_names parent chain
1 parent 1a350e4 commit 4c72021

File tree

5 files changed

+201
-3
lines changed

5 files changed

+201
-3
lines changed

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

+25
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,28 @@ bool DWARFIndex::GetFullyQualifiedTypeImpl(
126126
return callback(die);
127127
return true;
128128
}
129+
130+
void DWARFIndex::GetTypesWithQuery(
131+
TypeQuery &query, llvm::function_ref<bool(DWARFDIE die)> callback) {
132+
GetTypes(query.GetTypeBasename(), [&](DWARFDIE die) {
133+
return ProcessTypeDieMatchQuery(query, die, callback);
134+
});
135+
}
136+
137+
bool DWARFIndex::ProcessTypeDieMatchQuery(
138+
TypeQuery &query, DWARFDIE die,
139+
llvm::function_ref<bool(DWARFDIE die)> callback) {
140+
// Nothing to match from query
141+
if (query.GetContextRef().size() <= 1)
142+
return callback(die);
143+
144+
std::vector<lldb_private::CompilerContext> die_context;
145+
if (query.GetModuleSearch())
146+
die_context = die.GetDeclContext();
147+
else
148+
die_context = die.GetTypeLookupContext();
149+
150+
if (!query.ContextMatches(die_context))
151+
return true;
152+
return callback(die);
153+
}

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

+12
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ class DWARFIndex {
6464
virtual void
6565
GetNamespaces(ConstString name,
6666
llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
67+
/// Get type DIEs meeting requires of \a query.
68+
/// in its decl parent chain as subset. A base implementation is provided,
69+
/// Specializations should override this if they are able to provide a faster
70+
/// implementation.
71+
virtual void
72+
GetTypesWithQuery(TypeQuery &query,
73+
llvm::function_ref<bool(DWARFDIE die)> callback);
6774
virtual void
6875
GetFunctions(const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
6976
const CompilerDeclContext &parent_decl_ctx,
@@ -115,6 +122,11 @@ class DWARFIndex {
115122
bool
116123
GetFullyQualifiedTypeImpl(const DWARFDeclContext &context, DWARFDIE die,
117124
llvm::function_ref<bool(DWARFDIE die)> callback);
125+
126+
/// Check if the type \a die can meet the requirements of \a query.
127+
bool
128+
ProcessTypeDieMatchQuery(TypeQuery &query, DWARFDIE die,
129+
llvm::function_ref<bool(DWARFDIE die)> callback);
118130
};
119131
} // namespace dwarf
120132
} // namespace lldb_private::plugin

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

+127-1
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ using Entry = llvm::DWARFDebugNames::Entry;
301301
/// If any parent does not have an `IDX_parent`, or the Entry data is corrupted,
302302
/// nullopt is returned.
303303
std::optional<llvm::SmallVector<Entry, 4>>
304-
getParentChain(Entry entry, uint32_t max_parents) {
304+
getParentChain(Entry entry,
305+
uint32_t max_parents = std::numeric_limits<uint32_t>::max()) {
305306
llvm::SmallVector<Entry, 4> parent_entries;
306307

307308
do {
@@ -374,6 +375,21 @@ void DebugNamesDWARFIndex::GetFullyQualifiedType(
374375
m_fallback.GetFullyQualifiedType(context, callback);
375376
}
376377

378+
bool DebugNamesDWARFIndex::SameAsEntryContext(
379+
const CompilerContext &query_context,
380+
const DebugNames::Entry &entry) const {
381+
// TODO: check dwarf tag matches.
382+
// Peek at the AT_name of `entry` and test equality to `name`.
383+
auto maybe_dieoffset = entry.getDIEUnitOffset();
384+
if (!maybe_dieoffset)
385+
return false;
386+
DWARFUnit *unit = GetNonSkeletonUnit(entry);
387+
if (!unit)
388+
return false;
389+
return query_context.name ==
390+
unit->PeekDIEName(unit->GetOffset() + *maybe_dieoffset);
391+
}
392+
377393
bool DebugNamesDWARFIndex::SameParentChain(
378394
llvm::ArrayRef<llvm::StringRef> parent_names,
379395
llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
@@ -402,6 +418,49 @@ bool DebugNamesDWARFIndex::SameParentChain(
402418
return true;
403419
}
404420

421+
bool DebugNamesDWARFIndex::SameParentChain(
422+
llvm::ArrayRef<CompilerContext> parent_contexts,
423+
llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
424+
if (parent_entries.size() != parent_contexts.size())
425+
return false;
426+
427+
// If the AT_name of any parent fails to match the expected name, we don't
428+
// have a match.
429+
for (auto [parent_context, parent_entry] :
430+
llvm::zip_equal(parent_contexts, parent_entries))
431+
if (!SameAsEntryContext(parent_context, parent_entry))
432+
return false;
433+
return true;
434+
}
435+
436+
bool DebugNamesDWARFIndex::WithinParentChain(
437+
llvm::ArrayRef<CompilerContext> query_contexts,
438+
llvm::ArrayRef<DebugNames::Entry> parent_chain) const {
439+
if (query_contexts.size() == parent_chain.size())
440+
return SameParentChain(query_contexts, parent_chain);
441+
442+
size_t query_idx = 0, chain_idx = 0;
443+
while (query_idx < query_contexts.size() && chain_idx < parent_chain.size()) {
444+
if (query_contexts.size() - query_idx > parent_chain.size() - chain_idx) {
445+
// Parent chain has not enough entries, we can't possibly have a match.
446+
return false;
447+
}
448+
449+
if (SameAsEntryContext(query_contexts[query_idx],
450+
parent_chain[chain_idx])) {
451+
++query_idx;
452+
++chain_idx;
453+
} else {
454+
// Name does not match, try next parent_chain entry if the current entry
455+
// is namespace because the current one can be an inline namespace.
456+
if (parent_chain[chain_idx].tag() != DW_TAG_namespace)
457+
return false;
458+
++chain_idx;
459+
}
460+
}
461+
return query_idx == query_contexts.size();
462+
}
463+
405464
void DebugNamesDWARFIndex::GetTypes(
406465
ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
407466
for (const DebugNames::Entry &entry :
@@ -444,6 +503,73 @@ void DebugNamesDWARFIndex::GetNamespaces(
444503
m_fallback.GetNamespaces(name, callback);
445504
}
446505

506+
llvm::SmallVector<CompilerContext>
507+
DebugNamesDWARFIndex::GetTypeQueryParentContexts(TypeQuery &query) {
508+
std::vector<lldb_private::CompilerContext> &query_decl_context =
509+
query.GetContextRef();
510+
llvm::SmallVector<CompilerContext> parent_contexts;
511+
if (!query_decl_context.empty()) {
512+
auto rbegin = query_decl_context.rbegin(), rend = query_decl_context.rend();
513+
// Reverse the query decl context to match parent chain.
514+
// Skip the last entry, it is the type we are looking for.
515+
for (auto rit = rbegin + 1; rit != rend; ++rit)
516+
// Skip any context without name because .debug_names might not encode
517+
// them. (e.g. annonymous namespace)
518+
if ((rit->kind & CompilerContextKind::AnyType) !=
519+
CompilerContextKind::Invalid &&
520+
!rit->name.IsEmpty())
521+
parent_contexts.push_back(*rit);
522+
}
523+
return parent_contexts;
524+
}
525+
526+
void DebugNamesDWARFIndex::GetTypesWithQuery(
527+
TypeQuery &query, llvm::function_ref<bool(DWARFDIE die)> callback) {
528+
ConstString name = query.GetTypeBasename();
529+
std::vector<lldb_private::CompilerContext> query_context =
530+
query.GetContextRef();
531+
if (query_context.size() <= 1)
532+
return GetTypes(name, callback);
533+
534+
llvm::SmallVector<CompilerContext> parent_contexts =
535+
GetTypeQueryParentContexts(query);
536+
// For each entry, grab its parent chain and check if we have a match.
537+
for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
538+
if (!isType(entry.tag()))
539+
continue;
540+
541+
// If we get a NULL foreign_tu back, the entry doesn't match the type unit
542+
// in the .dwp file, or we were not able to load the .dwo file or the DWO ID
543+
// didn't match.
544+
std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
545+
if (foreign_tu && foreign_tu.value() == nullptr)
546+
continue;
547+
548+
std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
549+
getParentChain(entry);
550+
if (!parent_chain) {
551+
// Fallback: use the base class implementation.
552+
if (!ProcessEntry(entry, [&](DWARFDIE die) {
553+
return ProcessTypeDieMatchQuery(query, die, callback);
554+
}))
555+
return;
556+
continue;
557+
}
558+
559+
// If parent_chain is shorter than parent_contexts, we can't possibly match.
560+
if (parent_chain->size() < parent_contexts.size())
561+
continue;
562+
else if (WithinParentChain(parent_contexts, *parent_chain) &&
563+
!ProcessEntry(entry, [&](DWARFDIE die) {
564+
// After .debug_names filtering still sending to base class for
565+
// further filtering before calling the callback.
566+
return ProcessTypeDieMatchQuery(query, die, callback);
567+
}))
568+
return;
569+
}
570+
m_fallback.GetTypesWithQuery(query, callback);
571+
}
572+
447573
void DebugNamesDWARFIndex::GetFunctions(
448574
const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
449575
const CompilerDeclContext &parent_decl_ctx,

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

+34
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ class DebugNamesDWARFIndex : public DWARFIndex {
5252
llvm::function_ref<bool(DWARFDIE die)> callback) override;
5353
void GetNamespaces(ConstString name,
5454
llvm::function_ref<bool(DWARFDIE die)> callback) override;
55+
void
56+
GetTypesWithQuery(TypeQuery &query,
57+
llvm::function_ref<bool(DWARFDIE die)> callback) override;
58+
5559
void GetFunctions(const Module::LookupInfo &lookup_info,
5660
SymbolFileDWARF &dwarf,
5761
const CompilerDeclContext &parent_decl_ctx,
@@ -118,6 +122,36 @@ class DebugNamesDWARFIndex : public DWARFIndex {
118122
bool SameParentChain(llvm::ArrayRef<llvm::StringRef> parent_names,
119123
llvm::ArrayRef<DebugNames::Entry> parent_entries) const;
120124

125+
bool SameParentChain(llvm::ArrayRef<CompilerContext> parent_names,
126+
llvm::ArrayRef<DebugNames::Entry> parent_entries) const;
127+
128+
/// Returns true if \a parent_contexts entries are within \a parent_chain.
129+
/// This is diffferent from SameParentChain() which checks for exact match.
130+
/// This function is required because \a parent_chain can contain inline
131+
/// namespace entries which may not be specified in \a parent_contexts by
132+
/// client.
133+
///
134+
/// \param[in] parent_contexts
135+
/// The list of parent contexts to check for.
136+
///
137+
/// \param[in] parent_chain
138+
/// The fully qualified parent chain entries from .debug_names index table
139+
/// to check against.
140+
///
141+
/// \returns
142+
/// True if all \a parent_contexts entries are can be sequentially found
143+
/// inside
144+
/// \a parent_chain, otherwise False.
145+
bool WithinParentChain(llvm::ArrayRef<CompilerContext> parent_contexts,
146+
llvm::ArrayRef<DebugNames::Entry> parent_chain) const;
147+
148+
/// Returns true if .debug_names pool entry \p entry matches \p query_context.
149+
bool SameAsEntryContext(const CompilerContext &query_context,
150+
const DebugNames::Entry &entry) const;
151+
152+
llvm::SmallVector<CompilerContext>
153+
GetTypeQueryParentContexts(TypeQuery &query);
154+
121155
static void MaybeLogLookupError(llvm::Error error,
122156
const DebugNames::NameIndex &ni,
123157
llvm::StringRef name);

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -2748,8 +2748,9 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
27482748

27492749
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
27502750

2751+
TypeQuery query_full(query);
27512752
bool have_index_match = false;
2752-
m_index->GetTypes(type_basename, [&](DWARFDIE die) {
2753+
m_index->GetTypesWithQuery(query_full, [&](DWARFDIE die) {
27532754
// Check the language, but only if we have a language filter.
27542755
if (query.HasLanguage()) {
27552756
if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU())))
@@ -2813,7 +2814,7 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
28132814
auto type_basename_simple = query_simple.GetTypeBasename();
28142815
// Copy our match's context and update the basename we are looking for
28152816
// so we can use this only to compare the context correctly.
2816-
m_index->GetTypes(type_basename_simple, [&](DWARFDIE die) {
2817+
m_index->GetTypesWithQuery(query_simple, [&](DWARFDIE die) {
28172818
// Check the language, but only if we have a language filter.
28182819
if (query.HasLanguage()) {
28192820
if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU())))

0 commit comments

Comments
 (0)