1//===-- DWARFIndex.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/DWARFIndex.h"
10#include "Plugins/Language/ObjC/ObjCLanguage.h"
11#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
12#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
13
14#include "lldb/Core/Mangled.h"
15#include "lldb/Core/Module.h"
16#include "lldb/Target/Language.h"
17
18using namespace lldb_private;
19using namespace lldb;
20
21DWARFIndex::~DWARFIndex() = default;
22
23bool DWARFIndex::ProcessFunctionDIE(
24    const Module::LookupInfo &lookup_info, DIERef ref, SymbolFileDWARF &dwarf,
25    const CompilerDeclContext &parent_decl_ctx,
26    llvm::function_ref<bool(DWARFDIE die)> callback) {
27  llvm::StringRef name = lookup_info.GetLookupName().GetStringRef();
28  FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();
29  DWARFDIE die = dwarf.GetDIE(ref);
30  if (!die) {
31    ReportInvalidDIERef(ref, name);
32    return true;
33  }
34
35  if (!(name_type_mask & eFunctionNameTypeFull)) {
36    ConstString name_to_match_against;
37    if (const char *mangled_die_name = die.GetMangledName()) {
38      name_to_match_against = ConstString(mangled_die_name);
39    } else {
40      SymbolFileDWARF *symbols = die.GetDWARF();
41      if (ConstString demangled_die_name =
42              symbols->ConstructFunctionDemangledName(die))
43        name_to_match_against = demangled_die_name;
44    }
45
46    if (!lookup_info.NameMatchesLookupInfo(name_to_match_against,
47                                           lookup_info.GetLanguageType()))
48      return true;
49  }
50
51  // Exit early if we're searching exclusively for methods or selectors and
52  // we have a context specified (no methods in namespaces).
53  uint32_t looking_for_nonmethods =
54      name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector);
55  if (!looking_for_nonmethods && parent_decl_ctx.IsValid())
56    return true;
57
58  // Otherwise, we need to also check that the context matches. If it does not
59  // match, we do nothing.
60  if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
61    return true;
62
63  // In case of a full match, we just insert everything we find.
64  if (name_type_mask & eFunctionNameTypeFull && die.GetMangledName() == name)
65    return callback(die);
66
67  // If looking for ObjC selectors, we need to also check if the name is a
68  // possible selector.
69  if (name_type_mask & eFunctionNameTypeSelector &&
70      ObjCLanguage::IsPossibleObjCMethodName(die.GetName()))
71    return callback(die);
72
73  bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod;
74  bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase;
75  if (looking_for_methods || looking_for_functions) {
76    // If we're looking for either methods or functions, we definitely want this
77    // die. Otherwise, only keep it if the die type matches what we are
78    // searching for.
79    if ((looking_for_methods && looking_for_functions) ||
80        looking_for_methods == die.IsMethod())
81      return callback(die);
82  }
83
84  return true;
85}
86
87DWARFIndex::DIERefCallbackImpl::DIERefCallbackImpl(
88    const DWARFIndex &index, llvm::function_ref<bool(DWARFDIE die)> callback,
89    llvm::StringRef name)
90    : m_index(index),
91      m_dwarf(*llvm::cast<SymbolFileDWARF>(
92          index.m_module.GetSymbolFile()->GetBackingSymbolFile())),
93      m_callback(callback), m_name(name) {}
94
95bool DWARFIndex::DIERefCallbackImpl::operator()(DIERef ref) const {
96  if (DWARFDIE die = m_dwarf.GetDIE(ref))
97    return m_callback(die);
98  m_index.ReportInvalidDIERef(ref, m_name);
99  return true;
100}
101
102void DWARFIndex::ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const {
103  m_module.ReportErrorIfModifyDetected(
104      "the DWARF debug information has been modified (accelerator table had "
105      "bad die {0:x16} for '{1}')\n",
106      ref.die_offset(), name.str().c_str());
107}
108