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