xref: /llvm-project/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp (revision 0060c54e0da6d1429875da2d30895faa7562b706)
1 //===-- LVElement.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 // This implements the LVElement class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
14 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
15 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
16 #include "llvm/DebugInfo/LogicalView/Core/LVType.h"
17 
18 using namespace llvm;
19 using namespace llvm::codeview;
20 using namespace llvm::logicalview;
21 
22 #define DEBUG_TYPE "Element"
23 
24 LVElementDispatch LVElement::Dispatch = {
25     {LVElementKind::Discarded, &LVElement::getIsDiscarded},
26     {LVElementKind::Global, &LVElement::getIsGlobalReference},
27     {LVElementKind::Optimized, &LVElement::getIsOptimized}};
28 
29 LVType *LVElement::getTypeAsType() const {
30   return ElementType && ElementType->getIsType()
31              ? static_cast<LVType *>(ElementType)
32              : nullptr;
33 }
34 
35 LVScope *LVElement::getTypeAsScope() const {
36   return ElementType && ElementType->getIsScope()
37              ? static_cast<LVScope *>(ElementType)
38              : nullptr;
39 }
40 
41 // Set the element type.
42 void LVElement::setGenericType(LVElement *Element) {
43   if (!Element->isTemplateParam()) {
44     setType(Element);
45     return;
46   }
47   // For template parameters, the instance type can be a type or a scope.
48   if (options().getAttributeArgument()) {
49     if (Element->getIsKindType())
50       setType(Element->getTypeAsType());
51     else if (Element->getIsKindScope())
52       setType(Element->getTypeAsScope());
53   } else
54     setType(Element);
55 }
56 
57 // Discriminator as string.
58 std::string LVElement::discriminatorAsString() const {
59   uint32_t Discriminator = getDiscriminator();
60   std::string String;
61   raw_string_ostream Stream(String);
62   if (Discriminator && options().getAttributeDiscriminator())
63     Stream << "," << Discriminator;
64   return String;
65 }
66 
67 // Get the type as a string.
68 StringRef LVElement::typeAsString() const {
69   return getHasType() ? getTypeName() : typeVoid();
70 }
71 
72 // Get name for element type.
73 StringRef LVElement::getTypeName() const {
74   return ElementType ? ElementType->getName() : StringRef();
75 }
76 
77 static size_t getStringIndex(StringRef Name) {
78   // Convert the name to Unified format ('\' have been converted into '/').
79   std::string Pathname(transformPath(Name));
80 
81   // Depending on the --attribute=filename and --attribute=pathname command
82   // line options, use the basename or the full pathname as the name.
83   if (!options().getAttributePathname()) {
84     // Get the basename by ignoring any prefix up to the last slash ('/').
85     StringRef Basename = Pathname;
86     size_t Pos = Basename.rfind('/');
87     if (Pos != std::string::npos)
88       Basename = Basename.substr(Pos + 1);
89     return getStringPool().getIndex(Basename);
90   }
91 
92   return getStringPool().getIndex(Pathname);
93 }
94 
95 void LVElement::setName(StringRef ElementName) {
96   // In the case of Root or Compile Unit, get index for the flatted out name.
97   NameIndex = getTransformName() ? getStringIndex(ElementName)
98                                  : getStringPool().getIndex(ElementName);
99 }
100 
101 void LVElement::setFilename(StringRef Filename) {
102   // Get index for the flattened out filename.
103   FilenameIndex = getStringIndex(Filename);
104 }
105 
106 void LVElement::setInnerComponent(StringRef Name) {
107   if (Name.size()) {
108     StringRef InnerComponent;
109     std::tie(std::ignore, InnerComponent) = getInnerComponent(Name);
110     setName(InnerComponent);
111   }
112 }
113 
114 // Return the string representation of a DIE offset.
115 std::string LVElement::typeOffsetAsString() const {
116   if (options().getAttributeOffset()) {
117     LVElement *Element = getType();
118     return hexSquareString(Element ? Element->getOffset() : 0);
119   }
120   return {};
121 }
122 
123 StringRef LVElement::accessibilityString(uint32_t Access) const {
124   uint32_t Value = getAccessibilityCode();
125   switch (Value ? Value : Access) {
126   case dwarf::DW_ACCESS_public:
127     return "public";
128   case dwarf::DW_ACCESS_protected:
129     return "protected";
130   case dwarf::DW_ACCESS_private:
131     return "private";
132   default:
133     return StringRef();
134   }
135 }
136 
137 std::optional<uint32_t> LVElement::getAccessibilityCode(MemberAccess Access) {
138   switch (Access) {
139   case MemberAccess::Private:
140     return dwarf::DW_ACCESS_private;
141   case MemberAccess::Protected:
142     return dwarf::DW_ACCESS_protected;
143   case MemberAccess::Public:
144     return dwarf::DW_ACCESS_public;
145   default:
146     return std::nullopt;
147   }
148 }
149 
150 StringRef LVElement::externalString() const {
151   return getIsExternal() ? "extern" : StringRef();
152 }
153 
154 StringRef LVElement::inlineCodeString(uint32_t Code) const {
155   uint32_t Value = getInlineCode();
156   switch (Value ? Value : Code) {
157   case dwarf::DW_INL_not_inlined:
158     return "not_inlined";
159   case dwarf::DW_INL_inlined:
160     return "inlined";
161   case dwarf::DW_INL_declared_not_inlined:
162     return "declared_not_inlined";
163   case dwarf::DW_INL_declared_inlined:
164     return "declared_inlined";
165   default:
166     return StringRef();
167   }
168 }
169 
170 StringRef LVElement::virtualityString(uint32_t Virtuality) const {
171   uint32_t Value = getVirtualityCode();
172   switch (Value ? Value : Virtuality) {
173   case dwarf::DW_VIRTUALITY_none:
174     return StringRef();
175   case dwarf::DW_VIRTUALITY_virtual:
176     return "virtual";
177   case dwarf::DW_VIRTUALITY_pure_virtual:
178     return "pure virtual";
179   default:
180     return StringRef();
181   }
182 }
183 
184 std::optional<uint32_t> LVElement::getVirtualityCode(MethodKind Virtuality) {
185   switch (Virtuality) {
186   case MethodKind::Virtual:
187     return dwarf::DW_VIRTUALITY_virtual;
188   case MethodKind::PureVirtual:
189     return dwarf::DW_VIRTUALITY_pure_virtual;
190   case MethodKind::IntroducingVirtual:
191   case MethodKind::PureIntroducingVirtual:
192     // No direct equivalents in DWARF. Assume Virtual.
193     return dwarf::DW_VIRTUALITY_virtual;
194   default:
195     return std::nullopt;
196   }
197 }
198 
199 void LVElement::resolve() {
200   if (getIsResolved())
201     return;
202   setIsResolved();
203 
204   resolveReferences();
205   resolveParents();
206   resolveExtra();
207   resolveName();
208 }
209 
210 // Set File/Line using the specification element.
211 void LVElement::setFileLine(LVElement *Specification) {
212   // In the case of inlined functions, the correct scope must be associated
213   // with the file and line information of the outline version.
214   if (!isLined()) {
215     setLineNumber(Specification->getLineNumber());
216     setIsLineFromReference();
217   }
218   if (!isFiled()) {
219     setFilenameIndex(Specification->getFilenameIndex());
220     setIsFileFromReference();
221   }
222 }
223 
224 void LVElement::resolveName() {
225   // Set the qualified name if requested.
226   if (options().getAttributeQualified())
227     resolveQualifiedName();
228 
229   setIsResolvedName();
230 }
231 
232 // Resolve any parents.
233 void LVElement::resolveParents() {
234   if (isRoot() || isCompileUnit())
235     return;
236 
237   LVScope *Parent = getParentScope();
238   if (Parent && !Parent->getIsCompileUnit())
239     Parent->resolve();
240 }
241 
242 // Generate a name for unnamed elements.
243 void LVElement::generateName(std::string &Prefix) const {
244   LVScope *Scope = getParentScope();
245   if (!Scope)
246     return;
247 
248   // Use its parent name and any line information.
249   Prefix.append(std::string(Scope->getName()));
250   Prefix.append("::");
251   Prefix.append(isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?");
252 
253   // Remove any whitespaces.
254   llvm::erase_if(Prefix, ::isspace);
255 }
256 
257 // Generate a name for unnamed elements.
258 void LVElement::generateName() {
259   setIsAnonymous();
260   std::string Name;
261   generateName(Name);
262   setName(Name);
263   setIsGeneratedName();
264 }
265 
266 void LVElement::updateLevel(LVScope *Parent, bool Moved) {
267   setLevel(Parent->getLevel() + 1);
268   if (Moved)
269     setHasMoved();
270 }
271 
272 // Generate the full name for the element, to include special qualifiers.
273 void LVElement::resolveFullname(LVElement *BaseType, StringRef Name) {
274   // For the following sample code,
275   //   void *p;
276   // some compilers do not generate an attribute for the associated type:
277   //      DW_TAG_variable
278   //        DW_AT_name 'p'
279   //        DW_AT_type $1
280   //        ...
281   // $1:  DW_TAG_pointer_type
282   //      ...
283   // For those cases, generate the implicit 'void' type.
284   StringRef BaseTypename = BaseType ? BaseType->getName() : emptyString();
285   bool GetBaseTypename = false;
286   bool UseBaseTypename = true;
287   bool UseNameText = true;
288 
289   switch (getTag()) {
290   case dwarf::DW_TAG_pointer_type: // "*";
291     if (!BaseType)
292       BaseTypename = typeVoid();
293     break;
294   case dwarf::DW_TAG_const_type:            // "const"
295   case dwarf::DW_TAG_ptr_to_member_type:    // "*"
296   case dwarf::DW_TAG_rvalue_reference_type: // "&&"
297   case dwarf::DW_TAG_reference_type:        // "&"
298   case dwarf::DW_TAG_restrict_type:         // "restrict"
299   case dwarf::DW_TAG_volatile_type:         // "volatile"
300   case dwarf::DW_TAG_unaligned:             // "unaligned"
301     break;
302   case dwarf::DW_TAG_base_type:
303   case dwarf::DW_TAG_compile_unit:
304   case dwarf::DW_TAG_class_type:
305   case dwarf::DW_TAG_enumerator:
306   case dwarf::DW_TAG_namespace:
307   case dwarf::DW_TAG_skeleton_unit:
308   case dwarf::DW_TAG_structure_type:
309   case dwarf::DW_TAG_union_type:
310   case dwarf::DW_TAG_unspecified_type:
311   case dwarf::DW_TAG_GNU_template_parameter_pack:
312     GetBaseTypename = true;
313     break;
314   case dwarf::DW_TAG_array_type:
315   case dwarf::DW_TAG_call_site:
316   case dwarf::DW_TAG_entry_point:
317   case dwarf::DW_TAG_enumeration_type:
318   case dwarf::DW_TAG_GNU_call_site:
319   case dwarf::DW_TAG_imported_module:
320   case dwarf::DW_TAG_imported_declaration:
321   case dwarf::DW_TAG_inlined_subroutine:
322   case dwarf::DW_TAG_label:
323   case dwarf::DW_TAG_subprogram:
324   case dwarf::DW_TAG_subrange_type:
325   case dwarf::DW_TAG_subroutine_type:
326   case dwarf::DW_TAG_typedef:
327     GetBaseTypename = true;
328     UseBaseTypename = false;
329     break;
330   case dwarf::DW_TAG_template_type_parameter:
331   case dwarf::DW_TAG_template_value_parameter:
332     UseBaseTypename = false;
333     break;
334   case dwarf::DW_TAG_GNU_template_template_param:
335     break;
336   case dwarf::DW_TAG_catch_block:
337   case dwarf::DW_TAG_lexical_block:
338   case dwarf::DW_TAG_try_block:
339     UseNameText = false;
340     break;
341   default:
342     llvm_unreachable("Invalid type.");
343     return;
344     break;
345   }
346 
347   // Overwrite if no given value. 'Name' is empty when resolving for scopes
348   // and symbols. In the case of types, it represents the type base name.
349   if (Name.empty() && GetBaseTypename)
350     Name = getName();
351 
352   // Concatenate the elements to get the full type name.
353   // Type will be: base_parent + pre + base + parent + post.
354   std::string Fullname;
355 
356   if (UseNameText && Name.size())
357     Fullname.append(std::string(Name));
358   if (UseBaseTypename && BaseTypename.size()) {
359     if (UseNameText && Name.size())
360       Fullname.append(" ");
361     Fullname.append(std::string(BaseTypename));
362   }
363 
364   // For a better and consistent layout, check if the generated name
365   // contains double space sequences.
366   assert((Fullname.find("  ", 0) == std::string::npos) &&
367          "Extra double spaces in name.");
368 
369   LLVM_DEBUG({ dbgs() << "Fullname = '" << Fullname << "'\n"; });
370   setName(Fullname);
371 }
372 
373 void LVElement::setFile(LVElement *Reference) {
374   if (!options().getAttributeAnySource())
375     return;
376 
377   // At this point, any existing reference to another element, have been
378   // resolved and the file ID extracted from the DI entry.
379   if (Reference)
380     setFileLine(Reference);
381 
382   // The file information is used to show the source file for any element
383   // and display any new source file in relation to its parent element.
384   // a) Elements that are not inlined.
385   //    - We record the DW_AT_decl_line and DW_AT_decl_file.
386   // b) Elements that are inlined.
387   //    - We record the DW_AT_decl_line and DW_AT_decl_file.
388   //    - We record the DW_AT_call_line and DW_AT_call_file.
389   // For both cases, we use the DW_AT_decl_file value to detect any changes
390   // in the source filename containing the element. Changes on this value
391   // indicates that the element being printed is not contained in the
392   // previous printed filename.
393 
394   // The source files are indexed starting at 0, but DW_AT_decl_file defines
395   // that 0 means no file; a value of 1 means the 0th entry.
396   size_t Index = 0;
397 
398   // An element with no source file information will use the reference
399   // attribute (DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension)
400   // to update its information.
401   if (getIsFileFromReference() && Reference) {
402     Index = Reference->getFilenameIndex();
403     if (Reference->getInvalidFilename())
404       setInvalidFilename();
405     setFilenameIndex(Index);
406     return;
407   }
408 
409   // The source files are indexed starting at 0, but DW_AT_decl_file
410   // defines that 0 means no file; a value of 1 means the 0th entry.
411   Index = getFilenameIndex();
412   if (Index) {
413     StringRef Filename = getReader().getFilename(this, Index);
414     Filename.size() ? setFilename(Filename) : setInvalidFilename();
415   }
416 }
417 
418 LVScope *LVElement::traverseParents(LVScopeGetFunction GetFunction) const {
419   LVScope *Parent = getParentScope();
420   while (Parent && !(Parent->*GetFunction)())
421     Parent = Parent->getParentScope();
422   return Parent;
423 }
424 
425 LVScope *LVElement::getFunctionParent() const {
426   return traverseParents(&LVScope::getIsFunction);
427 }
428 
429 LVScope *LVElement::getCompileUnitParent() const {
430   return traverseParents(&LVScope::getIsCompileUnit);
431 }
432 
433 // Resolve the qualified name to include the parent hierarchy names.
434 void LVElement::resolveQualifiedName() {
435   if (!getIsReferencedType() || isBase() || getQualifiedResolved() ||
436       !getIncludeInPrint())
437     return;
438 
439   std::string Name;
440 
441   // Get the qualified name, excluding the Compile Unit.
442   LVScope *Parent = getParentScope();
443   if (Parent && !Parent->getIsRoot()) {
444     while (Parent && !Parent->getIsCompileUnit()) {
445       Name.insert(0, "::");
446       if (Parent->isNamed())
447         Name.insert(0, std::string(Parent->getName()));
448       else {
449         std::string Temp;
450         Parent->generateName(Temp);
451         Name.insert(0, Temp);
452       }
453       Parent = Parent->getParentScope();
454     }
455   }
456 
457   if (Name.size()) {
458     setQualifiedName(Name);
459     setQualifiedResolved();
460   }
461   LLVM_DEBUG({
462     dbgs() << "Offset: " << hexSquareString(getOffset())
463            << ", Kind: " << formattedKind(kind())
464            << ", Name: " << formattedName(getName())
465            << ", QualifiedName: " << formattedName(Name) << "\n";
466   });
467 }
468 
469 bool LVElement::referenceMatch(const LVElement *Element) const {
470   return (getHasReference() && Element->getHasReference()) ||
471          (!getHasReference() && !Element->getHasReference());
472 }
473 
474 bool LVElement::equals(const LVElement *Element) const {
475   // The minimum factors that must be the same for an equality are:
476   // line number, level, name, qualified name and filename.
477   LLVM_DEBUG({
478     dbgs() << "\n[Element::equals]\n";
479     if (options().getAttributeOffset()) {
480       dbgs() << "Reference: " << hexSquareString(getOffset()) << "\n";
481       dbgs() << "Target   : " << hexSquareString(Element->getOffset()) << "\n";
482     }
483     dbgs() << "Reference: "
484            << "Kind = " << formattedKind(kind()) << ", "
485            << "Name = " << formattedName(getName()) << ", "
486            << "Qualified = " << formattedName(getQualifiedName()) << "\n"
487            << "Target   : "
488            << "Kind = " << formattedKind(Element->kind()) << ", "
489            << "Name = " << formattedName(Element->getName()) << ", "
490            << "Qualified = " << formattedName(Element->getQualifiedName())
491            << "\n"
492            << "Reference: "
493            << "NameIndex = " << getNameIndex() << ", "
494            << "QualifiedNameIndex = " << getQualifiedNameIndex() << ", "
495            << "FilenameIndex = " << getFilenameIndex() << "\n"
496            << "Target   : "
497            << "NameIndex = " << Element->getNameIndex() << ", "
498            << "QualifiedNameIndex = " << Element->getQualifiedNameIndex()
499            << ", "
500            << "FilenameIndex = " << Element->getFilenameIndex() << "\n";
501   });
502   if ((getLineNumber() != Element->getLineNumber()) ||
503       (getLevel() != Element->getLevel()))
504     return false;
505 
506   if ((getQualifiedNameIndex() != Element->getQualifiedNameIndex()) ||
507       (getNameIndex() != Element->getNameIndex()) ||
508       (getFilenameIndex() != Element->getFilenameIndex()))
509     return false;
510 
511   if (!getType() && !Element->getType())
512     return true;
513   if (getType() && Element->getType())
514     return getType()->equals(Element->getType());
515   return false;
516 }
517 
518 // Print the FileName Index.
519 void LVElement::printFileIndex(raw_ostream &OS, bool Full) const {
520   if (options().getPrintFormatting() && options().getAttributeAnySource() &&
521       getFilenameIndex()) {
522 
523     // Check if there is a change in the File ID sequence.
524     size_t Index = getFilenameIndex();
525     if (options().changeFilenameIndex(Index)) {
526       // Just to keep a nice layout.
527       OS << "\n";
528       printAttributes(OS, /*Full=*/false);
529 
530       OS << "  {Source} ";
531       if (getInvalidFilename())
532         OS << format("[0x%08x]\n", Index);
533       else
534         OS << formattedName(getPathname()) << "\n";
535     }
536   }
537 }
538 
539 void LVElement::printReference(raw_ostream &OS, bool Full,
540                                LVElement *Parent) const {
541   if (options().getPrintFormatting() && options().getAttributeReference())
542     printAttributes(OS, Full, "{Reference} ", Parent,
543                     referenceAsString(getLineNumber(), /*Spaces=*/false),
544                     /*UseQuotes=*/false, /*PrintRef=*/true);
545 }
546 
547 void LVElement::printLinkageName(raw_ostream &OS, bool Full,
548                                  LVElement *Parent) const {
549   if (options().getPrintFormatting() && options().getAttributeLinkage()) {
550     printAttributes(OS, Full, "{Linkage} ", Parent, getLinkageName(),
551                     /*UseQuotes=*/true, /*PrintRef=*/false);
552   }
553 }
554 
555 void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
556                                  LVScope *Scope) const {
557   if (options().getPrintFormatting() && options().getAttributeLinkage()) {
558     LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
559     std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) +
560                         Twine(" '") + Twine(getLinkageName()) + Twine("'"))
561                            .str();
562     printAttributes(OS, Full, "{Linkage} ", Parent, Text,
563                     /*UseQuotes=*/false, /*PrintRef=*/false);
564   }
565 }
566