1//===-- LVSymbol.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 LVSymbol class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
14#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
15#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
16#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
17#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
18
19using namespace llvm;
20using namespace llvm::logicalview;
21
22#define DEBUG_TYPE "Symbol"
23
24namespace {
25const char *const KindCallSiteParameter = "CallSiteParameter";
26const char *const KindConstant = "Constant";
27const char *const KindInherits = "Inherits";
28const char *const KindMember = "Member";
29const char *const KindParameter = "Parameter";
30const char *const KindUndefined = "Undefined";
31const char *const KindUnspecified = "Unspecified";
32const char *const KindVariable = "Variable";
33} // end anonymous namespace
34
35// Return a string representation for the symbol kind.
36const char *LVSymbol::kind() const {
37 const char *Kind = KindUndefined;
38 if (getIsCallSiteParameter())
39 Kind = KindCallSiteParameter;
40 else if (getIsConstant())
41 Kind = KindConstant;
42 else if (getIsInheritance())
43 Kind = KindInherits;
44 else if (getIsMember())
45 Kind = KindMember;
46 else if (getIsParameter())
47 Kind = KindParameter;
48 else if (getIsUnspecified())
49 Kind = KindUnspecified;
50 else if (getIsVariable())
51 Kind = KindVariable;
52 return Kind;
53}
54
55LVSymbolDispatch LVSymbol::Dispatch = {
56 {LVSymbolKind::IsCallSiteParameter, &LVSymbol::getIsCallSiteParameter},
57 {LVSymbolKind::IsConstant, &LVSymbol::getIsConstant},
58 {LVSymbolKind::IsInheritance, &LVSymbol::getIsInheritance},
59 {LVSymbolKind::IsMember, &LVSymbol::getIsMember},
60 {LVSymbolKind::IsParameter, &LVSymbol::getIsParameter},
61 {LVSymbolKind::IsUnspecified, &LVSymbol::getIsUnspecified},
62 {LVSymbolKind::IsVariable, &LVSymbol::getIsVariable}};
63
64// Add a Location Entry.
65void LVSymbol::addLocation(dwarf::Attribute Attr, LVAddress LowPC,
66 LVAddress HighPC, LVUnsigned SectionOffset,
67 uint64_t LocDescOffset, bool CallSiteLocation) {
68 if (!Locations)
69 Locations = std::make_unique<LVLocations>();
70
71 // Create the location entry.
72 CurrentLocation = getReader().createLocationSymbol();
73 CurrentLocation->setParent(this);
74 CurrentLocation->setAttr(Attr);
75 if (CallSiteLocation)
76 CurrentLocation->setIsCallSite();
77 CurrentLocation->addObject(LowPC, HighPC, SectionOffset, LocDescOffset);
78 Locations->push_back(Elt: CurrentLocation);
79
80 // Mark the symbol as having location information.
81 setHasLocation();
82}
83
84// Add a Location Record.
85void LVSymbol::addLocationOperands(LVSmall Opcode,
86 ArrayRef<uint64_t> Operands) {
87 if (CurrentLocation)
88 CurrentLocation->addObject(Opcode, Operands);
89}
90
91// Add a Location Entry.
92void LVSymbol::addLocationConstant(dwarf::Attribute Attr, LVUnsigned Constant,
93 uint64_t LocDescOffset) {
94 // Create a Location Entry, with the global information.
95 addLocation(Attr,
96 /*LowPC=*/0, /*HighPC=*/-1,
97 /*SectionOffset=*/0, LocDescOffset);
98
99 // Add records to Location Entry.
100 addLocationOperands(/*Opcode=*/LVLocationMemberOffset, Operands: {Constant});
101}
102
103LVLocations::iterator LVSymbol::addLocationGap(LVLocations::iterator Pos,
104 LVAddress LowPC,
105 LVAddress HighPC) {
106 // Create a location entry for the gap.
107 LVLocation *Gap = getReader().createLocationSymbol();
108 Gap->setParent(this);
109 Gap->setAttr(dwarf::DW_AT_location);
110 Gap->addObject(LowPC, HighPC,
111 /*section_offset=*/SectionOffset: 0,
112 /*locdesc_offset=*/LocDescOffset: 0);
113
114 LVLocations::iterator Iter = Locations->insert(I: Pos, Elt: Gap);
115
116 // Add gap to Location Entry.
117 Gap->addObject(Opcode: dwarf::DW_OP_hi_user, Operands: {});
118
119 // Mark the entry as a gap.
120 Gap->setIsGapEntry();
121
122 return Iter;
123}
124
125void LVSymbol::fillLocationGaps() {
126 // The symbol has locations records. Fill gaps in the location list.
127 if (!getHasLocation() || !getFillGaps())
128 return;
129
130 // Get the parent range information and add dummy location entries.
131 const LVLocations *Ranges = getParentScope()->getRanges();
132 if (!Ranges)
133 return;
134
135 for (const LVLocation *Entry : *Ranges) {
136 LVAddress ParentLowPC = Entry->getLowerAddress();
137 LVAddress ParentHighPC = Entry->getUpperAddress();
138
139 // Traverse the symbol locations and for each location contained in
140 // the current parent range, insert locations for any existing gap.
141 LVLocation *Location;
142 LVAddress LowPC = 0;
143 LVAddress Marker = ParentLowPC;
144 for (LVLocations::iterator Iter = Locations->begin();
145 Iter != Locations->end(); ++Iter) {
146 Location = *Iter;
147 LowPC = Location->getLowerAddress();
148 if (LowPC != Marker) {
149 // We have a gap at [Marker,LowPC - 1].
150 Iter = addLocationGap(Pos: Iter, LowPC: Marker, HighPC: LowPC - 1);
151 ++Iter;
152 }
153
154 // Move to the next item in the location list.
155 Marker = Location->getUpperAddress() + 1;
156 }
157
158 // Check any gap at the end.
159 if (Marker < ParentHighPC)
160 // We have a gap at [Marker,ParentHighPC].
161 addLocationGap(Pos: Locations->end(), LowPC: Marker, HighPC: ParentHighPC);
162 }
163}
164
165// Get all the locations based on the valid function.
166void LVSymbol::getLocations(LVLocations &LocationList,
167 LVValidLocation ValidLocation, bool RecordInvalid) {
168 if (!Locations)
169 return;
170
171 for (LVLocation *Location : *Locations) {
172 // Add the invalid location object.
173 if (!(Location->*ValidLocation)() && RecordInvalid)
174 LocationList.push_back(Elt: Location);
175 }
176
177 // Calculate coverage factor.
178 calculateCoverage();
179}
180
181void LVSymbol::getLocations(LVLocations &LocationList) const {
182 if (!Locations)
183 return;
184
185 llvm::append_range(C&: LocationList, R&: *Locations);
186}
187
188// Calculate coverage factor.
189void LVSymbol::calculateCoverage() {
190 if (!LVLocation::calculateCoverage(Locations: Locations.get(), Factor&: CoverageFactor,
191 Percentage&: CoveragePercentage)) {
192 LVScope *Parent = getParentScope();
193 if (Parent->getIsInlinedFunction()) {
194 // For symbols representing the inlined function parameters and its
195 // variables, get the outer most parent that contains their location
196 // lower address.
197 // The symbol can have a set of non-contiguous locations. We are using
198 // only the first location entry to get the outermost parent.
199 // If no scope contains the location, assume its enclosing parent.
200 LVScope *Scope =
201 Parent->outermostParent(Address: Locations->front()->getLowerAddress());
202 if (Scope)
203 Parent = Scope;
204 }
205 unsigned CoverageParent = Parent->getCoverageFactor();
206 // Get a percentage rounded to two decimal digits. This avoids
207 // implementation-defined rounding inside printing functions.
208 CoveragePercentage =
209 CoverageParent
210 ? rint(x: (double(CoverageFactor) / CoverageParent) * 100.0 * 100.0) /
211 100.0
212 : 0;
213 // Record invalid coverage entry.
214 if (options().getWarningCoverages() && CoveragePercentage > 100)
215 getReaderCompileUnit()->addInvalidCoverage(Symbol: this);
216 }
217}
218
219void LVSymbol::resolveName() {
220 if (getIsResolvedName())
221 return;
222 setIsResolvedName();
223
224 LVElement::resolveName();
225
226 // Resolve any given pattern.
227 patterns().resolvePatternMatch(Symbol: this);
228}
229
230void LVSymbol::resolveReferences() {
231 // The symbols can have the following references to other elements:
232 // A Type:
233 // DW_AT_type -> Type or Scope
234 // DW_AT_import -> Type
235 // A Reference:
236 // DW_AT_specification -> Symbol
237 // DW_AT_abstract_origin -> Symbol
238 // DW_AT_extension -> Symbol
239
240 // Resolve any referenced symbol.
241 LVSymbol *Reference = getReference();
242 if (Reference) {
243 Reference->resolve();
244 // Recursively resolve the symbol names.
245 resolveReferencesChain();
246 }
247
248 // Set the file/line information using the Debug Information entry.
249 setFile(Reference);
250
251 // Resolve symbol type.
252 if (LVElement *Element = getType()) {
253 Element->resolve();
254
255 // In the case of demoted typedefs, use the underlying type.
256 if (Element->getIsTypedefReduced()) {
257 Element = Element->getType();
258 Element->resolve();
259 }
260
261 // If the type is a template parameter, get its type, which can
262 // point to a type or scope, depending on the argument instance.
263 setGenericType(Element);
264 }
265
266 // Resolve the variable associated type.
267 if (!getType() && Reference)
268 setType(Reference->getType());
269}
270
271StringRef LVSymbol::resolveReferencesChain() {
272 // If the symbol have a DW_AT_specification or DW_AT_abstract_origin,
273 // follow the chain to resolve the name from those references.
274 if (getHasReference() && !isNamed())
275 setName(getReference()->resolveReferencesChain());
276
277 return getName();
278}
279
280void LVSymbol::markMissingParents(const LVSymbols *References,
281 const LVSymbols *Targets) {
282 if (!(References && Targets))
283 return;
284
285 LLVM_DEBUG({
286 dbgs() << "\n[LVSymbol::markMissingParents]\n";
287 for (const LVSymbol *Reference : *References)
288 dbgs() << "References: "
289 << "Kind = " << formattedKind(Reference->kind()) << ", "
290 << "Name = " << formattedName(Reference->getName()) << "\n";
291 for (const LVSymbol *Target : *Targets)
292 dbgs() << "Targets : "
293 << "Kind = " << formattedKind(Target->kind()) << ", "
294 << "Name = " << formattedName(Target->getName()) << "\n";
295 });
296
297 for (LVSymbol *Reference : *References) {
298 LLVM_DEBUG({
299 dbgs() << "Search Reference: Name = "
300 << formattedName(Reference->getName()) << "\n";
301 });
302 if (!Reference->findIn(Targets))
303 Reference->markBranchAsMissing();
304 }
305}
306
307LVSymbol *LVSymbol::findIn(const LVSymbols *Targets) const {
308 if (!Targets)
309 return nullptr;
310
311 LLVM_DEBUG({
312 dbgs() << "\n[LVSymbol::findIn]\n"
313 << "Reference: "
314 << "Level = " << getLevel() << ", "
315 << "Kind = " << formattedKind(kind()) << ", "
316 << "Name = " << formattedName(getName()) << "\n";
317 for (const LVSymbol *Target : *Targets)
318 dbgs() << "Target : "
319 << "Level = " << Target->getLevel() << ", "
320 << "Kind = " << formattedKind(Target->kind()) << ", "
321 << "Name = " << formattedName(Target->getName()) << "\n";
322 });
323
324 for (LVSymbol *Target : *Targets)
325 if (equals(Symbol: Target))
326 return Target;
327
328 return nullptr;
329}
330
331// Check for a match on the arguments of a function.
332bool LVSymbol::parametersMatch(const LVSymbols *References,
333 const LVSymbols *Targets) {
334 if (!References && !Targets)
335 return true;
336 if (References && Targets) {
337 LVSymbols ReferenceParams;
338 getParameters(Symbols: References, Parameters: &ReferenceParams);
339 LVSymbols TargetParams;
340 getParameters(Symbols: Targets, Parameters: &TargetParams);
341 return LVSymbol::equals(References: &ReferenceParams, Targets: &TargetParams);
342 }
343 return false;
344}
345
346// Return the symbols which are parameters.
347void LVSymbol::getParameters(const LVSymbols *Symbols, LVSymbols *Parameters) {
348 if (Symbols)
349 for (LVSymbol *Symbol : *Symbols)
350 if (Symbol->getIsParameter())
351 Parameters->push_back(Elt: Symbol);
352}
353
354bool LVSymbol::equals(const LVSymbol *Symbol) const {
355 if (!LVElement::equals(Element: Symbol))
356 return false;
357
358 // Check if any reference is the same.
359 if (!referenceMatch(Element: Symbol))
360 return false;
361
362 if (getReference() && !getReference()->equals(Symbol: Symbol->getReference()))
363 return false;
364
365 return true;
366}
367
368bool LVSymbol::equals(const LVSymbols *References, const LVSymbols *Targets) {
369 if (!References && !Targets)
370 return true;
371 if (References && Targets && References->size() == Targets->size()) {
372 for (const LVSymbol *Reference : *References)
373 if (!Reference->findIn(Targets))
374 return false;
375 return true;
376 }
377 return false;
378}
379
380void LVSymbol::report(LVComparePass Pass) {
381 getComparator().printItem(Element: this, Pass);
382}
383
384void LVSymbol::printLocations(raw_ostream &OS, bool Full) const {
385 if (Locations)
386 for (const LVLocation *Location : *Locations)
387 Location->printRaw(OS, Full);
388}
389
390void LVSymbol::print(raw_ostream &OS, bool Full) const {
391 if (getIncludeInPrint() && getReader().doPrintSymbol(Symbol: this)) {
392 getReaderCompileUnit()->incrementPrintedSymbols();
393 LVElement::print(OS, Full);
394 printExtra(OS, Full);
395 }
396}
397
398void LVSymbol::printExtra(raw_ostream &OS, bool Full) const {
399 // Accessibility depends on the parent (class, structure).
400 uint32_t AccessCode = 0;
401 if (getIsMember() || getIsInheritance())
402 AccessCode = getParentScope()->getIsClass() ? dwarf::DW_ACCESS_private
403 : dwarf::DW_ACCESS_public;
404
405 const LVSymbol *Symbol = getIsInlined() ? Reference : this;
406 std::string Attributes =
407 Symbol->getIsCallSiteParameter()
408 ? ""
409 : formatAttributes(First: Symbol->externalString(),
410 Others: Symbol->accessibilityString(Access: AccessCode),
411 Others: virtualityString());
412
413 OS << formattedKind(Kind: Symbol->kind()) << " " << Attributes;
414 if (Symbol->getIsUnspecified())
415 OS << formattedName(Name: Symbol->getName());
416 else {
417 if (Symbol->getIsInheritance())
418 OS << Symbol->typeOffsetAsString()
419 << formattedNames(Name1: Symbol->getTypeQualifiedName(),
420 Name2: Symbol->typeAsString());
421 else {
422 OS << formattedName(Name: Symbol->getName());
423 // Print any bitfield information.
424 if (uint32_t Size = getBitSize())
425 OS << ":" << Size;
426 OS << " -> " << Symbol->typeOffsetAsString()
427 << formattedNames(Name1: Symbol->getTypeQualifiedName(),
428 Name2: Symbol->typeAsString());
429 }
430 }
431
432 // Print any initial value if any.
433 if (ValueIndex)
434 OS << " = " << formattedName(Name: getValue());
435 OS << "\n";
436
437 if (Full && options().getPrintFormatting()) {
438 if (getLinkageNameIndex())
439 printLinkageName(OS, Full, Parent: const_cast<LVSymbol *>(this));
440 if (LVSymbol *Reference = getReference())
441 Reference->printReference(OS, Full, Parent: const_cast<LVSymbol *>(this));
442
443 // Print location information.
444 LVLocation::print(Locations: Locations.get(), OS, Full);
445 }
446}
447