brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.2 KiB · a5f83e1 Raw
319 lines · cpp
1//===-- AppleDWARFIndex.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/AppleDWARFIndex.h"10#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"11#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"12#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"13 14#include "lldb/Core/Module.h"15#include "lldb/Symbol/Function.h"16#include "lldb/lldb-private-enumerations.h"17#include "llvm/Support/DJB.h"18 19using namespace lldb;20using namespace lldb_private;21using namespace lldb_private::plugin::dwarf;22using namespace llvm::dwarf;23 24std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create(25    Module &module, DWARFDataExtractor apple_names,26    DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,27    DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) {28 29  llvm::DataExtractor llvm_debug_str = debug_str.GetAsLLVM();30 31  auto apple_names_table_up = std::make_unique<llvm::AppleAcceleratorTable>(32      apple_names.GetAsLLVMDWARF(), llvm_debug_str);33 34  auto apple_namespaces_table_up =35      std::make_unique<llvm::AppleAcceleratorTable>(36          apple_namespaces.GetAsLLVMDWARF(), llvm_debug_str);37 38  auto apple_types_table_up = std::make_unique<llvm::AppleAcceleratorTable>(39      apple_types.GetAsLLVMDWARF(), llvm_debug_str);40 41  auto apple_objc_table_up = std::make_unique<llvm::AppleAcceleratorTable>(42      apple_objc.GetAsLLVMDWARF(), llvm_debug_str);43 44  auto extract_and_check = [](auto &TablePtr) {45    if (auto E = TablePtr->extract()) {46      llvm::consumeError(std::move(E));47      TablePtr.reset();48    }49  };50 51  extract_and_check(apple_names_table_up);52  extract_and_check(apple_namespaces_table_up);53  extract_and_check(apple_types_table_up);54  extract_and_check(apple_objc_table_up);55  assert(apple_names.GetByteSize() == 0 || apple_names.GetSharedDataBuffer());56  assert(apple_namespaces.GetByteSize() == 0 ||57         apple_namespaces.GetSharedDataBuffer());58  assert(apple_types.GetByteSize() == 0 || apple_types.GetSharedDataBuffer());59  assert(apple_objc.GetByteSize() == 0 || apple_objc.GetSharedDataBuffer());60 61  if (apple_names_table_up || apple_namespaces_table_up ||62      apple_types_table_up || apple_objc_table_up)63    return std::make_unique<AppleDWARFIndex>(64        module, std::move(apple_names_table_up),65        std::move(apple_namespaces_table_up), std::move(apple_types_table_up),66        std::move(apple_objc_table_up), apple_names.GetSharedDataBuffer(),67        apple_namespaces.GetSharedDataBuffer(),68        apple_types.GetSharedDataBuffer(), apple_objc.GetSharedDataBuffer());69 70  return nullptr;71}72 73/// Returns true if `tag` is a class_type of structure_type tag.74static bool IsClassOrStruct(dw_tag_t tag) {75  return tag == DW_TAG_class_type || tag == DW_TAG_structure_type;76}77 78/// Returns true if `entry` has an extractable DW_ATOM_qual_name_hash and it79/// matches `expected_hash`.80static bool81EntryHasMatchingQualhash(const llvm::AppleAcceleratorTable::Entry &entry,82                         uint32_t expected_hash) {83  std::optional<llvm::DWARFFormValue> form_value =84      entry.lookup(llvm::dwarf::DW_ATOM_qual_name_hash);85  if (!form_value)86    return false;87  std::optional<uint64_t> hash = form_value->getAsUnsignedConstant();88  return hash && (*hash == expected_hash);89}90 91/// Returns true if `entry` has an extractable DW_ATOM_die_tag and it matches92/// `expected_tag`. We also consider it a match if the tags are different but93/// in the set of {TAG_class_type, TAG_struct_type}.94static bool EntryHasMatchingTag(const llvm::AppleAcceleratorTable::Entry &entry,95                                dw_tag_t expected_tag) {96  std::optional<llvm::DWARFFormValue> form_value =97      entry.lookup(llvm::dwarf::DW_ATOM_die_tag);98  if (!form_value)99    return false;100  std::optional<uint64_t> maybe_tag = form_value->getAsUnsignedConstant();101  if (!maybe_tag)102    return false;103  auto tag = static_cast<dw_tag_t>(*maybe_tag);104  return tag == expected_tag ||105         (IsClassOrStruct(tag) && IsClassOrStruct(expected_tag));106}107 108/// Returns true if `entry` has an extractable DW_ATOM_type_flags and the flag109/// "DW_FLAG_type_implementation" is set.110static bool111HasImplementationFlag(const llvm::AppleAcceleratorTable::Entry &entry) {112  std::optional<llvm::DWARFFormValue> form_value =113      entry.lookup(llvm::dwarf::DW_ATOM_type_flags);114  if (!form_value)115    return false;116  std::optional<uint64_t> Flags = form_value->getAsUnsignedConstant();117  return Flags &&118         (*Flags & llvm::dwarf::AcceleratorTable::DW_FLAG_type_implementation);119}120 121void AppleDWARFIndex::SearchFor(122    const llvm::AppleAcceleratorTable &table, llvm::StringRef name,123    llvm::function_ref<IterationAction(DWARFDIE die)> callback,124    std::optional<dw_tag_t> search_for_tag,125    std::optional<uint32_t> search_for_qualhash) {126  auto converted_cb = DIERefCallback(callback, name);127  for (const auto &entry : table.equal_range(name)) {128    if (search_for_qualhash &&129        !EntryHasMatchingQualhash(entry, *search_for_qualhash))130      continue;131    if (search_for_tag && !EntryHasMatchingTag(entry, *search_for_tag))132      continue;133    if (converted_cb(entry) == IterationAction::Stop)134      break;135  }136}137 138void AppleDWARFIndex::GetGlobalVariables(139    ConstString basename,140    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {141  if (!m_apple_names_up)142    return;143  SearchFor(*m_apple_names_up, basename, callback);144}145 146void AppleDWARFIndex::GetGlobalVariables(147    const RegularExpression &regex,148    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {149  if (!m_apple_names_up)150    return;151 152  DIERefCallbackImpl converted_cb = DIERefCallback(callback, regex.GetText());153 154  for (const auto &entry : m_apple_names_up->entries())155    if (std::optional<llvm::StringRef> name = entry.readName();156        name && Mangled(*name).NameMatches(regex))157      if (converted_cb(entry.BaseEntry) == IterationAction::Stop)158        return;159}160 161void AppleDWARFIndex::GetGlobalVariables(162    DWARFUnit &cu, llvm::function_ref<IterationAction(DWARFDIE die)> callback) {163  if (!m_apple_names_up)164    return;165 166  const DWARFUnit &non_skeleton_cu = cu.GetNonSkeletonUnit();167  dw_offset_t lower_bound = non_skeleton_cu.GetOffset();168  dw_offset_t upper_bound = non_skeleton_cu.GetNextUnitOffset();169  auto is_in_range = [lower_bound, upper_bound](std::optional<uint32_t> val) {170    return val.has_value() && *val >= lower_bound && *val < upper_bound;171  };172 173  DIERefCallbackImpl converted_cb = DIERefCallback(callback);174  for (auto entry : m_apple_names_up->entries()) {175    if (is_in_range(entry.BaseEntry.getDIESectionOffset()))176      if (converted_cb(entry.BaseEntry) == IterationAction::Stop)177        return;178  }179}180 181void AppleDWARFIndex::GetObjCMethods(182    ConstString class_name,183    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {184  if (!m_apple_objc_up)185    return;186  SearchFor(*m_apple_objc_up, class_name, callback);187}188 189void AppleDWARFIndex::GetCompleteObjCClass(190    ConstString class_name, bool must_be_implementation,191    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {192  if (!m_apple_types_up)193    return;194 195  llvm::SmallVector<DIERef> decl_dies;196  auto converted_cb = DIERefCallback(callback, class_name);197 198  for (const auto &entry : m_apple_types_up->equal_range(class_name)) {199    if (HasImplementationFlag(entry)) {200      converted_cb(entry);201      return;202    }203 204    decl_dies.emplace_back(std::nullopt, DIERef::Section::DebugInfo,205                           *entry.getDIESectionOffset());206  }207 208  if (must_be_implementation)209    return;210  for (DIERef ref : decl_dies)211    if (converted_cb(ref) == IterationAction::Stop)212      return;213}214 215void AppleDWARFIndex::GetTypes(216    ConstString name,217    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {218  if (!m_apple_types_up)219    return;220  SearchFor(*m_apple_types_up, name, callback);221}222 223void AppleDWARFIndex::GetTypes(224    const DWARFDeclContext &context,225    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {226  if (!m_apple_types_up)227    return;228 229  Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);230  const bool entries_have_tag =231      m_apple_types_up->containsAtomType(DW_ATOM_die_tag);232  const bool entries_have_qual_hash =233      m_apple_types_up->containsAtomType(DW_ATOM_qual_name_hash);234 235  llvm::StringRef expected_name = context[0].name;236 237  if (entries_have_tag && entries_have_qual_hash) {238    const dw_tag_t expected_tag = context[0].tag;239    const uint32_t expected_qualname_hash =240        llvm::djbHash(context.GetQualifiedName());241    if (log)242      m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");243    SearchFor(*m_apple_types_up, expected_name, callback, expected_tag,244              expected_qualname_hash);245    return;246  }247 248  // Historically, if there are no tags, we also ignore qual_hash (why?)249  if (!entries_have_tag) {250    SearchFor(*m_apple_names_up, expected_name, callback);251    return;252  }253 254  // We have a tag but no qual hash.255 256  // When searching for a scoped type (for example,257  // "std::vector<int>::const_iterator") searching for the innermost258  // name alone ("const_iterator") could yield many false259  // positives. By searching for the parent type ("vector<int>")260  // first we can avoid extracting type DIEs from object files that261  // would fail the filter anyway.262  if ((context.GetSize() > 1) && IsClassOrStruct(context[1].tag))263    if (m_apple_types_up->equal_range(context[1].name).empty())264      return;265 266  if (log)267    m_module.LogMessage(log, "FindByNameAndTag()");268  const dw_tag_t expected_tag = context[0].tag;269  SearchFor(*m_apple_types_up, expected_name, callback, expected_tag);270}271 272void AppleDWARFIndex::GetNamespaces(273    ConstString name,274    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {275  if (!m_apple_namespaces_up)276    return;277  SearchFor(*m_apple_namespaces_up, name, callback);278}279 280void AppleDWARFIndex::GetFunctions(281    const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,282    const CompilerDeclContext &parent_decl_ctx,283    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {284  if (!m_apple_names_up)285    return;286 287  ConstString name = lookup_info.GetLookupName();288  for (const auto &entry : m_apple_names_up->equal_range(name)) {289    DIERef die_ref(std::nullopt, DIERef::Section::DebugInfo,290                   *entry.getDIESectionOffset());291    DWARFDIE die = dwarf.GetDIE(die_ref);292    if (!die) {293      ReportInvalidDIERef(die_ref, name);294      continue;295    }296    if (ProcessFunctionDIE(lookup_info, die, parent_decl_ctx, callback) ==297        IterationAction::Stop)298      return;299  }300}301 302void AppleDWARFIndex::GetFunctions(303    const RegularExpression &regex,304    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {305  return GetGlobalVariables(regex, callback);306}307 308void AppleDWARFIndex::Dump(Stream &s) {309  if (m_apple_names_up)310    s.PutCString(".apple_names index present\n");311  if (m_apple_namespaces_up)312    s.PutCString(".apple_namespaces index present\n");313  if (m_apple_types_up)314    s.PutCString(".apple_types index present\n");315  if (m_apple_objc_up)316    s.PutCString(".apple_objc index present\n");317  // TODO: Dump index contents318}319