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