LLDB mainline
DebugNamesDWARFIndex.cpp
Go to the documentation of this file.
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
13#include "lldb/Core/Module.h"
15#include "lldb/Utility/Stream.h"
16#include "llvm/ADT/Sequence.h"
17#include <optional>
18
19using namespace lldb_private;
20using namespace lldb;
21using namespace lldb_private::dwarf;
22using namespace lldb_private::plugin::dwarf;
23
24llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
26 DWARFDataExtractor debug_str,
28 auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVMDWARF(),
29 debug_str.GetAsLLVM());
30 if (llvm::Error E = index_up->extract())
31 return std::move(E);
32
33 return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
34 module, std::move(index_up), debug_names, debug_str, dwarf));
35}
36
37llvm::DenseSet<dw_offset_t>
39 llvm::DenseSet<dw_offset_t> result;
40 for (const DebugNames::NameIndex &ni : debug_names) {
41 const uint32_t num_cus = ni.getCUCount();
42 for (uint32_t cu = 0; cu < num_cus; ++cu)
43 result.insert(ni.getCUOffset(cu));
44 const uint32_t num_tus = ni.getLocalTUCount();
45 for (uint32_t tu = 0; tu < num_tus; ++tu)
46 result.insert(ni.getLocalTUOffset(tu));
47 }
48 return result;
49}
50
51std::optional<DIERef>
52DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) const {
53 // Look for a DWARF unit offset (CU offset or local TU offset) as they are
54 // both offsets into the .debug_info section.
55 std::optional<uint64_t> unit_offset = entry.getCUOffset();
56 if (!unit_offset) {
57 unit_offset = entry.getLocalTUOffset();
58 if (!unit_offset)
59 return std::nullopt;
60 }
61
62 DWARFUnit *cu =
64 if (!cu)
65 return std::nullopt;
66
67 cu = &cu->GetNonSkeletonUnit();
68 if (std::optional<uint64_t> die_offset = entry.getDIEUnitOffset())
70 DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
71
72 return std::nullopt;
73}
74
76 const DebugNames::Entry &entry,
77 llvm::function_ref<bool(DWARFDIE die)> callback) {
78 std::optional<DIERef> ref = ToDIERef(entry);
79 if (!ref)
80 return true;
81 SymbolFileDWARF &dwarf = *llvm::cast<SymbolFileDWARF>(
83 DWARFDIE die = dwarf.GetDIE(*ref);
84 if (!die)
85 return true;
86 return callback(die);
87}
88
90 const DebugNames::NameIndex &ni,
91 llvm::StringRef name) {
92 // Ignore SentinelErrors, log everything else.
95 handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
96 "Failed to parse index entries for index at {1:x}, name {2}: {0}",
97 ni.getUnitOffset(), name);
98}
99
101 ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
102 for (const DebugNames::Entry &entry :
103 m_debug_names_up->equal_range(basename.GetStringRef())) {
104 if (entry.tag() != DW_TAG_variable)
105 continue;
106
107 if (!ProcessEntry(entry, callback))
108 return;
109 }
110
111 m_fallback.GetGlobalVariables(basename, callback);
112}
113
115 const RegularExpression &regex,
116 llvm::function_ref<bool(DWARFDIE die)> callback) {
117 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
118 for (DebugNames::NameTableEntry nte: ni) {
119 Mangled mangled_name(nte.getString());
120 if (!mangled_name.NameMatches(regex))
121 continue;
122
123 uint64_t entry_offset = nte.getEntryOffset();
124 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
125 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
126 if (entry_or->tag() != DW_TAG_variable)
127 continue;
128
129 if (!ProcessEntry(*entry_or, callback))
130 return;
131 }
132 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
133 }
134 }
135
136 m_fallback.GetGlobalVariables(regex, callback);
137}
138
140 DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
141 uint64_t cu_offset = cu.GetOffset();
142 bool found_entry_for_cu = false;
143 for (const DebugNames::NameIndex &ni : *m_debug_names_up) {
144 // Check if this name index contains an entry for the given CU.
145 bool cu_matches = false;
146 for (uint32_t i = 0; i < ni.getCUCount(); ++i) {
147 if (ni.getCUOffset(i) == cu_offset) {
148 cu_matches = true;
149 break;
150 }
151 }
152 if (!cu_matches)
153 continue;
154
155 for (DebugNames::NameTableEntry nte : ni) {
156 uint64_t entry_offset = nte.getEntryOffset();
157 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
158 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
159 if (entry_or->tag() != DW_TAG_variable)
160 continue;
161 if (entry_or->getCUOffset() != cu_offset)
162 continue;
163
164 found_entry_for_cu = true;
165 if (!ProcessEntry(*entry_or, callback))
166 return;
167 }
168 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
169 }
170 }
171 // If no name index for that particular CU was found, fallback to
172 // creating the manual index.
173 if (!found_entry_for_cu)
174 m_fallback.GetGlobalVariables(cu, callback);
175}
176
178 ConstString class_name, bool must_be_implementation,
179 llvm::function_ref<bool(DWARFDIE die)> callback) {
180 // Keep a list of incomplete types as fallback for when we don't find the
181 // complete type.
182 DIEArray incomplete_types;
183
184 for (const DebugNames::Entry &entry :
185 m_debug_names_up->equal_range(class_name.GetStringRef())) {
186 if (entry.tag() != DW_TAG_structure_type &&
187 entry.tag() != DW_TAG_class_type)
188 continue;
189
190 std::optional<DIERef> ref = ToDIERef(entry);
191 if (!ref)
192 continue;
193
194 DWARFUnit *cu = m_debug_info.GetUnit(*ref);
195 if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
196 incomplete_types.push_back(*ref);
197 continue;
198 }
199
200 DWARFDIE die = m_debug_info.GetDIE(*ref);
201 if (!die) {
202 ReportInvalidDIERef(*ref, class_name.GetStringRef());
203 continue;
204 }
205
206 if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
207 // If we find the complete version we're done.
208 callback(die);
209 return;
210 }
211 incomplete_types.push_back(*ref);
212 }
213
214 auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef());
215 for (DIERef ref : incomplete_types)
216 if (!dierefcallback(ref))
217 return;
218
219 m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
220}
221
222namespace {
223using Entry = llvm::DWARFDebugNames::Entry;
224
225/// If `entry` and all of its parents have an `IDX_parent`, use that information
226/// to build and return a list of at most `max_parents` parent Entries.
227/// `entry` itself is not included in the list.
228/// If any parent does not have an `IDX_parent`, or the Entry data is corrupted,
229/// nullopt is returned.
230std::optional<llvm::SmallVector<Entry, 4>>
231getParentChain(Entry entry, uint32_t max_parents) {
232 llvm::SmallVector<Entry, 4> parent_entries;
233
234 do {
235 if (!entry.hasParentInformation())
236 return std::nullopt;
237
238 llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry();
239 if (!parent) {
240 // Bad data.
242 GetLog(DWARFLog::Lookups), parent.takeError(),
243 "Failed to extract parent entry from a non-empty IDX_parent");
244 return std::nullopt;
245 }
246
247 // Last parent in the chain.
248 if (!parent->has_value())
249 break;
250
251 parent_entries.push_back(**parent);
252 entry = **parent;
253 } while (parent_entries.size() < max_parents);
254
255 return parent_entries;
256}
257} // namespace
258
260 const DWARFDeclContext &context,
261 llvm::function_ref<bool(DWARFDIE die)> callback) {
262 if (context.GetSize() == 0)
263 return;
264
265 llvm::StringRef leaf_name = context[0].name;
266 llvm::SmallVector<llvm::StringRef> parent_names;
267 for (auto idx : llvm::seq<int>(1, context.GetSize()))
268 parent_names.emplace_back(context[idx].name);
269
270 // For each entry, grab its parent chain and check if we have a match.
271 for (const DebugNames::Entry &entry :
272 m_debug_names_up->equal_range(leaf_name)) {
273 if (!isType(entry.tag()))
274 continue;
275
276 // Grab at most one extra parent, subsequent parents are not necessary to
277 // test equality.
278 std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
279 getParentChain(entry, parent_names.size() + 1);
280
281 if (!parent_chain) {
282 // Fallback: use the base class implementation.
283 if (!ProcessEntry(entry, [&](DWARFDIE die) {
284 return GetFullyQualifiedTypeImpl(context, die, callback);
285 }))
286 return;
287 continue;
288 }
289
290 if (SameParentChain(parent_names, *parent_chain) &&
291 !ProcessEntry(entry, callback))
292 return;
293 }
294}
295
297 llvm::ArrayRef<llvm::StringRef> parent_names,
298 llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
299
300 if (parent_entries.size() != parent_names.size())
301 return false;
302
303 auto SameAsEntryATName = [this](llvm::StringRef name,
304 const DebugNames::Entry &entry) {
305 // Peek at the AT_name of `entry` and test equality to `name`.
306 auto maybe_dieoffset = entry.getDIEUnitOffset();
307 if (!maybe_dieoffset)
308 return false;
309 auto die_ref = ToDIERef(entry);
310 if (!die_ref)
311 return false;
312 return name == m_debug_info.PeekDIEName(*die_ref);
313 };
314
315 // If the AT_name of any parent fails to match the expected name, we don't
316 // have a match.
317 for (auto [parent_name, parent_entry] :
318 llvm::zip_equal(parent_names, parent_entries))
319 if (!SameAsEntryATName(parent_name, parent_entry))
320 return false;
321 return true;
322}
323
325 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
326 for (const DebugNames::Entry &entry :
327 m_debug_names_up->equal_range(name.GetStringRef())) {
328 if (isType(entry.tag())) {
329 if (!ProcessEntry(entry, callback))
330 return;
331 }
332 }
333
334 m_fallback.GetTypes(name, callback);
335}
336
338 const DWARFDeclContext &context,
339 llvm::function_ref<bool(DWARFDIE die)> callback) {
340 auto name = context[0].name;
341 for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
342 if (entry.tag() == context[0].tag) {
343 if (!ProcessEntry(entry, callback))
344 return;
345 }
346 }
347
348 m_fallback.GetTypes(context, callback);
349}
350
352 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
353 for (const DebugNames::Entry &entry :
354 m_debug_names_up->equal_range(name.GetStringRef())) {
355 lldb_private::dwarf::Tag entry_tag = entry.tag();
356 if (entry_tag == DW_TAG_namespace ||
357 entry_tag == DW_TAG_imported_declaration) {
358 if (!ProcessEntry(entry, callback))
359 return;
360 }
361 }
362
363 m_fallback.GetNamespaces(name, callback);
364}
365
367 const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
368 const CompilerDeclContext &parent_decl_ctx,
369 llvm::function_ref<bool(DWARFDIE die)> callback) {
370 ConstString name = lookup_info.GetLookupName();
371 std::set<DWARFDebugInfoEntry *> seen;
372 for (const DebugNames::Entry &entry :
373 m_debug_names_up->equal_range(name.GetStringRef())) {
374 Tag tag = entry.tag();
375 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
376 continue;
377
378 if (std::optional<DIERef> ref = ToDIERef(entry)) {
379 if (!ProcessFunctionDIE(lookup_info, *ref, dwarf, parent_decl_ctx,
380 [&](DWARFDIE die) {
381 if (!seen.insert(die.GetDIE()).second)
382 return true;
383 return callback(die);
384 }))
385 return;
386 }
387 }
388
389 m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
390}
391
393 const RegularExpression &regex,
394 llvm::function_ref<bool(DWARFDIE die)> callback) {
395 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
396 for (DebugNames::NameTableEntry nte: ni) {
397 if (!regex.Execute(nte.getString()))
398 continue;
399
400 uint64_t entry_offset = nte.getEntryOffset();
401 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
402 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
403 Tag tag = entry_or->tag();
404 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
405 continue;
406
407 if (!ProcessEntry(*entry_or, callback))
408 return;
409 }
410 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
411 }
412 }
413
414 m_fallback.GetFunctions(regex, callback);
415}
416
418 m_fallback.Dump(s);
419
420 std::string data;
421 llvm::raw_string_ostream os(data);
422 m_debug_names_up->dump(os);
423 s.PutCString(os.str());
424}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_ERROR(log, error,...)
Definition: Log.h:365
Represents a generic declaration context in a program.
A uniqued constant string class.
Definition: ConstString.h:40
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:197
llvm::DWARFDataExtractor GetAsLLVMDWARF() const
llvm::DataExtractor GetAsLLVM() const
A class that handles mangled names.
Definition: Mangled.h:33
bool NameMatches(ConstString name) const
Check if "name" matches either the mangled or demangled name.
Definition: Mangled.h:171
A class that encapsulates name lookup information.
Definition: Module.h:904
ConstString GetLookupName() const
Definition: Module.h:915
A class that describes an executable image and its associated object and symbol files.
Definition: Module.h:88
virtual SymbolFile * GetSymbolFile(bool can_create=true, Stream *feedback_strm=nullptr)
Get the module's symbol file.
Definition: Module.cpp:992
bool Execute(llvm::StringRef string, llvm::SmallVectorImpl< llvm::StringRef > *matches=nullptr) const
Execute a regular expression match using the compiled regular expression that is already in this obje...
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:65
virtual SymbolFile * GetBackingSymbolFile()
SymbolFileOnDemand class overrides this to return the underlying backing SymbolFile implementation th...
Definition: SymbolFile.h:87
Identifies a DWARF debug info entry within a given Module.
Definition: DIERef.h:30
uint64_t GetAttributeValueAsUnsigned(const dw_attr_t attr, uint64_t fail_value) const
DWARFDIE GetDIE(dw_offset_t die_offset) const
Definition: DWARFDIE.cpp:119
DWARFUnit * GetUnitAtOffset(DIERef::Section section, dw_offset_t cu_offset, uint32_t *idx_ptr=nullptr)
llvm::StringRef PeekDIEName(const DIERef &die_ref)
Returns the AT_Name of this DIE, if it exists, without parsing the entire compile unit.
DWARFDIE GetDIE(const DIERef &die_ref)
DWARFUnit * GetUnit(const DIERef &die_ref)
bool ProcessFunctionDIE(const Module::LookupInfo &lookup_info, DIERef ref, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, llvm::function_ref< bool(DWARFDIE die)> callback)
Helper function implementing common logic for processing function dies.
Definition: DWARFIndex.cpp:26
DIERefCallbackImpl DIERefCallback(llvm::function_ref< bool(DWARFDIE die)> callback, llvm::StringRef name={}) const
Definition: DWARFIndex.h:107
void ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const
Definition: DWARFIndex.cpp:111
bool GetFullyQualifiedTypeImpl(const DWARFDeclContext &context, DWARFDIE die, llvm::function_ref< bool(DWARFDIE die)> callback)
Implementation of GetFullyQualifiedType to check a single entry, shareable with derived classes.
Definition: DWARFIndex.cpp:126
SymbolFileDWARF & GetSymbolFileDWARF() const
Definition: DWARFUnit.h:181
static llvm::Expected< std::unique_ptr< DebugNamesDWARFIndex > > Create(Module &module, DWARFDataExtractor debug_names, DWARFDataExtractor debug_str, SymbolFileDWARF &dwarf)
std::optional< DIERef > ToDIERef(const DebugNames::Entry &entry) const
static void MaybeLogLookupError(llvm::Error error, const DebugNames::NameIndex &ni, llvm::StringRef name)
void GetTypes(ConstString name, llvm::function_ref< bool(DWARFDIE die)> callback) override
void GetFullyQualifiedType(const DWARFDeclContext &context, llvm::function_ref< bool(DWARFDIE die)> callback) override
Uses DWARF5's IDX_parent fields, when available, to speed up this query.
void GetNamespaces(ConstString name, llvm::function_ref< bool(DWARFDIE die)> callback) override
bool ProcessEntry(const DebugNames::Entry &entry, llvm::function_ref< bool(DWARFDIE die)> callback)
void GetGlobalVariables(ConstString basename, llvm::function_ref< bool(DWARFDIE die)> callback) override
Finds global variables with the given base name.
void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, llvm::function_ref< bool(DWARFDIE die)> callback) override
void GetFunctions(const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, llvm::function_ref< bool(DWARFDIE die)> callback) override
bool SameParentChain(llvm::ArrayRef< llvm::StringRef > parent_names, llvm::ArrayRef< DebugNames::Entry > parent_entries) const
Returns true if parent_entries have identical names to parent_names.
static llvm::DenseSet< dw_offset_t > GetUnits(const DebugNames &debug_names)
void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, llvm::function_ref< bool(DWARFDIE die)> callback) override
void GetTypes(ConstString name, llvm::function_ref< bool(DWARFDIE die)> callback) override
void GetNamespaces(ConstString name, llvm::function_ref< bool(DWARFDIE die)> callback) override
void GetFunctions(const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf, const CompilerDeclContext &parent_decl_ctx, llvm::function_ref< bool(DWARFDIE die)> callback) override
void GetGlobalVariables(ConstString basename, llvm::function_ref< bool(DWARFDIE die)> callback) override
Finds global variables with the given base name.
std::optional< uint64_t > GetFileIndex() const
std::vector< DIERef > DIEArray
Definition: DIERef.h:135
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:314
Definition: SBAddress.h:15