//===-- DWARFIndex.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Plugins/SymbolFile/DWARF/DWARFIndex.h" #include "DWARFDebugInfoEntry.h" #include "DWARFDeclContext.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "Plugins/SymbolFile/DWARF/DWARFDIE.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "lldb/Core/Mangled.h" #include "lldb/Core/Module.h" #include "lldb/Target/Language.h" #include "lldb/lldb-private-enumerations.h" using namespace lldb_private; using namespace lldb; using namespace lldb_private::plugin::dwarf; DWARFIndex::~DWARFIndex() = default; IterationAction DWARFIndex::ProcessFunctionDIE( const Module::LookupInfo &lookup_info, DWARFDIE die, const CompilerDeclContext &parent_decl_ctx, llvm::function_ref callback) { llvm::StringRef name = lookup_info.GetLookupName().GetStringRef(); FunctionNameType name_type_mask = lookup_info.GetNameTypeMask(); if (!(name_type_mask & eFunctionNameTypeFull)) { ConstString name_to_match_against; if (const char *mangled_die_name = die.GetMangledName()) { name_to_match_against = ConstString(mangled_die_name); } else { SymbolFileDWARF *symbols = die.GetDWARF(); if (ConstString demangled_die_name = symbols->ConstructFunctionDemangledName(die)) name_to_match_against = demangled_die_name; } if (!lookup_info.NameMatchesLookupInfo(name_to_match_against, lookup_info.GetLanguageType())) return IterationAction::Continue; } // Exit early if we're searching exclusively for methods or selectors and // we have a context specified (no methods in namespaces). uint32_t looking_for_nonmethods = name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector); if (!looking_for_nonmethods && parent_decl_ctx.IsValid()) return IterationAction::Continue; // Otherwise, we need to also check that the context matches. If it does not // match, we do nothing. if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) return IterationAction::Continue; // In case of a full match, we just insert everything we find. if (name_type_mask & eFunctionNameTypeFull && die.GetMangledName() == name) return callback(die); // If looking for ObjC selectors, we need to also check if the name is a // possible selector. if (name_type_mask & eFunctionNameTypeSelector && ObjCLanguage::IsPossibleObjCMethodName(die.GetName())) return callback(die); bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod; bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase; if (looking_for_methods || looking_for_functions) { // If we're looking for either methods or functions, we definitely want this // die. Otherwise, only keep it if the die type matches what we are // searching for. if ((looking_for_methods && looking_for_functions) || looking_for_methods == die.IsMethod()) return callback(die); } return IterationAction::Continue; } DWARFIndex::DIERefCallbackImpl::DIERefCallbackImpl( const DWARFIndex &index, llvm::function_ref callback, llvm::StringRef name) : m_index(index), m_dwarf(*llvm::cast( index.m_module.GetSymbolFile()->GetBackingSymbolFile())), m_callback(callback), m_name(name) {} IterationAction DWARFIndex::DIERefCallbackImpl::operator()(DIERef ref) const { if (DWARFDIE die = m_dwarf.GetDIE(ref)) return m_callback(die); m_index.ReportInvalidDIERef(ref, m_name); return IterationAction::Continue; } IterationAction DWARFIndex::DIERefCallbackImpl::operator()( const llvm::AppleAcceleratorTable::Entry &entry) const { return this->operator()(DIERef(std::nullopt, DIERef::Section::DebugInfo, *entry.getDIESectionOffset())); } void DWARFIndex::ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const { m_module.ReportErrorIfModifyDetected( "the DWARF debug information has been modified (accelerator table had " "bad die {0:x16} for '{1}')\n", ref.die_offset(), name.str().c_str()); } void DWARFIndex::GetFullyQualifiedType( const DWARFDeclContext &context, llvm::function_ref callback) { GetTypes(context, [&](DWARFDIE die) { return GetFullyQualifiedTypeImpl(context, die, callback); }); } IterationAction DWARFIndex::GetFullyQualifiedTypeImpl( const DWARFDeclContext &context, DWARFDIE die, llvm::function_ref callback) { DWARFDeclContext dwarf_decl_ctx = die.GetDWARFDeclContext(); if (dwarf_decl_ctx == context) return callback(die); return IterationAction::Continue; } void DWARFIndex::GetTypesWithQuery( TypeQuery &query, llvm::function_ref callback) { GetTypes(query.GetTypeBasename(), [&](DWARFDIE die) { return ProcessTypeDIEMatchQuery(query, die, callback); }); } IterationAction DWARFIndex::ProcessTypeDIEMatchQuery( TypeQuery &query, DWARFDIE die, llvm::function_ref callback) { // Check the language, but only if we have a language filter. if (query.HasLanguage() && !query.LanguageMatches(SymbolFileDWARF::GetLanguageFamily(*die.GetCU()))) return IterationAction::Continue; // Since mangled names are unique, we only need to check if the names are // the same. if (query.GetSearchByMangledName()) { if (die.GetMangledName(/*substitute_name_allowed=*/false) != query.GetTypeBasename().GetStringRef()) return IterationAction::Continue; return callback(die); } std::vector die_context; if (query.GetModuleSearch()) die_context = die.GetDeclContext(); else die_context = die.GetTypeLookupContext(); if (!query.ContextMatches(die_context)) return IterationAction::Continue; return callback(die); } void DWARFIndex::GetNamespacesWithParents( ConstString name, const CompilerDeclContext &parent_decl_ctx, llvm::function_ref callback) { GetNamespaces(name, [&](DWARFDIE die) { return ProcessNamespaceDieMatchParents(parent_decl_ctx, die, callback); }); } void DWARFIndex::GetFunctions( const std::vector &lookup_infos, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, llvm::function_ref callback) { for (auto &lookup_info : lookup_infos) GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback); } IterationAction DWARFIndex::ProcessNamespaceDieMatchParents( const CompilerDeclContext &parent_decl_ctx, DWARFDIE die, llvm::function_ref callback) { if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) return IterationAction::Continue; return callback(die); }