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-exception
6 //
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 
17 using namespace lldb_private;
18 using namespace lldb;
19 using namespace lldb_private::dwarf;
20 
21 std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create(
22     Module &module, DWARFDataExtractor apple_names,
23     DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,
24     DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) {
25   auto apple_names_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
26       apple_names, debug_str, ".apple_names");
27   if (!apple_names_table_up->IsValid())
28     apple_names_table_up.reset();
29 
30   auto apple_namespaces_table_up =
31       std::make_unique<DWARFMappedHash::MemoryTable>(
32           apple_namespaces, debug_str, ".apple_namespaces");
33   if (!apple_namespaces_table_up->IsValid())
34     apple_namespaces_table_up.reset();
35 
36   auto apple_types_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
37       apple_types, debug_str, ".apple_types");
38   if (!apple_types_table_up->IsValid())
39     apple_types_table_up.reset();
40 
41   auto apple_objc_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
42       apple_objc, debug_str, ".apple_objc");
43   if (!apple_objc_table_up->IsValid())
44     apple_objc_table_up.reset();
45 
46   if (apple_names_table_up || apple_namespaces_table_up ||
47       apple_types_table_up || apple_objc_table_up)
48     return std::make_unique<AppleDWARFIndex>(
49         module, std::move(apple_names_table_up),
50         std::move(apple_namespaces_table_up), std::move(apple_types_table_up),
51         std::move(apple_objc_table_up));
52 
53   return nullptr;
54 }
55 
56 void AppleDWARFIndex::GetGlobalVariables(
57     ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
58   if (!m_apple_names_up)
59     return;
60   m_apple_names_up->FindByName(
61       basename.GetStringRef(),
62       DIERefCallback(callback, basename.GetStringRef()));
63 }
64 
65 void AppleDWARFIndex::GetGlobalVariables(
66     const RegularExpression &regex,
67     llvm::function_ref<bool(DWARFDIE die)> callback) {
68   if (!m_apple_names_up)
69     return;
70 
71   DWARFMappedHash::DIEInfoArray hash_data;
72   m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data);
73   // This is not really the DIE name.
74   DWARFMappedHash::ExtractDIEArray(hash_data,
75                                    DIERefCallback(callback, regex.GetText()));
76 }
77 
78 void AppleDWARFIndex::GetGlobalVariables(
79     DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
80   if (!m_apple_names_up)
81     return;
82 
83   lldbassert(!cu.GetSymbolFileDWARF().GetDwoNum());
84   const DWARFUnit &non_skeleton_cu = cu.GetNonSkeletonUnit();
85   DWARFMappedHash::DIEInfoArray hash_data;
86   m_apple_names_up->AppendAllDIEsInRange(non_skeleton_cu.GetOffset(),
87                                          non_skeleton_cu.GetNextUnitOffset(),
88                                          hash_data);
89   DWARFMappedHash::ExtractDIEArray(hash_data, DIERefCallback(callback));
90 }
91 
92 void AppleDWARFIndex::GetObjCMethods(
93     ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) {
94   if (!m_apple_objc_up)
95     return;
96   m_apple_objc_up->FindByName(
97       class_name.GetStringRef(),
98       DIERefCallback(callback, class_name.GetStringRef()));
99 }
100 
101 void AppleDWARFIndex::GetCompleteObjCClass(
102     ConstString class_name, bool must_be_implementation,
103     llvm::function_ref<bool(DWARFDIE die)> callback) {
104   if (!m_apple_types_up)
105     return;
106   m_apple_types_up->FindCompleteObjCClassByName(
107       class_name.GetStringRef(),
108       DIERefCallback(callback, class_name.GetStringRef()),
109       must_be_implementation);
110 }
111 
112 void AppleDWARFIndex::GetTypes(
113     ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
114   if (!m_apple_types_up)
115     return;
116   m_apple_types_up->FindByName(name.GetStringRef(),
117                                DIERefCallback(callback, name.GetStringRef()));
118 }
119 
120 void AppleDWARFIndex::GetTypes(
121     const DWARFDeclContext &context,
122     llvm::function_ref<bool(DWARFDIE die)> callback) {
123   if (!m_apple_types_up)
124     return;
125 
126   Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
127   const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom(
128       DWARFMappedHash::eAtomTypeTag);
129   const bool has_qualified_name_hash =
130       m_apple_types_up->GetHeader().header_data.ContainsAtom(
131           DWARFMappedHash::eAtomTypeQualNameHash);
132 
133   const ConstString type_name(context[0].name);
134   const dw_tag_t tag = context[0].tag;
135   if (has_tag && has_qualified_name_hash) {
136     const char *qualified_name = context.GetQualifiedName();
137     const uint32_t qualified_name_hash = llvm::djbHash(qualified_name);
138     if (log)
139       m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
140     m_apple_types_up->FindByNameAndTagAndQualifiedNameHash(
141         type_name.GetStringRef(), tag, qualified_name_hash,
142         DIERefCallback(callback, type_name.GetStringRef()));
143     return;
144   }
145 
146   if (has_tag) {
147     // When searching for a scoped type (for example,
148     // "std::vector<int>::const_iterator") searching for the innermost
149     // name alone ("const_iterator") could yield many false
150     // positives. By searching for the parent type ("vector<int>")
151     // first we can avoid extracting type DIEs from object files that
152     // would fail the filter anyway.
153     if (!has_qualified_name_hash && (context.GetSize() > 1) &&
154         (context[1].tag == DW_TAG_class_type ||
155          context[1].tag == DW_TAG_structure_type)) {
156       if (m_apple_types_up->FindByName(context[1].name,
157                                        [&](DIERef ref) { return false; }))
158         return;
159     }
160 
161     if (log)
162       m_module.LogMessage(log, "FindByNameAndTag()");
163     m_apple_types_up->FindByNameAndTag(
164         type_name.GetStringRef(), tag,
165         DIERefCallback(callback, type_name.GetStringRef()));
166     return;
167   }
168 
169   m_apple_types_up->FindByName(
170       type_name.GetStringRef(),
171       DIERefCallback(callback, type_name.GetStringRef()));
172 }
173 
174 void AppleDWARFIndex::GetNamespaces(
175     ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
176   if (!m_apple_namespaces_up)
177     return;
178   m_apple_namespaces_up->FindByName(
179       name.GetStringRef(), DIERefCallback(callback, name.GetStringRef()));
180 }
181 
182 void AppleDWARFIndex::GetFunctions(
183     const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
184     const CompilerDeclContext &parent_decl_ctx,
185     llvm::function_ref<bool(DWARFDIE die)> callback) {
186   ConstString name = lookup_info.GetLookupName();
187   m_apple_names_up->FindByName(name.GetStringRef(), [&](DIERef die_ref) {
188     return ProcessFunctionDIE(lookup_info, die_ref, dwarf, parent_decl_ctx,
189                               callback);
190   });
191 }
192 
193 void AppleDWARFIndex::GetFunctions(
194     const RegularExpression &regex,
195     llvm::function_ref<bool(DWARFDIE die)> callback) {
196   if (!m_apple_names_up)
197     return;
198 
199   DWARFMappedHash::DIEInfoArray hash_data;
200   m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data);
201   DWARFMappedHash::ExtractDIEArray(hash_data,
202                                    DIERefCallback(callback, regex.GetText()));
203 }
204 
205 void AppleDWARFIndex::Dump(Stream &s) {
206   if (m_apple_names_up)
207     s.PutCString(".apple_names index present\n");
208   if (m_apple_namespaces_up)
209     s.PutCString(".apple_namespaces index present\n");
210   if (m_apple_types_up)
211     s.PutCString(".apple_types index present\n");
212   if (m_apple_objc_up)
213     s.PutCString(".apple_objc index present\n");
214   // TODO: Dump index contents
215 }
216