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