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 | |
19 | using namespace llvm; |
20 | using namespace llvm::logicalview; |
21 | |
22 | #define DEBUG_TYPE "Symbol" |
23 | |
24 | namespace { |
25 | const char *const KindCallSiteParameter = "CallSiteParameter" ; |
26 | const char *const KindConstant = "Constant" ; |
27 | const char *const KindInherits = "Inherits" ; |
28 | const char *const KindMember = "Member" ; |
29 | const char *const KindParameter = "Parameter" ; |
30 | const char *const KindUndefined = "Undefined" ; |
31 | const char *const KindUnspecified = "Unspecified" ; |
32 | const char *const KindVariable = "Variable" ; |
33 | } // end anonymous namespace |
34 | |
35 | // Return a string representation for the symbol kind. |
36 | const 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 | |
55 | LVSymbolDispatch 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. |
65 | void 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. |
85 | void LVSymbol::addLocationOperands(LVSmall Opcode, |
86 | ArrayRef<uint64_t> Operands) { |
87 | if (CurrentLocation) |
88 | CurrentLocation->addObject(Opcode, Operands); |
89 | } |
90 | |
91 | // Add a Location Entry. |
92 | void 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 | |
103 | LVLocations::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 | |
125 | void 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. |
166 | void 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 | |
181 | void 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. |
189 | void 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 | |
219 | void 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 | |
230 | void 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 | |
271 | StringRef 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 | |
280 | void 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 | |
307 | LVSymbol *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. |
332 | bool 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. |
347 | void 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 | |
354 | bool 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 | |
368 | bool 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 | |
380 | void LVSymbol::report(LVComparePass Pass) { |
381 | getComparator().printItem(Element: this, Pass); |
382 | } |
383 | |
384 | void LVSymbol::printLocations(raw_ostream &OS, bool Full) const { |
385 | if (Locations) |
386 | for (const LVLocation *Location : *Locations) |
387 | Location->printRaw(OS, Full); |
388 | } |
389 | |
390 | void 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 | |
398 | void LVSymbol::(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 | |