1 | //===-- LVScope.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 LVScope class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" |
14 | #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" |
15 | #include "llvm/DebugInfo/LogicalView/Core/LVLine.h" |
16 | #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h" |
17 | #include "llvm/DebugInfo/LogicalView/Core/LVRange.h" |
18 | #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" |
19 | #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" |
20 | #include "llvm/DebugInfo/LogicalView/Core/LVType.h" |
21 | |
22 | using namespace llvm; |
23 | using namespace llvm::logicalview; |
24 | |
25 | #define DEBUG_TYPE "Scope" |
26 | |
27 | namespace { |
28 | const char *const KindArray = "Array" ; |
29 | const char *const KindBlock = "Block" ; |
30 | const char *const KindCallSite = "CallSite" ; |
31 | const char *const KindClass = "Class" ; |
32 | const char *const KindCompileUnit = "CompileUnit" ; |
33 | const char *const KindEnumeration = "Enumeration" ; |
34 | const char *const KindFile = "File" ; |
35 | const char *const KindFunction = "Function" ; |
36 | const char *const KindInlinedFunction = "InlinedFunction" ; |
37 | const char *const KindNamespace = "Namespace" ; |
38 | const char *const KindStruct = "Struct" ; |
39 | const char *const KindTemplateAlias = "TemplateAlias" ; |
40 | const char *const KindTemplatePack = "TemplatePack" ; |
41 | const char *const KindUndefined = "Undefined" ; |
42 | const char *const KindUnion = "Union" ; |
43 | } // end anonymous namespace |
44 | |
45 | //===----------------------------------------------------------------------===// |
46 | // DWARF lexical block, such as: namespace, function, compile unit, module, etc. |
47 | //===----------------------------------------------------------------------===// |
48 | // Return a string representation for the scope kind. |
49 | const char *LVScope::kind() const { |
50 | const char *Kind = KindUndefined; |
51 | if (getIsArray()) |
52 | Kind = KindArray; |
53 | else if (getIsBlock()) |
54 | Kind = KindBlock; |
55 | else if (getIsCallSite()) |
56 | Kind = KindCallSite; |
57 | else if (getIsCompileUnit()) |
58 | Kind = KindCompileUnit; |
59 | else if (getIsEnumeration()) |
60 | Kind = KindEnumeration; |
61 | else if (getIsInlinedFunction()) |
62 | Kind = KindInlinedFunction; |
63 | else if (getIsNamespace()) |
64 | Kind = KindNamespace; |
65 | else if (getIsTemplatePack()) |
66 | Kind = KindTemplatePack; |
67 | else if (getIsRoot()) |
68 | Kind = KindFile; |
69 | else if (getIsTemplateAlias()) |
70 | Kind = KindTemplateAlias; |
71 | else if (getIsClass()) |
72 | Kind = KindClass; |
73 | else if (getIsFunction()) |
74 | Kind = KindFunction; |
75 | else if (getIsStructure()) |
76 | Kind = KindStruct; |
77 | else if (getIsUnion()) |
78 | Kind = KindUnion; |
79 | return Kind; |
80 | } |
81 | |
82 | LVScopeDispatch LVScope::Dispatch = { |
83 | {LVScopeKind::IsAggregate, &LVScope::getIsAggregate}, |
84 | {LVScopeKind::IsArray, &LVScope::getIsArray}, |
85 | {LVScopeKind::IsBlock, &LVScope::getIsBlock}, |
86 | {LVScopeKind::IsCallSite, &LVScope::getIsCallSite}, |
87 | {LVScopeKind::IsCatchBlock, &LVScope::getIsCatchBlock}, |
88 | {LVScopeKind::IsClass, &LVScope::getIsClass}, |
89 | {LVScopeKind::IsCompileUnit, &LVScope::getIsCompileUnit}, |
90 | {LVScopeKind::IsEntryPoint, &LVScope::getIsEntryPoint}, |
91 | {LVScopeKind::IsEnumeration, &LVScope::getIsEnumeration}, |
92 | {LVScopeKind::IsFunction, &LVScope::getIsFunction}, |
93 | {LVScopeKind::IsFunctionType, &LVScope::getIsFunctionType}, |
94 | {LVScopeKind::IsInlinedFunction, &LVScope::getIsInlinedFunction}, |
95 | {LVScopeKind::IsLabel, &LVScope::getIsLabel}, |
96 | {LVScopeKind::IsLexicalBlock, &LVScope::getIsLexicalBlock}, |
97 | {LVScopeKind::IsNamespace, &LVScope::getIsNamespace}, |
98 | {LVScopeKind::IsRoot, &LVScope::getIsRoot}, |
99 | {LVScopeKind::IsStructure, &LVScope::getIsStructure}, |
100 | {LVScopeKind::IsTemplate, &LVScope::getIsTemplate}, |
101 | {LVScopeKind::IsTemplateAlias, &LVScope::getIsTemplateAlias}, |
102 | {LVScopeKind::IsTemplatePack, &LVScope::getIsTemplatePack}, |
103 | {LVScopeKind::IsTryBlock, &LVScope::getIsTryBlock}, |
104 | {LVScopeKind::IsUnion, &LVScope::getIsUnion}}; |
105 | |
106 | void LVScope::addToChildren(LVElement *Element) { |
107 | if (!Children) |
108 | Children = std::make_unique<LVElements>(); |
109 | Children->push_back(Elt: Element); |
110 | } |
111 | |
112 | void LVScope::addElement(LVElement *Element) { |
113 | assert(Element && "Invalid element." ); |
114 | if (Element->getIsType()) |
115 | addElement(Type: static_cast<LVType *>(Element)); |
116 | else if (Element->getIsScope()) |
117 | addElement(Scope: static_cast<LVScope *>(Element)); |
118 | else if (Element->getIsSymbol()) |
119 | addElement(Symbol: static_cast<LVSymbol *>(Element)); |
120 | else if (Element->getIsLine()) |
121 | addElement(Line: static_cast<LVLine *>(Element)); |
122 | else |
123 | llvm_unreachable("Invalid Element." ); |
124 | } |
125 | |
126 | // Adds the line info item to the ones stored in the scope. |
127 | void LVScope::addElement(LVLine *Line) { |
128 | assert(Line && "Invalid line." ); |
129 | assert(!Line->getParent() && "Line already inserted" ); |
130 | if (!Lines) |
131 | Lines = std::make_unique<LVLines>(); |
132 | |
133 | // Add it to parent. |
134 | Lines->push_back(Elt: Line); |
135 | Line->setParent(this); |
136 | |
137 | // Notify the reader about the new element being added. |
138 | getReaderCompileUnit()->addedElement(Line); |
139 | |
140 | // All logical elements added to the children, are sorted by any of the |
141 | // following criterias: offset, name, line number, kind. |
142 | // Do not add the line records to the children, as they represent the |
143 | // logical view for the text section and any sorting will not preserve |
144 | // the original sequence. |
145 | |
146 | // Indicate that this tree branch has lines. |
147 | traverseParents(GetFunction: &LVScope::getHasLines, SetFunction: &LVScope::setHasLines); |
148 | } |
149 | |
150 | // Add a location. |
151 | void LVScope::addObject(LVLocation *Location) { |
152 | assert(Location && "Invalid location." ); |
153 | assert(!Location->getParent() && "Location already inserted" ); |
154 | if (!Ranges) |
155 | Ranges = std::make_unique<LVLocations>(); |
156 | |
157 | // Add it to parent. |
158 | Location->setParent(this); |
159 | Location->setOffset(getOffset()); |
160 | |
161 | Ranges->push_back(Elt: Location); |
162 | setHasRanges(); |
163 | } |
164 | |
165 | // Adds the scope to the child scopes and sets the parent in the child. |
166 | void LVScope::addElement(LVScope *Scope) { |
167 | assert(Scope && "Invalid scope." ); |
168 | assert(!Scope->getParent() && "Scope already inserted" ); |
169 | if (!Scopes) |
170 | Scopes = std::make_unique<LVScopes>(); |
171 | |
172 | // Add it to parent. |
173 | Scopes->push_back(Elt: Scope); |
174 | addToChildren(Element: Scope); |
175 | Scope->setParent(this); |
176 | |
177 | // Notify the reader about the new element being added. |
178 | getReaderCompileUnit()->addedElement(Scope); |
179 | |
180 | // If the element is a global reference, mark its parent as having global |
181 | // references; that information is used, to print only those branches |
182 | // with global references. |
183 | if (Scope->getIsGlobalReference()) |
184 | traverseParents(GetFunction: &LVScope::getHasGlobals, SetFunction: &LVScope::setHasGlobals); |
185 | else |
186 | traverseParents(GetFunction: &LVScope::getHasLocals, SetFunction: &LVScope::setHasLocals); |
187 | |
188 | // Indicate that this tree branch has scopes. |
189 | traverseParents(GetFunction: &LVScope::getHasScopes, SetFunction: &LVScope::setHasScopes); |
190 | } |
191 | |
192 | // Adds a symbol to the ones stored in the scope. |
193 | void LVScope::addElement(LVSymbol *Symbol) { |
194 | assert(Symbol && "Invalid symbol." ); |
195 | assert(!Symbol->getParent() && "Symbol already inserted" ); |
196 | if (!Symbols) |
197 | Symbols = std::make_unique<LVSymbols>(); |
198 | |
199 | // Add it to parent. |
200 | Symbols->push_back(Elt: Symbol); |
201 | addToChildren(Element: Symbol); |
202 | Symbol->setParent(this); |
203 | |
204 | // Notify the reader about the new element being added. |
205 | getReaderCompileUnit()->addedElement(Symbol); |
206 | |
207 | // If the element is a global reference, mark its parent as having global |
208 | // references; that information is used, to print only those branches |
209 | // with global references. |
210 | if (Symbol->getIsGlobalReference()) |
211 | traverseParents(GetFunction: &LVScope::getHasGlobals, SetFunction: &LVScope::setHasGlobals); |
212 | else |
213 | traverseParents(GetFunction: &LVScope::getHasLocals, SetFunction: &LVScope::setHasLocals); |
214 | |
215 | // Indicate that this tree branch has symbols. |
216 | traverseParents(GetFunction: &LVScope::getHasSymbols, SetFunction: &LVScope::setHasSymbols); |
217 | } |
218 | |
219 | // Adds a type to the ones stored in the scope. |
220 | void LVScope::addElement(LVType *Type) { |
221 | assert(Type && "Invalid type." ); |
222 | assert(!Type->getParent() && "Type already inserted" ); |
223 | if (!Types) |
224 | Types = std::make_unique<LVTypes>(); |
225 | |
226 | // Add it to parent. |
227 | Types->push_back(Elt: Type); |
228 | addToChildren(Element: Type); |
229 | Type->setParent(this); |
230 | |
231 | // Notify the reader about the new element being added. |
232 | getReaderCompileUnit()->addedElement(Type); |
233 | |
234 | // If the element is a global reference, mark its parent as having global |
235 | // references; that information is used, to print only those branches |
236 | // with global references. |
237 | if (Type->getIsGlobalReference()) |
238 | traverseParents(GetFunction: &LVScope::getHasGlobals, SetFunction: &LVScope::setHasGlobals); |
239 | else |
240 | traverseParents(GetFunction: &LVScope::getHasLocals, SetFunction: &LVScope::setHasLocals); |
241 | |
242 | // Indicate that this tree branch has types. |
243 | traverseParents(GetFunction: &LVScope::getHasTypes, SetFunction: &LVScope::setHasTypes); |
244 | } |
245 | |
246 | // Add a pair of ranges. |
247 | void LVScope::addObject(LVAddress LowerAddress, LVAddress UpperAddress) { |
248 | // Pack the ranges into a Location object. |
249 | LVLocation *Location = getReader().createLocation(); |
250 | Location->setLowerAddress(LowerAddress); |
251 | Location->setUpperAddress(UpperAddress); |
252 | Location->setIsAddressRange(); |
253 | |
254 | addObject(Location); |
255 | } |
256 | |
257 | bool LVScope::removeElement(LVElement *Element) { |
258 | auto Predicate = [Element](LVElement *Item) -> bool { |
259 | return Item == Element; |
260 | }; |
261 | auto RemoveElement = [Element, Predicate](auto &Container) -> bool { |
262 | auto Iter = std::remove_if(Container->begin(), Container->end(), Predicate); |
263 | if (Iter != Container->end()) { |
264 | Container->erase(Iter, Container->end()); |
265 | Element->resetParent(); |
266 | return true; |
267 | } |
268 | return false; |
269 | }; |
270 | |
271 | // As 'children' contains only (scopes, symbols and types), check if the |
272 | // element we are deleting is a line. |
273 | if (Element->getIsLine()) |
274 | return RemoveElement(Lines); |
275 | |
276 | if (RemoveElement(Children)) { |
277 | if (Element->getIsSymbol()) |
278 | return RemoveElement(Symbols); |
279 | if (Element->getIsType()) |
280 | return RemoveElement(Types); |
281 | if (Element->getIsScope()) |
282 | return RemoveElement(Scopes); |
283 | llvm_unreachable("Invalid element." ); |
284 | } |
285 | |
286 | return false; |
287 | } |
288 | |
289 | void LVScope::addMissingElements(LVScope *Reference) { |
290 | setAddedMissing(); |
291 | if (!Reference) |
292 | return; |
293 | |
294 | // Get abstract symbols for the given scope reference. |
295 | const LVSymbols *ReferenceSymbols = Reference->getSymbols(); |
296 | if (!ReferenceSymbols) |
297 | return; |
298 | |
299 | LVSymbols References; |
300 | References.append(in_start: ReferenceSymbols->begin(), in_end: ReferenceSymbols->end()); |
301 | |
302 | // Erase abstract symbols already in this scope from the collection of |
303 | // symbols in the referenced scope. |
304 | if (getSymbols()) |
305 | for (const LVSymbol *Symbol : *getSymbols()) |
306 | if (Symbol->getHasReferenceAbstract()) |
307 | llvm::erase(C&: References, V: Symbol->getReference()); |
308 | |
309 | // If we have elements left in 'References', those are the elements that |
310 | // need to be inserted in the current scope. |
311 | if (References.size()) { |
312 | LLVM_DEBUG({ |
313 | dbgs() << "Insert Missing Inlined Elements\n" |
314 | << "Offset = " << hexSquareString(getOffset()) << " " |
315 | << "Abstract = " << hexSquareString(Reference->getOffset()) |
316 | << "\n" ; |
317 | }); |
318 | for (LVSymbol *Reference : References) { |
319 | LLVM_DEBUG({ |
320 | dbgs() << "Missing Offset = " << hexSquareString(Reference->getOffset()) |
321 | << "\n" ; |
322 | }); |
323 | // We can't clone the abstract origin reference, as it contain extra |
324 | // information that is incorrect for the element to be inserted. |
325 | // As the symbol being added does not exist in the debug section, |
326 | // use its parent scope offset, to indicate its DIE location. |
327 | LVSymbol *Symbol = getReader().createSymbol(); |
328 | addElement(Symbol); |
329 | Symbol->setOffset(getOffset()); |
330 | Symbol->setIsOptimized(); |
331 | Symbol->setReference(Reference); |
332 | |
333 | // The symbol can be a constant, parameter or variable. |
334 | if (Reference->getIsConstant()) |
335 | Symbol->setIsConstant(); |
336 | else if (Reference->getIsParameter()) |
337 | Symbol->setIsParameter(); |
338 | else if (Reference->getIsVariable()) |
339 | Symbol->setIsVariable(); |
340 | else |
341 | llvm_unreachable("Invalid symbol kind." ); |
342 | } |
343 | } |
344 | } |
345 | |
346 | void LVScope::updateLevel(LVScope *Parent, bool Moved) { |
347 | // Update the level for the element itself and all its children, using the |
348 | // given scope parent as reference. |
349 | setLevel(Parent->getLevel() + 1); |
350 | |
351 | // Update the children. |
352 | if (Children) |
353 | for (LVElement *Element : *Children) |
354 | Element->updateLevel(Parent: this, Moved); |
355 | |
356 | // Update any lines. |
357 | if (Lines) |
358 | for (LVLine *Line : *Lines) |
359 | Line->updateLevel(Parent: this, Moved); |
360 | } |
361 | |
362 | void LVScope::resolve() { |
363 | if (getIsResolved()) |
364 | return; |
365 | |
366 | // Resolve the element itself. |
367 | LVElement::resolve(); |
368 | |
369 | // Resolve the children. |
370 | if (Children) |
371 | for (LVElement *Element : *Children) { |
372 | if (getIsGlobalReference()) |
373 | // If the scope is a global reference, mark all its children as well. |
374 | Element->setIsGlobalReference(); |
375 | Element->resolve(); |
376 | } |
377 | } |
378 | |
379 | void LVScope::resolveName() { |
380 | if (getIsResolvedName()) |
381 | return; |
382 | setIsResolvedName(); |
383 | |
384 | // If the scope is a template, resolve the template parameters and get |
385 | // the name for the template with the encoded arguments. |
386 | if (getIsTemplate()) |
387 | resolveTemplate(); |
388 | else { |
389 | if (LVElement *BaseType = getType()) { |
390 | BaseType->resolveName(); |
391 | resolveFullname(BaseType); |
392 | } |
393 | } |
394 | |
395 | // In the case of unnamed scopes, try to generate a name for it, using |
396 | // the parents name and the line information. In the case of compiler |
397 | // generated functions, use its linkage name if is available. |
398 | if (!isNamed()) { |
399 | if (getIsArtificial()) |
400 | setName(getLinkageName()); |
401 | else |
402 | generateName(); |
403 | } |
404 | |
405 | LVElement::resolveName(); |
406 | |
407 | // Resolve any given pattern. |
408 | patterns().resolvePatternMatch(Scope: this); |
409 | } |
410 | |
411 | void LVScope::resolveReferences() { |
412 | // The scopes can have the following references to other elements: |
413 | // A type: |
414 | // DW_AT_type -> Type or Scope |
415 | // DW_AT_import -> Type |
416 | // A Reference: |
417 | // DW_AT_specification -> Scope |
418 | // DW_AT_abstract_origin -> Scope |
419 | // DW_AT_extension -> Scope |
420 | |
421 | // Resolve any referenced scope. |
422 | LVScope *Reference = getReference(); |
423 | if (Reference) { |
424 | Reference->resolve(); |
425 | // Recursively resolve the scope names. |
426 | resolveReferencesChain(); |
427 | } |
428 | |
429 | // Set the file/line information using the Debug Information entry. |
430 | setFile(Reference); |
431 | |
432 | // Resolve any referenced type or scope. |
433 | if (LVElement *Element = getType()) |
434 | Element->resolve(); |
435 | } |
436 | |
437 | void LVScope::resolveElements() { |
438 | // The current element represents the Root. Traverse each Compile Unit. |
439 | if (!Scopes) |
440 | return; |
441 | |
442 | for (LVScope *Scope : *Scopes) { |
443 | LVScopeCompileUnit *CompileUnit = static_cast<LVScopeCompileUnit *>(Scope); |
444 | getReader().setCompileUnit(CompileUnit); |
445 | CompileUnit->resolve(); |
446 | // Propagate any matching information into the scopes tree. |
447 | CompileUnit->propagatePatternMatch(); |
448 | } |
449 | } |
450 | |
451 | StringRef LVScope::resolveReferencesChain() { |
452 | // If the scope has a DW_AT_specification or DW_AT_abstract_origin, |
453 | // follow the chain to resolve the name from those references. |
454 | if (getHasReference() && !isNamed()) |
455 | setName(getReference()->resolveReferencesChain()); |
456 | |
457 | return getName(); |
458 | } |
459 | |
460 | // Get template parameter types. |
461 | bool LVScope::getTemplateParameterTypes(LVTypes &Params) { |
462 | // Traverse the scope types and populate the given container with those |
463 | // types that are template parameters; that container will be used by |
464 | // 'encodeTemplateArguments' to resolve them. |
465 | if (const LVTypes *Types = getTypes()) |
466 | for (LVType *Type : *Types) |
467 | if (Type->getIsTemplateParam()) { |
468 | Type->resolve(); |
469 | Params.push_back(Elt: Type); |
470 | } |
471 | |
472 | return !Params.empty(); |
473 | } |
474 | |
475 | // Resolve the template parameters/arguments relationship. |
476 | void LVScope::resolveTemplate() { |
477 | if (getIsTemplateResolved()) |
478 | return; |
479 | setIsTemplateResolved(); |
480 | |
481 | // Check if we need to encode the template arguments. |
482 | if (options().getAttributeEncoded()) { |
483 | LVTypes Params; |
484 | if (getTemplateParameterTypes(Params)) { |
485 | std::string EncodedArgs; |
486 | // Encode the arguments as part of the template name and update the |
487 | // template name, to reflect the encoded parameters. |
488 | encodeTemplateArguments(Name&: EncodedArgs, Types: &Params); |
489 | setEncodedArgs(EncodedArgs); |
490 | } |
491 | } |
492 | } |
493 | |
494 | // Get the qualified name for the template. |
495 | void LVScope::getQualifiedName(std::string &QualifiedName) const { |
496 | if (getIsRoot() || getIsCompileUnit()) |
497 | return; |
498 | |
499 | if (LVScope *Parent = getParentScope()) |
500 | Parent->getQualifiedName(QualifiedName); |
501 | if (!QualifiedName.empty()) |
502 | QualifiedName.append(s: "::" ); |
503 | QualifiedName.append(str: std::string(getName())); |
504 | } |
505 | |
506 | // Encode the template arguments as part of the template name. |
507 | void LVScope::encodeTemplateArguments(std::string &Name) const { |
508 | // Qualify only when we are expanding parameters that are template |
509 | // instances; the debugger will assume the current scope symbol as |
510 | // the qualifying tag for the symbol being generated, which gives: |
511 | // namespace std { |
512 | // ... |
513 | // set<float,std::less<float>,std::allocator<float>> |
514 | // ... |
515 | // } |
516 | // The 'set' symbol is assumed to have the qualified tag 'std'. |
517 | |
518 | // We are resolving a template parameter which is another template. If |
519 | // it is already resolved, just get the qualified name and return. |
520 | std::string BaseName; |
521 | getQualifiedName(QualifiedName&: BaseName); |
522 | if (getIsTemplateResolved()) |
523 | Name.append(str: BaseName); |
524 | } |
525 | |
526 | void LVScope::encodeTemplateArguments(std::string &Name, |
527 | const LVTypes *Types) const { |
528 | // The encoded string will start with the scope name. |
529 | Name.append(s: "<" ); |
530 | |
531 | // The list of types are the template parameters. |
532 | if (Types) { |
533 | bool AddComma = false; |
534 | for (const LVType *Type : *Types) { |
535 | if (AddComma) |
536 | Name.append(s: ", " ); |
537 | Type->encodeTemplateArgument(Name); |
538 | AddComma = true; |
539 | } |
540 | } |
541 | |
542 | Name.append(s: ">" ); |
543 | } |
544 | |
545 | bool LVScope::resolvePrinting() const { |
546 | // The warnings collected during the scope creation as per compile unit. |
547 | // If there is a request for printing warnings, always print its associate |
548 | // Compile Unit. |
549 | if (options().getPrintWarnings() && (getIsRoot() || getIsCompileUnit())) |
550 | return true; |
551 | |
552 | // In selection mode, always print the root scope regardless of the |
553 | // number of matched elements. If no matches, the root by itself will |
554 | // indicate no matches. |
555 | if (options().getSelectExecute()) { |
556 | return getIsRoot() || getIsCompileUnit() || getHasPattern(); |
557 | } |
558 | |
559 | bool Globals = options().getAttributeGlobal(); |
560 | bool Locals = options().getAttributeLocal(); |
561 | if ((Globals && Locals) || (!Globals && !Locals)) { |
562 | // Print both Global and Local. |
563 | } else { |
564 | // Check for Global or Local Objects. |
565 | if ((Globals && !(getHasGlobals() || getIsGlobalReference())) || |
566 | (Locals && !(getHasLocals() || !getIsGlobalReference()))) |
567 | return false; |
568 | } |
569 | |
570 | // For the case of functions, skip it if is compiler generated. |
571 | if (getIsFunction() && getIsArtificial() && |
572 | !options().getAttributeGenerated()) |
573 | return false; |
574 | |
575 | return true; |
576 | } |
577 | |
578 | Error LVScope::doPrint(bool Split, bool Match, bool Print, raw_ostream &OS, |
579 | bool Full) const { |
580 | // During a view output splitting, use the output stream created by the |
581 | // split context, then switch to the reader output stream. |
582 | raw_ostream *StreamSplit = &OS; |
583 | |
584 | // Ignore the CU generated by the VS toolchain, when compiling to PDB. |
585 | if (getIsSystem() && !options().getAttributeSystem()) |
586 | return Error::success(); |
587 | |
588 | // If 'Split', we use the scope name (CU name) as the ouput file; the |
589 | // delimiters in the pathname, must be replaced by a normal character. |
590 | if (getIsCompileUnit()) { |
591 | getReader().setCompileUnit(const_cast<LVScope *>(this)); |
592 | if (Split) { |
593 | std::string ScopeName(getName()); |
594 | if (std::error_code EC = |
595 | getReaderSplitContext().open(Name: ScopeName, Extension: ".txt" , OS)) |
596 | return createStringError(EC, Fmt: "Unable to create split output file %s" , |
597 | Vals: ScopeName.c_str()); |
598 | StreamSplit = static_cast<raw_ostream *>(&getReaderSplitContext().os()); |
599 | } |
600 | } |
601 | |
602 | // Ignore discarded or stripped scopes (functions). |
603 | bool DoPrint = (options().getAttributeDiscarded()) ? true : !getIsDiscarded(); |
604 | |
605 | // If we are in compare mode, the only conditions are related to the |
606 | // element being missing. In the case of elements comparison, we print the |
607 | // augmented view, that includes added elements. |
608 | // In print mode, we check other conditions, such as local, global, etc. |
609 | if (DoPrint) { |
610 | DoPrint = |
611 | getIsInCompare() ? options().getReportExecute() : resolvePrinting(); |
612 | } |
613 | |
614 | // At this point we have checked for very specific options, to decide if the |
615 | // element will be printed. Include the caller's test for element general |
616 | // print. |
617 | DoPrint = DoPrint && (Print || options().getOutputSplit()); |
618 | |
619 | if (DoPrint) { |
620 | // Print the element itself. |
621 | print(OS&: *StreamSplit, Full); |
622 | |
623 | // Check if we have reached the requested lexical level specified in the |
624 | // command line options. Input file is level zero and the CU is level 1. |
625 | if ((getIsRoot() || options().getPrintAnyElement()) && |
626 | options().getPrintFormatting() && |
627 | getLevel() < options().getOutputLevel()) { |
628 | // Print the children. |
629 | if (Children) |
630 | for (const LVElement *Element : *Children) { |
631 | if (Match && !Element->getHasPattern()) |
632 | continue; |
633 | if (Error Err = |
634 | Element->doPrint(Split, Match, Print, OS&: *StreamSplit, Full)) |
635 | return Err; |
636 | } |
637 | |
638 | // Print the line records. |
639 | if (Lines) |
640 | for (const LVLine *Line : *Lines) { |
641 | if (Match && !Line->getHasPattern()) |
642 | continue; |
643 | if (Error Err = |
644 | Line->doPrint(Split, Match, Print, OS&: *StreamSplit, Full)) |
645 | return Err; |
646 | } |
647 | |
648 | // Print the warnings. |
649 | if (options().getPrintWarnings()) |
650 | printWarnings(OS&: *StreamSplit, Full); |
651 | } |
652 | } |
653 | |
654 | // Done printing the compile unit. Print any requested summary and |
655 | // restore the original output context. |
656 | if (getIsCompileUnit()) { |
657 | if (options().getPrintSummary()) |
658 | printSummary(OS&: *StreamSplit); |
659 | if (options().getPrintSizes()) |
660 | printSizes(OS&: *StreamSplit); |
661 | if (Split) { |
662 | getReaderSplitContext().close(); |
663 | StreamSplit = &getReader().outputStream(); |
664 | } |
665 | } |
666 | |
667 | if (getIsRoot() && options().getPrintWarnings()) { |
668 | getReader().printRecords(OS&: *StreamSplit); |
669 | } |
670 | |
671 | return Error::success(); |
672 | } |
673 | |
674 | void LVScope::sort() { |
675 | // Preserve the lines order as they are associated with user code. |
676 | LVSortFunction SortFunction = getSortFunction(); |
677 | if (SortFunction) { |
678 | std::function<void(LVScope * Parent, LVSortFunction SortFunction)> Sort = |
679 | [&](LVScope *Parent, LVSortFunction SortFunction) { |
680 | auto Traverse = [&](auto &Set, LVSortFunction SortFunction) { |
681 | if (Set) |
682 | std::stable_sort(Set->begin(), Set->end(), SortFunction); |
683 | }; |
684 | Traverse(Parent->Types, SortFunction); |
685 | Traverse(Parent->Symbols, SortFunction); |
686 | Traverse(Parent->Scopes, SortFunction); |
687 | Traverse(Parent->Ranges, compareRange); |
688 | Traverse(Parent->Children, SortFunction); |
689 | |
690 | if (Parent->Scopes) |
691 | for (LVScope *Scope : *Parent->Scopes) |
692 | Sort(Scope, SortFunction); |
693 | }; |
694 | |
695 | // Start traversing the scopes root and transform the element name. |
696 | Sort(this, SortFunction); |
697 | } |
698 | } |
699 | |
700 | void LVScope::traverseParents(LVScopeGetFunction GetFunction, |
701 | LVScopeSetFunction SetFunction) { |
702 | // Traverse the parent tree. |
703 | LVScope *Parent = this; |
704 | while (Parent) { |
705 | // Terminates if the 'SetFunction' has been already executed. |
706 | if ((Parent->*GetFunction)()) |
707 | break; |
708 | (Parent->*SetFunction)(); |
709 | Parent = Parent->getParentScope(); |
710 | } |
711 | } |
712 | |
713 | void LVScope::traverseParentsAndChildren(LVObjectGetFunction GetFunction, |
714 | LVObjectSetFunction SetFunction) { |
715 | if (options().getReportParents()) { |
716 | // First traverse the parent tree. |
717 | LVScope *Parent = this; |
718 | while (Parent) { |
719 | // Terminates if the 'SetFunction' has been already executed. |
720 | if ((Parent->*GetFunction)()) |
721 | break; |
722 | (Parent->*SetFunction)(); |
723 | Parent = Parent->getParentScope(); |
724 | } |
725 | } |
726 | |
727 | std::function<void(LVScope * Scope)> TraverseChildren = [&](LVScope *Scope) { |
728 | auto Traverse = [&](const auto *Set) { |
729 | if (Set) |
730 | for (const auto &Entry : *Set) |
731 | (Entry->*SetFunction)(); |
732 | }; |
733 | |
734 | (Scope->*SetFunction)(); |
735 | |
736 | Traverse(Scope->getTypes()); |
737 | Traverse(Scope->getSymbols()); |
738 | Traverse(Scope->getLines()); |
739 | |
740 | if (const LVScopes *Scopes = Scope->getScopes()) |
741 | for (LVScope *Scope : *Scopes) |
742 | TraverseChildren(Scope); |
743 | }; |
744 | |
745 | if (options().getReportChildren()) |
746 | TraverseChildren(this); |
747 | } |
748 | |
749 | // Traverse the symbol location ranges and for each range: |
750 | // - Apply the 'ValidLocation' validation criteria. |
751 | // - Add any failed range to the 'LocationList'. |
752 | // - Calculate location coverage. |
753 | void LVScope::getLocations(LVLocations &LocationList, |
754 | LVValidLocation ValidLocation, bool RecordInvalid) { |
755 | // Traverse scopes and symbols. |
756 | if (Symbols) |
757 | for (LVSymbol *Symbol : *Symbols) |
758 | Symbol->getLocations(LocationList, ValidLocation, RecordInvalid); |
759 | if (Scopes) |
760 | for (LVScope *Scope : *Scopes) |
761 | Scope->getLocations(LocationList, ValidLocation, RecordInvalid); |
762 | } |
763 | |
764 | // Traverse the scope ranges and for each range: |
765 | // - Apply the 'ValidLocation' validation criteria. |
766 | // - Add any failed range to the 'LocationList'. |
767 | // - Calculate location coverage. |
768 | void LVScope::getRanges(LVLocations &LocationList, |
769 | LVValidLocation ValidLocation, bool RecordInvalid) { |
770 | // Ignore discarded or stripped scopes (functions). |
771 | if (getIsDiscarded()) |
772 | return; |
773 | |
774 | // Process the ranges for current scope. |
775 | if (Ranges) { |
776 | for (LVLocation *Location : *Ranges) { |
777 | // Add the invalid location object. |
778 | if (!(Location->*ValidLocation)() && RecordInvalid) |
779 | LocationList.push_back(Elt: Location); |
780 | } |
781 | |
782 | // Calculate coverage factor. |
783 | calculateCoverage(); |
784 | } |
785 | |
786 | // Traverse the scopes. |
787 | if (Scopes) |
788 | for (LVScope *Scope : *Scopes) |
789 | Scope->getRanges(LocationList, ValidLocation, RecordInvalid); |
790 | } |
791 | |
792 | // Get all the ranges associated with scopes. |
793 | void LVScope::getRanges(LVRange &RangeList) { |
794 | // Ignore discarded or stripped scopes (functions). |
795 | if (getIsDiscarded()) |
796 | return; |
797 | |
798 | if (Ranges) |
799 | RangeList.addEntry(Scope: this); |
800 | if (Scopes) |
801 | for (LVScope *Scope : *Scopes) |
802 | Scope->getRanges(RangeList); |
803 | } |
804 | |
805 | LVScope *LVScope::outermostParent(LVAddress Address) { |
806 | LVScope *Parent = this; |
807 | while (Parent) { |
808 | const LVLocations *ParentRanges = Parent->getRanges(); |
809 | if (ParentRanges) |
810 | for (const LVLocation *Location : *ParentRanges) |
811 | if (Location->getLowerAddress() <= Address) |
812 | return Parent; |
813 | Parent = Parent->getParentScope(); |
814 | } |
815 | return Parent; |
816 | } |
817 | |
818 | LVScope *LVScope::findIn(const LVScopes *Targets) const { |
819 | if (!Targets) |
820 | return nullptr; |
821 | |
822 | // In the case of overloaded functions, sometimes the DWARF used to |
823 | // describe them, does not give suficient information. Try to find a |
824 | // perfect match or mark them as possible conflicts. |
825 | LVScopes Candidates; |
826 | for (LVScope *Target : *Targets) |
827 | if (LVScope::equals(Scope: Target)) |
828 | Candidates.push_back(Elt: Target); |
829 | |
830 | LLVM_DEBUG({ |
831 | if (!Candidates.empty()) { |
832 | dbgs() << "\n[LVScope::findIn]\n" |
833 | << "Reference: " |
834 | << "Offset = " << hexSquareString(getOffset()) << ", " |
835 | << "Level = " << getLevel() << ", " |
836 | << "Kind = " << formattedKind(kind()) << ", " |
837 | << "Name = " << formattedName(getName()) << "\n" ; |
838 | for (const LVScope *Candidate : Candidates) |
839 | dbgs() << "Candidate: " |
840 | << "Offset = " << hexSquareString(Candidate->getOffset()) << ", " |
841 | << "Level = " << Candidate->getLevel() << ", " |
842 | << "Kind = " << formattedKind(Candidate->kind()) << ", " |
843 | << "Name = " << formattedName(Candidate->getName()) << "\n" ; |
844 | } |
845 | }); |
846 | |
847 | if (!Candidates.empty()) |
848 | return (Candidates.size() == 1) |
849 | ? (equals(Scope: Candidates[0]) ? Candidates[0] : nullptr) |
850 | : findEqualScope(Scopes: &Candidates); |
851 | |
852 | return nullptr; |
853 | } |
854 | |
855 | bool LVScope::equalNumberOfChildren(const LVScope *Scope) const { |
856 | // Same number of children. Take into account which elements are requested |
857 | // to be included in the comparison. |
858 | return !( |
859 | (options().getCompareScopes() && scopeCount() != Scope->scopeCount()) || |
860 | (options().getCompareSymbols() && |
861 | symbolCount() != Scope->symbolCount()) || |
862 | (options().getCompareTypes() && typeCount() != Scope->typeCount()) || |
863 | (options().getCompareLines() && lineCount() != Scope->lineCount())); |
864 | } |
865 | |
866 | void LVScope::markMissingParents(const LVScope *Target, bool TraverseChildren) { |
867 | auto SetCompareState = [&](auto &Container) { |
868 | if (Container) |
869 | for (auto *Entry : *Container) |
870 | Entry->setIsInCompare(); |
871 | }; |
872 | SetCompareState(Types); |
873 | SetCompareState(Symbols); |
874 | SetCompareState(Lines); |
875 | SetCompareState(Scopes); |
876 | |
877 | // At this point, we are ready to start comparing the current scope, once |
878 | // the compare bits have been set. |
879 | if (options().getCompareTypes() && getTypes() && Target->getTypes()) |
880 | LVType::markMissingParents(References: getTypes(), Targets: Target->getTypes()); |
881 | if (options().getCompareSymbols() && getSymbols() && Target->getSymbols()) |
882 | LVSymbol::markMissingParents(References: getSymbols(), Targets: Target->getSymbols()); |
883 | if (options().getCompareLines() && getLines() && Target->getLines()) |
884 | LVLine::markMissingParents(References: getLines(), Targets: Target->getLines()); |
885 | if (getScopes() && Target->getScopes()) |
886 | LVScope::markMissingParents(References: getScopes(), Targets: Target->getScopes(), |
887 | TraverseChildren); |
888 | } |
889 | |
890 | void LVScope::markMissingParents(const LVScopes *References, |
891 | const LVScopes *Targets, |
892 | bool TraverseChildren) { |
893 | if (!(References && Targets)) |
894 | return; |
895 | |
896 | LLVM_DEBUG({ |
897 | dbgs() << "\n[LVScope::markMissingParents]\n" ; |
898 | for (const LVScope *Reference : *References) |
899 | dbgs() << "References: " |
900 | << "Offset = " << hexSquareString(Reference->getOffset()) << ", " |
901 | << "Level = " << Reference->getLevel() << ", " |
902 | << "Kind = " << formattedKind(Reference->kind()) << ", " |
903 | << "Name = " << formattedName(Reference->getName()) << "\n" ; |
904 | for (const LVScope *Target : *Targets) |
905 | dbgs() << "Targets : " |
906 | << "Offset = " << hexSquareString(Target->getOffset()) << ", " |
907 | << "Level = " << Target->getLevel() << ", " |
908 | << "Kind = " << formattedKind(Target->kind()) << ", " |
909 | << "Name = " << formattedName(Target->getName()) << "\n" ; |
910 | }); |
911 | |
912 | for (LVScope *Reference : *References) { |
913 | // Don't process 'Block' scopes, as we can't identify them. |
914 | if (Reference->getIsBlock() || Reference->getIsGeneratedName()) |
915 | continue; |
916 | |
917 | LLVM_DEBUG({ |
918 | dbgs() << "\nSearch Reference: " |
919 | << "Offset = " << hexSquareString(Reference->getOffset()) << " " |
920 | << "Name = " << formattedName(Reference->getName()) << "\n" ; |
921 | }); |
922 | LVScope *Target = Reference->findIn(Targets); |
923 | if (Target) { |
924 | LLVM_DEBUG({ |
925 | dbgs() << "\nFound Target: " |
926 | << "Offset = " << hexSquareString(Target->getOffset()) << " " |
927 | << "Name = " << formattedName(Target->getName()) << "\n" ; |
928 | }); |
929 | if (TraverseChildren) |
930 | Reference->markMissingParents(Target, TraverseChildren); |
931 | } else { |
932 | LLVM_DEBUG({ |
933 | dbgs() << "Missing Reference: " |
934 | << "Offset = " << hexSquareString(Reference->getOffset()) << " " |
935 | << "Name = " << formattedName(Reference->getName()) << "\n" ; |
936 | }); |
937 | Reference->markBranchAsMissing(); |
938 | } |
939 | } |
940 | } |
941 | |
942 | bool LVScope::equals(const LVScope *Scope) const { |
943 | if (!LVElement::equals(Element: Scope)) |
944 | return false; |
945 | // For lexical scopes, check if their parents are the same. |
946 | if (getIsLexicalBlock() && Scope->getIsLexicalBlock()) |
947 | return getParentScope()->equals(Scope: Scope->getParentScope()); |
948 | return true; |
949 | } |
950 | |
951 | LVScope *LVScope::findEqualScope(const LVScopes *Scopes) const { |
952 | assert(Scopes && "Scopes must not be nullptr" ); |
953 | for (LVScope *Scope : *Scopes) |
954 | if (equals(Scope)) |
955 | return Scope; |
956 | return nullptr; |
957 | } |
958 | |
959 | bool LVScope::equals(const LVScopes *References, const LVScopes *Targets) { |
960 | if (!References && !Targets) |
961 | return true; |
962 | if (References && Targets && References->size() == Targets->size()) { |
963 | for (const LVScope *Reference : *References) |
964 | if (!Reference->findIn(Targets)) |
965 | return false; |
966 | return true; |
967 | } |
968 | return false; |
969 | } |
970 | |
971 | void LVScope::report(LVComparePass Pass) { |
972 | getComparator().printItem(Element: this, Pass); |
973 | getComparator().push(Scope: this); |
974 | if (Children) |
975 | for (LVElement *Element : *Children) |
976 | Element->report(Pass); |
977 | |
978 | if (Lines) |
979 | for (LVLine *Line : *Lines) |
980 | Line->report(Pass); |
981 | getComparator().pop(); |
982 | } |
983 | |
984 | void LVScope::printActiveRanges(raw_ostream &OS, bool Full) const { |
985 | if (options().getPrintFormatting() && options().getAttributeRange() && |
986 | Ranges) { |
987 | for (const LVLocation *Location : *Ranges) |
988 | Location->print(OS, Full); |
989 | } |
990 | } |
991 | |
992 | void LVScope::printEncodedArgs(raw_ostream &OS, bool Full) const { |
993 | if (options().getPrintFormatting() && options().getAttributeEncoded()) |
994 | printAttributes(OS, Full, Name: "{Encoded} " , Parent: const_cast<LVScope *>(this), |
995 | Value: getEncodedArgs(), /*UseQuotes=*/false, /*PrintRef=*/false); |
996 | } |
997 | |
998 | void LVScope::print(raw_ostream &OS, bool Full) const { |
999 | if (getIncludeInPrint() && getReader().doPrintScope(Scope: this)) { |
1000 | // For a summary (printed elements), do not count the scope root. |
1001 | // For a summary (selected elements) do not count a compile unit. |
1002 | if (!(getIsRoot() || (getIsCompileUnit() && options().getSelectExecute()))) |
1003 | getReaderCompileUnit()->incrementPrintedScopes(); |
1004 | LVElement::print(OS, Full); |
1005 | printExtra(OS, Full); |
1006 | } |
1007 | } |
1008 | |
1009 | void LVScope::(raw_ostream &OS, bool Full) const { |
1010 | OS << formattedKind(Kind: kind()); |
1011 | // Do not print any type or name for a lexical block. |
1012 | if (!getIsBlock()) { |
1013 | OS << " " << formattedName(Name: getName()); |
1014 | if (!getIsAggregate()) |
1015 | OS << " -> " << typeOffsetAsString() |
1016 | << formattedNames(Name1: getTypeQualifiedName(), Name2: typeAsString()); |
1017 | } |
1018 | OS << "\n" ; |
1019 | |
1020 | // Print any active ranges. |
1021 | if (Full && getIsBlock()) |
1022 | printActiveRanges(OS, Full); |
1023 | } |
1024 | |
1025 | //===----------------------------------------------------------------------===// |
1026 | // DWARF Union/Structure/Class. |
1027 | //===----------------------------------------------------------------------===// |
1028 | bool LVScopeAggregate::equals(const LVScope *Scope) const { |
1029 | if (!LVScope::equals(Scope)) |
1030 | return false; |
1031 | |
1032 | if (!equalNumberOfChildren(Scope)) |
1033 | return false; |
1034 | |
1035 | // Check if the parameters match in the case of templates. |
1036 | if (!LVType::parametersMatch(References: getTypes(), Targets: Scope->getTypes())) |
1037 | return false; |
1038 | |
1039 | if (!isNamed() && !Scope->isNamed()) |
1040 | // In the case of unnamed union/structure/class compare the file name. |
1041 | if (getFilenameIndex() != Scope->getFilenameIndex()) |
1042 | return false; |
1043 | |
1044 | return true; |
1045 | } |
1046 | |
1047 | LVScope *LVScopeAggregate::findEqualScope(const LVScopes *Scopes) const { |
1048 | assert(Scopes && "Scopes must not be nullptr" ); |
1049 | for (LVScope *Scope : *Scopes) |
1050 | if (equals(Scope)) |
1051 | return Scope; |
1052 | return nullptr; |
1053 | } |
1054 | |
1055 | void LVScopeAggregate::(raw_ostream &OS, bool Full) const { |
1056 | LVScope::printExtra(OS, Full); |
1057 | if (Full) { |
1058 | if (getIsTemplateResolved()) |
1059 | printEncodedArgs(OS, Full); |
1060 | LVScope *Reference = getReference(); |
1061 | if (Reference) |
1062 | Reference->printReference(OS, Full, Parent: const_cast<LVScopeAggregate *>(this)); |
1063 | } |
1064 | } |
1065 | |
1066 | //===----------------------------------------------------------------------===// |
1067 | // DWARF Template alias. |
1068 | //===----------------------------------------------------------------------===// |
1069 | bool LVScopeAlias::equals(const LVScope *Scope) const { |
1070 | if (!LVScope::equals(Scope)) |
1071 | return false; |
1072 | return equalNumberOfChildren(Scope); |
1073 | } |
1074 | |
1075 | void LVScopeAlias::(raw_ostream &OS, bool Full) const { |
1076 | OS << formattedKind(Kind: kind()) << " " << formattedName(Name: getName()) << " -> " |
1077 | << typeOffsetAsString() |
1078 | << formattedNames(Name1: getTypeQualifiedName(), Name2: typeAsString()) << "\n" ; |
1079 | } |
1080 | |
1081 | //===----------------------------------------------------------------------===// |
1082 | // DWARF array (DW_TAG_array_type). |
1083 | //===----------------------------------------------------------------------===// |
1084 | void LVScopeArray::() { |
1085 | // If the scope is an array, resolve the subrange entries and get those |
1086 | // values encoded and assigned to the scope type. |
1087 | // Encode the array subrange entries as part of the name. |
1088 | if (getIsArrayResolved()) |
1089 | return; |
1090 | setIsArrayResolved(); |
1091 | |
1092 | // There are 2 cases to represent the bounds information for an array: |
1093 | // 1) DW_TAG_array_type |
1094 | // DW_AT_type --> ref_type |
1095 | // DW_TAG_subrange_type |
1096 | // DW_AT_type --> ref_type (type of object) |
1097 | // DW_AT_count --> value (number of elements in subrange) |
1098 | |
1099 | // 2) DW_TAG_array_type |
1100 | // DW_AT_type --> ref_type |
1101 | // DW_TAG_subrange_type |
1102 | // DW_AT_lower_bound --> value |
1103 | // DW_AT_upper_bound --> value |
1104 | |
1105 | // The idea is to represent the bounds as a string, depending on the format: |
1106 | // 1) [count] |
1107 | // 2) [lower][upper] |
1108 | |
1109 | // Traverse scope types, looking for those types that are subranges. |
1110 | LVTypes Subranges; |
1111 | if (const LVTypes *Types = getTypes()) |
1112 | for (LVType *Type : *Types) |
1113 | if (Type->getIsSubrange()) { |
1114 | Type->resolve(); |
1115 | Subranges.push_back(Elt: Type); |
1116 | } |
1117 | |
1118 | // Use the subrange types to generate the high level name for the array. |
1119 | // Check the type has been fully resolved. |
1120 | if (LVElement *BaseType = getType()) { |
1121 | BaseType->resolveName(); |
1122 | resolveFullname(BaseType); |
1123 | } |
1124 | |
1125 | // In 'resolveFullname' a check is done for double spaces in the type name. |
1126 | std::stringstream ArrayInfo; |
1127 | if (ElementType) |
1128 | ArrayInfo << getTypeName().str() << " " ; |
1129 | |
1130 | for (const LVType *Type : Subranges) { |
1131 | if (Type->getIsSubrangeCount()) |
1132 | // Check if we have DW_AT_count subrange style. |
1133 | ArrayInfo << "[" << Type->getCount() << "]" ; |
1134 | else { |
1135 | // Get lower and upper subrange values. |
1136 | unsigned LowerBound; |
1137 | unsigned UpperBound; |
1138 | std::tie(args&: LowerBound, args&: UpperBound) = Type->getBounds(); |
1139 | |
1140 | // The representation depends on the bound values. If the lower value |
1141 | // is zero, treat the pair as the elements count. Otherwise, just use |
1142 | // the pair, as they are representing arrays in languages other than |
1143 | // C/C++ and the lower limit is not zero. |
1144 | if (LowerBound) |
1145 | ArrayInfo << "[" << LowerBound << ".." << UpperBound << "]" ; |
1146 | else |
1147 | ArrayInfo << "[" << UpperBound + 1 << "]" ; |
1148 | } |
1149 | } |
1150 | |
1151 | // Update the scope name, to reflect the encoded subranges. |
1152 | setName(ArrayInfo.str()); |
1153 | } |
1154 | |
1155 | bool LVScopeArray::equals(const LVScope *Scope) const { |
1156 | if (!LVScope::equals(Scope)) |
1157 | return false; |
1158 | |
1159 | if (!equalNumberOfChildren(Scope)) |
1160 | return false; |
1161 | |
1162 | // Despite the arrays are encoded, to reflect the dimensions, we have to |
1163 | // check the subranges, in order to determine if they are the same. |
1164 | if (!LVType::equals(References: getTypes(), Targets: Scope->getTypes())) |
1165 | return false; |
1166 | |
1167 | return true; |
1168 | } |
1169 | |
1170 | void LVScopeArray::(raw_ostream &OS, bool Full) const { |
1171 | OS << formattedKind(Kind: kind()) << " " << typeOffsetAsString() |
1172 | << formattedName(Name: getName()) << "\n" ; |
1173 | } |
1174 | |
1175 | //===----------------------------------------------------------------------===// |
1176 | // An object file (single or multiple CUs). |
1177 | //===----------------------------------------------------------------------===// |
1178 | void LVScopeCompileUnit::addSize(LVScope *Scope, LVOffset Lower, |
1179 | LVOffset Upper) { |
1180 | LLVM_DEBUG({ |
1181 | dbgs() << format( |
1182 | "CU [0x%08" PRIx64 "], Scope [0x%08" PRIx64 "], Range [0x%08" PRIx64 |
1183 | ":0x%08" PRIx64 "], Size = %" PRId64 "\n" , |
1184 | getOffset(), Scope->getOffset(), Lower, Upper, Upper - Lower); |
1185 | }); |
1186 | |
1187 | // There is no need to check for a previous entry, as we are traversing the |
1188 | // debug information in sequential order. |
1189 | LVOffset Size = Upper - Lower; |
1190 | Sizes[Scope] = Size; |
1191 | if (this == Scope) |
1192 | // Record contribution size for the compilation unit. |
1193 | CUContributionSize = Size; |
1194 | } |
1195 | |
1196 | // Update parents and children with pattern information. |
1197 | void LVScopeCompileUnit::propagatePatternMatch() { |
1198 | // At this stage, we have finished creating the Scopes tree and we have |
1199 | // a list of elements that match the pattern specified in the command line. |
1200 | // The pattern corresponds to a scope or element; mark parents and/or |
1201 | // children as having that pattern, before any printing is done. |
1202 | if (!options().getSelectExecute()) |
1203 | return; |
1204 | |
1205 | if (MatchedScopes.size()) { |
1206 | for (LVScope *Scope : MatchedScopes) |
1207 | Scope->traverseParentsAndChildren(GetFunction: &LVScope::getHasPattern, |
1208 | SetFunction: &LVScope::setHasPattern); |
1209 | } else { |
1210 | // Mark the compile unit as having a pattern to enable any requests to |
1211 | // print sizes and summary as that information is recorded at that level. |
1212 | setHasPattern(); |
1213 | } |
1214 | } |
1215 | |
1216 | void LVScopeCompileUnit::processRangeLocationCoverage( |
1217 | LVValidLocation ValidLocation) { |
1218 | if (options().getAttributeRange()) { |
1219 | // Traverse the scopes to get scopes that have invalid ranges. |
1220 | LVLocations Locations; |
1221 | bool RecordInvalid = options().getWarningRanges(); |
1222 | getRanges(LocationList&: Locations, ValidLocation, RecordInvalid); |
1223 | |
1224 | // Validate ranges associated with scopes. |
1225 | if (RecordInvalid) |
1226 | for (LVLocation *Location : Locations) |
1227 | addInvalidRange(Location); |
1228 | } |
1229 | |
1230 | if (options().getAttributeLocation()) { |
1231 | // Traverse the scopes to get locations that have invalid ranges. |
1232 | LVLocations Locations; |
1233 | bool RecordInvalid = options().getWarningLocations(); |
1234 | getLocations(LocationList&: Locations, ValidLocation, RecordInvalid); |
1235 | |
1236 | // Validate ranges associated with locations. |
1237 | if (RecordInvalid) |
1238 | for (LVLocation *Location : Locations) |
1239 | addInvalidLocation(Location); |
1240 | } |
1241 | } |
1242 | |
1243 | void LVScopeCompileUnit::addMapping(LVLine *Line, LVSectionIndex SectionIndex) { |
1244 | LVAddress Address = Line->getOffset(); |
1245 | SectionMappings.add(FirstKey: SectionIndex, SecondKey: Address, Value: Line); |
1246 | } |
1247 | |
1248 | LVLine *LVScopeCompileUnit::lineLowerBound(LVAddress Address, |
1249 | LVScope *Scope) const { |
1250 | LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope); |
1251 | LVAddressToLine *Map = SectionMappings.findMap(FirstKey: SectionIndex); |
1252 | if (!Map || Map->empty()) |
1253 | return nullptr; |
1254 | LVAddressToLine::const_iterator Iter = Map->lower_bound(x: Address); |
1255 | return (Iter != Map->end()) ? Iter->second : nullptr; |
1256 | } |
1257 | |
1258 | LVLine *LVScopeCompileUnit::lineUpperBound(LVAddress Address, |
1259 | LVScope *Scope) const { |
1260 | LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope); |
1261 | LVAddressToLine *Map = SectionMappings.findMap(FirstKey: SectionIndex); |
1262 | if (!Map || Map->empty()) |
1263 | return nullptr; |
1264 | LVAddressToLine::const_iterator Iter = Map->upper_bound(x: Address); |
1265 | if (Iter != Map->begin()) |
1266 | Iter = std::prev(x: Iter); |
1267 | return Iter->second; |
1268 | } |
1269 | |
1270 | LVLineRange LVScopeCompileUnit::lineRange(LVLocation *Location) const { |
1271 | // The parent of a location can be a symbol or a scope. |
1272 | LVElement *Element = Location->getParent(); |
1273 | LVScope *Parent = Element->getIsScope() ? static_cast<LVScope *>(Element) |
1274 | : Element->getParentScope(); |
1275 | LVLine *LowLine = lineLowerBound(Address: Location->getLowerAddress(), Scope: Parent); |
1276 | LVLine *HighLine = lineUpperBound(Address: Location->getUpperAddress(), Scope: Parent); |
1277 | return LVLineRange(LowLine, HighLine); |
1278 | } |
1279 | |
1280 | StringRef LVScopeCompileUnit::getFilename(size_t Index) const { |
1281 | if (Index <= 0 || Index > Filenames.size()) |
1282 | return StringRef(); |
1283 | return getStringPool().getString(Index: Filenames[Index - 1]); |
1284 | } |
1285 | |
1286 | bool LVScopeCompileUnit::equals(const LVScope *Scope) const { |
1287 | if (!LVScope::equals(Scope)) |
1288 | return false; |
1289 | |
1290 | return getNameIndex() == Scope->getNameIndex(); |
1291 | } |
1292 | |
1293 | void LVScopeCompileUnit::incrementPrintedLines() { |
1294 | options().getSelectExecute() ? ++Found.Lines : ++Printed.Lines; |
1295 | } |
1296 | void LVScopeCompileUnit::incrementPrintedScopes() { |
1297 | options().getSelectExecute() ? ++Found.Scopes : ++Printed.Scopes; |
1298 | } |
1299 | void LVScopeCompileUnit::incrementPrintedSymbols() { |
1300 | options().getSelectExecute() ? ++Found.Symbols : ++Printed.Symbols; |
1301 | } |
1302 | void LVScopeCompileUnit::incrementPrintedTypes() { |
1303 | options().getSelectExecute() ? ++Found.Types : ++Printed.Types; |
1304 | } |
1305 | |
1306 | // Values are used by '--summary' option (allocated). |
1307 | void LVScopeCompileUnit::increment(LVLine *Line) { |
1308 | if (Line->getIncludeInPrint()) |
1309 | ++Allocated.Lines; |
1310 | } |
1311 | void LVScopeCompileUnit::increment(LVScope *Scope) { |
1312 | if (Scope->getIncludeInPrint()) |
1313 | ++Allocated.Scopes; |
1314 | } |
1315 | void LVScopeCompileUnit::increment(LVSymbol *Symbol) { |
1316 | if (Symbol->getIncludeInPrint()) |
1317 | ++Allocated.Symbols; |
1318 | } |
1319 | void LVScopeCompileUnit::increment(LVType *Type) { |
1320 | if (Type->getIncludeInPrint()) |
1321 | ++Allocated.Types; |
1322 | } |
1323 | |
1324 | // A new element has been added to the scopes tree. Take the following steps: |
1325 | // Increase the added element counters, for printing summary. |
1326 | // During comparison notify the Reader of the new element. |
1327 | void LVScopeCompileUnit::addedElement(LVLine *Line) { |
1328 | increment(Line); |
1329 | getReader().notifyAddedElement(Line); |
1330 | } |
1331 | void LVScopeCompileUnit::addedElement(LVScope *Scope) { |
1332 | increment(Scope); |
1333 | getReader().notifyAddedElement(Scope); |
1334 | } |
1335 | void LVScopeCompileUnit::addedElement(LVSymbol *Symbol) { |
1336 | increment(Symbol); |
1337 | getReader().notifyAddedElement(Symbol); |
1338 | } |
1339 | void LVScopeCompileUnit::addedElement(LVType *Type) { |
1340 | increment(Type); |
1341 | getReader().notifyAddedElement(Type); |
1342 | } |
1343 | |
1344 | // Record unsuported DWARF tags. |
1345 | void LVScopeCompileUnit::addDebugTag(dwarf::Tag Target, LVOffset Offset) { |
1346 | addItem<LVTagOffsetsMap, dwarf::Tag, LVOffset>(Map: &DebugTags, Key: Target, Value: Offset); |
1347 | } |
1348 | |
1349 | // Record elements with invalid offsets. |
1350 | void LVScopeCompileUnit::addInvalidOffset(LVOffset Offset, LVElement *Element) { |
1351 | if (WarningOffsets.find(x: Offset) == WarningOffsets.end()) |
1352 | WarningOffsets.emplace(args&: Offset, args&: Element); |
1353 | } |
1354 | |
1355 | // Record symbols with invalid coverage values. |
1356 | void LVScopeCompileUnit::addInvalidCoverage(LVSymbol *Symbol) { |
1357 | LVOffset Offset = Symbol->getOffset(); |
1358 | if (InvalidCoverages.find(x: Offset) == InvalidCoverages.end()) |
1359 | InvalidCoverages.emplace(args&: Offset, args&: Symbol); |
1360 | } |
1361 | |
1362 | // Record symbols with invalid locations. |
1363 | void LVScopeCompileUnit::addInvalidLocation(LVLocation *Location) { |
1364 | addInvalidLocationOrRange(Location, Element: Location->getParentSymbol(), |
1365 | Map: &InvalidLocations); |
1366 | } |
1367 | |
1368 | // Record scopes with invalid ranges. |
1369 | void LVScopeCompileUnit::addInvalidRange(LVLocation *Location) { |
1370 | addInvalidLocationOrRange(Location, Element: Location->getParentScope(), |
1371 | Map: &InvalidRanges); |
1372 | } |
1373 | |
1374 | // Record line zero. |
1375 | void LVScopeCompileUnit::addLineZero(LVLine *Line) { |
1376 | LVScope *Scope = Line->getParentScope(); |
1377 | LVOffset Offset = Scope->getOffset(); |
1378 | addInvalidOffset(Offset, Element: Scope); |
1379 | addItem<LVOffsetLinesMap, LVOffset, LVLine *>(Map: &LinesZero, Key: Offset, Value: Line); |
1380 | } |
1381 | |
1382 | void LVScopeCompileUnit::printLocalNames(raw_ostream &OS, bool Full) const { |
1383 | if (!options().getPrintFormatting()) |
1384 | return; |
1385 | |
1386 | // Calculate an indentation value, to preserve a nice layout. |
1387 | size_t Indentation = options().indentationSize() + |
1388 | lineNumberAsString().length() + |
1389 | indentAsString(Level: getLevel() + 1).length() + 3; |
1390 | |
1391 | enum class Option { Directory, File }; |
1392 | auto PrintNames = [&](Option Action) { |
1393 | StringRef Kind = Action == Option::Directory ? "Directory" : "File" ; |
1394 | std::set<std::string> UniqueNames; |
1395 | for (size_t Index : Filenames) { |
1396 | // In the case of missing directory name in the .debug_line table, |
1397 | // the returned string has a leading '/'. |
1398 | StringRef Name = getStringPool().getString(Index); |
1399 | size_t Pos = Name.rfind(C: '/'); |
1400 | if (Pos != std::string::npos) |
1401 | Name = (Action == Option::File) ? Name.substr(Start: Pos + 1) |
1402 | : Name.substr(Start: 0, N: Pos); |
1403 | // Collect only unique names. |
1404 | UniqueNames.insert(x: std::string(Name)); |
1405 | } |
1406 | for (const std::string &Name : UniqueNames) |
1407 | OS << std::string(Indentation, ' ') << formattedKind(Kind) << " " |
1408 | << formattedName(Name) << "\n" ; |
1409 | }; |
1410 | |
1411 | if (options().getAttributeDirectories()) |
1412 | PrintNames(Option::Directory); |
1413 | if (options().getAttributeFiles()) |
1414 | PrintNames(Option::File); |
1415 | if (options().getAttributePublics()) { |
1416 | StringRef Kind = "Public" ; |
1417 | // The public names are indexed by 'LVScope *'. We want to print |
1418 | // them by logical element address, to show the scopes layout. |
1419 | using OffsetSorted = std::map<LVAddress, LVPublicNames::const_iterator>; |
1420 | OffsetSorted SortedNames; |
1421 | for (LVPublicNames::const_iterator Iter = PublicNames.begin(); |
1422 | Iter != PublicNames.end(); ++Iter) |
1423 | SortedNames.emplace(args: Iter->first->getOffset(), args&: Iter); |
1424 | |
1425 | LVPublicNames::const_iterator Iter; |
1426 | for (OffsetSorted::reference Entry : SortedNames) { |
1427 | Iter = Entry.second; |
1428 | OS << std::string(Indentation, ' ') << formattedKind(Kind) << " " |
1429 | << formattedName(Name: (*Iter).first->getName()); |
1430 | if (options().getAttributeOffset()) { |
1431 | LVAddress Address = (*Iter).second.first; |
1432 | size_t Size = (*Iter).second.second; |
1433 | OS << " [" << hexString(Value: Address) << ":" << hexString(Value: Address + Size) |
1434 | << "]" ; |
1435 | } |
1436 | OS << "\n" ; |
1437 | } |
1438 | } |
1439 | } |
1440 | |
1441 | void LVScopeCompileUnit::printWarnings(raw_ostream &OS, bool Full) const { |
1442 | auto = [&](const char *) { OS << "\n" << Header << ":\n" ; }; |
1443 | auto = [&](auto &Set) { |
1444 | if (Set.empty()) |
1445 | OS << "None\n" ; |
1446 | }; |
1447 | auto PrintOffset = [&](unsigned &Count, LVOffset Offset) { |
1448 | if (Count == 5) { |
1449 | Count = 0; |
1450 | OS << "\n" ; |
1451 | } |
1452 | ++Count; |
1453 | OS << hexSquareString(Value: Offset) << " " ; |
1454 | }; |
1455 | auto PrintElement = [&](const LVOffsetElementMap &Map, LVOffset Offset) { |
1456 | LVOffsetElementMap::const_iterator Iter = Map.find(x: Offset); |
1457 | LVElement *Element = Iter != Map.end() ? Iter->second : nullptr; |
1458 | OS << "[" << hexString(Value: Offset) << "]" ; |
1459 | if (Element) |
1460 | OS << " " << formattedKind(Kind: Element->kind()) << " " |
1461 | << formattedName(Name: Element->getName()); |
1462 | OS << "\n" ; |
1463 | }; |
1464 | auto PrintInvalidLocations = [&](const LVOffsetLocationsMap &Map, |
1465 | const char *) { |
1466 | PrintHeader(Header); |
1467 | for (LVOffsetLocationsMap::const_reference Entry : Map) { |
1468 | PrintElement(WarningOffsets, Entry.first); |
1469 | for (const LVLocation *Location : Entry.second) |
1470 | OS << hexSquareString(Value: Location->getOffset()) << " " |
1471 | << Location->getIntervalInfo() << "\n" ; |
1472 | } |
1473 | PrintFooter(Map); |
1474 | }; |
1475 | |
1476 | if (options().getInternalTag() && getReader().isBinaryTypeELF()) { |
1477 | PrintHeader("Unsupported DWARF Tags" ); |
1478 | for (LVTagOffsetsMap::const_reference Entry : DebugTags) { |
1479 | OS << format(Fmt: "\n0x%02x" , Vals: (unsigned)Entry.first) << ", " |
1480 | << dwarf::TagString(Tag: Entry.first) << "\n" ; |
1481 | unsigned Count = 0; |
1482 | for (const LVOffset &Offset : Entry.second) |
1483 | PrintOffset(Count, Offset); |
1484 | OS << "\n" ; |
1485 | } |
1486 | PrintFooter(DebugTags); |
1487 | } |
1488 | |
1489 | if (options().getWarningCoverages()) { |
1490 | PrintHeader("Symbols Invalid Coverages" ); |
1491 | for (LVOffsetSymbolMap::const_reference Entry : InvalidCoverages) { |
1492 | // Symbol basic information. |
1493 | LVSymbol *Symbol = Entry.second; |
1494 | OS << hexSquareString(Value: Entry.first) << " {Coverage} " |
1495 | << format(Fmt: "%.2f%%" , Vals: Symbol->getCoveragePercentage()) << " " |
1496 | << formattedKind(Kind: Symbol->kind()) << " " |
1497 | << formattedName(Name: Symbol->getName()) << "\n" ; |
1498 | } |
1499 | PrintFooter(InvalidCoverages); |
1500 | } |
1501 | |
1502 | if (options().getWarningLines()) { |
1503 | PrintHeader("Lines Zero References" ); |
1504 | for (LVOffsetLinesMap::const_reference Entry : LinesZero) { |
1505 | PrintElement(WarningOffsets, Entry.first); |
1506 | unsigned Count = 0; |
1507 | for (const LVLine *Line : Entry.second) |
1508 | PrintOffset(Count, Line->getOffset()); |
1509 | OS << "\n" ; |
1510 | } |
1511 | PrintFooter(LinesZero); |
1512 | } |
1513 | |
1514 | if (options().getWarningLocations()) |
1515 | PrintInvalidLocations(InvalidLocations, "Invalid Location Ranges" ); |
1516 | |
1517 | if (options().getWarningRanges()) |
1518 | PrintInvalidLocations(InvalidRanges, "Invalid Code Ranges" ); |
1519 | } |
1520 | |
1521 | void LVScopeCompileUnit::printTotals(raw_ostream &OS) const { |
1522 | OS << "\nTotals by lexical level:\n" ; |
1523 | for (size_t Index = 1; Index <= MaxSeenLevel; ++Index) |
1524 | OS << format(Fmt: "[%03d]: %10d (%6.2f%%)\n" , Vals: Index, Vals: Totals[Index].first, |
1525 | Vals: Totals[Index].second); |
1526 | } |
1527 | |
1528 | void LVScopeCompileUnit::printScopeSize(const LVScope *Scope, raw_ostream &OS) { |
1529 | LVSizesMap::const_iterator Iter = Sizes.find(x: Scope); |
1530 | if (Iter != Sizes.end()) { |
1531 | LVOffset Size = Iter->second; |
1532 | assert(CUContributionSize && "Invalid CU contribution size." ); |
1533 | // Get a percentage rounded to two decimal digits. This avoids |
1534 | // implementation-defined rounding inside printing functions. |
1535 | float Percentage = |
1536 | rint(x: (float(Size) / CUContributionSize) * 100.0 * 100.0) / 100.0; |
1537 | OS << format(Fmt: "%10" PRId64 " (%6.2f%%) : " , Vals: Size, Vals: Percentage); |
1538 | Scope->print(OS); |
1539 | |
1540 | // Keep record of the total sizes at each lexical level. |
1541 | LVLevel Level = Scope->getLevel(); |
1542 | if (Level > MaxSeenLevel) |
1543 | MaxSeenLevel = Level; |
1544 | if (Level >= Totals.size()) |
1545 | Totals.resize(N: 2 * Level); |
1546 | Totals[Level].first += Size; |
1547 | Totals[Level].second += Percentage; |
1548 | } |
1549 | } |
1550 | |
1551 | void LVScopeCompileUnit::printSizes(raw_ostream &OS) const { |
1552 | // Recursively print the contributions for each scope. |
1553 | std::function<void(const LVScope *Scope)> PrintScope = |
1554 | [&](const LVScope *Scope) { |
1555 | // If we have selection criteria, then use only the selected scopes. |
1556 | if (options().getSelectExecute() && options().getReportAnyView()) { |
1557 | for (const LVScope *Scope : MatchedScopes) |
1558 | if (Scope->getLevel() < options().getOutputLevel()) |
1559 | printScopeSize(Scope, OS); |
1560 | return; |
1561 | } |
1562 | if (Scope->getLevel() < options().getOutputLevel()) { |
1563 | if (const LVScopes *Scopes = Scope->getScopes()) |
1564 | for (const LVScope *Scope : *Scopes) { |
1565 | printScopeSize(Scope, OS); |
1566 | PrintScope(Scope); |
1567 | } |
1568 | } |
1569 | }; |
1570 | |
1571 | bool PrintScopes = options().getPrintScopes(); |
1572 | if (!PrintScopes) |
1573 | options().setPrintScopes(); |
1574 | getReader().setCompileUnit(const_cast<LVScopeCompileUnit *>(this)); |
1575 | |
1576 | OS << "\nScope Sizes:\n" ; |
1577 | options().resetPrintFormatting(); |
1578 | options().setPrintOffset(); |
1579 | |
1580 | // Print the scopes regardless if the user has requested any scopes |
1581 | // printing. Set the option just to allow printing the contributions. |
1582 | printScopeSize(Scope: this, OS); |
1583 | PrintScope(this); |
1584 | |
1585 | // Print total scope sizes by level. |
1586 | printTotals(OS); |
1587 | |
1588 | options().resetPrintOffset(); |
1589 | options().setPrintFormatting(); |
1590 | |
1591 | if (!PrintScopes) |
1592 | options().resetPrintScopes(); |
1593 | } |
1594 | |
1595 | void LVScopeCompileUnit::printSummary(raw_ostream &OS) const { |
1596 | printSummary(OS, Counter: options().getSelectExecute() ? Found : Printed, Header: "Printed" ); |
1597 | } |
1598 | |
1599 | // Print summary details for the scopes tree. |
1600 | void LVScopeCompileUnit::printSummary(raw_ostream &OS, const LVCounter &Counter, |
1601 | const char *) const { |
1602 | std::string Separator = std::string(29, '-'); |
1603 | auto PrintSeparator = [&]() { OS << Separator << "\n" ; }; |
1604 | auto PrintHeadingRow = [&](const char *T, const char *U, const char *V) { |
1605 | OS << format(Fmt: "%-9s%9s %9s\n" , Vals: T, Vals: U, Vals: V); |
1606 | }; |
1607 | auto PrintDataRow = [&](const char *T, unsigned U, unsigned V) { |
1608 | OS << format(Fmt: "%-9s%9d %9d\n" , Vals: T, Vals: U, Vals: V); |
1609 | }; |
1610 | |
1611 | OS << "\n" ; |
1612 | PrintSeparator(); |
1613 | PrintHeadingRow("Element" , "Total" , Header); |
1614 | PrintSeparator(); |
1615 | PrintDataRow("Scopes" , Allocated.Scopes, Counter.Scopes); |
1616 | PrintDataRow("Symbols" , Allocated.Symbols, Counter.Symbols); |
1617 | PrintDataRow("Types" , Allocated.Types, Counter.Types); |
1618 | PrintDataRow("Lines" , Allocated.Lines, Counter.Lines); |
1619 | PrintSeparator(); |
1620 | PrintDataRow( |
1621 | "Total" , |
1622 | Allocated.Scopes + Allocated.Symbols + Allocated.Lines + Allocated.Types, |
1623 | Counter.Scopes + Counter.Symbols + Counter.Lines + Counter.Types); |
1624 | } |
1625 | |
1626 | void LVScopeCompileUnit::printMatchedElements(raw_ostream &OS, |
1627 | bool UseMatchedElements) { |
1628 | LVSortFunction SortFunction = getSortFunction(); |
1629 | if (SortFunction) |
1630 | std::stable_sort(first: MatchedElements.begin(), last: MatchedElements.end(), |
1631 | comp: SortFunction); |
1632 | |
1633 | // Check the type of elements required to be printed. 'MatchedElements' |
1634 | // contains generic elements (lines, scopes, symbols, types). If we have a |
1635 | // request to print any generic element, then allow the normal printing. |
1636 | if (options().getPrintAnyElement()) { |
1637 | if (UseMatchedElements) |
1638 | OS << "\n" ; |
1639 | print(OS); |
1640 | |
1641 | if (UseMatchedElements) { |
1642 | // Print the details for the matched elements. |
1643 | for (const LVElement *Element : MatchedElements) |
1644 | Element->print(OS); |
1645 | } else { |
1646 | // Print the view for the matched scopes. |
1647 | for (const LVScope *Scope : MatchedScopes) { |
1648 | Scope->print(OS); |
1649 | if (const LVElements *Elements = Scope->getChildren()) |
1650 | for (LVElement *Element : *Elements) |
1651 | Element->print(OS); |
1652 | } |
1653 | } |
1654 | |
1655 | // Print any requested summary. |
1656 | if (options().getPrintSummary()) { |
1657 | // In the case of '--report=details' the matched elements are |
1658 | // already counted; just proceed to print any requested summary. |
1659 | // Otherwise, count them and print the summary. |
1660 | if (!options().getReportList()) { |
1661 | for (LVElement *Element : MatchedElements) { |
1662 | if (!Element->getIncludeInPrint()) |
1663 | continue; |
1664 | if (Element->getIsType()) |
1665 | ++Found.Types; |
1666 | else if (Element->getIsSymbol()) |
1667 | ++Found.Symbols; |
1668 | else if (Element->getIsScope()) |
1669 | ++Found.Scopes; |
1670 | else if (Element->getIsLine()) |
1671 | ++Found.Lines; |
1672 | else |
1673 | assert(Element && "Invalid element." ); |
1674 | } |
1675 | } |
1676 | printSummary(OS, Counter: Found, Header: "Printed" ); |
1677 | } |
1678 | } |
1679 | |
1680 | // Check if we have a request to print sizes for the matched elements |
1681 | // that are scopes. |
1682 | if (options().getPrintSizes()) { |
1683 | OS << "\n" ; |
1684 | print(OS); |
1685 | |
1686 | OS << "\nScope Sizes:\n" ; |
1687 | printScopeSize(Scope: this, OS); |
1688 | for (LVElement *Element : MatchedElements) |
1689 | if (Element->getIsScope()) |
1690 | // Print sizes only for scopes. |
1691 | printScopeSize(Scope: static_cast<LVScope *>(Element), OS); |
1692 | |
1693 | printTotals(OS); |
1694 | } |
1695 | } |
1696 | |
1697 | void LVScopeCompileUnit::print(raw_ostream &OS, bool Full) const { |
1698 | // Reset counters for printed and found elements. |
1699 | const_cast<LVScopeCompileUnit *>(this)->Found.reset(); |
1700 | const_cast<LVScopeCompileUnit *>(this)->Printed.reset(); |
1701 | |
1702 | if (getReader().doPrintScope(Scope: this) && options().getPrintFormatting()) |
1703 | OS << "\n" ; |
1704 | |
1705 | LVScope::print(OS, Full); |
1706 | } |
1707 | |
1708 | void LVScopeCompileUnit::(raw_ostream &OS, bool Full) const { |
1709 | OS << formattedKind(Kind: kind()) << " '" << getName() << "'\n" ; |
1710 | if (options().getPrintFormatting() && options().getAttributeProducer()) |
1711 | printAttributes(OS, Full, Name: "{Producer} " , |
1712 | Parent: const_cast<LVScopeCompileUnit *>(this), Value: getProducer(), |
1713 | /*UseQuotes=*/true, |
1714 | /*PrintRef=*/false); |
1715 | |
1716 | // Reset file index, to allow its children to print the correct filename. |
1717 | options().resetFilenameIndex(); |
1718 | |
1719 | // Print any files, directories, public names and active ranges. |
1720 | if (Full) { |
1721 | printLocalNames(OS, Full); |
1722 | printActiveRanges(OS, Full); |
1723 | } |
1724 | } |
1725 | |
1726 | //===----------------------------------------------------------------------===// |
1727 | // DWARF enumeration (DW_TAG_enumeration_type). |
1728 | //===----------------------------------------------------------------------===// |
1729 | bool LVScopeEnumeration::equals(const LVScope *Scope) const { |
1730 | if (!LVScope::equals(Scope)) |
1731 | return false; |
1732 | return equalNumberOfChildren(Scope); |
1733 | } |
1734 | |
1735 | void LVScopeEnumeration::(raw_ostream &OS, bool Full) const { |
1736 | // Print the full type name. |
1737 | OS << formattedKind(Kind: kind()) << " " << (getIsEnumClass() ? "class " : "" ) |
1738 | << formattedName(Name: getName()); |
1739 | if (getHasType()) |
1740 | OS << " -> " << typeOffsetAsString() |
1741 | << formattedNames(Name1: getTypeQualifiedName(), Name2: typeAsString()); |
1742 | OS << "\n" ; |
1743 | } |
1744 | |
1745 | //===----------------------------------------------------------------------===// |
1746 | // DWARF formal parameter pack (DW_TAG_GNU_formal_parameter_pack). |
1747 | //===----------------------------------------------------------------------===// |
1748 | bool LVScopeFormalPack::equals(const LVScope *Scope) const { |
1749 | if (!LVScope::equals(Scope)) |
1750 | return false; |
1751 | return equalNumberOfChildren(Scope); |
1752 | } |
1753 | |
1754 | void LVScopeFormalPack::(raw_ostream &OS, bool Full) const { |
1755 | OS << formattedKind(Kind: kind()) << " " << formattedName(Name: getName()) << "\n" ; |
1756 | } |
1757 | |
1758 | //===----------------------------------------------------------------------===// |
1759 | // DWARF function. |
1760 | //===----------------------------------------------------------------------===// |
1761 | void LVScopeFunction::resolveReferences() { |
1762 | // Before we resolve any references to other elements, check if we have |
1763 | // to insert missing elements, that have been stripped, which will help |
1764 | // the logical view comparison. |
1765 | if (options().getAttributeInserted() && getHasReferenceAbstract() && |
1766 | !getAddedMissing()) { |
1767 | // Add missing elements at the function scope. |
1768 | addMissingElements(Reference: getReference()); |
1769 | if (Scopes) |
1770 | for (LVScope *Scope : *Scopes) |
1771 | if (Scope->getHasReferenceAbstract() && !Scope->getAddedMissing()) |
1772 | Scope->addMissingElements(Reference: Scope->getReference()); |
1773 | } |
1774 | |
1775 | LVScope::resolveReferences(); |
1776 | |
1777 | // The DWARF 'extern' attribute is generated at the class level. |
1778 | // 0000003f DW_TAG_class_type "CLASS" |
1779 | // 00000048 DW_TAG_subprogram "bar" |
1780 | // DW_AT_external DW_FORM_flag_present |
1781 | // 00000070 DW_TAG_subprogram "bar" |
1782 | // DW_AT_specification DW_FORM_ref4 0x00000048 |
1783 | // CodeView does not include any information at the class level to |
1784 | // mark the member function as external. |
1785 | // If there is a reference linking the declaration and definition, mark |
1786 | // the definition as extern, to facilitate the logical view comparison. |
1787 | if (getHasReferenceSpecification()) { |
1788 | LVScope *Reference = getReference(); |
1789 | if (Reference && Reference->getIsExternal()) { |
1790 | Reference->resetIsExternal(); |
1791 | setIsExternal(); |
1792 | } |
1793 | } |
1794 | |
1795 | // Resolve the function associated type. |
1796 | if (!getType()) |
1797 | if (LVScope *Reference = getReference()) |
1798 | setType(Reference->getType()); |
1799 | } |
1800 | |
1801 | void LVScopeFunction::setName(StringRef ObjectName) { |
1802 | LVScope::setName(ObjectName); |
1803 | // Check for system generated functions. |
1804 | getReader().isSystemEntry(Element: this, Name: ObjectName); |
1805 | } |
1806 | |
1807 | void LVScopeFunction::() { |
1808 | // Check if we need to encode the template arguments. |
1809 | if (getIsTemplate()) |
1810 | resolveTemplate(); |
1811 | } |
1812 | |
1813 | bool LVScopeFunction::equals(const LVScope *Scope) const { |
1814 | if (!LVScope::equals(Scope)) |
1815 | return false; |
1816 | |
1817 | // When comparing logical elements, ignore any difference in the children. |
1818 | if (options().getCompareContext() && !equalNumberOfChildren(Scope)) |
1819 | return false; |
1820 | |
1821 | // Check if the linkage name matches. |
1822 | if (getLinkageNameIndex() != Scope->getLinkageNameIndex()) |
1823 | return false; |
1824 | |
1825 | // Check if the parameters match in the case of templates. |
1826 | if (!LVType::parametersMatch(References: getTypes(), Targets: Scope->getTypes())) |
1827 | return false; |
1828 | |
1829 | // Check if the arguments match. |
1830 | if (!LVSymbol::parametersMatch(References: getSymbols(), Targets: Scope->getSymbols())) |
1831 | return false; |
1832 | |
1833 | // Check if the lines match. |
1834 | if (options().getCompareLines() && |
1835 | !LVLine::equals(References: getLines(), Targets: Scope->getLines())) |
1836 | return false; |
1837 | |
1838 | // Check if any reference is the same. |
1839 | if (!referenceMatch(Element: Scope)) |
1840 | return false; |
1841 | |
1842 | if (getReference() && !getReference()->equals(Scope: Scope->getReference())) |
1843 | return false; |
1844 | |
1845 | return true; |
1846 | } |
1847 | |
1848 | LVScope *LVScopeFunction::findEqualScope(const LVScopes *Scopes) const { |
1849 | assert(Scopes && "Scopes must not be nullptr" ); |
1850 | // Go through candidates and try to find a best match. |
1851 | for (LVScope *Scope : *Scopes) |
1852 | // Match arguments, children, lines, references. |
1853 | if (equals(Scope)) |
1854 | return Scope; |
1855 | return nullptr; |
1856 | } |
1857 | |
1858 | void LVScopeFunction::(raw_ostream &OS, bool Full) const { |
1859 | LVScope *Reference = getReference(); |
1860 | |
1861 | // Inline attributes based on the reference element. |
1862 | uint32_t InlineCode = |
1863 | Reference ? Reference->getInlineCode() : getInlineCode(); |
1864 | |
1865 | // Accessibility depends on the parent (class, structure). |
1866 | uint32_t AccessCode = 0; |
1867 | if (getIsMember()) |
1868 | AccessCode = getParentScope()->getIsClass() ? dwarf::DW_ACCESS_private |
1869 | : dwarf::DW_ACCESS_public; |
1870 | |
1871 | std::string Attributes = |
1872 | getIsCallSite() |
1873 | ? "" |
1874 | : formatAttributes(First: externalString(), Others: accessibilityString(Access: AccessCode), |
1875 | Others: inlineCodeString(Code: InlineCode), Others: virtualityString()); |
1876 | |
1877 | OS << formattedKind(Kind: kind()) << " " << Attributes << formattedName(Name: getName()) |
1878 | << discriminatorAsString() << " -> " << typeOffsetAsString() |
1879 | << formattedNames(Name1: getTypeQualifiedName(), Name2: typeAsString()) << "\n" ; |
1880 | |
1881 | // Print any active ranges. |
1882 | if (Full) { |
1883 | if (getIsTemplateResolved()) |
1884 | printEncodedArgs(OS, Full); |
1885 | printActiveRanges(OS, Full); |
1886 | if (getLinkageNameIndex()) |
1887 | printLinkageName(OS, Full, Parent: const_cast<LVScopeFunction *>(this), |
1888 | Scope: const_cast<LVScopeFunction *>(this)); |
1889 | if (Reference) |
1890 | Reference->printReference(OS, Full, Parent: const_cast<LVScopeFunction *>(this)); |
1891 | } |
1892 | } |
1893 | |
1894 | //===----------------------------------------------------------------------===// |
1895 | // DWARF inlined function (DW_TAG_inlined_function). |
1896 | //===----------------------------------------------------------------------===// |
1897 | void LVScopeFunctionInlined::() { |
1898 | // Check if we need to encode the template arguments. |
1899 | if (getIsTemplate()) |
1900 | resolveTemplate(); |
1901 | } |
1902 | |
1903 | bool LVScopeFunctionInlined::equals(const LVScope *Scope) const { |
1904 | if (!LVScopeFunction::equals(Scope)) |
1905 | return false; |
1906 | |
1907 | // Check if any reference is the same. |
1908 | if (getHasDiscriminator() && Scope->getHasDiscriminator()) |
1909 | if (getDiscriminator() != Scope->getDiscriminator()) |
1910 | return false; |
1911 | |
1912 | // Check the call site information. |
1913 | if (getCallFilenameIndex() != Scope->getCallFilenameIndex() || |
1914 | getCallLineNumber() != Scope->getCallLineNumber()) |
1915 | return false; |
1916 | |
1917 | return true; |
1918 | } |
1919 | |
1920 | LVScope *LVScopeFunctionInlined::findEqualScope(const LVScopes *Scopes) const { |
1921 | return LVScopeFunction::findEqualScope(Scopes); |
1922 | } |
1923 | |
1924 | void LVScopeFunctionInlined::(raw_ostream &OS, bool Full) const { |
1925 | LVScopeFunction::printExtra(OS, Full); |
1926 | } |
1927 | |
1928 | //===----------------------------------------------------------------------===// |
1929 | // DWARF subroutine type. |
1930 | //===----------------------------------------------------------------------===// |
1931 | // Resolve a Subroutine Type (Callback). |
1932 | void LVScopeFunctionType::() { |
1933 | if (getIsMemberPointerResolved()) |
1934 | return; |
1935 | setIsMemberPointerResolved(); |
1936 | |
1937 | // The encoded string has the return type and the formal parameters type. |
1938 | std::string Name(typeAsString()); |
1939 | Name.append(s: " (*)" ); |
1940 | Name.append(s: "(" ); |
1941 | |
1942 | // Traverse the scope symbols, looking for those which are parameters. |
1943 | if (const LVSymbols *Symbols = getSymbols()) { |
1944 | bool AddComma = false; |
1945 | for (LVSymbol *Symbol : *Symbols) |
1946 | if (Symbol->getIsParameter()) { |
1947 | Symbol->resolve(); |
1948 | if (LVElement *Type = Symbol->getType()) |
1949 | Type->resolveName(); |
1950 | if (AddComma) |
1951 | Name.append(s: ", " ); |
1952 | Name.append(str: std::string(Symbol->getTypeName())); |
1953 | AddComma = true; |
1954 | } |
1955 | } |
1956 | |
1957 | Name.append(s: ")" ); |
1958 | |
1959 | // Update the scope name, to reflect the encoded parameters. |
1960 | setName(Name); |
1961 | } |
1962 | |
1963 | //===----------------------------------------------------------------------===// |
1964 | // DWARF namespace (DW_TAG_namespace). |
1965 | //===----------------------------------------------------------------------===// |
1966 | bool LVScopeNamespace::equals(const LVScope *Scope) const { |
1967 | if (!LVScope::equals(Scope)) |
1968 | return false; |
1969 | |
1970 | if (!equalNumberOfChildren(Scope)) |
1971 | return false; |
1972 | |
1973 | // Check if any reference is the same. |
1974 | if (!referenceMatch(Element: Scope)) |
1975 | return false; |
1976 | |
1977 | if (getReference() && !getReference()->equals(Scope: Scope->getReference())) |
1978 | return false; |
1979 | |
1980 | return true; |
1981 | } |
1982 | |
1983 | LVScope *LVScopeNamespace::findEqualScope(const LVScopes *Scopes) const { |
1984 | assert(Scopes && "Scopes must not be nullptr" ); |
1985 | // Go through candidates and try to find a best match. |
1986 | for (LVScope *Scope : *Scopes) |
1987 | if (equals(Scope)) |
1988 | return Scope; |
1989 | return nullptr; |
1990 | } |
1991 | |
1992 | void LVScopeNamespace::(raw_ostream &OS, bool Full) const { |
1993 | OS << formattedKind(Kind: kind()) << " " << formattedName(Name: getName()) << "\n" ; |
1994 | |
1995 | // Print any active ranges. |
1996 | if (Full) { |
1997 | printActiveRanges(OS, Full); |
1998 | |
1999 | if (LVScope *Reference = getReference()) |
2000 | Reference->printReference(OS, Full, Parent: const_cast<LVScopeNamespace *>(this)); |
2001 | } |
2002 | } |
2003 | |
2004 | //===----------------------------------------------------------------------===// |
2005 | // An object file (single or multiple CUs). |
2006 | //===----------------------------------------------------------------------===// |
2007 | void LVScopeRoot::processRangeInformation() { |
2008 | if (!options().getAttributeAnyLocation()) |
2009 | return; |
2010 | |
2011 | if (Scopes) |
2012 | for (LVScope *Scope : *Scopes) { |
2013 | LVScopeCompileUnit *CompileUnit = |
2014 | static_cast<LVScopeCompileUnit *>(Scope); |
2015 | getReader().setCompileUnit(CompileUnit); |
2016 | CompileUnit->processRangeLocationCoverage(); |
2017 | } |
2018 | } |
2019 | |
2020 | void LVScopeRoot::transformScopedName() { |
2021 | // Recursively transform all names. |
2022 | std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) { |
2023 | auto Traverse = [&](const auto *Set) { |
2024 | if (Set) |
2025 | for (const auto &Entry : *Set) |
2026 | Entry->setInnerComponent(); |
2027 | }; |
2028 | if (const LVScopes *Scopes = Parent->getScopes()) |
2029 | for (LVScope *Scope : *Scopes) { |
2030 | Scope->setInnerComponent(); |
2031 | TraverseScope(Scope); |
2032 | } |
2033 | Traverse(Parent->getSymbols()); |
2034 | Traverse(Parent->getTypes()); |
2035 | Traverse(Parent->getLines()); |
2036 | }; |
2037 | |
2038 | // Start traversing the scopes root and transform the element name. |
2039 | TraverseScope(this); |
2040 | } |
2041 | |
2042 | bool LVScopeRoot::equals(const LVScope *Scope) const { |
2043 | return LVScope::equals(Scope); |
2044 | } |
2045 | |
2046 | void LVScopeRoot::print(raw_ostream &OS, bool Full) const { |
2047 | OS << "\nLogical View:\n" ; |
2048 | LVScope::print(OS, Full); |
2049 | } |
2050 | |
2051 | void LVScopeRoot::(raw_ostream &OS, bool Full) const { |
2052 | OS << formattedKind(Kind: kind()) << " " << formattedName(Name: getName()) << "" ; |
2053 | if (options().getAttributeFormat()) |
2054 | OS << " -> " << getFileFormatName(); |
2055 | OS << "\n" ; |
2056 | } |
2057 | |
2058 | Error LVScopeRoot::doPrintMatches(bool Split, raw_ostream &OS, |
2059 | bool UseMatchedElements) const { |
2060 | // During a view output splitting, use the output stream created by the |
2061 | // split context, then switch to the reader output stream. |
2062 | static raw_ostream *StreamSplit = &OS; |
2063 | |
2064 | if (Scopes) { |
2065 | if (UseMatchedElements) |
2066 | options().resetPrintFormatting(); |
2067 | print(OS); |
2068 | |
2069 | for (LVScope *Scope : *Scopes) { |
2070 | getReader().setCompileUnit(const_cast<LVScope *>(Scope)); |
2071 | |
2072 | // If 'Split', we use the scope name (CU name) as the ouput file; the |
2073 | // delimiters in the pathname, must be replaced by a normal character. |
2074 | if (Split) { |
2075 | std::string ScopeName(Scope->getName()); |
2076 | if (std::error_code EC = |
2077 | getReaderSplitContext().open(Name: ScopeName, Extension: ".txt" , OS)) |
2078 | return createStringError(EC, Fmt: "Unable to create split output file %s" , |
2079 | Vals: ScopeName.c_str()); |
2080 | StreamSplit = static_cast<raw_ostream *>(&getReaderSplitContext().os()); |
2081 | } |
2082 | |
2083 | Scope->printMatchedElements(OS&: *StreamSplit, UseMatchedElements); |
2084 | |
2085 | // Done printing the compile unit. Restore the original output context. |
2086 | if (Split) { |
2087 | getReaderSplitContext().close(); |
2088 | StreamSplit = &getReader().outputStream(); |
2089 | } |
2090 | } |
2091 | if (UseMatchedElements) |
2092 | options().setPrintFormatting(); |
2093 | } |
2094 | |
2095 | return Error::success(); |
2096 | } |
2097 | |
2098 | //===----------------------------------------------------------------------===// |
2099 | // DWARF template parameter pack (DW_TAG_GNU_template_parameter_pack). |
2100 | //===----------------------------------------------------------------------===// |
2101 | bool LVScopeTemplatePack::equals(const LVScope *Scope) const { |
2102 | if (!LVScope::equals(Scope)) |
2103 | return false; |
2104 | return equalNumberOfChildren(Scope); |
2105 | } |
2106 | |
2107 | void LVScopeTemplatePack::(raw_ostream &OS, bool Full) const { |
2108 | OS << formattedKind(Kind: kind()) << " " << formattedName(Name: getName()) << "\n" ; |
2109 | } |
2110 | |