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/DWARFDIE.cpp
39645 views
1
//===-- DWARFDIE.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 "DWARFDIE.h"
10
11
#include "DWARFASTParser.h"
12
#include "DWARFDebugInfo.h"
13
#include "DWARFDebugInfoEntry.h"
14
#include "DWARFDeclContext.h"
15
#include "DWARFUnit.h"
16
#include "lldb/Symbol/Type.h"
17
18
#include "llvm/ADT/iterator.h"
19
#include "llvm/BinaryFormat/Dwarf.h"
20
21
using namespace lldb_private;
22
using namespace lldb_private::dwarf;
23
using namespace lldb_private::plugin::dwarf;
24
25
namespace {
26
27
/// Iterate through all DIEs elaborating (i.e. reachable by a chain of
28
/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For
29
/// convenience, the starting die is included in the sequence as the first
30
/// item.
31
class ElaboratingDIEIterator
32
: public llvm::iterator_facade_base<
33
ElaboratingDIEIterator, std::input_iterator_tag, DWARFDIE,
34
std::ptrdiff_t, DWARFDIE *, DWARFDIE *> {
35
36
// The operating invariant is: top of m_worklist contains the "current" item
37
// and the rest of the list are items yet to be visited. An empty worklist
38
// means we've reached the end.
39
// Infinite recursion is prevented by maintaining a list of seen DIEs.
40
// Container sizes are optimized for the case of following DW_AT_specification
41
// and DW_AT_abstract_origin just once.
42
llvm::SmallVector<DWARFDIE, 2> m_worklist;
43
llvm::SmallSet<DWARFDebugInfoEntry *, 3> m_seen;
44
45
void Next() {
46
assert(!m_worklist.empty() && "Incrementing end iterator?");
47
48
// Pop the current item from the list.
49
DWARFDIE die = m_worklist.back();
50
m_worklist.pop_back();
51
52
// And add back any items that elaborate it.
53
for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) {
54
if (DWARFDIE d = die.GetReferencedDIE(attr))
55
if (m_seen.insert(die.GetDIE()).second)
56
m_worklist.push_back(d);
57
}
58
}
59
60
public:
61
/// An iterator starting at die d.
62
explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {}
63
64
/// End marker
65
ElaboratingDIEIterator() = default;
66
67
const DWARFDIE &operator*() const { return m_worklist.back(); }
68
ElaboratingDIEIterator &operator++() {
69
Next();
70
return *this;
71
}
72
73
friend bool operator==(const ElaboratingDIEIterator &a,
74
const ElaboratingDIEIterator &b) {
75
if (a.m_worklist.empty() || b.m_worklist.empty())
76
return a.m_worklist.empty() == b.m_worklist.empty();
77
return a.m_worklist.back() == b.m_worklist.back();
78
}
79
};
80
81
llvm::iterator_range<ElaboratingDIEIterator>
82
elaborating_dies(const DWARFDIE &die) {
83
return llvm::make_range(ElaboratingDIEIterator(die),
84
ElaboratingDIEIterator());
85
}
86
} // namespace
87
88
DWARFDIE
89
DWARFDIE::GetParent() const {
90
if (IsValid())
91
return DWARFDIE(m_cu, m_die->GetParent());
92
else
93
return DWARFDIE();
94
}
95
96
DWARFDIE
97
DWARFDIE::GetFirstChild() const {
98
if (IsValid())
99
return DWARFDIE(m_cu, m_die->GetFirstChild());
100
else
101
return DWARFDIE();
102
}
103
104
DWARFDIE
105
DWARFDIE::GetSibling() const {
106
if (IsValid())
107
return DWARFDIE(m_cu, m_die->GetSibling());
108
else
109
return DWARFDIE();
110
}
111
112
DWARFDIE
113
DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const {
114
if (IsValid())
115
return m_die->GetAttributeValueAsReference(GetCU(), attr);
116
else
117
return {};
118
}
119
120
DWARFDIE
121
DWARFDIE::GetDIE(dw_offset_t die_offset) const {
122
if (IsValid())
123
return m_cu->GetDIE(die_offset);
124
else
125
return DWARFDIE();
126
}
127
128
DWARFDIE
129
DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const {
130
if (IsValid()) {
131
DWARFUnit *cu = GetCU();
132
const bool check_specification_or_abstract_origin = true;
133
DWARFFormValue form_value;
134
if (m_die->GetAttributeValue(cu, attr, form_value, nullptr,
135
check_specification_or_abstract_origin))
136
return form_value.Reference();
137
}
138
return DWARFDIE();
139
}
140
141
DWARFDIE
142
DWARFDIE::LookupDeepestBlock(lldb::addr_t address) const {
143
if (!IsValid())
144
return DWARFDIE();
145
146
DWARFDIE result;
147
bool check_children = false;
148
bool match_addr_range = false;
149
switch (Tag()) {
150
case DW_TAG_class_type:
151
case DW_TAG_namespace:
152
case DW_TAG_structure_type:
153
case DW_TAG_common_block:
154
check_children = true;
155
break;
156
case DW_TAG_compile_unit:
157
case DW_TAG_module:
158
case DW_TAG_catch_block:
159
case DW_TAG_subprogram:
160
case DW_TAG_try_block:
161
case DW_TAG_partial_unit:
162
match_addr_range = true;
163
break;
164
case DW_TAG_lexical_block:
165
case DW_TAG_inlined_subroutine:
166
check_children = true;
167
match_addr_range = true;
168
break;
169
default:
170
break;
171
}
172
173
if (match_addr_range) {
174
DWARFRangeList ranges =
175
m_die->GetAttributeAddressRanges(m_cu, /*check_hi_lo_pc=*/true);
176
if (ranges.FindEntryThatContains(address)) {
177
check_children = true;
178
switch (Tag()) {
179
default:
180
break;
181
182
case DW_TAG_inlined_subroutine: // Inlined Function
183
case DW_TAG_lexical_block: // Block { } in code
184
result = *this;
185
break;
186
}
187
} else {
188
check_children = false;
189
}
190
}
191
192
if (check_children) {
193
for (DWARFDIE child : children()) {
194
if (DWARFDIE child_result = child.LookupDeepestBlock(address))
195
return child_result;
196
}
197
}
198
return result;
199
}
200
201
const char *DWARFDIE::GetMangledName() const {
202
if (IsValid())
203
return m_die->GetMangledName(m_cu);
204
else
205
return nullptr;
206
}
207
208
const char *DWARFDIE::GetPubname() const {
209
if (IsValid())
210
return m_die->GetPubname(m_cu);
211
else
212
return nullptr;
213
}
214
215
// GetName
216
//
217
// Get value of the DW_AT_name attribute and place that value into the supplied
218
// stream object. If the DIE is a NULL object "NULL" is placed into the stream,
219
// and if no DW_AT_name attribute exists for the DIE then nothing is printed.
220
void DWARFDIE::GetName(Stream &s) const {
221
if (!IsValid())
222
return;
223
if (GetDIE()->IsNULL()) {
224
s.PutCString("NULL");
225
return;
226
}
227
const char *name = GetDIE()->GetAttributeValueAsString(GetCU(), DW_AT_name, nullptr, true);
228
if (!name)
229
return;
230
s.PutCString(name);
231
}
232
233
// AppendTypeName
234
//
235
// Follows the type name definition down through all needed tags to end up with
236
// a fully qualified type name and dump the results to the supplied stream.
237
// This is used to show the name of types given a type identifier.
238
void DWARFDIE::AppendTypeName(Stream &s) const {
239
if (!IsValid())
240
return;
241
if (GetDIE()->IsNULL()) {
242
s.PutCString("NULL");
243
return;
244
}
245
if (const char *name = GetPubname()) {
246
s.PutCString(name);
247
return;
248
}
249
switch (Tag()) {
250
case DW_TAG_array_type:
251
break; // print out a "[]" after printing the full type of the element
252
// below
253
case DW_TAG_base_type:
254
s.PutCString("base ");
255
break;
256
case DW_TAG_class_type:
257
s.PutCString("class ");
258
break;
259
case DW_TAG_const_type:
260
s.PutCString("const ");
261
break;
262
case DW_TAG_enumeration_type:
263
s.PutCString("enum ");
264
break;
265
case DW_TAG_file_type:
266
s.PutCString("file ");
267
break;
268
case DW_TAG_interface_type:
269
s.PutCString("interface ");
270
break;
271
case DW_TAG_packed_type:
272
s.PutCString("packed ");
273
break;
274
case DW_TAG_pointer_type:
275
break; // print out a '*' after printing the full type below
276
case DW_TAG_ptr_to_member_type:
277
break; // print out a '*' after printing the full type below
278
case DW_TAG_reference_type:
279
break; // print out a '&' after printing the full type below
280
case DW_TAG_restrict_type:
281
s.PutCString("restrict ");
282
break;
283
case DW_TAG_set_type:
284
s.PutCString("set ");
285
break;
286
case DW_TAG_shared_type:
287
s.PutCString("shared ");
288
break;
289
case DW_TAG_string_type:
290
s.PutCString("string ");
291
break;
292
case DW_TAG_structure_type:
293
s.PutCString("struct ");
294
break;
295
case DW_TAG_subrange_type:
296
s.PutCString("subrange ");
297
break;
298
case DW_TAG_subroutine_type:
299
s.PutCString("function ");
300
break;
301
case DW_TAG_thrown_type:
302
s.PutCString("thrown ");
303
break;
304
case DW_TAG_union_type:
305
s.PutCString("union ");
306
break;
307
case DW_TAG_unspecified_type:
308
s.PutCString("unspecified ");
309
break;
310
case DW_TAG_volatile_type:
311
s.PutCString("volatile ");
312
break;
313
case DW_TAG_LLVM_ptrauth_type: {
314
unsigned key = GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_key, 0);
315
bool isAddressDiscriminated = GetAttributeValueAsUnsigned(
316
DW_AT_LLVM_ptrauth_address_discriminated, 0);
317
unsigned extraDiscriminator =
318
GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_extra_discriminator, 0);
319
bool isaPointer =
320
GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_isa_pointer, 0);
321
bool authenticatesNullValues = GetAttributeValueAsUnsigned(
322
DW_AT_LLVM_ptrauth_authenticates_null_values, 0);
323
unsigned authenticationMode =
324
GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_authentication_mode, 3);
325
326
s.Printf("__ptrauth(%d, %d, 0x0%x, %d, %d, %d)", key,
327
isAddressDiscriminated, extraDiscriminator, isaPointer,
328
authenticatesNullValues, authenticationMode);
329
break;
330
}
331
default:
332
return;
333
}
334
335
// Follow the DW_AT_type if possible
336
if (DWARFDIE next_die = GetAttributeValueAsReferenceDIE(DW_AT_type))
337
next_die.AppendTypeName(s);
338
339
switch (Tag()) {
340
case DW_TAG_array_type:
341
s.PutCString("[]");
342
break;
343
case DW_TAG_pointer_type:
344
s.PutChar('*');
345
break;
346
case DW_TAG_ptr_to_member_type:
347
s.PutChar('*');
348
break;
349
case DW_TAG_reference_type:
350
s.PutChar('&');
351
break;
352
default:
353
break;
354
}
355
}
356
357
lldb_private::Type *DWARFDIE::ResolveType() const {
358
if (IsValid())
359
return GetDWARF()->ResolveType(*this, true);
360
else
361
return nullptr;
362
}
363
364
lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const {
365
if (SymbolFileDWARF *dwarf = GetDWARF())
366
return dwarf->ResolveTypeUID(die, true);
367
return nullptr;
368
}
369
370
static void GetDeclContextImpl(DWARFDIE die,
371
llvm::SmallSet<lldb::user_id_t, 4> &seen,
372
std::vector<CompilerContext> &context) {
373
// Stop if we hit a cycle.
374
while (die && seen.insert(die.GetID()).second) {
375
// Handle outline member function DIEs by following the specification.
376
if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_specification)) {
377
die = spec;
378
continue;
379
}
380
// To find the name of a type in a type unit, we must follow the signature.
381
if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) {
382
die = spec;
383
continue;
384
}
385
386
// Add this DIE's contribution at the end of the chain.
387
auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {
388
context.push_back({kind, ConstString(name)});
389
};
390
switch (die.Tag()) {
391
case DW_TAG_module:
392
push_ctx(CompilerContextKind::Module, die.GetName());
393
break;
394
case DW_TAG_namespace:
395
push_ctx(CompilerContextKind::Namespace, die.GetName());
396
break;
397
case DW_TAG_class_type:
398
case DW_TAG_structure_type:
399
push_ctx(CompilerContextKind::ClassOrStruct, die.GetName());
400
break;
401
case DW_TAG_union_type:
402
push_ctx(CompilerContextKind::Union, die.GetName());
403
break;
404
case DW_TAG_enumeration_type:
405
push_ctx(CompilerContextKind::Enum, die.GetName());
406
break;
407
case DW_TAG_subprogram:
408
push_ctx(CompilerContextKind::Function, die.GetName());
409
break;
410
case DW_TAG_variable:
411
push_ctx(CompilerContextKind::Variable, die.GetPubname());
412
break;
413
case DW_TAG_typedef:
414
push_ctx(CompilerContextKind::Typedef, die.GetName());
415
break;
416
default:
417
break;
418
}
419
// Now process the parent.
420
die = die.GetParent();
421
}
422
}
423
424
std::vector<CompilerContext> DWARFDIE::GetDeclContext() const {
425
llvm::SmallSet<lldb::user_id_t, 4> seen;
426
std::vector<CompilerContext> context;
427
GetDeclContextImpl(*this, seen, context);
428
std::reverse(context.begin(), context.end());
429
return context;
430
}
431
432
static void GetTypeLookupContextImpl(DWARFDIE die,
433
llvm::SmallSet<lldb::user_id_t, 4> &seen,
434
std::vector<CompilerContext> &context) {
435
// Stop if we hit a cycle.
436
while (die && seen.insert(die.GetID()).second) {
437
// To find the name of a type in a type unit, we must follow the signature.
438
if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) {
439
die = spec;
440
continue;
441
}
442
443
// If there is no name, then there is no need to look anything up for this
444
// DIE.
445
const char *name = die.GetName();
446
if (!name || !name[0])
447
return;
448
449
// Add this DIE's contribution at the end of the chain.
450
auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) {
451
context.push_back({kind, ConstString(name)});
452
};
453
switch (die.Tag()) {
454
case DW_TAG_namespace:
455
push_ctx(CompilerContextKind::Namespace, die.GetName());
456
break;
457
case DW_TAG_class_type:
458
case DW_TAG_structure_type:
459
push_ctx(CompilerContextKind::ClassOrStruct, die.GetName());
460
break;
461
case DW_TAG_union_type:
462
push_ctx(CompilerContextKind::Union, die.GetName());
463
break;
464
case DW_TAG_enumeration_type:
465
push_ctx(CompilerContextKind::Enum, die.GetName());
466
break;
467
case DW_TAG_variable:
468
push_ctx(CompilerContextKind::Variable, die.GetPubname());
469
break;
470
case DW_TAG_typedef:
471
push_ctx(CompilerContextKind::Typedef, die.GetName());
472
break;
473
case DW_TAG_base_type:
474
push_ctx(CompilerContextKind::Builtin, name);
475
break;
476
// If any of the tags below appear in the parent chain, stop the decl
477
// context and return. Prior to these being in here, if a type existed in a
478
// namespace "a" like "a::my_struct", but we also have a function in that
479
// same namespace "a" which contained a type named "my_struct", both would
480
// return "a::my_struct" as the declaration context since the
481
// DW_TAG_subprogram would be skipped and its parent would be found.
482
case DW_TAG_compile_unit:
483
case DW_TAG_type_unit:
484
case DW_TAG_subprogram:
485
case DW_TAG_lexical_block:
486
case DW_TAG_inlined_subroutine:
487
return;
488
default:
489
break;
490
}
491
// Now process the parent.
492
die = die.GetParent();
493
}
494
}
495
496
std::vector<CompilerContext> DWARFDIE::GetTypeLookupContext() const {
497
llvm::SmallSet<lldb::user_id_t, 4> seen;
498
std::vector<CompilerContext> context;
499
GetTypeLookupContextImpl(*this, seen, context);
500
std::reverse(context.begin(), context.end());
501
return context;
502
}
503
504
static DWARFDeclContext GetDWARFDeclContextImpl(DWARFDIE die) {
505
DWARFDeclContext dwarf_decl_ctx;
506
while (die) {
507
const dw_tag_t tag = die.Tag();
508
if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)
509
break;
510
dwarf_decl_ctx.AppendDeclContext(tag, die.GetName());
511
DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE();
512
if (parent_decl_ctx_die == die)
513
break;
514
die = parent_decl_ctx_die;
515
}
516
return dwarf_decl_ctx;
517
}
518
519
DWARFDeclContext DWARFDIE::GetDWARFDeclContext() const {
520
return GetDWARFDeclContextImpl(*this);
521
}
522
523
static DWARFDIE GetParentDeclContextDIEImpl(DWARFDIE die) {
524
DWARFDIE orig_die = die;
525
while (die) {
526
// If this is the original DIE that we are searching for a declaration for,
527
// then don't look in the cache as we don't want our own decl context to be
528
// our decl context...
529
if (die != orig_die) {
530
switch (die.Tag()) {
531
case DW_TAG_compile_unit:
532
case DW_TAG_partial_unit:
533
case DW_TAG_namespace:
534
case DW_TAG_structure_type:
535
case DW_TAG_union_type:
536
case DW_TAG_class_type:
537
return die;
538
539
default:
540
break;
541
}
542
}
543
544
if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification)) {
545
if (DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE())
546
return decl_ctx_die;
547
}
548
549
if (DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin)) {
550
if (DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE())
551
return decl_ctx_die;
552
}
553
554
die = die.GetParent();
555
}
556
return DWARFDIE();
557
}
558
559
DWARFDIE
560
DWARFDIE::GetParentDeclContextDIE() const {
561
return GetParentDeclContextDIEImpl(*this);
562
}
563
564
bool DWARFDIE::IsStructUnionOrClass() const {
565
const dw_tag_t tag = Tag();
566
return tag == DW_TAG_class_type || tag == DW_TAG_structure_type ||
567
tag == DW_TAG_union_type;
568
}
569
570
bool DWARFDIE::IsMethod() const {
571
for (DWARFDIE d : elaborating_dies(*this))
572
if (d.GetParent().IsStructUnionOrClass())
573
return true;
574
return false;
575
}
576
577
bool DWARFDIE::GetDIENamesAndRanges(
578
const char *&name, const char *&mangled, DWARFRangeList &ranges,
579
std::optional<int> &decl_file, std::optional<int> &decl_line,
580
std::optional<int> &decl_column, std::optional<int> &call_file,
581
std::optional<int> &call_line, std::optional<int> &call_column,
582
lldb_private::DWARFExpressionList *frame_base) const {
583
if (IsValid()) {
584
return m_die->GetDIENamesAndRanges(
585
GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column,
586
call_file, call_line, call_column, frame_base);
587
} else
588
return false;
589
}
590
591
llvm::iterator_range<DWARFDIE::child_iterator> DWARFDIE::children() const {
592
return llvm::make_range(child_iterator(*this), child_iterator());
593
}
594
595