xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- DebugNamesDWARFIndex.cpp ------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
10061da546Spatrick #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
11061da546Spatrick #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
12061da546Spatrick #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
13dda28197Spatrick #include "lldb/Core/Module.h"
14061da546Spatrick #include "lldb/Utility/RegularExpression.h"
15061da546Spatrick #include "lldb/Utility/Stream.h"
16*f6aab3d8Srobert #include <optional>
17061da546Spatrick 
18061da546Spatrick using namespace lldb_private;
19061da546Spatrick using namespace lldb;
20*f6aab3d8Srobert using namespace lldb_private::dwarf;
21061da546Spatrick 
22061da546Spatrick llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
Create(Module & module,DWARFDataExtractor debug_names,DWARFDataExtractor debug_str,SymbolFileDWARF & dwarf)23061da546Spatrick DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
24061da546Spatrick                              DWARFDataExtractor debug_str,
25dda28197Spatrick                              SymbolFileDWARF &dwarf) {
26061da546Spatrick   auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVM(),
27061da546Spatrick                                                 debug_str.GetAsLLVM());
28061da546Spatrick   if (llvm::Error E = index_up->extract())
29061da546Spatrick     return std::move(E);
30061da546Spatrick 
31061da546Spatrick   return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
32dda28197Spatrick       module, std::move(index_up), debug_names, debug_str, dwarf));
33061da546Spatrick }
34061da546Spatrick 
35061da546Spatrick llvm::DenseSet<dw_offset_t>
GetUnits(const DebugNames & debug_names)36061da546Spatrick DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
37061da546Spatrick   llvm::DenseSet<dw_offset_t> result;
38061da546Spatrick   for (const DebugNames::NameIndex &ni : debug_names) {
39061da546Spatrick     for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
40061da546Spatrick       result.insert(ni.getCUOffset(cu));
41061da546Spatrick   }
42061da546Spatrick   return result;
43061da546Spatrick }
44061da546Spatrick 
45*f6aab3d8Srobert std::optional<DIERef>
ToDIERef(const DebugNames::Entry & entry)46061da546Spatrick DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
47*f6aab3d8Srobert   std::optional<uint64_t> cu_offset = entry.getCUOffset();
48061da546Spatrick   if (!cu_offset)
49*f6aab3d8Srobert     return std::nullopt;
50061da546Spatrick 
51061da546Spatrick   DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
52061da546Spatrick   if (!cu)
53*f6aab3d8Srobert     return std::nullopt;
54061da546Spatrick 
55061da546Spatrick   cu = &cu->GetNonSkeletonUnit();
56*f6aab3d8Srobert   if (std::optional<uint64_t> die_offset = entry.getDIEUnitOffset())
57061da546Spatrick     return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(),
58061da546Spatrick                   DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
59061da546Spatrick 
60*f6aab3d8Srobert   return std::nullopt;
61061da546Spatrick }
62061da546Spatrick 
ProcessEntry(const DebugNames::Entry & entry,llvm::function_ref<bool (DWARFDIE die)> callback,llvm::StringRef name)63dda28197Spatrick bool DebugNamesDWARFIndex::ProcessEntry(
64dda28197Spatrick     const DebugNames::Entry &entry,
65dda28197Spatrick     llvm::function_ref<bool(DWARFDIE die)> callback, llvm::StringRef name) {
66*f6aab3d8Srobert   std::optional<DIERef> ref = ToDIERef(entry);
67dda28197Spatrick   if (!ref)
68dda28197Spatrick     return true;
69*f6aab3d8Srobert   SymbolFileDWARF &dwarf = *llvm::cast<SymbolFileDWARF>(
70*f6aab3d8Srobert       m_module.GetSymbolFile()->GetBackingSymbolFile());
71dda28197Spatrick   DWARFDIE die = dwarf.GetDIE(*ref);
72dda28197Spatrick   if (!die)
73dda28197Spatrick     return true;
74dda28197Spatrick   return callback(die);
75061da546Spatrick }
76061da546Spatrick 
MaybeLogLookupError(llvm::Error error,const DebugNames::NameIndex & ni,llvm::StringRef name)77061da546Spatrick void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
78061da546Spatrick                                                const DebugNames::NameIndex &ni,
79061da546Spatrick                                                llvm::StringRef name) {
80061da546Spatrick   // Ignore SentinelErrors, log everything else.
81061da546Spatrick   LLDB_LOG_ERROR(
82*f6aab3d8Srobert       GetLog(DWARFLog::Lookups),
83061da546Spatrick       handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
84061da546Spatrick       "Failed to parse index entries for index at {1:x}, name {2}: {0}",
85061da546Spatrick       ni.getUnitOffset(), name);
86061da546Spatrick }
87061da546Spatrick 
GetGlobalVariables(ConstString basename,llvm::function_ref<bool (DWARFDIE die)> callback)88dda28197Spatrick void DebugNamesDWARFIndex::GetGlobalVariables(
89dda28197Spatrick     ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
90061da546Spatrick   for (const DebugNames::Entry &entry :
91061da546Spatrick        m_debug_names_up->equal_range(basename.GetStringRef())) {
92061da546Spatrick     if (entry.tag() != DW_TAG_variable)
93061da546Spatrick       continue;
94061da546Spatrick 
95dda28197Spatrick     if (!ProcessEntry(entry, callback, basename.GetStringRef()))
96dda28197Spatrick       return;
97061da546Spatrick   }
98061da546Spatrick 
99dda28197Spatrick   m_fallback.GetGlobalVariables(basename, callback);
100dda28197Spatrick }
101061da546Spatrick 
GetGlobalVariables(const RegularExpression & regex,llvm::function_ref<bool (DWARFDIE die)> callback)102dda28197Spatrick void DebugNamesDWARFIndex::GetGlobalVariables(
103dda28197Spatrick     const RegularExpression &regex,
104dda28197Spatrick     llvm::function_ref<bool(DWARFDIE die)> callback) {
105061da546Spatrick   for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
106061da546Spatrick     for (DebugNames::NameTableEntry nte: ni) {
107061da546Spatrick       if (!regex.Execute(nte.getString()))
108061da546Spatrick         continue;
109061da546Spatrick 
110061da546Spatrick       uint64_t entry_offset = nte.getEntryOffset();
111061da546Spatrick       llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
112061da546Spatrick       for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
113061da546Spatrick         if (entry_or->tag() != DW_TAG_variable)
114061da546Spatrick           continue;
115061da546Spatrick 
116dda28197Spatrick         if (!ProcessEntry(*entry_or, callback,
117dda28197Spatrick                           llvm::StringRef(nte.getString())))
118dda28197Spatrick           return;
119061da546Spatrick       }
120061da546Spatrick       MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
121061da546Spatrick     }
122061da546Spatrick   }
123dda28197Spatrick 
124dda28197Spatrick   m_fallback.GetGlobalVariables(regex, callback);
125061da546Spatrick }
126061da546Spatrick 
GetGlobalVariables(DWARFUnit & cu,llvm::function_ref<bool (DWARFDIE die)> callback)127dda28197Spatrick void DebugNamesDWARFIndex::GetGlobalVariables(
128*f6aab3d8Srobert     DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
129*f6aab3d8Srobert   lldbassert(!cu.GetSymbolFileDWARF().GetDwoNum());
130061da546Spatrick   uint64_t cu_offset = cu.GetOffset();
131*f6aab3d8Srobert   bool found_entry_for_cu = false;
132061da546Spatrick   for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
133061da546Spatrick     for (DebugNames::NameTableEntry nte: ni) {
134061da546Spatrick       uint64_t entry_offset = nte.getEntryOffset();
135061da546Spatrick       llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
136061da546Spatrick       for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
137061da546Spatrick         if (entry_or->tag() != DW_TAG_variable)
138061da546Spatrick           continue;
139061da546Spatrick         if (entry_or->getCUOffset() != cu_offset)
140061da546Spatrick           continue;
141061da546Spatrick 
142*f6aab3d8Srobert         found_entry_for_cu = true;
143dda28197Spatrick         if (!ProcessEntry(*entry_or, callback,
144dda28197Spatrick                           llvm::StringRef(nte.getString())))
145dda28197Spatrick           return;
146061da546Spatrick       }
147061da546Spatrick       MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
148061da546Spatrick     }
149061da546Spatrick   }
150*f6aab3d8Srobert   // If no name index for that particular CU was found, fallback to
151*f6aab3d8Srobert   // creating the manual index.
152*f6aab3d8Srobert   if (!found_entry_for_cu)
153dda28197Spatrick     m_fallback.GetGlobalVariables(cu, callback);
154061da546Spatrick }
155061da546Spatrick 
GetCompleteObjCClass(ConstString class_name,bool must_be_implementation,llvm::function_ref<bool (DWARFDIE die)> callback)156dda28197Spatrick void DebugNamesDWARFIndex::GetCompleteObjCClass(
157dda28197Spatrick     ConstString class_name, bool must_be_implementation,
158dda28197Spatrick     llvm::function_ref<bool(DWARFDIE die)> callback) {
159061da546Spatrick   // Keep a list of incomplete types as fallback for when we don't find the
160061da546Spatrick   // complete type.
161061da546Spatrick   DIEArray incomplete_types;
162061da546Spatrick 
163061da546Spatrick   for (const DebugNames::Entry &entry :
164061da546Spatrick        m_debug_names_up->equal_range(class_name.GetStringRef())) {
165061da546Spatrick     if (entry.tag() != DW_TAG_structure_type &&
166061da546Spatrick         entry.tag() != DW_TAG_class_type)
167061da546Spatrick       continue;
168061da546Spatrick 
169*f6aab3d8Srobert     std::optional<DIERef> ref = ToDIERef(entry);
170061da546Spatrick     if (!ref)
171061da546Spatrick       continue;
172061da546Spatrick 
173061da546Spatrick     DWARFUnit *cu = m_debug_info.GetUnit(*ref);
174061da546Spatrick     if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
175061da546Spatrick       incomplete_types.push_back(*ref);
176061da546Spatrick       continue;
177061da546Spatrick     }
178061da546Spatrick 
179061da546Spatrick     DWARFDIE die = m_debug_info.GetDIE(*ref);
180dda28197Spatrick     if (!die) {
181dda28197Spatrick       ReportInvalidDIERef(*ref, class_name.GetStringRef());
182061da546Spatrick       continue;
183dda28197Spatrick     }
184061da546Spatrick 
185061da546Spatrick     if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
186061da546Spatrick       // If we find the complete version we're done.
187dda28197Spatrick       callback(die);
188061da546Spatrick       return;
189dda28197Spatrick     }
190061da546Spatrick     incomplete_types.push_back(*ref);
191061da546Spatrick   }
192dda28197Spatrick 
193dda28197Spatrick   auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef());
194dda28197Spatrick   for (DIERef ref : incomplete_types)
195dda28197Spatrick     if (!dierefcallback(ref))
196dda28197Spatrick       return;
197dda28197Spatrick 
198dda28197Spatrick   m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
199061da546Spatrick }
200061da546Spatrick 
GetTypes(ConstString name,llvm::function_ref<bool (DWARFDIE die)> callback)201dda28197Spatrick void DebugNamesDWARFIndex::GetTypes(
202dda28197Spatrick     ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
203061da546Spatrick   for (const DebugNames::Entry &entry :
204061da546Spatrick        m_debug_names_up->equal_range(name.GetStringRef())) {
205dda28197Spatrick     if (isType(entry.tag())) {
206dda28197Spatrick       if (!ProcessEntry(entry, callback, name.GetStringRef()))
207dda28197Spatrick         return;
208061da546Spatrick     }
209061da546Spatrick   }
210061da546Spatrick 
211dda28197Spatrick   m_fallback.GetTypes(name, callback);
212dda28197Spatrick }
213061da546Spatrick 
GetTypes(const DWARFDeclContext & context,llvm::function_ref<bool (DWARFDIE die)> callback)214dda28197Spatrick void DebugNamesDWARFIndex::GetTypes(
215dda28197Spatrick     const DWARFDeclContext &context,
216dda28197Spatrick     llvm::function_ref<bool(DWARFDIE die)> callback) {
217dda28197Spatrick   auto name = context[0].name;
218dda28197Spatrick   for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
219dda28197Spatrick     if (entry.tag() == context[0].tag) {
220dda28197Spatrick       if (!ProcessEntry(entry, callback, name))
221dda28197Spatrick         return;
222061da546Spatrick     }
223061da546Spatrick   }
224061da546Spatrick 
225dda28197Spatrick   m_fallback.GetTypes(context, callback);
226dda28197Spatrick }
227061da546Spatrick 
GetNamespaces(ConstString name,llvm::function_ref<bool (DWARFDIE die)> callback)228dda28197Spatrick void DebugNamesDWARFIndex::GetNamespaces(
229dda28197Spatrick     ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
230061da546Spatrick   for (const DebugNames::Entry &entry :
231061da546Spatrick        m_debug_names_up->equal_range(name.GetStringRef())) {
232dda28197Spatrick     if (entry.tag() == DW_TAG_namespace) {
233dda28197Spatrick       if (!ProcessEntry(entry, callback, name.GetStringRef()))
234dda28197Spatrick         return;
235061da546Spatrick     }
236061da546Spatrick   }
237061da546Spatrick 
238dda28197Spatrick   m_fallback.GetNamespaces(name, callback);
239dda28197Spatrick }
240dda28197Spatrick 
GetFunctions(const Module::LookupInfo & lookup_info,SymbolFileDWARF & dwarf,const CompilerDeclContext & parent_decl_ctx,llvm::function_ref<bool (DWARFDIE die)> callback)241061da546Spatrick void DebugNamesDWARFIndex::GetFunctions(
242*f6aab3d8Srobert     const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
243*f6aab3d8Srobert     const CompilerDeclContext &parent_decl_ctx,
244dda28197Spatrick     llvm::function_ref<bool(DWARFDIE die)> callback) {
245*f6aab3d8Srobert   ConstString name = lookup_info.GetLookupName();
246dda28197Spatrick   std::set<DWARFDebugInfoEntry *> seen;
247061da546Spatrick   for (const DebugNames::Entry &entry :
248061da546Spatrick        m_debug_names_up->equal_range(name.GetStringRef())) {
249061da546Spatrick     Tag tag = entry.tag();
250061da546Spatrick     if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
251061da546Spatrick       continue;
252061da546Spatrick 
253*f6aab3d8Srobert     if (std::optional<DIERef> ref = ToDIERef(entry)) {
254*f6aab3d8Srobert       if (!ProcessFunctionDIE(lookup_info, *ref, dwarf, parent_decl_ctx,
255*f6aab3d8Srobert                               [&](DWARFDIE die) {
256dda28197Spatrick                                 if (!seen.insert(die.GetDIE()).second)
257dda28197Spatrick                                   return true;
258dda28197Spatrick                                 return callback(die);
259dda28197Spatrick                               }))
260dda28197Spatrick         return;
261dda28197Spatrick     }
262061da546Spatrick   }
263061da546Spatrick 
264*f6aab3d8Srobert   m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
265061da546Spatrick }
266061da546Spatrick 
GetFunctions(const RegularExpression & regex,llvm::function_ref<bool (DWARFDIE die)> callback)267dda28197Spatrick void DebugNamesDWARFIndex::GetFunctions(
268dda28197Spatrick     const RegularExpression &regex,
269dda28197Spatrick     llvm::function_ref<bool(DWARFDIE die)> callback) {
270061da546Spatrick   for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
271061da546Spatrick     for (DebugNames::NameTableEntry nte: ni) {
272061da546Spatrick       if (!regex.Execute(nte.getString()))
273061da546Spatrick         continue;
274061da546Spatrick 
275061da546Spatrick       uint64_t entry_offset = nte.getEntryOffset();
276061da546Spatrick       llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
277061da546Spatrick       for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
278061da546Spatrick         Tag tag = entry_or->tag();
279061da546Spatrick         if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
280061da546Spatrick           continue;
281061da546Spatrick 
282dda28197Spatrick         if (!ProcessEntry(*entry_or, callback,
283dda28197Spatrick                           llvm::StringRef(nte.getString())))
284dda28197Spatrick           return;
285061da546Spatrick       }
286061da546Spatrick       MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
287061da546Spatrick     }
288061da546Spatrick   }
289dda28197Spatrick 
290dda28197Spatrick   m_fallback.GetFunctions(regex, callback);
291061da546Spatrick }
292061da546Spatrick 
Dump(Stream & s)293061da546Spatrick void DebugNamesDWARFIndex::Dump(Stream &s) {
294061da546Spatrick   m_fallback.Dump(s);
295061da546Spatrick 
296061da546Spatrick   std::string data;
297061da546Spatrick   llvm::raw_string_ostream os(data);
298061da546Spatrick   m_debug_names_up->dump(os);
299061da546Spatrick   s.PutCString(os.str());
300061da546Spatrick }
301