1 #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
2 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
3 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
4 #include "llvm/Support/ScopedPrinter.h"
5 namespace llvm {
6 using namespace dwarf;
appendTypeTagName(dwarf::Tag T)7 void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) {
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
appendArrayType(const DWARFDie & D)18 void DWARFTypePrinter::appendArrayType(const DWARFDie &D) {
19 for (const DWARFDie &C : D.children()) {
20 if (C.getTag() != DW_TAG_subrange_type)
21 continue;
22 Optional<uint64_t> LB;
23 Optional<uint64_t> Count;
24 Optional<uint64_t> UB;
25 Optional<unsigned> DefaultLB;
26 if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
27 LB = L->getAsUnsignedConstant();
28 if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
29 Count = CountV->getAsUnsignedConstant();
30 if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
31 UB = UpperV->getAsUnsignedConstant();
32 if (Optional<DWARFFormValue> LV =
33 D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
34 if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
35 if ((DefaultLB =
36 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
37 if (LB && *LB == *DefaultLB)
38 LB = None;
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
resolveReferencedType(DWARFDie D,dwarf::Attribute Attr=DW_AT_type)65 static DWARFDie resolveReferencedType(DWARFDie D,
66 dwarf::Attribute Attr = DW_AT_type) {
67 return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
68 }
resolveReferencedType(DWARFDie D,DWARFFormValue F)69 static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
70 return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
71 }
skipQualifiers(DWARFDie D)72 DWARFDie DWARFTypePrinter::skipQualifiers(DWARFDie D) {
73 while (D && (D.getTag() == DW_TAG_const_type ||
74 D.getTag() == DW_TAG_volatile_type))
75 D = resolveReferencedType(D);
76 return D;
77 }
78
needsParens(DWARFDie D)79 bool DWARFTypePrinter::needsParens(DWARFDie D) {
80 D = skipQualifiers(D);
81 return D && (D.getTag() == DW_TAG_subroutine_type ||
82 D.getTag() == DW_TAG_array_type);
83 }
84
appendPointerLikeTypeBefore(DWARFDie D,DWARFDie Inner,StringRef Ptr)85 void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner,
86 StringRef Ptr) {
87 appendQualifiedNameBefore(Inner);
88 if (Word)
89 OS << ' ';
90 if (needsParens(Inner))
91 OS << '(';
92 OS << Ptr;
93 Word = false;
94 EndedWithTemplate = false;
95 }
96
97 DWARFDie
appendUnqualifiedNameBefore(DWARFDie D,std::string * OriginalFullName)98 DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
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: {
114 appendQualifiedNameBefore(Inner());
115 if (Word) {
116 OS << ' ';
117 }
118 Word = false;
119 break;
120 }
121 case DW_TAG_array_type: {
122 appendQualifiedNameBefore(Inner());
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: {
132 appendQualifiedNameBefore(Inner());
133 if (needsParens(InnerDIE))
134 OS << '(';
135 else if (Word)
136 OS << ' ';
137 if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) {
138 appendQualifiedName(Cont);
139 EndedWithTemplate = false;
140 OS << "::";
141 }
142 OS << "*";
143 Word = false;
144 break;
145 }
146 case DW_TAG_const_type:
147 case DW_TAG_volatile_type:
148 appendConstVolatileQualifierBefore(D);
149 break;
150 case DW_TAG_namespace: {
151 if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
152 OS << Name;
153 else
154 OS << "(anonymous namespace)";
155 break;
156 }
157 case DW_TAG_unspecified_type: {
158 StringRef TypeName = D.getShortName();
159 if (TypeName == "decltype(nullptr)")
160 TypeName = "std::nullptr_t";
161 Word = true;
162 OS << TypeName;
163 EndedWithTemplate = false;
164 break;
165 }
166 /*
167 case DW_TAG_structure_type:
168 case DW_TAG_class_type:
169 case DW_TAG_enumeration_type:
170 case DW_TAG_base_type:
171 */
172 default: {
173 const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
174 if (!NamePtr) {
175 appendTypeTagName(D.getTag());
176 return DWARFDie();
177 }
178 Word = true;
179 StringRef Name = NamePtr;
180 static constexpr StringRef MangledPrefix = "_STN|";
181 if (Name.startswith(MangledPrefix)) {
182 Name = Name.drop_front(MangledPrefix.size());
183 auto Separator = Name.find('|');
184 assert(Separator != StringRef::npos);
185 StringRef BaseName = Name.substr(0, Separator);
186 StringRef TemplateArgs = Name.substr(Separator + 1);
187 if (OriginalFullName)
188 *OriginalFullName = (BaseName + TemplateArgs).str();
189 Name = BaseName;
190 } else
191 EndedWithTemplate = Name.endswith(">");
192 OS << Name;
193 // This check would be insufficient for operator overloads like
194 // "operator>>" - but for now Clang doesn't try to simplify them, so this
195 // is OK. Add more nuanced operator overload handling here if/when needed.
196 if (Name.endswith(">"))
197 break;
198 if (!appendTemplateParameters(D))
199 break;
200
201 if (EndedWithTemplate)
202 OS << ' ';
203 OS << '>';
204 EndedWithTemplate = true;
205 Word = true;
206 break;
207 }
208 }
209 return InnerDIE;
210 }
211
appendUnqualifiedNameAfter(DWARFDie D,DWARFDie Inner,bool SkipFirstParamIfArtificial)212 void DWARFTypePrinter::appendUnqualifiedNameAfter(
213 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
214 if (!D)
215 return;
216 switch (D.getTag()) {
217 case DW_TAG_subroutine_type: {
218 appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
219 false);
220 break;
221 }
222 case DW_TAG_array_type: {
223 appendArrayType(D);
224 break;
225 }
226 case DW_TAG_const_type:
227 case DW_TAG_volatile_type:
228 appendConstVolatileQualifierAfter(D);
229 break;
230 case DW_TAG_ptr_to_member_type:
231 case DW_TAG_reference_type:
232 case DW_TAG_rvalue_reference_type:
233 case DW_TAG_pointer_type: {
234 if (needsParens(Inner))
235 OS << ')';
236 appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
237 /*SkipFirstParamIfArtificial=*/D.getTag() ==
238 DW_TAG_ptr_to_member_type);
239 break;
240 }
241 /*
242 case DW_TAG_structure_type:
243 case DW_TAG_class_type:
244 case DW_TAG_enumeration_type:
245 case DW_TAG_base_type:
246 case DW_TAG_namespace:
247 */
248 default:
249 break;
250 }
251 }
252
appendQualifiedName(DWARFDie D)253 void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
254 if (D)
255 appendScopes(D.getParent());
256 appendUnqualifiedName(D);
257 }
appendQualifiedNameBefore(DWARFDie D)258 DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
259 if (D)
260 appendScopes(D.getParent());
261 return appendUnqualifiedNameBefore(D);
262 }
appendTemplateParameters(DWARFDie D,bool * FirstParameter)263 bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D,
264 bool *FirstParameter) {
265 bool FirstParameterValue = true;
266 bool IsTemplate = false;
267 if (!FirstParameter)
268 FirstParameter = &FirstParameterValue;
269 for (const DWARFDie &C : D) {
270 auto Sep = [&] {
271 if (*FirstParameter)
272 OS << '<';
273 else
274 OS << ", ";
275 IsTemplate = true;
276 EndedWithTemplate = false;
277 *FirstParameter = false;
278 };
279 if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
280 IsTemplate = true;
281 appendTemplateParameters(C, FirstParameter);
282 }
283 if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
284 DWARFDie T = resolveReferencedType(C);
285 Sep();
286 if (T.getTag() == DW_TAG_enumeration_type) {
287 OS << '(';
288 appendQualifiedName(T);
289 OS << ')';
290 auto V = C.find(DW_AT_const_value);
291 OS << std::to_string(*V->getAsSignedConstant());
292 continue;
293 }
294 // /Maybe/ we could do pointer type parameters, looking for the
295 // symbol in the ELF symbol table to get back to the variable...
296 // but probably not worth it.
297 if (T.getTag() == DW_TAG_pointer_type)
298 continue;
299 const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
300 assert(RawName);
301 StringRef Name = RawName;
302 auto V = C.find(DW_AT_const_value);
303 bool IsQualifiedChar = false;
304 if (Name == "bool") {
305 OS << (*V->getAsUnsignedConstant() ? "true" : "false");
306 } else if (Name == "short") {
307 OS << "(short)";
308 OS << std::to_string(*V->getAsSignedConstant());
309 } else if (Name == "unsigned short") {
310 OS << "(unsigned short)";
311 OS << std::to_string(*V->getAsSignedConstant());
312 } else if (Name == "int")
313 OS << std::to_string(*V->getAsSignedConstant());
314 else if (Name == "long") {
315 OS << std::to_string(*V->getAsSignedConstant());
316 OS << "L";
317 } else if (Name == "long long") {
318 OS << std::to_string(*V->getAsSignedConstant());
319 OS << "LL";
320 } else if (Name == "unsigned int") {
321 OS << std::to_string(*V->getAsUnsignedConstant());
322 OS << "U";
323 } else if (Name == "unsigned long") {
324 OS << std::to_string(*V->getAsUnsignedConstant());
325 OS << "UL";
326 } else if (Name == "unsigned long long") {
327 OS << std::to_string(*V->getAsUnsignedConstant());
328 OS << "ULL";
329 } else if (Name == "char" ||
330 (IsQualifiedChar =
331 (Name == "unsigned char" || Name == "signed char"))) {
332 // FIXME: check T's DW_AT_type to see if it's signed or not (since
333 // char signedness is implementation defined).
334 auto Val = *V->getAsSignedConstant();
335 // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
336 // (doesn't actually support different character types/widths, sign
337 // handling's not done, and doesn't correctly test if a character is
338 // printable or needs to use a numeric escape sequence instead)
339 if (IsQualifiedChar) {
340 OS << '(';
341 OS << Name;
342 OS << ')';
343 }
344 switch (Val) {
345 case '\\':
346 OS << "'\\\\'";
347 break;
348 case '\'':
349 OS << "'\\''";
350 break;
351 case '\a':
352 // TODO: K&R: the meaning of '\\a' is different in traditional C
353 OS << "'\\a'";
354 break;
355 case '\b':
356 OS << "'\\b'";
357 break;
358 case '\f':
359 OS << "'\\f'";
360 break;
361 case '\n':
362 OS << "'\\n'";
363 break;
364 case '\r':
365 OS << "'\\r'";
366 break;
367 case '\t':
368 OS << "'\\t'";
369 break;
370 case '\v':
371 OS << "'\\v'";
372 break;
373 default:
374 if ((Val & ~0xFFu) == ~0xFFu)
375 Val &= 0xFFu;
376 if (Val < 127 && Val >= 32) {
377 OS << "'";
378 OS << (char)Val;
379 OS << "'";
380 } else if (Val < 256)
381 OS << to_string(llvm::format("'\\x%02x'", Val));
382 else if (Val <= 0xFFFF)
383 OS << to_string(llvm::format("'\\u%04x'", Val));
384 else
385 OS << to_string(llvm::format("'\\U%08x'", Val));
386 }
387 }
388 continue;
389 }
390 if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
391 const char *RawName =
392 dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
393 assert(RawName);
394 StringRef Name = RawName;
395 Sep();
396 OS << Name;
397 continue;
398 }
399 if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
400 continue;
401 auto TypeAttr = C.find(DW_AT_type);
402 Sep();
403 appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
404 : DWARFDie());
405 }
406 if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
407 OS << '<';
408 EndedWithTemplate = false;
409 }
410 return IsTemplate;
411 }
decomposeConstVolatile(DWARFDie & N,DWARFDie & T,DWARFDie & C,DWARFDie & V)412 void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T,
413 DWARFDie &C, DWARFDie &V) {
414 (N.getTag() == DW_TAG_const_type ? C : V) = N;
415 T = resolveReferencedType(N);
416 if (T) {
417 auto Tag = T.getTag();
418 if (Tag == DW_TAG_const_type) {
419 C = T;
420 T = resolveReferencedType(T);
421 } else if (Tag == DW_TAG_volatile_type) {
422 V = T;
423 T = resolveReferencedType(T);
424 }
425 }
426 }
appendConstVolatileQualifierAfter(DWARFDie N)427 void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
428 DWARFDie C;
429 DWARFDie V;
430 DWARFDie T;
431 decomposeConstVolatile(N, T, C, V);
432 if (T && T.getTag() == DW_TAG_subroutine_type)
433 appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
434 V.isValid());
435 else
436 appendUnqualifiedNameAfter(T, resolveReferencedType(T));
437 }
appendConstVolatileQualifierBefore(DWARFDie N)438 void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
439 DWARFDie C;
440 DWARFDie V;
441 DWARFDie T;
442 decomposeConstVolatile(N, T, C, V);
443 bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
444 DWARFDie A = T;
445 while (A && A.getTag() == DW_TAG_array_type)
446 A = resolveReferencedType(A);
447 bool Leading =
448 (!A || (A.getTag() != DW_TAG_pointer_type &&
449 A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
450 !Subroutine;
451 if (Leading) {
452 if (C)
453 OS << "const ";
454 if (V)
455 OS << "volatile ";
456 }
457 appendQualifiedNameBefore(T);
458 if (!Leading && !Subroutine) {
459 Word = true;
460 if (C)
461 OS << "const";
462 if (V) {
463 if (C)
464 OS << ' ';
465 OS << "volatile";
466 }
467 }
468 }
appendUnqualifiedName(DWARFDie D,std::string * OriginalFullName)469 void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D,
470 std::string *OriginalFullName) {
471 // FIXME: We should have pretty printers per language. Currently we print
472 // everything as if it was C++ and fall back to the TAG type name.
473 DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
474 appendUnqualifiedNameAfter(D, Inner);
475 }
appendSubroutineNameAfter(DWARFDie D,DWARFDie Inner,bool SkipFirstParamIfArtificial,bool Const,bool Volatile)476 void DWARFTypePrinter::appendSubroutineNameAfter(
477 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
478 bool Volatile) {
479 DWARFDie FirstParamIfArtificial;
480 OS << '(';
481 EndedWithTemplate = false;
482 bool First = true;
483 bool RealFirst = true;
484 for (DWARFDie P : D) {
485 if (P.getTag() != DW_TAG_formal_parameter &&
486 P.getTag() != DW_TAG_unspecified_parameters)
487 return;
488 DWARFDie T = resolveReferencedType(P);
489 if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
490 FirstParamIfArtificial = T;
491 RealFirst = false;
492 continue;
493 }
494 if (!First) {
495 OS << ", ";
496 }
497 First = false;
498 if (P.getTag() == DW_TAG_unspecified_parameters)
499 OS << "...";
500 else
501 appendQualifiedName(T);
502 }
503 EndedWithTemplate = false;
504 OS << ')';
505 if (FirstParamIfArtificial) {
506 if (DWARFDie P = FirstParamIfArtificial) {
507 if (P.getTag() == DW_TAG_pointer_type) {
508 auto CVStep = [&](DWARFDie CV) {
509 if (DWARFDie U = resolveReferencedType(CV)) {
510 Const |= U.getTag() == DW_TAG_const_type;
511 Volatile |= U.getTag() == DW_TAG_volatile_type;
512 return U;
513 }
514 return DWARFDie();
515 };
516 if (DWARFDie CV = CVStep(P)) {
517 CVStep(CV);
518 }
519 }
520 }
521 }
522
523 if (auto CC = D.find(DW_AT_calling_convention)) {
524 switch (*CC->getAsUnsignedConstant()) {
525 case CallingConvention::DW_CC_BORLAND_stdcall:
526 OS << " __attribute__((stdcall))";
527 break;
528 case CallingConvention::DW_CC_BORLAND_msfastcall:
529 OS << " __attribute__((fastcall))";
530 break;
531 case CallingConvention::DW_CC_BORLAND_thiscall:
532 OS << " __attribute__((thiscall))";
533 break;
534 case CallingConvention::DW_CC_LLVM_vectorcall:
535 OS << " __attribute__((vectorcall))";
536 break;
537 case CallingConvention::DW_CC_BORLAND_pascal:
538 OS << " __attribute__((pascal))";
539 break;
540 case CallingConvention::DW_CC_LLVM_Win64:
541 OS << " __attribute__((ms_abi))";
542 break;
543 case CallingConvention::DW_CC_LLVM_X86_64SysV:
544 OS << " __attribute__((sysv_abi))";
545 break;
546 case CallingConvention::DW_CC_LLVM_AAPCS:
547 // AArch64VectorCall missing?
548 OS << " __attribute__((pcs(\"aapcs\")))";
549 break;
550 case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
551 OS << " __attribute__((pcs(\"aapcs-vfp\")))";
552 break;
553 case CallingConvention::DW_CC_LLVM_IntelOclBicc:
554 OS << " __attribute__((intel_ocl_bicc))";
555 break;
556 case CallingConvention::DW_CC_LLVM_SpirFunction:
557 case CallingConvention::DW_CC_LLVM_OpenCLKernel:
558 // These aren't available as attributes, but maybe we should still
559 // render them somehow? (Clang doesn't render them, but that's an issue
560 // for template names too - since then the DWARF names of templates
561 // instantiated with function types with these calling conventions won't
562 // have distinct names - so we'd need to fix that too)
563 break;
564 case CallingConvention::DW_CC_LLVM_Swift:
565 // SwiftAsync missing
566 OS << " __attribute__((swiftcall))";
567 break;
568 case CallingConvention::DW_CC_LLVM_PreserveMost:
569 OS << " __attribute__((preserve_most))";
570 break;
571 case CallingConvention::DW_CC_LLVM_PreserveAll:
572 OS << " __attribute__((preserve_all))";
573 break;
574 case CallingConvention::DW_CC_LLVM_X86RegCall:
575 OS << " __attribute__((regcall))";
576 break;
577 }
578 }
579
580 if (Const)
581 OS << " const";
582 if (Volatile)
583 OS << " volatile";
584 if (D.find(DW_AT_reference))
585 OS << " &";
586 if (D.find(DW_AT_rvalue_reference))
587 OS << " &&";
588
589 appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
590 }
appendScopes(DWARFDie D)591 void DWARFTypePrinter::appendScopes(DWARFDie D) {
592 if (D.getTag() == DW_TAG_compile_unit)
593 return;
594 if (D.getTag() == DW_TAG_type_unit)
595 return;
596 if (D.getTag() == DW_TAG_skeleton_unit)
597 return;
598 if (D.getTag() == DW_TAG_subprogram)
599 return;
600 if (D.getTag() == DW_TAG_lexical_block)
601 return;
602 D = D.resolveTypeUnitReference();
603 if (DWARFDie P = D.getParent())
604 appendScopes(P);
605 appendUnqualifiedName(D);
606 OS << "::";
607 }
608 } // namespace llvm
609