1 //===-- DebugNamesDWARFIndex.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/DebugNamesDWARFIndex.h"
10 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
11 #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
12 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Utility/RegularExpression.h"
15 #include "lldb/Utility/Stream.h"
16
17 using namespace lldb_private;
18 using namespace lldb;
19 using namespace lldb_private::dwarf;
20
21 llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
Create(Module & module,DWARFDataExtractor debug_names,DWARFDataExtractor debug_str,SymbolFileDWARF & dwarf)22 DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
23 DWARFDataExtractor debug_str,
24 SymbolFileDWARF &dwarf) {
25 auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVM(),
26 debug_str.GetAsLLVM());
27 if (llvm::Error E = index_up->extract())
28 return std::move(E);
29
30 return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
31 module, std::move(index_up), debug_names, debug_str, dwarf));
32 }
33
34 llvm::DenseSet<dw_offset_t>
GetUnits(const DebugNames & debug_names)35 DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
36 llvm::DenseSet<dw_offset_t> result;
37 for (const DebugNames::NameIndex &ni : debug_names) {
38 for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
39 result.insert(ni.getCUOffset(cu));
40 }
41 return result;
42 }
43
44 llvm::Optional<DIERef>
ToDIERef(const DebugNames::Entry & entry)45 DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
46 llvm::Optional<uint64_t> cu_offset = entry.getCUOffset();
47 if (!cu_offset)
48 return llvm::None;
49
50 DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
51 if (!cu)
52 return llvm::None;
53
54 cu = &cu->GetNonSkeletonUnit();
55 if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset())
56 return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(),
57 DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
58
59 return llvm::None;
60 }
61
ProcessEntry(const DebugNames::Entry & entry,llvm::function_ref<bool (DWARFDIE die)> callback,llvm::StringRef name)62 bool DebugNamesDWARFIndex::ProcessEntry(
63 const DebugNames::Entry &entry,
64 llvm::function_ref<bool(DWARFDIE die)> callback, llvm::StringRef name) {
65 llvm::Optional<DIERef> ref = ToDIERef(entry);
66 if (!ref)
67 return true;
68 SymbolFileDWARF &dwarf = *llvm::cast<SymbolFileDWARF>(
69 m_module.GetSymbolFile()->GetBackingSymbolFile());
70 DWARFDIE die = dwarf.GetDIE(*ref);
71 if (!die)
72 return true;
73 return callback(die);
74 }
75
MaybeLogLookupError(llvm::Error error,const DebugNames::NameIndex & ni,llvm::StringRef name)76 void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
77 const DebugNames::NameIndex &ni,
78 llvm::StringRef name) {
79 // Ignore SentinelErrors, log everything else.
80 LLDB_LOG_ERROR(
81 GetLog(DWARFLog::Lookups),
82 handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
83 "Failed to parse index entries for index at {1:x}, name {2}: {0}",
84 ni.getUnitOffset(), name);
85 }
86
GetGlobalVariables(ConstString basename,llvm::function_ref<bool (DWARFDIE die)> callback)87 void DebugNamesDWARFIndex::GetGlobalVariables(
88 ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
89 for (const DebugNames::Entry &entry :
90 m_debug_names_up->equal_range(basename.GetStringRef())) {
91 if (entry.tag() != DW_TAG_variable)
92 continue;
93
94 if (!ProcessEntry(entry, callback, basename.GetStringRef()))
95 return;
96 }
97
98 m_fallback.GetGlobalVariables(basename, callback);
99 }
100
GetGlobalVariables(const RegularExpression & regex,llvm::function_ref<bool (DWARFDIE die)> callback)101 void DebugNamesDWARFIndex::GetGlobalVariables(
102 const RegularExpression ®ex,
103 llvm::function_ref<bool(DWARFDIE die)> callback) {
104 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
105 for (DebugNames::NameTableEntry nte: ni) {
106 if (!regex.Execute(nte.getString()))
107 continue;
108
109 uint64_t entry_offset = nte.getEntryOffset();
110 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
111 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
112 if (entry_or->tag() != DW_TAG_variable)
113 continue;
114
115 if (!ProcessEntry(*entry_or, callback,
116 llvm::StringRef(nte.getString())))
117 return;
118 }
119 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
120 }
121 }
122
123 m_fallback.GetGlobalVariables(regex, callback);
124 }
125
GetGlobalVariables(DWARFUnit & cu,llvm::function_ref<bool (DWARFDIE die)> callback)126 void DebugNamesDWARFIndex::GetGlobalVariables(
127 DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
128 lldbassert(!cu.GetSymbolFileDWARF().GetDwoNum());
129 uint64_t cu_offset = cu.GetOffset();
130 bool found_entry_for_cu = false;
131 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
132 for (DebugNames::NameTableEntry nte: ni) {
133 uint64_t entry_offset = nte.getEntryOffset();
134 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
135 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
136 if (entry_or->tag() != DW_TAG_variable)
137 continue;
138 if (entry_or->getCUOffset() != cu_offset)
139 continue;
140
141 found_entry_for_cu = true;
142 if (!ProcessEntry(*entry_or, callback,
143 llvm::StringRef(nte.getString())))
144 return;
145 }
146 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
147 }
148 }
149 // If no name index for that particular CU was found, fallback to
150 // creating the manual index.
151 if (!found_entry_for_cu)
152 m_fallback.GetGlobalVariables(cu, callback);
153 }
154
GetCompleteObjCClass(ConstString class_name,bool must_be_implementation,llvm::function_ref<bool (DWARFDIE die)> callback)155 void DebugNamesDWARFIndex::GetCompleteObjCClass(
156 ConstString class_name, bool must_be_implementation,
157 llvm::function_ref<bool(DWARFDIE die)> callback) {
158 // Keep a list of incomplete types as fallback for when we don't find the
159 // complete type.
160 DIEArray incomplete_types;
161
162 for (const DebugNames::Entry &entry :
163 m_debug_names_up->equal_range(class_name.GetStringRef())) {
164 if (entry.tag() != DW_TAG_structure_type &&
165 entry.tag() != DW_TAG_class_type)
166 continue;
167
168 llvm::Optional<DIERef> ref = ToDIERef(entry);
169 if (!ref)
170 continue;
171
172 DWARFUnit *cu = m_debug_info.GetUnit(*ref);
173 if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
174 incomplete_types.push_back(*ref);
175 continue;
176 }
177
178 DWARFDIE die = m_debug_info.GetDIE(*ref);
179 if (!die) {
180 ReportInvalidDIERef(*ref, class_name.GetStringRef());
181 continue;
182 }
183
184 if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
185 // If we find the complete version we're done.
186 callback(die);
187 return;
188 }
189 incomplete_types.push_back(*ref);
190 }
191
192 auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef());
193 for (DIERef ref : incomplete_types)
194 if (!dierefcallback(ref))
195 return;
196
197 m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
198 }
199
GetTypes(ConstString name,llvm::function_ref<bool (DWARFDIE die)> callback)200 void DebugNamesDWARFIndex::GetTypes(
201 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
202 for (const DebugNames::Entry &entry :
203 m_debug_names_up->equal_range(name.GetStringRef())) {
204 if (isType(entry.tag())) {
205 if (!ProcessEntry(entry, callback, name.GetStringRef()))
206 return;
207 }
208 }
209
210 m_fallback.GetTypes(name, callback);
211 }
212
GetTypes(const DWARFDeclContext & context,llvm::function_ref<bool (DWARFDIE die)> callback)213 void DebugNamesDWARFIndex::GetTypes(
214 const DWARFDeclContext &context,
215 llvm::function_ref<bool(DWARFDIE die)> callback) {
216 auto name = context[0].name;
217 for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
218 if (entry.tag() == context[0].tag) {
219 if (!ProcessEntry(entry, callback, name))
220 return;
221 }
222 }
223
224 m_fallback.GetTypes(context, callback);
225 }
226
GetNamespaces(ConstString name,llvm::function_ref<bool (DWARFDIE die)> callback)227 void DebugNamesDWARFIndex::GetNamespaces(
228 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
229 for (const DebugNames::Entry &entry :
230 m_debug_names_up->equal_range(name.GetStringRef())) {
231 if (entry.tag() == DW_TAG_namespace) {
232 if (!ProcessEntry(entry, callback, name.GetStringRef()))
233 return;
234 }
235 }
236
237 m_fallback.GetNamespaces(name, callback);
238 }
239
GetFunctions(ConstString name,SymbolFileDWARF & dwarf,const CompilerDeclContext & parent_decl_ctx,uint32_t name_type_mask,llvm::function_ref<bool (DWARFDIE die)> callback)240 void DebugNamesDWARFIndex::GetFunctions(
241 ConstString name, SymbolFileDWARF &dwarf,
242 const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
243 llvm::function_ref<bool(DWARFDIE die)> callback) {
244
245 std::set<DWARFDebugInfoEntry *> seen;
246 for (const DebugNames::Entry &entry :
247 m_debug_names_up->equal_range(name.GetStringRef())) {
248 Tag tag = entry.tag();
249 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
250 continue;
251
252 if (llvm::Optional<DIERef> ref = ToDIERef(entry)) {
253 if (!ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx,
254 name_type_mask, [&](DWARFDIE die) {
255 if (!seen.insert(die.GetDIE()).second)
256 return true;
257 return callback(die);
258 }))
259 return;
260 }
261 }
262
263 m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask,
264 callback);
265 }
266
GetFunctions(const RegularExpression & regex,llvm::function_ref<bool (DWARFDIE die)> callback)267 void DebugNamesDWARFIndex::GetFunctions(
268 const RegularExpression ®ex,
269 llvm::function_ref<bool(DWARFDIE die)> callback) {
270 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
271 for (DebugNames::NameTableEntry nte: ni) {
272 if (!regex.Execute(nte.getString()))
273 continue;
274
275 uint64_t entry_offset = nte.getEntryOffset();
276 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
277 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
278 Tag tag = entry_or->tag();
279 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
280 continue;
281
282 if (!ProcessEntry(*entry_or, callback,
283 llvm::StringRef(nte.getString())))
284 return;
285 }
286 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
287 }
288 }
289
290 m_fallback.GetFunctions(regex, callback);
291 }
292
Dump(Stream & s)293 void DebugNamesDWARFIndex::Dump(Stream &s) {
294 m_fallback.Dump(s);
295
296 std::string data;
297 llvm::raw_string_ostream os(data);
298 m_debug_names_up->dump(os);
299 s.PutCString(os.str());
300 }
301