Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
39645 views
//===-- AppleDWARFIndex.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h"9#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"10#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"11#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"1213#include "lldb/Core/Module.h"14#include "lldb/Symbol/Function.h"15#include "llvm/Support/DJB.h"1617using namespace lldb_private;18using namespace lldb;19using namespace lldb_private::dwarf;20using namespace lldb_private::plugin::dwarf;2122std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create(23Module &module, DWARFDataExtractor apple_names,24DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,25DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) {2627llvm::DataExtractor llvm_debug_str = debug_str.GetAsLLVM();2829auto apple_names_table_up = std::make_unique<llvm::AppleAcceleratorTable>(30apple_names.GetAsLLVMDWARF(), llvm_debug_str);3132auto apple_namespaces_table_up =33std::make_unique<llvm::AppleAcceleratorTable>(34apple_namespaces.GetAsLLVMDWARF(), llvm_debug_str);3536auto apple_types_table_up = std::make_unique<llvm::AppleAcceleratorTable>(37apple_types.GetAsLLVMDWARF(), llvm_debug_str);3839auto apple_objc_table_up = std::make_unique<llvm::AppleAcceleratorTable>(40apple_objc.GetAsLLVMDWARF(), llvm_debug_str);4142auto extract_and_check = [](auto &TablePtr) {43if (auto E = TablePtr->extract()) {44llvm::consumeError(std::move(E));45TablePtr.reset();46}47};4849extract_and_check(apple_names_table_up);50extract_and_check(apple_namespaces_table_up);51extract_and_check(apple_types_table_up);52extract_and_check(apple_objc_table_up);53assert(apple_names.GetByteSize() == 0 || apple_names.GetSharedDataBuffer());54assert(apple_namespaces.GetByteSize() == 0 ||55apple_namespaces.GetSharedDataBuffer());56assert(apple_types.GetByteSize() == 0 || apple_types.GetSharedDataBuffer());57assert(apple_objc.GetByteSize() == 0 || apple_objc.GetSharedDataBuffer());5859if (apple_names_table_up || apple_namespaces_table_up ||60apple_types_table_up || apple_objc_table_up)61return std::make_unique<AppleDWARFIndex>(62module, std::move(apple_names_table_up),63std::move(apple_namespaces_table_up), std::move(apple_types_table_up),64std::move(apple_objc_table_up), apple_names.GetSharedDataBuffer(),65apple_namespaces.GetSharedDataBuffer(),66apple_types.GetSharedDataBuffer(), apple_objc.GetSharedDataBuffer());6768return nullptr;69}7071/// Returns true if `tag` is a class_type of structure_type tag.72static bool IsClassOrStruct(dw_tag_t tag) {73return tag == DW_TAG_class_type || tag == DW_TAG_structure_type;74}7576/// Returns true if `entry` has an extractable DW_ATOM_qual_name_hash and it77/// matches `expected_hash`.78static bool79EntryHasMatchingQualhash(const llvm::AppleAcceleratorTable::Entry &entry,80uint32_t expected_hash) {81std::optional<llvm::DWARFFormValue> form_value =82entry.lookup(dwarf::DW_ATOM_qual_name_hash);83if (!form_value)84return false;85std::optional<uint64_t> hash = form_value->getAsUnsignedConstant();86return hash && (*hash == expected_hash);87}8889/// Returns true if `entry` has an extractable DW_ATOM_die_tag and it matches90/// `expected_tag`. We also consider it a match if the tags are different but91/// in the set of {TAG_class_type, TAG_struct_type}.92static bool EntryHasMatchingTag(const llvm::AppleAcceleratorTable::Entry &entry,93dw_tag_t expected_tag) {94std::optional<llvm::DWARFFormValue> form_value =95entry.lookup(dwarf::DW_ATOM_die_tag);96if (!form_value)97return false;98std::optional<uint64_t> maybe_tag = form_value->getAsUnsignedConstant();99if (!maybe_tag)100return false;101auto tag = static_cast<dw_tag_t>(*maybe_tag);102return tag == expected_tag ||103(IsClassOrStruct(tag) && IsClassOrStruct(expected_tag));104}105106/// Returns true if `entry` has an extractable DW_ATOM_type_flags and the flag107/// "DW_FLAG_type_implementation" is set.108static bool109HasImplementationFlag(const llvm::AppleAcceleratorTable::Entry &entry) {110std::optional<llvm::DWARFFormValue> form_value =111entry.lookup(dwarf::DW_ATOM_type_flags);112if (!form_value)113return false;114std::optional<uint64_t> Flags = form_value->getAsUnsignedConstant();115return Flags &&116(*Flags & llvm::dwarf::AcceleratorTable::DW_FLAG_type_implementation);117}118119void AppleDWARFIndex::SearchFor(const llvm::AppleAcceleratorTable &table,120llvm::StringRef name,121llvm::function_ref<bool(DWARFDIE die)> callback,122std::optional<dw_tag_t> search_for_tag,123std::optional<uint32_t> search_for_qualhash) {124auto converted_cb = DIERefCallback(callback, name);125for (const auto &entry : table.equal_range(name)) {126if (search_for_qualhash &&127!EntryHasMatchingQualhash(entry, *search_for_qualhash))128continue;129if (search_for_tag && !EntryHasMatchingTag(entry, *search_for_tag))130continue;131if (!converted_cb(entry))132break;133}134}135136void AppleDWARFIndex::GetGlobalVariables(137ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {138if (!m_apple_names_up)139return;140SearchFor(*m_apple_names_up, basename, callback);141}142143void AppleDWARFIndex::GetGlobalVariables(144const RegularExpression ®ex,145llvm::function_ref<bool(DWARFDIE die)> callback) {146if (!m_apple_names_up)147return;148149DIERefCallbackImpl converted_cb = DIERefCallback(callback, regex.GetText());150151for (const auto &entry : m_apple_names_up->entries())152if (std::optional<llvm::StringRef> name = entry.readName();153name && Mangled(*name).NameMatches(regex))154if (!converted_cb(entry.BaseEntry))155return;156}157158void AppleDWARFIndex::GetGlobalVariables(159DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {160if (!m_apple_names_up)161return;162163const DWARFUnit &non_skeleton_cu = cu.GetNonSkeletonUnit();164dw_offset_t lower_bound = non_skeleton_cu.GetOffset();165dw_offset_t upper_bound = non_skeleton_cu.GetNextUnitOffset();166auto is_in_range = [lower_bound, upper_bound](std::optional<uint32_t> val) {167return val.has_value() && *val >= lower_bound && *val < upper_bound;168};169170DIERefCallbackImpl converted_cb = DIERefCallback(callback);171for (auto entry : m_apple_names_up->entries()) {172if (is_in_range(entry.BaseEntry.getDIESectionOffset()))173if (!converted_cb(entry.BaseEntry))174return;175}176}177178void AppleDWARFIndex::GetObjCMethods(179ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) {180if (!m_apple_objc_up)181return;182SearchFor(*m_apple_objc_up, class_name, callback);183}184185void AppleDWARFIndex::GetCompleteObjCClass(186ConstString class_name, bool must_be_implementation,187llvm::function_ref<bool(DWARFDIE die)> callback) {188if (!m_apple_types_up)189return;190191llvm::SmallVector<DIERef> decl_dies;192auto converted_cb = DIERefCallback(callback, class_name);193194for (const auto &entry : m_apple_types_up->equal_range(class_name)) {195if (HasImplementationFlag(entry)) {196converted_cb(entry);197return;198}199200decl_dies.emplace_back(std::nullopt, DIERef::Section::DebugInfo,201*entry.getDIESectionOffset());202}203204if (must_be_implementation)205return;206for (DIERef ref : decl_dies)207if (!converted_cb(ref))208return;209}210211void AppleDWARFIndex::GetTypes(212ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {213if (!m_apple_types_up)214return;215SearchFor(*m_apple_types_up, name, callback);216}217218void AppleDWARFIndex::GetTypes(219const DWARFDeclContext &context,220llvm::function_ref<bool(DWARFDIE die)> callback) {221if (!m_apple_types_up)222return;223224Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);225const bool entries_have_tag =226m_apple_types_up->containsAtomType(DW_ATOM_die_tag);227const bool entries_have_qual_hash =228m_apple_types_up->containsAtomType(DW_ATOM_qual_name_hash);229230llvm::StringRef expected_name = context[0].name;231232if (entries_have_tag && entries_have_qual_hash) {233const dw_tag_t expected_tag = context[0].tag;234const uint32_t expected_qualname_hash =235llvm::djbHash(context.GetQualifiedName());236if (log)237m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");238SearchFor(*m_apple_types_up, expected_name, callback, expected_tag,239expected_qualname_hash);240return;241}242243// Historically, if there are no tags, we also ignore qual_hash (why?)244if (!entries_have_tag) {245SearchFor(*m_apple_names_up, expected_name, callback);246return;247}248249// We have a tag but no qual hash.250251// When searching for a scoped type (for example,252// "std::vector<int>::const_iterator") searching for the innermost253// name alone ("const_iterator") could yield many false254// positives. By searching for the parent type ("vector<int>")255// first we can avoid extracting type DIEs from object files that256// would fail the filter anyway.257if ((context.GetSize() > 1) && IsClassOrStruct(context[1].tag))258if (m_apple_types_up->equal_range(context[1].name).empty())259return;260261if (log)262m_module.LogMessage(log, "FindByNameAndTag()");263const dw_tag_t expected_tag = context[0].tag;264SearchFor(*m_apple_types_up, expected_name, callback, expected_tag);265return;266}267268void AppleDWARFIndex::GetNamespaces(269ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {270if (!m_apple_namespaces_up)271return;272SearchFor(*m_apple_namespaces_up, name, callback);273}274275void AppleDWARFIndex::GetFunctions(276const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,277const CompilerDeclContext &parent_decl_ctx,278llvm::function_ref<bool(DWARFDIE die)> callback) {279if (!m_apple_names_up)280return;281282ConstString name = lookup_info.GetLookupName();283for (const auto &entry : m_apple_names_up->equal_range(name)) {284DIERef die_ref(std::nullopt, DIERef::Section::DebugInfo,285*entry.getDIESectionOffset());286DWARFDIE die = dwarf.GetDIE(die_ref);287if (!die) {288ReportInvalidDIERef(die_ref, name);289continue;290}291if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx, callback))292return;293}294}295296void AppleDWARFIndex::GetFunctions(297const RegularExpression ®ex,298llvm::function_ref<bool(DWARFDIE die)> callback) {299return GetGlobalVariables(regex, callback);300}301302void AppleDWARFIndex::Dump(Stream &s) {303if (m_apple_names_up)304s.PutCString(".apple_names index present\n");305if (m_apple_namespaces_up)306s.PutCString(".apple_namespaces index present\n");307if (m_apple_types_up)308s.PutCString(".apple_types index present\n");309if (m_apple_objc_up)310s.PutCString(".apple_objc index present\n");311// TODO: Dump index contents312}313314315