LLVM 17.0.0git
DWARFTypePrinter.cpp
Go to the documentation of this file.
5namespace llvm {
6using namespace dwarf;
8 StringRef TagStr = TagString(T);
9 static constexpr StringRef Prefix = "DW_TAG_";
10 static constexpr StringRef Suffix = "_type";
11 if (!TagStr.startswith(Prefix) || !TagStr.endswith(Suffix))
12 return;
13 OS << TagStr.substr(Prefix.size(),
14 TagStr.size() - (Prefix.size() + Suffix.size()))
15 << " ";
16}
17
19 for (const DWARFDie &C : D.children()) {
20 if (C.getTag() != DW_TAG_subrange_type)
21 continue;
22 std::optional<uint64_t> LB;
23 std::optional<uint64_t> Count;
24 std::optional<uint64_t> UB;
25 std::optional<unsigned> DefaultLB;
26 if (std::optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
27 LB = L->getAsUnsignedConstant();
28 if (std::optional<DWARFFormValue> CountV = C.find(DW_AT_count))
29 Count = CountV->getAsUnsignedConstant();
30 if (std::optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
31 UB = UpperV->getAsUnsignedConstant();
32 if (std::optional<DWARFFormValue> LV =
33 D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
34 if (std::optional<uint64_t> LC = LV->getAsUnsignedConstant())
35 if ((DefaultLB =
36 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
37 if (LB && *LB == *DefaultLB)
38 LB = std::nullopt;
39 if (!LB && !Count && !UB)
40 OS << "[]";
41 else if (!LB && (Count || UB) && DefaultLB)
42 OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
43 else {
44 OS << "[[";
45 if (LB)
46 OS << *LB;
47 else
48 OS << '?';
49 OS << ", ";
50 if (Count)
51 if (LB)
52 OS << *LB + *Count;
53 else
54 OS << "? + " << *Count;
55 else if (UB)
56 OS << *UB + 1;
57 else
58 OS << '?';
59 OS << ")]";
60 }
61 }
62 EndedWithTemplate = false;
63}
64
66 dwarf::Attribute Attr = DW_AT_type) {
67 return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
68}
70 return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
71}
73 while (D && (D.getTag() == DW_TAG_const_type ||
74 D.getTag() == DW_TAG_volatile_type))
76 return D;
77}
78
81 return D && (D.getTag() == DW_TAG_subroutine_type ||
82 D.getTag() == DW_TAG_array_type);
83}
84
86 StringRef Ptr) {
88 if (Word)
89 OS << ' ';
90 if (needsParens(Inner))
91 OS << '(';
92 OS << Ptr;
93 Word = false;
94 EndedWithTemplate = false;
95}
96
99 std::string *OriginalFullName) {
100 Word = true;
101 if (!D) {
102 OS << "void";
103 return DWARFDie();
104 }
105 DWARFDie InnerDIE;
106 auto Inner = [&] { return InnerDIE = resolveReferencedType(D); };
107 const dwarf::Tag T = D.getTag();
108 switch (T) {
109 case DW_TAG_pointer_type: {
110 appendPointerLikeTypeBefore(D, Inner(), "*");
111 break;
112 }
113 case DW_TAG_subroutine_type: {
115 if (Word) {
116 OS << ' ';
117 }
118 Word = false;
119 break;
120 }
121 case DW_TAG_array_type: {
123 break;
124 }
125 case DW_TAG_reference_type:
126 appendPointerLikeTypeBefore(D, Inner(), "&");
127 break;
128 case DW_TAG_rvalue_reference_type:
129 appendPointerLikeTypeBefore(D, Inner(), "&&");
130 break;
131 case DW_TAG_ptr_to_member_type: {
133 if (needsParens(InnerDIE))
134 OS << '(';
135 else if (Word)
136 OS << ' ';
137 if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) {
139 EndedWithTemplate = false;
140 OS << "::";
141 }
142 OS << "*";
143 Word = false;
144 break;
145 }
146 case DW_TAG_LLVM_ptrauth_type:
148 break;
149 case DW_TAG_const_type:
150 case DW_TAG_volatile_type:
152 break;
153 case DW_TAG_namespace: {
154 if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
155 OS << Name;
156 else
157 OS << "(anonymous namespace)";
158 break;
159 }
160 case DW_TAG_unspecified_type: {
161 StringRef TypeName = D.getShortName();
162 if (TypeName == "decltype(nullptr)")
163 TypeName = "std::nullptr_t";
164 Word = true;
165 OS << TypeName;
166 EndedWithTemplate = false;
167 break;
168 }
169 /*
170 case DW_TAG_structure_type:
171 case DW_TAG_class_type:
172 case DW_TAG_enumeration_type:
173 case DW_TAG_base_type:
174 */
175 default: {
176 const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
177 if (!NamePtr) {
178 appendTypeTagName(D.getTag());
179 return DWARFDie();
180 }
181 Word = true;
182 StringRef Name = NamePtr;
183 static constexpr StringRef MangledPrefix = "_STN|";
184 if (Name.startswith(MangledPrefix)) {
185 Name = Name.drop_front(MangledPrefix.size());
186 auto Separator = Name.find('|');
187 assert(Separator != StringRef::npos);
188 StringRef BaseName = Name.substr(0, Separator);
189 StringRef TemplateArgs = Name.substr(Separator + 1);
190 if (OriginalFullName)
191 *OriginalFullName = (BaseName + TemplateArgs).str();
192 Name = BaseName;
193 } else
194 EndedWithTemplate = Name.endswith(">");
195 OS << Name;
196 // This check would be insufficient for operator overloads like
197 // "operator>>" - but for now Clang doesn't try to simplify them, so this
198 // is OK. Add more nuanced operator overload handling here if/when needed.
199 if (Name.endswith(">"))
200 break;
202 break;
203
205 OS << ' ';
206 OS << '>';
207 EndedWithTemplate = true;
208 Word = true;
209 break;
210 }
211 }
212 return InnerDIE;
213}
214
216 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
217 if (!D)
218 return;
219 switch (D.getTag()) {
220 case DW_TAG_subroutine_type: {
221 appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
222 false);
223 break;
224 }
225 case DW_TAG_array_type: {
227 break;
228 }
229 case DW_TAG_const_type:
230 case DW_TAG_volatile_type:
232 break;
233 case DW_TAG_ptr_to_member_type:
234 case DW_TAG_reference_type:
235 case DW_TAG_rvalue_reference_type:
236 case DW_TAG_pointer_type: {
237 if (needsParens(Inner))
238 OS << ')';
240 /*SkipFirstParamIfArtificial=*/D.getTag() ==
241 DW_TAG_ptr_to_member_type);
242 break;
243 }
244 case DW_TAG_LLVM_ptrauth_type: {
245 auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
246 if (auto Form = D.find(Attr))
247 return *Form->getAsUnsignedConstant();
248 return 0;
249 };
251 if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer))
252 optionsVec.push_back("isa-pointer");
253 if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values))
254 optionsVec.push_back("authenticates-null-values");
255 std::string options;
256 for (const auto *option : optionsVec) {
257 if (options.size())
258 options += ",";
259 options += option;
260 }
261 if (options.size())
262 options = ", \"" + options + "\"";
263 std::string PtrauthString;
264 llvm::raw_string_ostream PtrauthStream(PtrauthString);
265 PtrauthStream
266 << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", "
267 << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0"
268 << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), true)
269 << options << ")";
270 OS << PtrauthStream.str();
271 break;
272 }
273 /*
274 case DW_TAG_structure_type:
275 case DW_TAG_class_type:
276 case DW_TAG_enumeration_type:
277 case DW_TAG_base_type:
278 case DW_TAG_namespace:
279 */
280 default:
281 break;
282 }
283}
284
285/// Returns True if the DIE TAG is one of the ones that is scopped.
287 switch (Tag) {
288 case dwarf::DW_TAG_structure_type:
289 case dwarf::DW_TAG_class_type:
290 case dwarf::DW_TAG_union_type:
291 case dwarf::DW_TAG_namespace:
292 case dwarf::DW_TAG_enumeration_type:
293 return true;
294 default:
295 break;
296 }
297 return false;
298}
300 if (D && scopedTAGs(D.getTag()))
301 appendScopes(D.getParent());
303}
305 if (D && scopedTAGs(D.getTag()))
306 appendScopes(D.getParent());
308}
310 bool *FirstParameter) {
311 bool FirstParameterValue = true;
312 bool IsTemplate = false;
313 if (!FirstParameter)
314 FirstParameter = &FirstParameterValue;
315 for (const DWARFDie &C : D) {
316 auto Sep = [&] {
317 if (*FirstParameter)
318 OS << '<';
319 else
320 OS << ", ";
321 IsTemplate = true;
322 EndedWithTemplate = false;
323 *FirstParameter = false;
324 };
325 if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
326 IsTemplate = true;
327 appendTemplateParameters(C, FirstParameter);
328 }
329 if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
331 Sep();
332 if (T.getTag() == DW_TAG_enumeration_type) {
333 OS << '(';
335 OS << ')';
336 auto V = C.find(DW_AT_const_value);
337 OS << std::to_string(*V->getAsSignedConstant());
338 continue;
339 }
340 // /Maybe/ we could do pointer type parameters, looking for the
341 // symbol in the ELF symbol table to get back to the variable...
342 // but probably not worth it.
343 if (T.getTag() == DW_TAG_pointer_type)
344 continue;
345 const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
346 assert(RawName);
347 StringRef Name = RawName;
348 auto V = C.find(DW_AT_const_value);
349 bool IsQualifiedChar = false;
350 if (Name == "bool") {
351 OS << (*V->getAsUnsignedConstant() ? "true" : "false");
352 } else if (Name == "short") {
353 OS << "(short)";
354 OS << std::to_string(*V->getAsSignedConstant());
355 } else if (Name == "unsigned short") {
356 OS << "(unsigned short)";
357 OS << std::to_string(*V->getAsSignedConstant());
358 } else if (Name == "int")
359 OS << std::to_string(*V->getAsSignedConstant());
360 else if (Name == "long") {
361 OS << std::to_string(*V->getAsSignedConstant());
362 OS << "L";
363 } else if (Name == "long long") {
364 OS << std::to_string(*V->getAsSignedConstant());
365 OS << "LL";
366 } else if (Name == "unsigned int") {
367 OS << std::to_string(*V->getAsUnsignedConstant());
368 OS << "U";
369 } else if (Name == "unsigned long") {
370 OS << std::to_string(*V->getAsUnsignedConstant());
371 OS << "UL";
372 } else if (Name == "unsigned long long") {
373 OS << std::to_string(*V->getAsUnsignedConstant());
374 OS << "ULL";
375 } else if (Name == "char" ||
376 (IsQualifiedChar =
377 (Name == "unsigned char" || Name == "signed char"))) {
378 // FIXME: check T's DW_AT_type to see if it's signed or not (since
379 // char signedness is implementation defined).
380 auto Val = *V->getAsSignedConstant();
381 // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
382 // (doesn't actually support different character types/widths, sign
383 // handling's not done, and doesn't correctly test if a character is
384 // printable or needs to use a numeric escape sequence instead)
385 if (IsQualifiedChar) {
386 OS << '(';
387 OS << Name;
388 OS << ')';
389 }
390 switch (Val) {
391 case '\\':
392 OS << "'\\\\'";
393 break;
394 case '\'':
395 OS << "'\\''";
396 break;
397 case '\a':
398 // TODO: K&R: the meaning of '\\a' is different in traditional C
399 OS << "'\\a'";
400 break;
401 case '\b':
402 OS << "'\\b'";
403 break;
404 case '\f':
405 OS << "'\\f'";
406 break;
407 case '\n':
408 OS << "'\\n'";
409 break;
410 case '\r':
411 OS << "'\\r'";
412 break;
413 case '\t':
414 OS << "'\\t'";
415 break;
416 case '\v':
417 OS << "'\\v'";
418 break;
419 default:
420 if ((Val & ~0xFFu) == ~0xFFu)
421 Val &= 0xFFu;
422 if (Val < 127 && Val >= 32) {
423 OS << "'";
424 OS << (char)Val;
425 OS << "'";
426 } else if (Val < 256)
427 OS << to_string(llvm::format("'\\x%02x'", Val));
428 else if (Val <= 0xFFFF)
429 OS << to_string(llvm::format("'\\u%04x'", Val));
430 else
431 OS << to_string(llvm::format("'\\U%08x'", Val));
432 }
433 }
434 continue;
435 }
436 if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
437 const char *RawName =
438 dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
439 assert(RawName);
440 StringRef Name = RawName;
441 Sep();
442 OS << Name;
443 continue;
444 }
445 if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
446 continue;
447 auto TypeAttr = C.find(DW_AT_type);
448 Sep();
449 appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
450 : DWARFDie());
451 }
452 if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
453 OS << '<';
454 EndedWithTemplate = false;
455 }
456 return IsTemplate;
457}
459 DWARFDie &C, DWARFDie &V) {
460 (N.getTag() == DW_TAG_const_type ? C : V) = N;
462 if (T) {
463 auto Tag = T.getTag();
464 if (Tag == DW_TAG_const_type) {
465 C = T;
467 } else if (Tag == DW_TAG_volatile_type) {
468 V = T;
470 }
471 }
472}
474 DWARFDie C;
475 DWARFDie V;
476 DWARFDie T;
478 if (T && T.getTag() == DW_TAG_subroutine_type)
480 V.isValid());
481 else
483}
485 DWARFDie C;
486 DWARFDie V;
487 DWARFDie T;
489 bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
490 DWARFDie A = T;
491 while (A && A.getTag() == DW_TAG_array_type)
493 bool Leading =
494 (!A || (A.getTag() != DW_TAG_pointer_type &&
495 A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
496 !Subroutine;
497 if (Leading) {
498 if (C)
499 OS << "const ";
500 if (V)
501 OS << "volatile ";
502 }
504 if (!Leading && !Subroutine) {
505 Word = true;
506 if (C)
507 OS << "const";
508 if (V) {
509 if (C)
510 OS << ' ';
511 OS << "volatile";
512 }
513 }
514}
516 std::string *OriginalFullName) {
517 // FIXME: We should have pretty printers per language. Currently we print
518 // everything as if it was C++ and fall back to the TAG type name.
519 DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
521}
523 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
524 bool Volatile) {
525 DWARFDie FirstParamIfArtificial;
526 OS << '(';
527 EndedWithTemplate = false;
528 bool First = true;
529 bool RealFirst = true;
530 for (DWARFDie P : D) {
531 if (P.getTag() != DW_TAG_formal_parameter &&
532 P.getTag() != DW_TAG_unspecified_parameters)
533 return;
535 if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
536 FirstParamIfArtificial = T;
537 RealFirst = false;
538 continue;
539 }
540 if (!First) {
541 OS << ", ";
542 }
543 First = false;
544 if (P.getTag() == DW_TAG_unspecified_parameters)
545 OS << "...";
546 else
548 }
549 EndedWithTemplate = false;
550 OS << ')';
551 if (FirstParamIfArtificial) {
552 if (DWARFDie P = FirstParamIfArtificial) {
553 if (P.getTag() == DW_TAG_pointer_type) {
554 auto CVStep = [&](DWARFDie CV) {
555 if (DWARFDie U = resolveReferencedType(CV)) {
556 Const |= U.getTag() == DW_TAG_const_type;
557 Volatile |= U.getTag() == DW_TAG_volatile_type;
558 return U;
559 }
560 return DWARFDie();
561 };
562 if (DWARFDie CV = CVStep(P)) {
563 CVStep(CV);
564 }
565 }
566 }
567 }
568
569 if (auto CC = D.find(DW_AT_calling_convention)) {
570 switch (*CC->getAsUnsignedConstant()) {
571 case CallingConvention::DW_CC_BORLAND_stdcall:
572 OS << " __attribute__((stdcall))";
573 break;
574 case CallingConvention::DW_CC_BORLAND_msfastcall:
575 OS << " __attribute__((fastcall))";
576 break;
577 case CallingConvention::DW_CC_BORLAND_thiscall:
578 OS << " __attribute__((thiscall))";
579 break;
580 case CallingConvention::DW_CC_LLVM_vectorcall:
581 OS << " __attribute__((vectorcall))";
582 break;
583 case CallingConvention::DW_CC_BORLAND_pascal:
584 OS << " __attribute__((pascal))";
585 break;
586 case CallingConvention::DW_CC_LLVM_Win64:
587 OS << " __attribute__((ms_abi))";
588 break;
589 case CallingConvention::DW_CC_LLVM_X86_64SysV:
590 OS << " __attribute__((sysv_abi))";
591 break;
592 case CallingConvention::DW_CC_LLVM_AAPCS:
593 // AArch64VectorCall missing?
594 OS << " __attribute__((pcs(\"aapcs\")))";
595 break;
596 case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
597 OS << " __attribute__((pcs(\"aapcs-vfp\")))";
598 break;
599 case CallingConvention::DW_CC_LLVM_IntelOclBicc:
600 OS << " __attribute__((intel_ocl_bicc))";
601 break;
602 case CallingConvention::DW_CC_LLVM_SpirFunction:
603 case CallingConvention::DW_CC_LLVM_OpenCLKernel:
604 // These aren't available as attributes, but maybe we should still
605 // render them somehow? (Clang doesn't render them, but that's an issue
606 // for template names too - since then the DWARF names of templates
607 // instantiated with function types with these calling conventions won't
608 // have distinct names - so we'd need to fix that too)
609 break;
610 case CallingConvention::DW_CC_LLVM_Swift:
611 // SwiftAsync missing
612 OS << " __attribute__((swiftcall))";
613 break;
614 case CallingConvention::DW_CC_LLVM_PreserveMost:
615 OS << " __attribute__((preserve_most))";
616 break;
617 case CallingConvention::DW_CC_LLVM_PreserveAll:
618 OS << " __attribute__((preserve_all))";
619 break;
620 case CallingConvention::DW_CC_LLVM_X86RegCall:
621 OS << " __attribute__((regcall))";
622 break;
623 }
624 }
625
626 if (Const)
627 OS << " const";
628 if (Volatile)
629 OS << " volatile";
630 if (D.find(DW_AT_reference))
631 OS << " &";
632 if (D.find(DW_AT_rvalue_reference))
633 OS << " &&";
634
636}
638 if (D.getTag() == DW_TAG_compile_unit)
639 return;
640 if (D.getTag() == DW_TAG_type_unit)
641 return;
642 if (D.getTag() == DW_TAG_skeleton_unit)
643 return;
644 if (D.getTag() == DW_TAG_subprogram)
645 return;
646 if (D.getTag() == DW_TAG_lexical_block)
647 return;
648 D = D.resolveTypeUnitReference();
649 if (DWARFDie P = D.getParent())
652 OS << "::";
653}
654} // namespace llvm
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
std::string Name
#define F(x, y, z)
Definition: MD5.cpp:55
#define T
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition: DWARFDie.h:42
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:569
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
bool endswith(StringRef Suffix) const
Definition: StringRef.h:277
static constexpr size_t npos
Definition: StringRef.h:52
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:642
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:660
StringRef TagString(unsigned Tag)
Definition: Dwarf.cpp:21
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
Attribute
Attributes.
Definition: Dwarf.h:123
std::optional< unsigned > LanguageLowerBound(SourceLanguage L)
Definition: Dwarf.cpp:369
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
SourceLanguage
Definition: Dwarf.h:199
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::string to_string(const T &Value)
Definition: ScopedPrinter.h:85
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
static DWARFDie resolveReferencedType(DWARFDie D, dwarf::Attribute Attr=DW_AT_type)
static bool scopedTAGs(dwarf::Tag Tag)
Returns True if the DIE TAG is one of the ones that is scopped.
#define N
void appendQualifiedName(DWARFDie D)
void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial=false)
void appendUnqualifiedName(DWARFDie D, std::string *OriginalFullName=nullptr)
Recursively append the DIE type name when applicable.
DWARFDie appendUnqualifiedNameBefore(DWARFDie D, std::string *OriginalFullName=nullptr)
void appendSubroutineNameAfter(DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const, bool Volatile)
bool appendTemplateParameters(DWARFDie D, bool *FirstParameter=nullptr)
bool needsParens(DWARFDie D)
void appendConstVolatileQualifierBefore(DWARFDie N)
void appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, StringRef Ptr)
DWARFDie appendQualifiedNameBefore(DWARFDie D)
void decomposeConstVolatile(DWARFDie &N, DWARFDie &T, DWARFDie &C, DWARFDie &V)
void appendConstVolatileQualifierAfter(DWARFDie N)
DWARFDie skipQualifiers(DWARFDie D)
void appendTypeTagName(dwarf::Tag T)
Dump the name encoded in the type tag.
void appendScopes(DWARFDie D)
void appendArrayType(const DWARFDie &D)