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::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 
getTypeAsType() const29 LVType *LVElement::getTypeAsType() const {
30   return ElementType && ElementType->getIsType()
31              ? static_cast<LVType *>(ElementType)
32              : nullptr;
33 }
34 
getTypeAsScope() const35 LVScope *LVElement::getTypeAsScope() const {
36   return ElementType && ElementType->getIsScope()
37              ? static_cast<LVScope *>(ElementType)
38              : nullptr;
39 }
40 
41 // Set the element type.
setGenericType(LVElement * Element)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.
discriminatorAsString() const58 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.
typeAsString() const68 StringRef LVElement::typeAsString() const {
69   return getHasType() ? getTypeName() : typeVoid();
70 }
71 
72 // Get name for element type.
getTypeName() const73 StringRef LVElement::getTypeName() const {
74   return ElementType ? ElementType->getName() : StringRef();
75 }
76 
getStringIndex(StringRef Name)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 
setName(StringRef ElementName)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 
setFilename(StringRef Filename)101 void LVElement::setFilename(StringRef Filename) {
102   // Get index for the flattened out filename.
103   FilenameIndex = getStringIndex(Filename);
104 }
105 
106 // Return the string representation of a DIE offset.
typeOffsetAsString() const107 std::string LVElement::typeOffsetAsString() const {
108   if (options().getAttributeOffset()) {
109     LVElement *Element = getType();
110     return hexSquareString(Element ? Element->getOffset() : 0);
111   }
112   return {};
113 }
114 
accessibilityString(uint32_t Access) const115 StringRef LVElement::accessibilityString(uint32_t Access) const {
116   uint32_t Value = getAccessibilityCode();
117   switch (Value ? Value : Access) {
118   case dwarf::DW_ACCESS_public:
119     return "public";
120   case dwarf::DW_ACCESS_protected:
121     return "protected";
122   case dwarf::DW_ACCESS_private:
123     return "private";
124   default:
125     return StringRef();
126   }
127 }
128 
externalString() const129 StringRef LVElement::externalString() const {
130   return getIsExternal() ? "extern" : StringRef();
131 }
132 
inlineCodeString(uint32_t Code) const133 StringRef LVElement::inlineCodeString(uint32_t Code) const {
134   uint32_t Value = getInlineCode();
135   switch (Value ? Value : Code) {
136   case dwarf::DW_INL_not_inlined:
137     return "not_inlined";
138   case dwarf::DW_INL_inlined:
139     return "inlined";
140   case dwarf::DW_INL_declared_not_inlined:
141     return "declared_not_inlined";
142   case dwarf::DW_INL_declared_inlined:
143     return "declared_inlined";
144   default:
145     return StringRef();
146   }
147 }
148 
virtualityString(uint32_t Virtuality) const149 StringRef LVElement::virtualityString(uint32_t Virtuality) const {
150   uint32_t Value = getVirtualityCode();
151   switch (Value ? Value : Virtuality) {
152   case dwarf::DW_VIRTUALITY_none:
153     return StringRef();
154   case dwarf::DW_VIRTUALITY_virtual:
155     return "virtual";
156   case dwarf::DW_VIRTUALITY_pure_virtual:
157     return "pure virtual";
158   default:
159     return StringRef();
160   }
161 }
162 
resolve()163 void LVElement::resolve() {
164   if (getIsResolved())
165     return;
166   setIsResolved();
167 
168   resolveReferences();
169   resolveParents();
170   resolveExtra();
171   resolveName();
172 }
173 
174 // Set File/Line using the specification element.
setFileLine(LVElement * Specification)175 void LVElement::setFileLine(LVElement *Specification) {
176   // In the case of inlined functions, the correct scope must be associated
177   // with the file and line information of the outline version.
178   if (!isLined()) {
179     setLineNumber(Specification->getLineNumber());
180     setIsLineFromReference();
181   }
182   if (!isFiled()) {
183     setFilenameIndex(Specification->getFilenameIndex());
184     setIsFileFromReference();
185   }
186 }
187 
resolveName()188 void LVElement::resolveName() {
189   // Set the qualified name if requested.
190   if (options().getAttributeQualified())
191     resolveQualifiedName();
192 
193   setIsResolvedName();
194 }
195 
196 // Resolve any parents.
resolveParents()197 void LVElement::resolveParents() {
198   if (isRoot() || isCompileUnit())
199     return;
200 
201   LVScope *Parent = getParentScope();
202   if (Parent && !Parent->getIsCompileUnit())
203     Parent->resolve();
204 }
205 
206 // Generate a name for unnamed elements.
generateName(std::string & Prefix) const207 void LVElement::generateName(std::string &Prefix) const {
208   LVScope *Scope = getParentScope();
209   if (!Scope)
210     return;
211 
212   // Use its parent name and any line information.
213   Prefix.append(std::string(Scope->getName()));
214   Prefix.append("::");
215   Prefix.append(isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?");
216 
217   // Remove any whitespaces.
218   Prefix.erase(std::remove_if(Prefix.begin(), Prefix.end(), ::isspace),
219                Prefix.end());
220 }
221 
222 // Generate a name for unnamed elements.
generateName()223 void LVElement::generateName() {
224   setIsAnonymous();
225   std::string Name;
226   generateName(Name);
227   setName(Name);
228   setIsGeneratedName();
229 }
230 
updateLevel(LVScope * Parent,bool Moved)231 void LVElement::updateLevel(LVScope *Parent, bool Moved) {
232   setLevel(Parent->getLevel() + 1);
233   if (Moved)
234     setHasMoved();
235 }
236 
237 // Generate the full name for the element, to include special qualifiers.
resolveFullname(LVElement * BaseType,StringRef Name)238 void LVElement::resolveFullname(LVElement *BaseType, StringRef Name) {
239   // For the following sample code,
240   //   void *p;
241   // some compilers do not generate an attribute for the associated type:
242   //      DW_TAG_variable
243   //        DW_AT_name 'p'
244   //        DW_AT_type $1
245   //        ...
246   // $1:  DW_TAG_pointer_type
247   //      ...
248   // For those cases, generate the implicit 'void' type.
249   StringRef BaseTypename = BaseType ? BaseType->getName() : emptyString();
250   bool GetBaseTypename = false;
251   bool UseBaseTypename = true;
252   bool UseNameText = true;
253 
254   switch (getTag()) {
255   case dwarf::DW_TAG_pointer_type: // "*";
256     if (!BaseType)
257       BaseTypename = typeVoid();
258     break;
259   case dwarf::DW_TAG_const_type:            // "const"
260   case dwarf::DW_TAG_ptr_to_member_type:    // "*"
261   case dwarf::DW_TAG_rvalue_reference_type: // "&&"
262   case dwarf::DW_TAG_reference_type:        // "&"
263   case dwarf::DW_TAG_restrict_type:         // "restrict"
264   case dwarf::DW_TAG_volatile_type:         // "volatile"
265   case dwarf::DW_TAG_unaligned:             // "unaligned"
266     break;
267   case dwarf::DW_TAG_base_type:
268   case dwarf::DW_TAG_compile_unit:
269   case dwarf::DW_TAG_class_type:
270   case dwarf::DW_TAG_enumerator:
271   case dwarf::DW_TAG_namespace:
272   case dwarf::DW_TAG_skeleton_unit:
273   case dwarf::DW_TAG_structure_type:
274   case dwarf::DW_TAG_union_type:
275   case dwarf::DW_TAG_unspecified_type:
276   case dwarf::DW_TAG_GNU_template_parameter_pack:
277     GetBaseTypename = true;
278     break;
279   case dwarf::DW_TAG_array_type:
280   case dwarf::DW_TAG_call_site:
281   case dwarf::DW_TAG_entry_point:
282   case dwarf::DW_TAG_enumeration_type:
283   case dwarf::DW_TAG_GNU_call_site:
284   case dwarf::DW_TAG_imported_module:
285   case dwarf::DW_TAG_imported_declaration:
286   case dwarf::DW_TAG_inlined_subroutine:
287   case dwarf::DW_TAG_label:
288   case dwarf::DW_TAG_subprogram:
289   case dwarf::DW_TAG_subrange_type:
290   case dwarf::DW_TAG_subroutine_type:
291   case dwarf::DW_TAG_typedef:
292     GetBaseTypename = true;
293     UseBaseTypename = false;
294     break;
295   case dwarf::DW_TAG_template_type_parameter:
296   case dwarf::DW_TAG_template_value_parameter:
297     UseBaseTypename = false;
298     break;
299   case dwarf::DW_TAG_GNU_template_template_param:
300     break;
301   case dwarf::DW_TAG_catch_block:
302   case dwarf::DW_TAG_lexical_block:
303   case dwarf::DW_TAG_try_block:
304     UseNameText = false;
305     break;
306   default:
307     llvm_unreachable("Invalid type.");
308     return;
309     break;
310   }
311 
312   // Overwrite if no given value. 'Name' is empty when resolving for scopes
313   // and symbols. In the case of types, it represents the type base name.
314   if (Name.empty() && GetBaseTypename)
315     Name = getName();
316 
317   // Concatenate the elements to get the full type name.
318   // Type will be: base_parent + pre + base + parent + post.
319   std::string Fullname;
320 
321   if (UseNameText && Name.size())
322     Fullname.append(std::string(Name));
323   if (UseBaseTypename && BaseTypename.size()) {
324     if (UseNameText && Name.size())
325       Fullname.append(" ");
326     Fullname.append(std::string(BaseTypename));
327   }
328 
329   // For a better and consistent layout, check if the generated name
330   // contains double space sequences.
331   assert((Fullname.find("  ", 0) == std::string::npos) &&
332          "Extra double spaces in name.");
333 
334   LLVM_DEBUG({ dbgs() << "Fullname = '" << Fullname << "'\n"; });
335   setName(Fullname);
336 }
337 
setFile(LVElement * Reference)338 void LVElement::setFile(LVElement *Reference) {
339   if (!options().getAttributeAnySource())
340     return;
341 
342   // At this point, any existing reference to another element, have been
343   // resolved and the file ID extracted from the DI entry.
344   if (Reference)
345     setFileLine(Reference);
346 
347   // The file information is used to show the source file for any element
348   // and display any new source file in relation to its parent element.
349   // a) Elements that are not inlined.
350   //    - We record the DW_AT_decl_line and DW_AT_decl_file.
351   // b) Elements that are inlined.
352   //    - We record the DW_AT_decl_line and DW_AT_decl_file.
353   //    - We record the DW_AT_call_line and DW_AT_call_file.
354   // For both cases, we use the DW_AT_decl_file value to detect any changes
355   // in the source filename containing the element. Changes on this value
356   // indicates that the element being printed is not contained in the
357   // previous printed filename.
358 
359   // The source files are indexed starting at 0, but DW_AT_decl_file defines
360   // that 0 means no file; a value of 1 means the 0th entry.
361   size_t Index = 0;
362 
363   // An element with no source file information will use the reference
364   // attribute (DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension)
365   // to update its information.
366   if (getIsFileFromReference() && Reference) {
367     Index = Reference->getFilenameIndex();
368     if (Reference->getInvalidFilename())
369       setInvalidFilename();
370     setFilenameIndex(Index);
371     return;
372   }
373 
374   // The source files are indexed starting at 0, but DW_AT_decl_file
375   // defines that 0 means no file; a value of 1 means the 0th entry.
376   Index = getFilenameIndex();
377   if (Index) {
378     StringRef Filename = getReader().getFilename(this, Index);
379     Filename.size() ? setFilename(Filename) : setInvalidFilename();
380   }
381 }
382 
traverseParents(LVScopeGetFunction GetFunction) const383 LVScope *LVElement::traverseParents(LVScopeGetFunction GetFunction) const {
384   LVScope *Parent = getParentScope();
385   while (Parent && !(Parent->*GetFunction)())
386     Parent = Parent->getParentScope();
387   return Parent;
388 }
389 
getFunctionParent() const390 LVScope *LVElement::getFunctionParent() const {
391   return traverseParents(&LVScope::getIsFunction);
392 }
393 
getCompileUnitParent() const394 LVScope *LVElement::getCompileUnitParent() const {
395   return traverseParents(&LVScope::getIsCompileUnit);
396 }
397 
398 // Resolve the qualified name to include the parent hierarchy names.
resolveQualifiedName()399 void LVElement::resolveQualifiedName() {
400   if (!getIsReferencedType() || isBase() || getQualifiedResolved() ||
401       !getIncludeInPrint())
402     return;
403 
404   std::string Name;
405 
406   // Get the qualified name, excluding the Compile Unit.
407   LVScope *Parent = getParentScope();
408   if (Parent && !Parent->getIsRoot()) {
409     while (Parent && !Parent->getIsCompileUnit()) {
410       Name.insert(0, "::");
411       if (Parent->isNamed())
412         Name.insert(0, std::string(Parent->getName()));
413       else {
414         std::string Temp;
415         Parent->generateName(Temp);
416         Name.insert(0, Temp);
417       }
418       Parent = Parent->getParentScope();
419     }
420   }
421 
422   if (Name.size()) {
423     setQualifiedName(Name);
424     setQualifiedResolved();
425   }
426   LLVM_DEBUG({
427     dbgs() << "Offset: " << hexSquareString(getOffset())
428            << ", Kind: " << formattedKind(kind())
429            << ", Name: " << formattedName(getName())
430            << ", QualifiedName: " << formattedName(Name) << "\n";
431   });
432 }
433 
referenceMatch(const LVElement * Element) const434 bool LVElement::referenceMatch(const LVElement *Element) const {
435   return (getHasReference() && Element->getHasReference()) ||
436          (!getHasReference() && !Element->getHasReference());
437 }
438 
equals(const LVElement * Element) const439 bool LVElement::equals(const LVElement *Element) const {
440   // The minimum factors that must be the same for an equality are:
441   // line number, level, name, qualified name and filename.
442   LLVM_DEBUG({
443     dbgs() << "\n[Element::equals]\n";
444     if (options().getAttributeOffset()) {
445       dbgs() << "Reference: " << hexSquareString(getOffset()) << "\n";
446       dbgs() << "Target   : " << hexSquareString(Element->getOffset()) << "\n";
447     }
448     dbgs() << "Reference: "
449            << "Kind = " << formattedKind(kind()) << ", "
450            << "Name = " << formattedName(getName()) << ", "
451            << "Qualified = " << formattedName(getQualifiedName()) << "\n"
452            << "Target   : "
453            << "Kind = " << formattedKind(Element->kind()) << ", "
454            << "Name = " << formattedName(Element->getName()) << ", "
455            << "Qualified = " << formattedName(Element->getQualifiedName())
456            << "\n"
457            << "Reference: "
458            << "NameIndex = " << getNameIndex() << ", "
459            << "QualifiedNameIndex = " << getQualifiedNameIndex() << ", "
460            << "FilenameIndex = " << getFilenameIndex() << "\n"
461            << "Target   : "
462            << "NameIndex = " << Element->getNameIndex() << ", "
463            << "QualifiedNameIndex = " << Element->getQualifiedNameIndex()
464            << ", "
465            << "FilenameIndex = " << Element->getFilenameIndex() << "\n";
466   });
467   if ((getLineNumber() != Element->getLineNumber()) ||
468       (getLevel() != Element->getLevel()))
469     return false;
470 
471   if ((getQualifiedNameIndex() != Element->getQualifiedNameIndex()) ||
472       (getNameIndex() != Element->getNameIndex()) ||
473       (getFilenameIndex() != Element->getFilenameIndex()))
474     return false;
475 
476   if (!getType() && !Element->getType())
477     return true;
478   if (getType() && Element->getType())
479     return getType()->equals(Element->getType());
480   return false;
481 }
482 
483 // Print the FileName Index.
printFileIndex(raw_ostream & OS,bool Full) const484 void LVElement::printFileIndex(raw_ostream &OS, bool Full) const {
485   if (options().getPrintFormatting() && options().getAttributeAnySource() &&
486       getFilenameIndex()) {
487 
488     // Check if there is a change in the File ID sequence.
489     size_t Index = getFilenameIndex();
490     if (options().changeFilenameIndex(Index)) {
491       // Just to keep a nice layout.
492       OS << "\n";
493       printAttributes(OS, /*Full=*/false);
494 
495       OS << "  {Source} ";
496       if (getInvalidFilename())
497         OS << format("[0x%08x]\n", Index);
498       else
499         OS << formattedName(getPathname()) << "\n";
500     }
501   }
502 }
503 
printReference(raw_ostream & OS,bool Full,LVElement * Parent) const504 void LVElement::printReference(raw_ostream &OS, bool Full,
505                                LVElement *Parent) const {
506   if (options().getPrintFormatting() && options().getAttributeReference())
507     printAttributes(OS, Full, "{Reference} ", Parent,
508                     referenceAsString(getLineNumber(), /*Spaces=*/false),
509                     /*UseQuotes=*/false, /*PrintRef=*/true);
510 }
511 
printLinkageName(raw_ostream & OS,bool Full,LVElement * Parent) const512 void LVElement::printLinkageName(raw_ostream &OS, bool Full,
513                                  LVElement *Parent) const {
514   if (options().getPrintFormatting() && options().getAttributeLinkage()) {
515     printAttributes(OS, Full, "{Linkage} ", Parent, getLinkageName(),
516                     /*UseQuotes=*/true, /*PrintRef=*/false);
517   }
518 }
519 
printLinkageName(raw_ostream & OS,bool Full,LVElement * Parent,LVScope * Scope) const520 void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
521                                  LVScope *Scope) const {
522   if (options().getPrintFormatting() && options().getAttributeLinkage()) {
523     LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
524     std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) +
525                         Twine(" '") + Twine(getLinkageName()) + Twine("'"))
526                            .str();
527     printAttributes(OS, Full, "{Linkage} ", Parent, Text,
528                     /*UseQuotes=*/false, /*PrintRef=*/false);
529   }
530 }
531