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