1//===-- DebugNamesDWARFIndex.cpp ------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
10#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
11#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
12#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
13#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
14#include "lldb/Core/Module.h"
15#include "lldb/Utility/RegularExpression.h"
16#include "lldb/Utility/Stream.h"
17#include "llvm/ADT/Sequence.h"
18#include <optional>
19
20using namespace lldb_private;
21using namespace lldb;
22using namespace lldb_private::dwarf;
23using namespace lldb_private::plugin::dwarf;
24
25llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
26DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
27 DWARFDataExtractor debug_str,
28 SymbolFileDWARF &dwarf) {
29 auto index_up = std::make_unique<DebugNames>(args: debug_names.GetAsLLVMDWARF(),
30 args: debug_str.GetAsLLVM());
31 if (llvm::Error E = index_up->extract())
32 return std::move(E);
33
34 return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
35 module, std::move(index_up), debug_names, debug_str, dwarf));
36}
37
38llvm::DenseSet<uint64_t>
39DebugNamesDWARFIndex::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(V: ni.getForeignTUSignature(TU: tu));
45 }
46 return result;
47}
48
49llvm::DenseSet<dw_offset_t>
50DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
51 llvm::DenseSet<dw_offset_t> result;
52 for (const DebugNames::NameIndex &ni : debug_names) {
53 const uint32_t num_cus = ni.getCUCount();
54 for (uint32_t cu = 0; cu < num_cus; ++cu)
55 result.insert(V: ni.getCUOffset(CU: cu));
56 const uint32_t num_tus = ni.getLocalTUCount();
57 for (uint32_t tu = 0; tu < num_tus; ++tu)
58 result.insert(V: ni.getLocalTUOffset(TU: tu));
59 }
60 return result;
61}
62
63std::optional<DWARFTypeUnit *>
64DebugNamesDWARFIndex::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(section: DIERef::Section::DebugInfo, cu_offset: *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 hash: *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(hash: *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(attr: DW_AT_dwo_name, fail_value: nullptr);
113 llvm::StringRef tu_dwo_name =
114 tu_die.GetAttributeValueAsString(attr: DW_AT_dwo_name, fail_value: 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
120DWARFUnit *
121DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const {
122
123 if (std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry))
124 return foreign_tu.value();
125
126 // Look for a DWARF unit offset (CU offset or local TU offset) as they are
127 // both offsets into the .debug_info section.
128 std::optional<uint64_t> unit_offset = entry.getCUOffset();
129 if (!unit_offset)
130 unit_offset = entry.getLocalTUOffset();
131 if (unit_offset) {
132 if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(section: DIERef::Section::DebugInfo,
133 cu_offset: *unit_offset))
134 return &cu->GetNonSkeletonUnit();
135 }
136 return nullptr;
137}
138
139DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const {
140 DWARFUnit *unit = GetNonSkeletonUnit(entry);
141 std::optional<uint64_t> die_offset = entry.getDIEUnitOffset();
142 if (!unit || !die_offset)
143 return DWARFDIE();
144 if (DWARFDIE die = unit->GetDIE(die_offset: unit->GetOffset() + *die_offset))
145 return die;
146
147 m_module.ReportErrorIfModifyDetected(
148 format: "the DWARF debug information has been modified (bad offset {0:x} in "
149 "debug_names section)\n",
150 args&: *die_offset);
151 return DWARFDIE();
152}
153
154bool DebugNamesDWARFIndex::ProcessEntry(
155 const DebugNames::Entry &entry,
156 llvm::function_ref<bool(DWARFDIE die)> callback) {
157 DWARFDIE die = GetDIE(entry);
158 if (!die)
159 return true;
160 // Clang used to erroneously emit index entries for declaration DIEs in case
161 // when the definition is in a type unit (llvm.org/pr77696).
162 if (die.IsStructUnionOrClass() &&
163 die.GetAttributeValueAsUnsigned(attr: DW_AT_declaration, fail_value: 0))
164 return true;
165 return callback(die);
166}
167
168void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
169 const DebugNames::NameIndex &ni,
170 llvm::StringRef name) {
171 // Ignore SentinelErrors, log everything else.
172 LLDB_LOG_ERROR(
173 GetLog(DWARFLog::Lookups),
174 handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
175 "Failed to parse index entries for index at {1:x}, name {2}: {0}",
176 ni.getUnitOffset(), name);
177}
178
179void DebugNamesDWARFIndex::GetGlobalVariables(
180 ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
181 for (const DebugNames::Entry &entry :
182 m_debug_names_up->equal_range(Key: basename.GetStringRef())) {
183 if (entry.tag() != DW_TAG_variable)
184 continue;
185
186 if (!ProcessEntry(entry, callback))
187 return;
188 }
189
190 m_fallback.GetGlobalVariables(basename, callback);
191}
192
193void DebugNamesDWARFIndex::GetGlobalVariables(
194 const RegularExpression &regex,
195 llvm::function_ref<bool(DWARFDIE die)> callback) {
196 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
197 for (DebugNames::NameTableEntry nte: ni) {
198 Mangled mangled_name(nte.getString());
199 if (!mangled_name.NameMatches(regex))
200 continue;
201
202 uint64_t entry_offset = nte.getEntryOffset();
203 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(Offset: &entry_offset);
204 for (; entry_or; entry_or = ni.getEntry(Offset: &entry_offset)) {
205 if (entry_or->tag() != DW_TAG_variable)
206 continue;
207
208 if (!ProcessEntry(entry: *entry_or, callback))
209 return;
210 }
211 MaybeLogLookupError(error: entry_or.takeError(), ni, name: nte.getString());
212 }
213 }
214
215 m_fallback.GetGlobalVariables(regex, callback);
216}
217
218void DebugNamesDWARFIndex::GetGlobalVariables(
219 DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
220 uint64_t cu_offset = cu.GetOffset();
221 bool found_entry_for_cu = false;
222 for (const DebugNames::NameIndex &ni : *m_debug_names_up) {
223 // Check if this name index contains an entry for the given CU.
224 bool cu_matches = false;
225 for (uint32_t i = 0; i < ni.getCUCount(); ++i) {
226 if (ni.getCUOffset(CU: i) == cu_offset) {
227 cu_matches = true;
228 break;
229 }
230 }
231 if (!cu_matches)
232 continue;
233
234 for (DebugNames::NameTableEntry nte : ni) {
235 uint64_t entry_offset = nte.getEntryOffset();
236 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(Offset: &entry_offset);
237 for (; entry_or; entry_or = ni.getEntry(Offset: &entry_offset)) {
238 if (entry_or->tag() != DW_TAG_variable)
239 continue;
240 if (entry_or->getCUOffset() != cu_offset)
241 continue;
242
243 found_entry_for_cu = true;
244 if (!ProcessEntry(entry: *entry_or, callback))
245 return;
246 }
247 MaybeLogLookupError(error: entry_or.takeError(), ni, name: nte.getString());
248 }
249 }
250 // If no name index for that particular CU was found, fallback to
251 // creating the manual index.
252 if (!found_entry_for_cu)
253 m_fallback.GetGlobalVariables(unit&: cu, callback);
254}
255
256void DebugNamesDWARFIndex::GetCompleteObjCClass(
257 ConstString class_name, bool must_be_implementation,
258 llvm::function_ref<bool(DWARFDIE die)> callback) {
259 // Keep a list of incomplete types as fallback for when we don't find the
260 // complete type.
261 std::vector<DWARFDIE> incomplete_types;
262
263 for (const DebugNames::Entry &entry :
264 m_debug_names_up->equal_range(Key: class_name.GetStringRef())) {
265 if (entry.tag() != DW_TAG_structure_type &&
266 entry.tag() != DW_TAG_class_type)
267 continue;
268
269 DWARFDIE die = GetDIE(entry);
270 if (!die) {
271 // Report invalid
272 continue;
273 }
274
275 if (die.GetAttributeValueAsUnsigned(attr: DW_AT_APPLE_objc_complete_type, fail_value: 0)) {
276 // If we find the complete version we're done.
277 callback(die);
278 return;
279 }
280 incomplete_types.push_back(x: die);
281 }
282
283 for (DWARFDIE die : incomplete_types)
284 if (!callback(die))
285 return;
286
287 m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
288}
289
290namespace {
291using Entry = llvm::DWARFDebugNames::Entry;
292
293/// If `entry` and all of its parents have an `IDX_parent`, use that information
294/// to build and return a list of at most `max_parents` parent Entries.
295/// `entry` itself is not included in the list.
296/// If any parent does not have an `IDX_parent`, or the Entry data is corrupted,
297/// nullopt is returned.
298std::optional<llvm::SmallVector<Entry, 4>>
299getParentChain(Entry entry,
300 uint32_t max_parents = std::numeric_limits<uint32_t>::max()) {
301 llvm::SmallVector<Entry, 4> parent_entries;
302
303 do {
304 if (!entry.hasParentInformation())
305 return std::nullopt;
306
307 llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry();
308 if (!parent) {
309 // Bad data.
310 LLDB_LOG_ERROR(
311 GetLog(DWARFLog::Lookups), parent.takeError(),
312 "Failed to extract parent entry from a non-empty IDX_parent");
313 return std::nullopt;
314 }
315
316 // Last parent in the chain.
317 if (!parent->has_value())
318 break;
319
320 parent_entries.push_back(Elt: **parent);
321 entry = **parent;
322 } while (parent_entries.size() < max_parents);
323
324 return parent_entries;
325}
326} // namespace
327
328void DebugNamesDWARFIndex::GetFullyQualifiedType(
329 const DWARFDeclContext &context,
330 llvm::function_ref<bool(DWARFDIE die)> callback) {
331 if (context.GetSize() == 0)
332 return;
333
334 llvm::StringRef leaf_name = context[0].name;
335 llvm::SmallVector<llvm::StringRef> parent_names;
336 for (auto idx : llvm::seq<int>(Begin: 1, End: context.GetSize()))
337 parent_names.emplace_back(Args: context[idx].name);
338
339 // For each entry, grab its parent chain and check if we have a match.
340 for (const DebugNames::Entry &entry :
341 m_debug_names_up->equal_range(Key: leaf_name)) {
342 if (!isType(T: entry.tag()))
343 continue;
344
345 // If we get a NULL foreign_tu back, the entry doesn't match the type unit
346 // in the .dwp file, or we were not able to load the .dwo file or the DWO ID
347 // didn't match.
348 std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
349 if (foreign_tu && foreign_tu.value() == nullptr)
350 continue;
351
352 // Grab at most one extra parent, subsequent parents are not necessary to
353 // test equality.
354 std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
355 getParentChain(entry, max_parents: parent_names.size() + 1);
356
357 if (!parent_chain) {
358 // Fallback: use the base class implementation.
359 if (!ProcessEntry(entry, callback: [&](DWARFDIE die) {
360 return GetFullyQualifiedTypeImpl(context, die, callback);
361 }))
362 return;
363 continue;
364 }
365
366 if (SameParentChain(parent_names, parent_entries: *parent_chain)) {
367 if (!ProcessEntry(entry, callback))
368 return;
369 }
370 }
371 m_fallback.GetFullyQualifiedType(context, callback);
372}
373
374bool DebugNamesDWARFIndex::SameAsEntryContext(
375 const CompilerContext &query_context,
376 const DebugNames::Entry &entry) const {
377 // TODO: check dwarf tag matches.
378 // Peek at the AT_name of `entry` and test equality to `name`.
379 auto maybe_dieoffset = entry.getDIEUnitOffset();
380 if (!maybe_dieoffset)
381 return false;
382 DWARFUnit *unit = GetNonSkeletonUnit(entry);
383 if (!unit)
384 return false;
385 return query_context.name ==
386 unit->PeekDIEName(die_offset: unit->GetOffset() + *maybe_dieoffset);
387}
388
389bool DebugNamesDWARFIndex::SameParentChain(
390 llvm::ArrayRef<llvm::StringRef> parent_names,
391 llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
392
393 if (parent_entries.size() != parent_names.size())
394 return false;
395
396 auto SameAsEntryATName = [this](llvm::StringRef name,
397 const DebugNames::Entry &entry) {
398 // Peek at the AT_name of `entry` and test equality to `name`.
399 auto maybe_dieoffset = entry.getDIEUnitOffset();
400 if (!maybe_dieoffset)
401 return false;
402 DWARFUnit *unit = GetNonSkeletonUnit(entry);
403 if (!unit)
404 return false;
405 return name == unit->PeekDIEName(die_offset: unit->GetOffset() + *maybe_dieoffset);
406 };
407
408 // If the AT_name of any parent fails to match the expected name, we don't
409 // have a match.
410 for (auto [parent_name, parent_entry] :
411 llvm::zip_equal(t&: parent_names, u&: parent_entries))
412 if (!SameAsEntryATName(parent_name, parent_entry))
413 return false;
414 return true;
415}
416
417bool DebugNamesDWARFIndex::SameParentChain(
418 llvm::ArrayRef<CompilerContext> parent_contexts,
419 llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
420 if (parent_entries.size() != parent_contexts.size())
421 return false;
422
423 // If the AT_name of any parent fails to match the expected name, we don't
424 // have a match.
425 for (auto [parent_context, parent_entry] :
426 llvm::zip_equal(t&: parent_contexts, u&: parent_entries))
427 if (!SameAsEntryContext(query_context: parent_context, entry: parent_entry))
428 return false;
429 return true;
430}
431
432bool DebugNamesDWARFIndex::WithinParentChain(
433 llvm::ArrayRef<CompilerContext> query_contexts,
434 llvm::ArrayRef<DebugNames::Entry> parent_chain) const {
435 if (query_contexts.size() == parent_chain.size())
436 return SameParentChain(parent_contexts: query_contexts, parent_entries: parent_chain);
437
438 // If parent chain does not have enough entries, we can't possibly have a
439 // match.
440 while (!query_contexts.empty() &&
441 query_contexts.size() <= parent_chain.size()) {
442 if (SameAsEntryContext(query_context: query_contexts.front(), entry: parent_chain.front())) {
443 query_contexts = query_contexts.drop_front();
444 parent_chain = parent_chain.drop_front();
445 } else {
446 // Name does not match, try next parent_chain entry if the current entry
447 // is namespace because the current one can be an inline namespace.
448 if (parent_chain.front().tag() != DW_TAG_namespace)
449 return false;
450 parent_chain = parent_chain.drop_front();
451 }
452 }
453 return query_contexts.empty();
454}
455
456void DebugNamesDWARFIndex::GetTypes(
457 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
458 for (const DebugNames::Entry &entry :
459 m_debug_names_up->equal_range(Key: name.GetStringRef())) {
460 if (isType(T: entry.tag())) {
461 if (!ProcessEntry(entry, callback))
462 return;
463 }
464 }
465
466 m_fallback.GetTypes(name, callback);
467}
468
469void DebugNamesDWARFIndex::GetTypes(
470 const DWARFDeclContext &context,
471 llvm::function_ref<bool(DWARFDIE die)> callback) {
472 auto name = context[0].name;
473 for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(Key: name)) {
474 if (entry.tag() == context[0].tag) {
475 if (!ProcessEntry(entry, callback))
476 return;
477 }
478 }
479
480 m_fallback.GetTypes(context, callback);
481}
482
483void DebugNamesDWARFIndex::GetNamespaces(
484 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
485 for (const DebugNames::Entry &entry :
486 m_debug_names_up->equal_range(Key: name.GetStringRef())) {
487 lldb_private::dwarf::Tag entry_tag = entry.tag();
488 if (entry_tag == DW_TAG_namespace ||
489 entry_tag == DW_TAG_imported_declaration) {
490 if (!ProcessEntry(entry, callback))
491 return;
492 }
493 }
494
495 m_fallback.GetNamespaces(name, callback);
496}
497
498llvm::SmallVector<CompilerContext>
499DebugNamesDWARFIndex::GetTypeQueryParentContexts(TypeQuery &query) {
500 std::vector<lldb_private::CompilerContext> &query_decl_context =
501 query.GetContextRef();
502 llvm::SmallVector<CompilerContext> parent_contexts;
503 if (!query_decl_context.empty()) {
504 // Skip the last entry as it's the type we're matching parents for.
505 // Reverse the query decl context to match parent chain order.
506 llvm::ArrayRef<CompilerContext> parent_contexts_ref(
507 query_decl_context.data(), query_decl_context.size() - 1);
508 for (const CompilerContext &ctx : llvm::reverse(C&: parent_contexts_ref)) {
509 // Skip any context without name because .debug_names might not encode
510 // them. (e.g. annonymous namespace)
511 if ((ctx.kind & CompilerContextKind::AnyType) !=
512 CompilerContextKind::Invalid &&
513 !ctx.name.IsEmpty())
514 parent_contexts.push_back(Elt: ctx);
515 }
516 }
517 return parent_contexts;
518}
519
520void DebugNamesDWARFIndex::GetTypesWithQuery(
521 TypeQuery &query, llvm::function_ref<bool(DWARFDIE die)> callback) {
522 ConstString name = query.GetTypeBasename();
523 std::vector<lldb_private::CompilerContext> query_context =
524 query.GetContextRef();
525 if (query_context.size() <= 1 && !query.GetExactMatch())
526 return GetTypes(name, callback);
527
528 llvm::SmallVector<CompilerContext> parent_contexts =
529 GetTypeQueryParentContexts(query);
530 // For each entry, grab its parent chain and check if we have a match.
531 for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(Key: name)) {
532 if (!isType(T: entry.tag()))
533 continue;
534
535 // If we get a NULL foreign_tu back, the entry doesn't match the type unit
536 // in the .dwp file, or we were not able to load the .dwo file or the DWO ID
537 // didn't match.
538 std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
539 if (foreign_tu && foreign_tu.value() == nullptr)
540 continue;
541
542 std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
543 getParentChain(entry);
544 if (!parent_chain) {
545 // Fallback: use the base class implementation.
546 if (!ProcessEntry(entry, callback: [&](DWARFDIE die) {
547 return ProcessTypeDIEMatchQuery(query, die, callback);
548 }))
549 return;
550 continue;
551 }
552
553 if (WithinParentChain(query_contexts: parent_contexts, parent_chain: *parent_chain)) {
554 if (!ProcessEntry(entry, callback: [&](DWARFDIE die) {
555 // After .debug_names filtering still sending to base class for
556 // further filtering before calling the callback.
557 return ProcessTypeDIEMatchQuery(query, die, callback);
558 }))
559 // If the callback returns false, we're done.
560 return;
561 }
562 }
563 m_fallback.GetTypesWithQuery(query, callback);
564}
565
566void DebugNamesDWARFIndex::GetNamespacesWithParents(
567 ConstString name, const CompilerDeclContext &parent_decl_ctx,
568 llvm::function_ref<bool(DWARFDIE die)> callback) {
569 std::vector<lldb_private::CompilerContext> parent_contexts =
570 parent_decl_ctx.GetCompilerContext();
571 llvm::SmallVector<CompilerContext> parent_named_contexts;
572 std::copy_if(first: parent_contexts.rbegin(), last: parent_contexts.rend(),
573 result: std::back_inserter(x&: parent_named_contexts),
574 pred: [](const CompilerContext &ctx) { return !ctx.name.IsEmpty(); });
575 for (const DebugNames::Entry &entry :
576 m_debug_names_up->equal_range(Key: name.GetStringRef())) {
577 lldb_private::dwarf::Tag entry_tag = entry.tag();
578 if (entry_tag == DW_TAG_namespace ||
579 entry_tag == DW_TAG_imported_declaration) {
580 std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
581 getParentChain(entry);
582 if (!parent_chain) {
583 // Fallback: use the base class implementation.
584 if (!ProcessEntry(entry, callback: [&](DWARFDIE die) {
585 return ProcessNamespaceDieMatchParents(parent_decl_ctx, die,
586 callback);
587 }))
588 return;
589 continue;
590 }
591
592 if (WithinParentChain(query_contexts: parent_named_contexts, parent_chain: *parent_chain)) {
593 if (!ProcessEntry(entry, callback: [&](DWARFDIE die) {
594 // After .debug_names filtering still sending to base class for
595 // further filtering before calling the callback.
596 return ProcessNamespaceDieMatchParents(parent_decl_ctx, die,
597 callback);
598 }))
599 // If the callback returns false, we're done.
600 return;
601 }
602 }
603 }
604 m_fallback.GetNamespacesWithParents(name, parent_decl_ctx, callback);
605}
606
607void DebugNamesDWARFIndex::GetFunctions(
608 const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
609 const CompilerDeclContext &parent_decl_ctx,
610 llvm::function_ref<bool(DWARFDIE die)> callback) {
611 ConstString name = lookup_info.GetLookupName();
612 std::set<DWARFDebugInfoEntry *> seen;
613 for (const DebugNames::Entry &entry :
614 m_debug_names_up->equal_range(Key: name.GetStringRef())) {
615 Tag tag = entry.tag();
616 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
617 continue;
618
619 if (DWARFDIE die = GetDIE(entry)) {
620 if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx,
621 callback: [&](DWARFDIE die) {
622 if (!seen.insert(x: die.GetDIE()).second)
623 return true;
624 return callback(die);
625 }))
626 return;
627 }
628 }
629
630 m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
631}
632
633void DebugNamesDWARFIndex::GetFunctions(
634 const RegularExpression &regex,
635 llvm::function_ref<bool(DWARFDIE die)> callback) {
636 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
637 for (DebugNames::NameTableEntry nte: ni) {
638 if (!regex.Execute(string: nte.getString()))
639 continue;
640
641 uint64_t entry_offset = nte.getEntryOffset();
642 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(Offset: &entry_offset);
643 for (; entry_or; entry_or = ni.getEntry(Offset: &entry_offset)) {
644 Tag tag = entry_or->tag();
645 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
646 continue;
647
648 if (!ProcessEntry(entry: *entry_or, callback))
649 return;
650 }
651 MaybeLogLookupError(error: entry_or.takeError(), ni, name: nte.getString());
652 }
653 }
654
655 m_fallback.GetFunctions(regex, callback);
656}
657
658void DebugNamesDWARFIndex::Dump(Stream &s) {
659 m_fallback.Dump(s);
660
661 std::string data;
662 llvm::raw_string_ostream os(data);
663 m_debug_names_up->dump(OS&: os);
664 s.PutCString(cstr: data);
665}
666

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