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