Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
39644 views
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/LogChannelDWARF.h"
13
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
14
#include "lldb/Core/Module.h"
15
#include "lldb/Utility/RegularExpression.h"
16
#include "lldb/Utility/Stream.h"
17
#include "llvm/ADT/Sequence.h"
18
#include <optional>
19
20
using namespace lldb_private;
21
using namespace lldb;
22
using namespace lldb_private::dwarf;
23
using namespace lldb_private::plugin::dwarf;
24
25
llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
26
DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
27
DWARFDataExtractor debug_str,
28
SymbolFileDWARF &dwarf) {
29
auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVMDWARF(),
30
debug_str.GetAsLLVM());
31
if (llvm::Error E = index_up->extract())
32
return std::move(E);
33
34
return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
35
module, std::move(index_up), debug_names, debug_str, dwarf));
36
}
37
38
llvm::DenseSet<uint64_t>
39
DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) {
40
llvm::DenseSet<uint64_t> result;
41
for (const DebugNames::NameIndex &ni : debug_names) {
42
const uint32_t num_tus = ni.getForeignTUCount();
43
for (uint32_t tu = 0; tu < num_tus; ++tu)
44
result.insert(ni.getForeignTUSignature(tu));
45
}
46
return result;
47
}
48
49
llvm::DenseSet<dw_offset_t>
50
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
51
llvm::DenseSet<dw_offset_t> result;
52
for (const DebugNames::NameIndex &ni : debug_names) {
53
const uint32_t num_cus = ni.getCUCount();
54
for (uint32_t cu = 0; cu < num_cus; ++cu)
55
result.insert(ni.getCUOffset(cu));
56
const uint32_t num_tus = ni.getLocalTUCount();
57
for (uint32_t tu = 0; tu < num_tus; ++tu)
58
result.insert(ni.getLocalTUOffset(tu));
59
}
60
return result;
61
}
62
63
std::optional<DWARFTypeUnit *>
64
DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const {
65
std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature();
66
if (!type_sig.has_value())
67
return std::nullopt;
68
69
// Ask the entry for the skeleton compile unit offset and fetch the .dwo
70
// file from it and get the type unit by signature from there. If we find
71
// the type unit in the .dwo file, we don't need to check that the
72
// DW_AT_dwo_name matches because each .dwo file can have its own type unit.
73
std::optional<uint64_t> cu_offset = entry.getRelatedCUOffset();
74
if (!cu_offset)
75
return nullptr; // Return NULL, this is a type unit, but couldn't find it.
76
77
DWARFUnit *cu =
78
m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
79
if (!cu)
80
return nullptr; // Return NULL, this is a type unit, but couldn't find it.
81
82
auto dwp_sp = m_debug_info.GetDwpSymbolFile();
83
if (!dwp_sp) {
84
// No .dwp file, we need to load the .dwo file.
85
DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit();
86
// We don't need the check if the type unit matches the .dwo file if we have
87
// a .dwo file (not a .dwp), so we can just return the value here.
88
if (!dwo_cu.IsDWOUnit())
89
return nullptr; // We weren't able to load the .dwo file.
90
return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(
91
*type_sig);
92
}
93
// We have a .dwp file, just get the type unit from there. We need to verify
94
// that the type unit that ended up in the final .dwp file is the right type
95
// unit. Type units have signatures which are the same across multiple .dwo
96
// files, but only one of those type units will end up in the .dwp file. The
97
// contents of type units for the same type can be different in different .dwo
98
// files, which means the DIE offsets might not be the same between two
99
// different type units. So we need to determine if this accelerator table
100
// matches the type unit that ended up in the .dwp file. If it doesn't match,
101
// then we need to ignore this accelerator table entry as the type unit that
102
// is in the .dwp file will have its own index. In order to determine if the
103
// type unit that ended up in a .dwp file matches this DebugNames::Entry, we
104
// need to find the skeleton compile unit for this entry.
105
DWARFTypeUnit *foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig);
106
if (!foreign_tu)
107
return nullptr; // Return NULL, this is a type unit, but couldn't find it.
108
109
DWARFBaseDIE cu_die = cu->GetUnitDIEOnly();
110
DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly();
111
llvm::StringRef cu_dwo_name =
112
cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
113
llvm::StringRef tu_dwo_name =
114
tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
115
if (cu_dwo_name == tu_dwo_name)
116
return foreign_tu; // We found a match!
117
return nullptr; // Return NULL, this is a type unit, but couldn't find it.
118
}
119
120
DWARFUnit *
121
DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const {
122
123
if (std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry))
124
return foreign_tu.value();
125
126
// Look for a DWARF unit offset (CU offset or local TU offset) as they are
127
// both offsets into the .debug_info section.
128
std::optional<uint64_t> unit_offset = entry.getCUOffset();
129
if (!unit_offset)
130
unit_offset = entry.getLocalTUOffset();
131
if (unit_offset) {
132
if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo,
133
*unit_offset))
134
return &cu->GetNonSkeletonUnit();
135
}
136
return nullptr;
137
}
138
139
DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const {
140
DWARFUnit *unit = GetNonSkeletonUnit(entry);
141
std::optional<uint64_t> die_offset = entry.getDIEUnitOffset();
142
if (!unit || !die_offset)
143
return DWARFDIE();
144
if (DWARFDIE die = unit->GetDIE(unit->GetOffset() + *die_offset))
145
return die;
146
147
m_module.ReportErrorIfModifyDetected(
148
"the DWARF debug information has been modified (bad offset {0:x} in "
149
"debug_names section)\n",
150
*die_offset);
151
return DWARFDIE();
152
}
153
154
bool DebugNamesDWARFIndex::ProcessEntry(
155
const DebugNames::Entry &entry,
156
llvm::function_ref<bool(DWARFDIE die)> callback) {
157
DWARFDIE die = GetDIE(entry);
158
if (!die)
159
return true;
160
// Clang used to erroneously emit index entries for declaration DIEs in case
161
// when the definition is in a type unit (llvm.org/pr77696).
162
if (die.IsStructUnionOrClass() &&
163
die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
164
return true;
165
return callback(die);
166
}
167
168
void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
169
const DebugNames::NameIndex &ni,
170
llvm::StringRef name) {
171
// Ignore SentinelErrors, log everything else.
172
LLDB_LOG_ERROR(
173
GetLog(DWARFLog::Lookups),
174
handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
175
"Failed to parse index entries for index at {1:x}, name {2}: {0}",
176
ni.getUnitOffset(), name);
177
}
178
179
void DebugNamesDWARFIndex::GetGlobalVariables(
180
ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
181
for (const DebugNames::Entry &entry :
182
m_debug_names_up->equal_range(basename.GetStringRef())) {
183
if (entry.tag() != DW_TAG_variable)
184
continue;
185
186
if (!ProcessEntry(entry, callback))
187
return;
188
}
189
190
m_fallback.GetGlobalVariables(basename, callback);
191
}
192
193
void DebugNamesDWARFIndex::GetGlobalVariables(
194
const RegularExpression &regex,
195
llvm::function_ref<bool(DWARFDIE die)> callback) {
196
for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
197
for (DebugNames::NameTableEntry nte: ni) {
198
Mangled mangled_name(nte.getString());
199
if (!mangled_name.NameMatches(regex))
200
continue;
201
202
uint64_t entry_offset = nte.getEntryOffset();
203
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
204
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
205
if (entry_or->tag() != DW_TAG_variable)
206
continue;
207
208
if (!ProcessEntry(*entry_or, callback))
209
return;
210
}
211
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
212
}
213
}
214
215
m_fallback.GetGlobalVariables(regex, callback);
216
}
217
218
void DebugNamesDWARFIndex::GetGlobalVariables(
219
DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
220
uint64_t cu_offset = cu.GetOffset();
221
bool found_entry_for_cu = false;
222
for (const DebugNames::NameIndex &ni : *m_debug_names_up) {
223
// Check if this name index contains an entry for the given CU.
224
bool cu_matches = false;
225
for (uint32_t i = 0; i < ni.getCUCount(); ++i) {
226
if (ni.getCUOffset(i) == cu_offset) {
227
cu_matches = true;
228
break;
229
}
230
}
231
if (!cu_matches)
232
continue;
233
234
for (DebugNames::NameTableEntry nte : ni) {
235
uint64_t entry_offset = nte.getEntryOffset();
236
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
237
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
238
if (entry_or->tag() != DW_TAG_variable)
239
continue;
240
if (entry_or->getCUOffset() != cu_offset)
241
continue;
242
243
found_entry_for_cu = true;
244
if (!ProcessEntry(*entry_or, callback))
245
return;
246
}
247
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
248
}
249
}
250
// If no name index for that particular CU was found, fallback to
251
// creating the manual index.
252
if (!found_entry_for_cu)
253
m_fallback.GetGlobalVariables(cu, callback);
254
}
255
256
void DebugNamesDWARFIndex::GetCompleteObjCClass(
257
ConstString class_name, bool must_be_implementation,
258
llvm::function_ref<bool(DWARFDIE die)> callback) {
259
// Keep a list of incomplete types as fallback for when we don't find the
260
// complete type.
261
std::vector<DWARFDIE> incomplete_types;
262
263
for (const DebugNames::Entry &entry :
264
m_debug_names_up->equal_range(class_name.GetStringRef())) {
265
if (entry.tag() != DW_TAG_structure_type &&
266
entry.tag() != DW_TAG_class_type)
267
continue;
268
269
DWARFDIE die = GetDIE(entry);
270
if (!die) {
271
// Report invalid
272
continue;
273
}
274
DWARFUnit *cu = die.GetCU();
275
if (!cu->Supports_DW_AT_APPLE_objc_complete_type()) {
276
incomplete_types.push_back(die);
277
continue;
278
}
279
280
if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
281
// If we find the complete version we're done.
282
callback(die);
283
return;
284
}
285
incomplete_types.push_back(die);
286
}
287
288
for (DWARFDIE die : incomplete_types)
289
if (!callback(die))
290
return;
291
292
m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
293
}
294
295
namespace {
296
using Entry = llvm::DWARFDebugNames::Entry;
297
298
/// If `entry` and all of its parents have an `IDX_parent`, use that information
299
/// to build and return a list of at most `max_parents` parent Entries.
300
/// `entry` itself is not included in the list.
301
/// If any parent does not have an `IDX_parent`, or the Entry data is corrupted,
302
/// nullopt is returned.
303
std::optional<llvm::SmallVector<Entry, 4>>
304
getParentChain(Entry entry, uint32_t max_parents) {
305
llvm::SmallVector<Entry, 4> parent_entries;
306
307
do {
308
if (!entry.hasParentInformation())
309
return std::nullopt;
310
311
llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry();
312
if (!parent) {
313
// Bad data.
314
LLDB_LOG_ERROR(
315
GetLog(DWARFLog::Lookups), parent.takeError(),
316
"Failed to extract parent entry from a non-empty IDX_parent");
317
return std::nullopt;
318
}
319
320
// Last parent in the chain.
321
if (!parent->has_value())
322
break;
323
324
parent_entries.push_back(**parent);
325
entry = **parent;
326
} while (parent_entries.size() < max_parents);
327
328
return parent_entries;
329
}
330
} // namespace
331
332
void DebugNamesDWARFIndex::GetFullyQualifiedType(
333
const DWARFDeclContext &context,
334
llvm::function_ref<bool(DWARFDIE die)> callback) {
335
if (context.GetSize() == 0)
336
return;
337
338
llvm::StringRef leaf_name = context[0].name;
339
llvm::SmallVector<llvm::StringRef> parent_names;
340
for (auto idx : llvm::seq<int>(1, context.GetSize()))
341
parent_names.emplace_back(context[idx].name);
342
343
// For each entry, grab its parent chain and check if we have a match.
344
for (const DebugNames::Entry &entry :
345
m_debug_names_up->equal_range(leaf_name)) {
346
if (!isType(entry.tag()))
347
continue;
348
349
// If we get a NULL foreign_tu back, the entry doesn't match the type unit
350
// in the .dwp file, or we were not able to load the .dwo file or the DWO ID
351
// didn't match.
352
std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
353
if (foreign_tu && foreign_tu.value() == nullptr)
354
continue;
355
356
// Grab at most one extra parent, subsequent parents are not necessary to
357
// test equality.
358
std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
359
getParentChain(entry, parent_names.size() + 1);
360
361
if (!parent_chain) {
362
// Fallback: use the base class implementation.
363
if (!ProcessEntry(entry, [&](DWARFDIE die) {
364
return GetFullyQualifiedTypeImpl(context, die, callback);
365
}))
366
return;
367
continue;
368
}
369
370
if (SameParentChain(parent_names, *parent_chain) &&
371
!ProcessEntry(entry, callback))
372
return;
373
}
374
}
375
376
bool DebugNamesDWARFIndex::SameParentChain(
377
llvm::ArrayRef<llvm::StringRef> parent_names,
378
llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
379
380
if (parent_entries.size() != parent_names.size())
381
return false;
382
383
auto SameAsEntryATName = [this](llvm::StringRef name,
384
const DebugNames::Entry &entry) {
385
// Peek at the AT_name of `entry` and test equality to `name`.
386
auto maybe_dieoffset = entry.getDIEUnitOffset();
387
if (!maybe_dieoffset)
388
return false;
389
DWARFUnit *unit = GetNonSkeletonUnit(entry);
390
if (!unit)
391
return false;
392
return name == unit->PeekDIEName(unit->GetOffset() + *maybe_dieoffset);
393
};
394
395
// If the AT_name of any parent fails to match the expected name, we don't
396
// have a match.
397
for (auto [parent_name, parent_entry] :
398
llvm::zip_equal(parent_names, parent_entries))
399
if (!SameAsEntryATName(parent_name, parent_entry))
400
return false;
401
return true;
402
}
403
404
void DebugNamesDWARFIndex::GetTypes(
405
ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
406
for (const DebugNames::Entry &entry :
407
m_debug_names_up->equal_range(name.GetStringRef())) {
408
if (isType(entry.tag())) {
409
if (!ProcessEntry(entry, callback))
410
return;
411
}
412
}
413
414
m_fallback.GetTypes(name, callback);
415
}
416
417
void DebugNamesDWARFIndex::GetTypes(
418
const DWARFDeclContext &context,
419
llvm::function_ref<bool(DWARFDIE die)> callback) {
420
auto name = context[0].name;
421
for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
422
if (entry.tag() == context[0].tag) {
423
if (!ProcessEntry(entry, callback))
424
return;
425
}
426
}
427
428
m_fallback.GetTypes(context, callback);
429
}
430
431
void DebugNamesDWARFIndex::GetNamespaces(
432
ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
433
for (const DebugNames::Entry &entry :
434
m_debug_names_up->equal_range(name.GetStringRef())) {
435
lldb_private::dwarf::Tag entry_tag = entry.tag();
436
if (entry_tag == DW_TAG_namespace ||
437
entry_tag == DW_TAG_imported_declaration) {
438
if (!ProcessEntry(entry, callback))
439
return;
440
}
441
}
442
443
m_fallback.GetNamespaces(name, callback);
444
}
445
446
void DebugNamesDWARFIndex::GetFunctions(
447
const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
448
const CompilerDeclContext &parent_decl_ctx,
449
llvm::function_ref<bool(DWARFDIE die)> callback) {
450
ConstString name = lookup_info.GetLookupName();
451
std::set<DWARFDebugInfoEntry *> seen;
452
for (const DebugNames::Entry &entry :
453
m_debug_names_up->equal_range(name.GetStringRef())) {
454
Tag tag = entry.tag();
455
if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
456
continue;
457
458
if (DWARFDIE die = GetDIE(entry)) {
459
if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx,
460
[&](DWARFDIE die) {
461
if (!seen.insert(die.GetDIE()).second)
462
return true;
463
return callback(die);
464
}))
465
return;
466
}
467
}
468
469
m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
470
}
471
472
void DebugNamesDWARFIndex::GetFunctions(
473
const RegularExpression &regex,
474
llvm::function_ref<bool(DWARFDIE die)> callback) {
475
for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
476
for (DebugNames::NameTableEntry nte: ni) {
477
if (!regex.Execute(nte.getString()))
478
continue;
479
480
uint64_t entry_offset = nte.getEntryOffset();
481
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
482
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
483
Tag tag = entry_or->tag();
484
if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
485
continue;
486
487
if (!ProcessEntry(*entry_or, callback))
488
return;
489
}
490
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
491
}
492
}
493
494
m_fallback.GetFunctions(regex, callback);
495
}
496
497
void DebugNamesDWARFIndex::Dump(Stream &s) {
498
m_fallback.Dump(s);
499
500
std::string data;
501
llvm::raw_string_ostream os(data);
502
m_debug_names_up->dump(os);
503
s.PutCString(os.str());
504
}
505
506