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