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 <optional>
17
18using namespace lldb_private;
19using namespace lldb;
20using namespace lldb_private::dwarf;
21
22llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
24 DWARFDataExtractor debug_str,
26 auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVMDWARF(),
27 debug_str.GetAsLLVM());
28 if (llvm::Error E = index_up->extract())
29 return std::move(E);
30
31 return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
32 module, std::move(index_up), debug_names, debug_str, dwarf));
33}
34
35llvm::DenseSet<dw_offset_t>
37 llvm::DenseSet<dw_offset_t> result;
38 for (const DebugNames::NameIndex &ni : debug_names) {
39 for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
40 result.insert(ni.getCUOffset(cu));
41 }
42 return result;
43}
44
45std::optional<DIERef>
46DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
47 std::optional<uint64_t> cu_offset = entry.getCUOffset();
48 if (!cu_offset)
49 return std::nullopt;
50
52 if (!cu)
53 return std::nullopt;
54
55 cu = &cu->GetNonSkeletonUnit();
56 if (std::optional<uint64_t> die_offset = entry.getDIEUnitOffset())
58 DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
59
60 return std::nullopt;
61}
62
64 const DebugNames::Entry &entry,
65 llvm::function_ref<bool(DWARFDIE die)> callback) {
66 std::optional<DIERef> ref = ToDIERef(entry);
67 if (!ref)
68 return true;
69 SymbolFileDWARF &dwarf = *llvm::cast<SymbolFileDWARF>(
71 DWARFDIE die = dwarf.GetDIE(*ref);
72 if (!die)
73 return true;
74 return callback(die);
75}
76
78 const DebugNames::NameIndex &ni,
79 llvm::StringRef name) {
80 // Ignore SentinelErrors, log everything else.
83 handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
84 "Failed to parse index entries for index at {1:x}, name {2}: {0}",
85 ni.getUnitOffset(), name);
86}
87
89 ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
90 for (const DebugNames::Entry &entry :
91 m_debug_names_up->equal_range(basename.GetStringRef())) {
92 if (entry.tag() != DW_TAG_variable)
93 continue;
94
95 if (!ProcessEntry(entry, callback))
96 return;
97 }
98
99 m_fallback.GetGlobalVariables(basename, callback);
100}
101
103 const RegularExpression &regex,
104 llvm::function_ref<bool(DWARFDIE die)> callback) {
105 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
106 for (DebugNames::NameTableEntry nte: ni) {
107 Mangled mangled_name(nte.getString());
108 if (!mangled_name.NameMatches(regex))
109 continue;
110
111 uint64_t entry_offset = nte.getEntryOffset();
112 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
113 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
114 if (entry_or->tag() != DW_TAG_variable)
115 continue;
116
117 if (!ProcessEntry(*entry_or, callback))
118 return;
119 }
120 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
121 }
122 }
123
124 m_fallback.GetGlobalVariables(regex, callback);
125}
126
128 DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
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 return;
144 }
145 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
146 }
147 }
148 // If no name index for that particular CU was found, fallback to
149 // creating the manual index.
150 if (!found_entry_for_cu)
151 m_fallback.GetGlobalVariables(cu, callback);
152}
153
155 ConstString class_name, bool must_be_implementation,
156 llvm::function_ref<bool(DWARFDIE die)> callback) {
157 // Keep a list of incomplete types as fallback for when we don't find the
158 // complete type.
159 DIEArray incomplete_types;
160
161 for (const DebugNames::Entry &entry :
162 m_debug_names_up->equal_range(class_name.GetStringRef())) {
163 if (entry.tag() != DW_TAG_structure_type &&
164 entry.tag() != DW_TAG_class_type)
165 continue;
166
167 std::optional<DIERef> ref = ToDIERef(entry);
168 if (!ref)
169 continue;
170
171 DWARFUnit *cu = m_debug_info.GetUnit(*ref);
172 if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
173 incomplete_types.push_back(*ref);
174 continue;
175 }
176
177 DWARFDIE die = m_debug_info.GetDIE(*ref);
178 if (!die) {
179 ReportInvalidDIERef(*ref, class_name.GetStringRef());
180 continue;
181 }
182
183 if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
184 // If we find the complete version we're done.
185 callback(die);
186 return;
187 }
188 incomplete_types.push_back(*ref);
189 }
190
191 auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef());
192 for (DIERef ref : incomplete_types)
193 if (!dierefcallback(ref))
194 return;
195
196 m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
197}
198
200 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
201 for (const DebugNames::Entry &entry :
202 m_debug_names_up->equal_range(name.GetStringRef())) {
203 if (isType(entry.tag())) {
204 if (!ProcessEntry(entry, callback))
205 return;
206 }
207 }
208
209 m_fallback.GetTypes(name, callback);
210}
211
213 const DWARFDeclContext &context,
214 llvm::function_ref<bool(DWARFDIE die)> callback) {
215 auto name = context[0].name;
216 for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
217 if (entry.tag() == context[0].tag) {
218 if (!ProcessEntry(entry, callback))
219 return;
220 }
221 }
222
223 m_fallback.GetTypes(context, callback);
224}
225
227 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
228 for (const DebugNames::Entry &entry :
229 m_debug_names_up->equal_range(name.GetStringRef())) {
230 dwarf::Tag entry_tag = entry.tag();
231 if (entry_tag == DW_TAG_namespace ||
232 entry_tag == DW_TAG_imported_declaration) {
233 if (!ProcessEntry(entry, callback))
234 return;
235 }
236 }
237
238 m_fallback.GetNamespaces(name, callback);
239}
240
242 const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
243 const CompilerDeclContext &parent_decl_ctx,
244 llvm::function_ref<bool(DWARFDIE die)> callback) {
245 ConstString name = lookup_info.GetLookupName();
246 std::set<DWARFDebugInfoEntry *> seen;
247 for (const DebugNames::Entry &entry :
248 m_debug_names_up->equal_range(name.GetStringRef())) {
249 Tag tag = entry.tag();
250 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
251 continue;
252
253 if (std::optional<DIERef> ref = ToDIERef(entry)) {
254 if (!ProcessFunctionDIE(lookup_info, *ref, dwarf, parent_decl_ctx,
255 [&](DWARFDIE die) {
256 if (!seen.insert(die.GetDIE()).second)
257 return true;
258 return callback(die);
259 }))
260 return;
261 }
262 }
263
264 m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
265}
266
268 const RegularExpression &regex,
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 return;
284 }
285 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
286 }
287 }
288
289 m_fallback.GetFunctions(regex, callback);
290}
291
293 m_fallback.Dump(s);
294
295 std::string data;
296 llvm::raw_string_ostream os(data);
297 m_debug_names_up->dump(os);
298 s.PutCString(os.str());
299}
static llvm::raw_ostream & error(Stream &strm)
std::vector< DIERef > DIEArray
Definition: DIERef.h:133
#define LLDB_LOG_ERROR(log, error,...)
Definition: Log.h:365
Identifies a DWARF debug info entry within a given Module.
Definition: DIERef.h:28
@ DebugInfo
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:118
DWARFUnit * GetUnitAtOffset(DIERef::Section section, dw_offset_t cu_offset, uint32_t *idx_ptr=nullptr)
DWARFDIE GetDIE(const DIERef &die_ref)
DWARFUnit * GetUnit(const DIERef &die_ref)
SymbolFileDWARF & GetSymbolFileDWARF() const
Definition: DWARFUnit.h:200
bool Supports_DW_AT_APPLE_objc_complete_type()
Definition: DWARFUnit.cpp:682
DWARFUnit & GetNonSkeletonUnit()
Definition: DWARFUnit.cpp:663
dw_offset_t GetOffset() const
Definition: DWARFUnit.h:134
std::optional< uint64_t > GetFileIndex() const
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:191
llvm::DWARFDataExtractor GetAsLLVMDWARF() const
llvm::DataExtractor GetAsLLVM() const
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:23
void ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const
Definition: DWARFIndex.cpp:108
DIERefCallbackImpl DIERefCallback(llvm::function_ref< bool(DWARFDIE die)> callback, llvm::StringRef name={}) const
Definition: DWARFIndex.h:98
static llvm::Expected< std::unique_ptr< DebugNamesDWARFIndex > > Create(Module &module, DWARFDataExtractor debug_names, DWARFDataExtractor debug_str, SymbolFileDWARF &dwarf)
static void MaybeLogLookupError(llvm::Error error, const DebugNames::NameIndex &ni, llvm::StringRef name)
std::optional< DIERef > ToDIERef(const DebugNames::Entry &entry)
void GetTypes(ConstString name, llvm::function_ref< bool(DWARFDIE die)> callback) override
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
static llvm::DenseSet< dw_offset_t > GetUnits(const DebugNames &debug_names)
std::unique_ptr< DebugNames > m_debug_names_up
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
void Dump(Stream &s) override
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.
A class that encapsulates name lookup information.
Definition: Module.h:949
ConstString GetLookupName() const
Definition: Module.h:960
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:1065
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:63
virtual SymbolFile * GetBackingSymbolFile()
SymbolFileOnDemand class overrides this to return the underlying backing SymbolFile implementation th...
Definition: SymbolFile.h:86
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