File: LVElement.cpp

package info (click to toggle)
llvm-toolchain-17 1%3A17.0.6-22
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,799,624 kB
  • sloc: cpp: 6,428,607; ansic: 1,383,196; asm: 793,408; python: 223,504; objc: 75,364; f90: 60,502; lisp: 33,869; pascal: 15,282; sh: 9,684; perl: 7,453; ml: 4,937; awk: 3,523; makefile: 2,889; javascript: 2,149; xml: 888; fortran: 619; cs: 573
file content (567 lines) | stat: -rw-r--r-- 18,613 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
//===-- LVElement.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This implements the LVElement class.
//
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
#include "llvm/DebugInfo/LogicalView/Core/LVType.h"

using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::logicalview;

#define DEBUG_TYPE "Element"

LVElementDispatch LVElement::Dispatch = {
    {LVElementKind::Discarded, &LVElement::getIsDiscarded},
    {LVElementKind::Global, &LVElement::getIsGlobalReference},
    {LVElementKind::Optimized, &LVElement::getIsOptimized}};

LVType *LVElement::getTypeAsType() const {
  return ElementType && ElementType->getIsType()
             ? static_cast<LVType *>(ElementType)
             : nullptr;
}

LVScope *LVElement::getTypeAsScope() const {
  return ElementType && ElementType->getIsScope()
             ? static_cast<LVScope *>(ElementType)
             : nullptr;
}

// Set the element type.
void LVElement::setGenericType(LVElement *Element) {
  if (!Element->isTemplateParam()) {
    setType(Element);
    return;
  }
  // For template parameters, the instance type can be a type or a scope.
  if (options().getAttributeArgument()) {
    if (Element->getIsKindType())
      setType(Element->getTypeAsType());
    else if (Element->getIsKindScope())
      setType(Element->getTypeAsScope());
  } else
    setType(Element);
}

// Discriminator as string.
std::string LVElement::discriminatorAsString() const {
  uint32_t Discriminator = getDiscriminator();
  std::string String;
  raw_string_ostream Stream(String);
  if (Discriminator && options().getAttributeDiscriminator())
    Stream << "," << Discriminator;
  return String;
}

// Get the type as a string.
StringRef LVElement::typeAsString() const {
  return getHasType() ? getTypeName() : typeVoid();
}

// Get name for element type.
StringRef LVElement::getTypeName() const {
  return ElementType ? ElementType->getName() : StringRef();
}

static size_t getStringIndex(StringRef Name) {
  // Convert the name to Unified format ('\' have been converted into '/').
  std::string Pathname(transformPath(Name));

  // Depending on the --attribute=filename and --attribute=pathname command
  // line options, use the basename or the full pathname as the name.
  if (!options().getAttributePathname()) {
    // Get the basename by ignoring any prefix up to the last slash ('/').
    StringRef Basename = Pathname;
    size_t Pos = Basename.rfind('/');
    if (Pos != std::string::npos)
      Basename = Basename.substr(Pos + 1);
    return getStringPool().getIndex(Basename);
  }

  return getStringPool().getIndex(Pathname);
}

void LVElement::setName(StringRef ElementName) {
  // In the case of Root or Compile Unit, get index for the flatted out name.
  NameIndex = getTransformName() ? getStringIndex(ElementName)
                                 : getStringPool().getIndex(ElementName);
}

void LVElement::setFilename(StringRef Filename) {
  // Get index for the flattened out filename.
  FilenameIndex = getStringIndex(Filename);
}

void LVElement::setInnerComponent(StringRef Name) {
  if (Name.size()) {
    StringRef InnerComponent;
    std::tie(std::ignore, InnerComponent) = getInnerComponent(Name);
    setName(InnerComponent);
  }
}

// Return the string representation of a DIE offset.
std::string LVElement::typeOffsetAsString() const {
  if (options().getAttributeOffset()) {
    LVElement *Element = getType();
    return hexSquareString(Element ? Element->getOffset() : 0);
  }
  return {};
}

StringRef LVElement::accessibilityString(uint32_t Access) const {
  uint32_t Value = getAccessibilityCode();
  switch (Value ? Value : Access) {
  case dwarf::DW_ACCESS_public:
    return "public";
  case dwarf::DW_ACCESS_protected:
    return "protected";
  case dwarf::DW_ACCESS_private:
    return "private";
  default:
    return StringRef();
  }
}

std::optional<uint32_t> LVElement::getAccessibilityCode(MemberAccess Access) {
  switch (Access) {
  case MemberAccess::Private:
    return dwarf::DW_ACCESS_private;
  case MemberAccess::Protected:
    return dwarf::DW_ACCESS_protected;
  case MemberAccess::Public:
    return dwarf::DW_ACCESS_public;
  default:
    return std::nullopt;
  }
}

StringRef LVElement::externalString() const {
  return getIsExternal() ? "extern" : StringRef();
}

StringRef LVElement::inlineCodeString(uint32_t Code) const {
  uint32_t Value = getInlineCode();
  switch (Value ? Value : Code) {
  case dwarf::DW_INL_not_inlined:
    return "not_inlined";
  case dwarf::DW_INL_inlined:
    return "inlined";
  case dwarf::DW_INL_declared_not_inlined:
    return "declared_not_inlined";
  case dwarf::DW_INL_declared_inlined:
    return "declared_inlined";
  default:
    return StringRef();
  }
}

StringRef LVElement::virtualityString(uint32_t Virtuality) const {
  uint32_t Value = getVirtualityCode();
  switch (Value ? Value : Virtuality) {
  case dwarf::DW_VIRTUALITY_none:
    return StringRef();
  case dwarf::DW_VIRTUALITY_virtual:
    return "virtual";
  case dwarf::DW_VIRTUALITY_pure_virtual:
    return "pure virtual";
  default:
    return StringRef();
  }
}

std::optional<uint32_t> LVElement::getVirtualityCode(MethodKind Virtuality) {
  switch (Virtuality) {
  case MethodKind::Virtual:
    return dwarf::DW_VIRTUALITY_virtual;
  case MethodKind::PureVirtual:
    return dwarf::DW_VIRTUALITY_pure_virtual;
  case MethodKind::IntroducingVirtual:
  case MethodKind::PureIntroducingVirtual:
    // No direct equivalents in DWARF. Assume Virtual.
    return dwarf::DW_VIRTUALITY_virtual;
  default:
    return std::nullopt;
  }
}

void LVElement::resolve() {
  if (getIsResolved())
    return;
  setIsResolved();

  resolveReferences();
  resolveParents();
  resolveExtra();
  resolveName();
}

// Set File/Line using the specification element.
void LVElement::setFileLine(LVElement *Specification) {
  // In the case of inlined functions, the correct scope must be associated
  // with the file and line information of the outline version.
  if (!isLined()) {
    setLineNumber(Specification->getLineNumber());
    setIsLineFromReference();
  }
  if (!isFiled()) {
    setFilenameIndex(Specification->getFilenameIndex());
    setIsFileFromReference();
  }
}

void LVElement::resolveName() {
  // Set the qualified name if requested.
  if (options().getAttributeQualified())
    resolveQualifiedName();

  setIsResolvedName();
}

// Resolve any parents.
void LVElement::resolveParents() {
  if (isRoot() || isCompileUnit())
    return;

  LVScope *Parent = getParentScope();
  if (Parent && !Parent->getIsCompileUnit())
    Parent->resolve();
}

// Generate a name for unnamed elements.
void LVElement::generateName(std::string &Prefix) const {
  LVScope *Scope = getParentScope();
  if (!Scope)
    return;

  // Use its parent name and any line information.
  Prefix.append(std::string(Scope->getName()));
  Prefix.append("::");
  Prefix.append(isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?");

  // Remove any whitespaces.
  Prefix.erase(std::remove_if(Prefix.begin(), Prefix.end(), ::isspace),
               Prefix.end());
}

// Generate a name for unnamed elements.
void LVElement::generateName() {
  setIsAnonymous();
  std::string Name;
  generateName(Name);
  setName(Name);
  setIsGeneratedName();
}

void LVElement::updateLevel(LVScope *Parent, bool Moved) {
  setLevel(Parent->getLevel() + 1);
  if (Moved)
    setHasMoved();
}

// Generate the full name for the element, to include special qualifiers.
void LVElement::resolveFullname(LVElement *BaseType, StringRef Name) {
  // For the following sample code,
  //   void *p;
  // some compilers do not generate an attribute for the associated type:
  //      DW_TAG_variable
  //        DW_AT_name 'p'
  //        DW_AT_type $1
  //        ...
  // $1:  DW_TAG_pointer_type
  //      ...
  // For those cases, generate the implicit 'void' type.
  StringRef BaseTypename = BaseType ? BaseType->getName() : emptyString();
  bool GetBaseTypename = false;
  bool UseBaseTypename = true;
  bool UseNameText = true;

  switch (getTag()) {
  case dwarf::DW_TAG_pointer_type: // "*";
    if (!BaseType)
      BaseTypename = typeVoid();
    break;
  case dwarf::DW_TAG_const_type:            // "const"
  case dwarf::DW_TAG_ptr_to_member_type:    // "*"
  case dwarf::DW_TAG_rvalue_reference_type: // "&&"
  case dwarf::DW_TAG_reference_type:        // "&"
  case dwarf::DW_TAG_restrict_type:         // "restrict"
  case dwarf::DW_TAG_volatile_type:         // "volatile"
  case dwarf::DW_TAG_unaligned:             // "unaligned"
    break;
  case dwarf::DW_TAG_base_type:
  case dwarf::DW_TAG_compile_unit:
  case dwarf::DW_TAG_class_type:
  case dwarf::DW_TAG_enumerator:
  case dwarf::DW_TAG_namespace:
  case dwarf::DW_TAG_skeleton_unit:
  case dwarf::DW_TAG_structure_type:
  case dwarf::DW_TAG_union_type:
  case dwarf::DW_TAG_unspecified_type:
  case dwarf::DW_TAG_GNU_template_parameter_pack:
    GetBaseTypename = true;
    break;
  case dwarf::DW_TAG_array_type:
  case dwarf::DW_TAG_call_site:
  case dwarf::DW_TAG_entry_point:
  case dwarf::DW_TAG_enumeration_type:
  case dwarf::DW_TAG_GNU_call_site:
  case dwarf::DW_TAG_imported_module:
  case dwarf::DW_TAG_imported_declaration:
  case dwarf::DW_TAG_inlined_subroutine:
  case dwarf::DW_TAG_label:
  case dwarf::DW_TAG_subprogram:
  case dwarf::DW_TAG_subrange_type:
  case dwarf::DW_TAG_subroutine_type:
  case dwarf::DW_TAG_typedef:
    GetBaseTypename = true;
    UseBaseTypename = false;
    break;
  case dwarf::DW_TAG_template_type_parameter:
  case dwarf::DW_TAG_template_value_parameter:
    UseBaseTypename = false;
    break;
  case dwarf::DW_TAG_GNU_template_template_param:
    break;
  case dwarf::DW_TAG_catch_block:
  case dwarf::DW_TAG_lexical_block:
  case dwarf::DW_TAG_try_block:
    UseNameText = false;
    break;
  default:
    llvm_unreachable("Invalid type.");
    return;
    break;
  }

  // Overwrite if no given value. 'Name' is empty when resolving for scopes
  // and symbols. In the case of types, it represents the type base name.
  if (Name.empty() && GetBaseTypename)
    Name = getName();

  // Concatenate the elements to get the full type name.
  // Type will be: base_parent + pre + base + parent + post.
  std::string Fullname;

  if (UseNameText && Name.size())
    Fullname.append(std::string(Name));
  if (UseBaseTypename && BaseTypename.size()) {
    if (UseNameText && Name.size())
      Fullname.append(" ");
    Fullname.append(std::string(BaseTypename));
  }

  // For a better and consistent layout, check if the generated name
  // contains double space sequences.
  assert((Fullname.find("  ", 0) == std::string::npos) &&
         "Extra double spaces in name.");

  LLVM_DEBUG({ dbgs() << "Fullname = '" << Fullname << "'\n"; });
  setName(Fullname);
}

void LVElement::setFile(LVElement *Reference) {
  if (!options().getAttributeAnySource())
    return;

  // At this point, any existing reference to another element, have been
  // resolved and the file ID extracted from the DI entry.
  if (Reference)
    setFileLine(Reference);

  // The file information is used to show the source file for any element
  // and display any new source file in relation to its parent element.
  // a) Elements that are not inlined.
  //    - We record the DW_AT_decl_line and DW_AT_decl_file.
  // b) Elements that are inlined.
  //    - We record the DW_AT_decl_line and DW_AT_decl_file.
  //    - We record the DW_AT_call_line and DW_AT_call_file.
  // For both cases, we use the DW_AT_decl_file value to detect any changes
  // in the source filename containing the element. Changes on this value
  // indicates that the element being printed is not contained in the
  // previous printed filename.

  // The source files are indexed starting at 0, but DW_AT_decl_file defines
  // that 0 means no file; a value of 1 means the 0th entry.
  size_t Index = 0;

  // An element with no source file information will use the reference
  // attribute (DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension)
  // to update its information.
  if (getIsFileFromReference() && Reference) {
    Index = Reference->getFilenameIndex();
    if (Reference->getInvalidFilename())
      setInvalidFilename();
    setFilenameIndex(Index);
    return;
  }

  // The source files are indexed starting at 0, but DW_AT_decl_file
  // defines that 0 means no file; a value of 1 means the 0th entry.
  Index = getFilenameIndex();
  if (Index) {
    StringRef Filename = getReader().getFilename(this, Index);
    Filename.size() ? setFilename(Filename) : setInvalidFilename();
  }
}

LVScope *LVElement::traverseParents(LVScopeGetFunction GetFunction) const {
  LVScope *Parent = getParentScope();
  while (Parent && !(Parent->*GetFunction)())
    Parent = Parent->getParentScope();
  return Parent;
}

LVScope *LVElement::getFunctionParent() const {
  return traverseParents(&LVScope::getIsFunction);
}

LVScope *LVElement::getCompileUnitParent() const {
  return traverseParents(&LVScope::getIsCompileUnit);
}

// Resolve the qualified name to include the parent hierarchy names.
void LVElement::resolveQualifiedName() {
  if (!getIsReferencedType() || isBase() || getQualifiedResolved() ||
      !getIncludeInPrint())
    return;

  std::string Name;

  // Get the qualified name, excluding the Compile Unit.
  LVScope *Parent = getParentScope();
  if (Parent && !Parent->getIsRoot()) {
    while (Parent && !Parent->getIsCompileUnit()) {
      Name.insert(0, "::");
      if (Parent->isNamed())
        Name.insert(0, std::string(Parent->getName()));
      else {
        std::string Temp;
        Parent->generateName(Temp);
        Name.insert(0, Temp);
      }
      Parent = Parent->getParentScope();
    }
  }

  if (Name.size()) {
    setQualifiedName(Name);
    setQualifiedResolved();
  }
  LLVM_DEBUG({
    dbgs() << "Offset: " << hexSquareString(getOffset())
           << ", Kind: " << formattedKind(kind())
           << ", Name: " << formattedName(getName())
           << ", QualifiedName: " << formattedName(Name) << "\n";
  });
}

bool LVElement::referenceMatch(const LVElement *Element) const {
  return (getHasReference() && Element->getHasReference()) ||
         (!getHasReference() && !Element->getHasReference());
}

bool LVElement::equals(const LVElement *Element) const {
  // The minimum factors that must be the same for an equality are:
  // line number, level, name, qualified name and filename.
  LLVM_DEBUG({
    dbgs() << "\n[Element::equals]\n";
    if (options().getAttributeOffset()) {
      dbgs() << "Reference: " << hexSquareString(getOffset()) << "\n";
      dbgs() << "Target   : " << hexSquareString(Element->getOffset()) << "\n";
    }
    dbgs() << "Reference: "
           << "Kind = " << formattedKind(kind()) << ", "
           << "Name = " << formattedName(getName()) << ", "
           << "Qualified = " << formattedName(getQualifiedName()) << "\n"
           << "Target   : "
           << "Kind = " << formattedKind(Element->kind()) << ", "
           << "Name = " << formattedName(Element->getName()) << ", "
           << "Qualified = " << formattedName(Element->getQualifiedName())
           << "\n"
           << "Reference: "
           << "NameIndex = " << getNameIndex() << ", "
           << "QualifiedNameIndex = " << getQualifiedNameIndex() << ", "
           << "FilenameIndex = " << getFilenameIndex() << "\n"
           << "Target   : "
           << "NameIndex = " << Element->getNameIndex() << ", "
           << "QualifiedNameIndex = " << Element->getQualifiedNameIndex()
           << ", "
           << "FilenameIndex = " << Element->getFilenameIndex() << "\n";
  });
  if ((getLineNumber() != Element->getLineNumber()) ||
      (getLevel() != Element->getLevel()))
    return false;

  if ((getQualifiedNameIndex() != Element->getQualifiedNameIndex()) ||
      (getNameIndex() != Element->getNameIndex()) ||
      (getFilenameIndex() != Element->getFilenameIndex()))
    return false;

  if (!getType() && !Element->getType())
    return true;
  if (getType() && Element->getType())
    return getType()->equals(Element->getType());
  return false;
}

// Print the FileName Index.
void LVElement::printFileIndex(raw_ostream &OS, bool Full) const {
  if (options().getPrintFormatting() && options().getAttributeAnySource() &&
      getFilenameIndex()) {

    // Check if there is a change in the File ID sequence.
    size_t Index = getFilenameIndex();
    if (options().changeFilenameIndex(Index)) {
      // Just to keep a nice layout.
      OS << "\n";
      printAttributes(OS, /*Full=*/false);

      OS << "  {Source} ";
      if (getInvalidFilename())
        OS << format("[0x%08x]\n", Index);
      else
        OS << formattedName(getPathname()) << "\n";
    }
  }
}

void LVElement::printReference(raw_ostream &OS, bool Full,
                               LVElement *Parent) const {
  if (options().getPrintFormatting() && options().getAttributeReference())
    printAttributes(OS, Full, "{Reference} ", Parent,
                    referenceAsString(getLineNumber(), /*Spaces=*/false),
                    /*UseQuotes=*/false, /*PrintRef=*/true);
}

void LVElement::printLinkageName(raw_ostream &OS, bool Full,
                                 LVElement *Parent) const {
  if (options().getPrintFormatting() && options().getAttributeLinkage()) {
    printAttributes(OS, Full, "{Linkage} ", Parent, getLinkageName(),
                    /*UseQuotes=*/true, /*PrintRef=*/false);
  }
}

void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
                                 LVScope *Scope) const {
  if (options().getPrintFormatting() && options().getAttributeLinkage()) {
    LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
    std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) +
                        Twine(" '") + Twine(getLinkageName()) + Twine("'"))
                           .str();
    printAttributes(OS, Full, "{Linkage} ", Parent, Text,
                    /*UseQuotes=*/false, /*PrintRef=*/false);
  }
}