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 | for (LVLocation *Location : *Locations) |
186 | LocationList.push_back(Elt: Location); |
187 | } |
188 | |
189 | // Calculate coverage factor. |
190 | void LVSymbol::calculateCoverage() { |
191 | if (!LVLocation::calculateCoverage(Locations: Locations.get(), Factor&: CoverageFactor, |
192 | Percentage&: CoveragePercentage)) { |
193 | LVScope *Parent = getParentScope(); |
194 | if (Parent->getIsInlinedFunction()) { |
195 | // For symbols representing the inlined function parameters and its |
196 | // variables, get the outer most parent that contains their location |
197 | // lower address. |
198 | // The symbol can have a set of non-contiguous locations. We are using |
199 | // only the first location entry to get the outermost parent. |
200 | // If no scope contains the location, assume its enclosing parent. |
201 | LVScope *Scope = |
202 | Parent->outermostParent(Address: Locations->front()->getLowerAddress()); |
203 | if (Scope) |
204 | Parent = Scope; |
205 | } |
206 | unsigned CoverageParent = Parent->getCoverageFactor(); |
207 | // Get a percentage rounded to two decimal digits. This avoids |
208 | // implementation-defined rounding inside printing functions. |
209 | CoveragePercentage = |
210 | CoverageParent |
211 | ? rint(x: (double(CoverageFactor) / CoverageParent) * 100.0 * 100.0) / |
212 | 100.0 |
213 | : 0; |
214 | // Record invalid coverage entry. |
215 | if (options().getWarningCoverages() && CoveragePercentage > 100) |
216 | getReaderCompileUnit()->addInvalidCoverage(Symbol: this); |
217 | } |
218 | } |
219 | |
220 | void LVSymbol::resolveName() { |
221 | if (getIsResolvedName()) |
222 | return; |
223 | setIsResolvedName(); |
224 | |
225 | LVElement::resolveName(); |
226 | |
227 | // Resolve any given pattern. |
228 | patterns().resolvePatternMatch(Symbol: this); |
229 | } |
230 | |
231 | void LVSymbol::resolveReferences() { |
232 | // The symbols can have the following references to other elements: |
233 | // A Type: |
234 | // DW_AT_type -> Type or Scope |
235 | // DW_AT_import -> Type |
236 | // A Reference: |
237 | // DW_AT_specification -> Symbol |
238 | // DW_AT_abstract_origin -> Symbol |
239 | // DW_AT_extension -> Symbol |
240 | |
241 | // Resolve any referenced symbol. |
242 | LVSymbol *Reference = getReference(); |
243 | if (Reference) { |
244 | Reference->resolve(); |
245 | // Recursively resolve the symbol names. |
246 | resolveReferencesChain(); |
247 | } |
248 | |
249 | // Set the file/line information using the Debug Information entry. |
250 | setFile(Reference); |
251 | |
252 | // Resolve symbol type. |
253 | if (LVElement *Element = getType()) { |
254 | Element->resolve(); |
255 | |
256 | // In the case of demoted typedefs, use the underlying type. |
257 | if (Element->getIsTypedefReduced()) { |
258 | Element = Element->getType(); |
259 | Element->resolve(); |
260 | } |
261 | |
262 | // If the type is a template parameter, get its type, which can |
263 | // point to a type or scope, depending on the argument instance. |
264 | setGenericType(Element); |
265 | } |
266 | |
267 | // Resolve the variable associated type. |
268 | if (!getType() && Reference) |
269 | setType(Reference->getType()); |
270 | } |
271 | |
272 | StringRef LVSymbol::resolveReferencesChain() { |
273 | // If the symbol have a DW_AT_specification or DW_AT_abstract_origin, |
274 | // follow the chain to resolve the name from those references. |
275 | if (getHasReference() && !isNamed()) |
276 | setName(getReference()->resolveReferencesChain()); |
277 | |
278 | return getName(); |
279 | } |
280 | |
281 | void LVSymbol::markMissingParents(const LVSymbols *References, |
282 | const LVSymbols *Targets) { |
283 | if (!(References && Targets)) |
284 | return; |
285 | |
286 | LLVM_DEBUG({ |
287 | dbgs() << "\n[LVSymbol::markMissingParents]\n" ; |
288 | for (const LVSymbol *Reference : *References) |
289 | dbgs() << "References: " |
290 | << "Kind = " << formattedKind(Reference->kind()) << ", " |
291 | << "Name = " << formattedName(Reference->getName()) << "\n" ; |
292 | for (const LVSymbol *Target : *Targets) |
293 | dbgs() << "Targets : " |
294 | << "Kind = " << formattedKind(Target->kind()) << ", " |
295 | << "Name = " << formattedName(Target->getName()) << "\n" ; |
296 | }); |
297 | |
298 | for (LVSymbol *Reference : *References) { |
299 | LLVM_DEBUG({ |
300 | dbgs() << "Search Reference: Name = " |
301 | << formattedName(Reference->getName()) << "\n" ; |
302 | }); |
303 | if (!Reference->findIn(Targets)) |
304 | Reference->markBranchAsMissing(); |
305 | } |
306 | } |
307 | |
308 | LVSymbol *LVSymbol::findIn(const LVSymbols *Targets) const { |
309 | if (!Targets) |
310 | return nullptr; |
311 | |
312 | LLVM_DEBUG({ |
313 | dbgs() << "\n[LVSymbol::findIn]\n" |
314 | << "Reference: " |
315 | << "Level = " << getLevel() << ", " |
316 | << "Kind = " << formattedKind(kind()) << ", " |
317 | << "Name = " << formattedName(getName()) << "\n" ; |
318 | for (const LVSymbol *Target : *Targets) |
319 | dbgs() << "Target : " |
320 | << "Level = " << Target->getLevel() << ", " |
321 | << "Kind = " << formattedKind(Target->kind()) << ", " |
322 | << "Name = " << formattedName(Target->getName()) << "\n" ; |
323 | }); |
324 | |
325 | for (LVSymbol *Target : *Targets) |
326 | if (equals(Symbol: Target)) |
327 | return Target; |
328 | |
329 | return nullptr; |
330 | } |
331 | |
332 | // Check for a match on the arguments of a function. |
333 | bool LVSymbol::parametersMatch(const LVSymbols *References, |
334 | const LVSymbols *Targets) { |
335 | if (!References && !Targets) |
336 | return true; |
337 | if (References && Targets) { |
338 | LVSymbols ReferenceParams; |
339 | getParameters(Symbols: References, Parameters: &ReferenceParams); |
340 | LVSymbols TargetParams; |
341 | getParameters(Symbols: Targets, Parameters: &TargetParams); |
342 | return LVSymbol::equals(References: &ReferenceParams, Targets: &TargetParams); |
343 | } |
344 | return false; |
345 | } |
346 | |
347 | // Return the symbols which are parameters. |
348 | void LVSymbol::getParameters(const LVSymbols *Symbols, LVSymbols *Parameters) { |
349 | if (Symbols) |
350 | for (LVSymbol *Symbol : *Symbols) |
351 | if (Symbol->getIsParameter()) |
352 | Parameters->push_back(Elt: Symbol); |
353 | } |
354 | |
355 | bool LVSymbol::equals(const LVSymbol *Symbol) const { |
356 | if (!LVElement::equals(Element: Symbol)) |
357 | return false; |
358 | |
359 | // Check if any reference is the same. |
360 | if (!referenceMatch(Element: Symbol)) |
361 | return false; |
362 | |
363 | if (getReference() && !getReference()->equals(Symbol: Symbol->getReference())) |
364 | return false; |
365 | |
366 | return true; |
367 | } |
368 | |
369 | bool LVSymbol::equals(const LVSymbols *References, const LVSymbols *Targets) { |
370 | if (!References && !Targets) |
371 | return true; |
372 | if (References && Targets && References->size() == Targets->size()) { |
373 | for (const LVSymbol *Reference : *References) |
374 | if (!Reference->findIn(Targets)) |
375 | return false; |
376 | return true; |
377 | } |
378 | return false; |
379 | } |
380 | |
381 | void LVSymbol::report(LVComparePass Pass) { |
382 | getComparator().printItem(Element: this, Pass); |
383 | } |
384 | |
385 | void LVSymbol::printLocations(raw_ostream &OS, bool Full) const { |
386 | if (Locations) |
387 | for (const LVLocation *Location : *Locations) |
388 | Location->printRaw(OS, Full); |
389 | } |
390 | |
391 | void LVSymbol::print(raw_ostream &OS, bool Full) const { |
392 | if (getIncludeInPrint() && getReader().doPrintSymbol(Symbol: this)) { |
393 | getReaderCompileUnit()->incrementPrintedSymbols(); |
394 | LVElement::print(OS, Full); |
395 | printExtra(OS, Full); |
396 | } |
397 | } |
398 | |
399 | void LVSymbol::(raw_ostream &OS, bool Full) const { |
400 | // Accessibility depends on the parent (class, structure). |
401 | uint32_t AccessCode = 0; |
402 | if (getIsMember() || getIsInheritance()) |
403 | AccessCode = getParentScope()->getIsClass() ? dwarf::DW_ACCESS_private |
404 | : dwarf::DW_ACCESS_public; |
405 | |
406 | const LVSymbol *Symbol = getIsInlined() ? Reference : this; |
407 | std::string Attributes = |
408 | Symbol->getIsCallSiteParameter() |
409 | ? "" |
410 | : formatAttributes(First: Symbol->externalString(), |
411 | Others: Symbol->accessibilityString(Access: AccessCode), |
412 | Others: virtualityString()); |
413 | |
414 | OS << formattedKind(Kind: Symbol->kind()) << " " << Attributes; |
415 | if (Symbol->getIsUnspecified()) |
416 | OS << formattedName(Name: Symbol->getName()); |
417 | else { |
418 | if (Symbol->getIsInheritance()) |
419 | OS << Symbol->typeOffsetAsString() |
420 | << formattedNames(Name1: Symbol->getTypeQualifiedName(), |
421 | Name2: Symbol->typeAsString()); |
422 | else { |
423 | OS << formattedName(Name: Symbol->getName()); |
424 | // Print any bitfield information. |
425 | if (uint32_t Size = getBitSize()) |
426 | OS << ":" << Size; |
427 | OS << " -> " << Symbol->typeOffsetAsString() |
428 | << formattedNames(Name1: Symbol->getTypeQualifiedName(), |
429 | Name2: Symbol->typeAsString()); |
430 | } |
431 | } |
432 | |
433 | // Print any initial value if any. |
434 | if (ValueIndex) |
435 | OS << " = " << formattedName(Name: getValue()); |
436 | OS << "\n" ; |
437 | |
438 | if (Full && options().getPrintFormatting()) { |
439 | if (getLinkageNameIndex()) |
440 | printLinkageName(OS, Full, Parent: const_cast<LVSymbol *>(this)); |
441 | if (LVSymbol *Reference = getReference()) |
442 | Reference->printReference(OS, Full, Parent: const_cast<LVSymbol *>(this)); |
443 | |
444 | // Print location information. |
445 | LVLocation::print(Locations: Locations.get(), OS, Full); |
446 | } |
447 | } |
448 | |