Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===-- LVObject.h ----------------------------------------------*- C++ -*-===// |
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 file defines the LVObject class, which is used to describe a debug |
||
10 | // information object. |
||
11 | // |
||
12 | //===----------------------------------------------------------------------===// |
||
13 | |||
14 | #ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |
||
15 | #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |
||
16 | |||
17 | #include "llvm/BinaryFormat/Dwarf.h" |
||
18 | #include "llvm/DebugInfo/CodeView/CodeView.h" |
||
19 | #include "llvm/DebugInfo/CodeView/TypeIndex.h" |
||
20 | #include "llvm/DebugInfo/LogicalView/Core/LVSupport.h" |
||
21 | #include <limits> |
||
22 | #include <list> |
||
23 | #include <map> |
||
24 | #include <string> |
||
25 | |||
26 | namespace llvm { |
||
27 | namespace dwarf { |
||
28 | // Support for CodeView ModifierOptions::Unaligned. |
||
29 | constexpr Tag DW_TAG_unaligned = Tag(dwarf::DW_TAG_hi_user + 1); |
||
30 | } // namespace dwarf |
||
31 | } // namespace llvm |
||
32 | |||
33 | namespace llvm { |
||
34 | namespace logicalview { |
||
35 | |||
36 | using LVSectionIndex = uint64_t; |
||
37 | using LVAddress = uint64_t; |
||
38 | using LVHalf = uint16_t; |
||
39 | using LVLevel = uint32_t; |
||
40 | using LVOffset = uint64_t; |
||
41 | using LVSigned = int64_t; |
||
42 | using LVUnsigned = uint64_t; |
||
43 | using LVSmall = uint8_t; |
||
44 | |||
45 | class LVElement; |
||
46 | class LVLine; |
||
47 | class LVLocation; |
||
48 | class LVLocationSymbol; |
||
49 | class LVObject; |
||
50 | class LVOperation; |
||
51 | class LVScope; |
||
52 | class LVSymbol; |
||
53 | class LVType; |
||
54 | |||
55 | class LVOptions; |
||
56 | class LVPatterns; |
||
57 | |||
58 | StringRef typeNone(); |
||
59 | StringRef typeVoid(); |
||
60 | StringRef typeInt(); |
||
61 | StringRef typeUnknown(); |
||
62 | StringRef emptyString(); |
||
63 | |||
64 | using LVElementSetFunction = void (LVElement::*)(); |
||
65 | using LVElementGetFunction = bool (LVElement::*)() const; |
||
66 | using LVLineSetFunction = void (LVLine::*)(); |
||
67 | using LVLineGetFunction = bool (LVLine::*)() const; |
||
68 | using LVObjectSetFunction = void (LVObject::*)(); |
||
69 | using LVObjectGetFunction = bool (LVObject::*)() const; |
||
70 | using LVScopeSetFunction = void (LVScope::*)(); |
||
71 | using LVScopeGetFunction = bool (LVScope::*)() const; |
||
72 | using LVSymbolSetFunction = void (LVSymbol::*)(); |
||
73 | using LVSymbolGetFunction = bool (LVSymbol::*)() const; |
||
74 | using LVTypeSetFunction = void (LVType::*)(); |
||
75 | using LVTypeGetFunction = bool (LVType::*)() const; |
||
76 | |||
77 | // The LVScope class represents a logical scope and uses vectors to store its |
||
78 | // children, which are pointers to other allocated logical elements (types, |
||
79 | // symbols, lines, scopes, ranges). On destruction, we have to traverse each |
||
80 | // vector and destroy its elements. The other case is LVSymbol. |
||
81 | // These definitions are intended to be used by the LVScope and LVSymbol |
||
82 | // to support automatic vector cleanup. |
||
83 | using LVAutoLines = LVAutoSmallVector<LVLine *>; |
||
84 | using LVAutoLocations = LVAutoSmallVector<LVLocation *>; |
||
85 | using LVAutoOperations = LVAutoSmallVector<LVOperation *, 8>; |
||
86 | using LVAutoScopes = LVAutoSmallVector<LVScope *>; |
||
87 | using LVAutoSymbols = LVAutoSmallVector<LVSymbol *>; |
||
88 | using LVAutoTypes = LVAutoSmallVector<LVType *>; |
||
89 | |||
90 | // These definitions are intended to be used when the vector will be used |
||
91 | // just a container, with no automatic destruction. |
||
92 | using LVElements = SmallVector<LVElement *, 8>; |
||
93 | using LVLines = SmallVector<LVLine *, 8>; |
||
94 | using LVLocations = SmallVector<LVLocation *, 8>; |
||
95 | using LVOperations = SmallVector<LVOperation *, 8>; |
||
96 | using LVScopes = SmallVector<LVScope *, 8>; |
||
97 | using LVSymbols = SmallVector<LVSymbol *, 8>; |
||
98 | using LVTypes = SmallVector<LVType *, 8>; |
||
99 | |||
100 | using LVOffsets = SmallVector<LVOffset, 8>; |
||
101 | |||
102 | const LVAddress MaxAddress = std::numeric_limits<uint64_t>::max(); |
||
103 | |||
104 | enum class LVBinaryType { NONE, ELF, COFF }; |
||
105 | enum class LVComparePass { Missing, Added }; |
||
106 | |||
107 | // Validate functions. |
||
108 | using LVValidLocation = bool (LVLocation::*)(); |
||
109 | |||
110 | // Keep counters of objects. |
||
111 | struct LVCounter { |
||
112 | unsigned Lines = 0; |
||
113 | unsigned Scopes = 0; |
||
114 | unsigned Symbols = 0; |
||
115 | unsigned Types = 0; |
||
116 | void reset() { |
||
117 | Lines = 0; |
||
118 | Scopes = 0; |
||
119 | Symbols = 0; |
||
120 | Types = 0; |
||
121 | } |
||
122 | }; |
||
123 | |||
124 | class LVObject { |
||
125 | enum class Property { |
||
126 | IsLocation, // Location. |
||
127 | IsGlobalReference, // This object is being referenced from another CU. |
||
128 | IsGeneratedName, // The Object name was generated. |
||
129 | IsResolved, // Object has been resolved. |
||
130 | IsResolvedName, // Object name has been resolved. |
||
131 | IsDiscarded, // Object has been stripped by the linker. |
||
132 | IsOptimized, // Object has been optimized by the compiler. |
||
133 | IsAdded, // Object has been 'added'. |
||
134 | IsMatched, // Object has been matched to a given pattern. |
||
135 | IsMissing, // Object is 'missing'. |
||
136 | IsMissingLink, // Object is indirectly 'missing'. |
||
137 | IsInCompare, // In 'compare' mode. |
||
138 | IsFileFromReference, // File ID from specification. |
||
139 | IsLineFromReference, // Line No from specification. |
||
140 | HasMoved, // The object was moved from 'target' to 'reference'. |
||
141 | HasPattern, // The object has a pattern. |
||
142 | IsFinalized, // CodeView object is finalized. |
||
143 | IsReferenced, // CodeView object being referenced. |
||
144 | HasCodeViewLocation, // CodeView object with debug location. |
||
145 | LastEntry |
||
146 | }; |
||
147 | // Typed bitvector with properties for this object. |
||
148 | LVProperties<Property> Properties; |
||
149 | |||
150 | LVOffset Offset = 0; |
||
151 | uint32_t LineNumber = 0; |
||
152 | LVLevel ScopeLevel = 0; |
||
153 | union { |
||
154 | dwarf::Tag Tag; |
||
155 | dwarf::Attribute Attr; |
||
156 | LVSmall Opcode; |
||
157 | } TagAttrOpcode = {dwarf::DW_TAG_null}; |
||
158 | |||
159 | // The parent of this object (nullptr if the root scope). For locations, |
||
160 | // the parent is a symbol object; otherwise it is a scope object. |
||
161 | union { |
||
162 | LVElement *Element; |
||
163 | LVScope *Scope; |
||
164 | LVSymbol *Symbol; |
||
165 | } Parent = {nullptr}; |
||
166 | |||
167 | // We do not support any object duplication, as they are created by parsing |
||
168 | // the debug information. There is only the case where we need a very basic |
||
169 | // object, to manipulate its offset, line number and scope level. Allow the |
||
170 | // copy constructor to create that object; it is used to print a reference |
||
171 | // to another object and in the case of templates, to print its encoded args. |
||
172 | LVObject(const LVObject &Object) { |
||
173 | #ifndef NDEBUG |
||
174 | incID(); |
||
175 | #endif |
||
176 | Properties = Object.Properties; |
||
177 | Offset = Object.Offset; |
||
178 | LineNumber = Object.LineNumber; |
||
179 | ScopeLevel = Object.ScopeLevel; |
||
180 | TagAttrOpcode = Object.TagAttrOpcode; |
||
181 | Parent = Object.Parent; |
||
182 | } |
||
183 | |||
184 | #ifndef NDEBUG |
||
185 | // This is an internal ID used for debugging logical elements. It is used |
||
186 | // for cases where an unique offset within the binary input file is not |
||
187 | // available. |
||
188 | static uint64_t GID; |
||
189 | uint64_t ID = 0; |
||
190 | |||
191 | void incID() { |
||
192 | ++GID; |
||
193 | ID = GID; |
||
194 | } |
||
195 | #endif |
||
196 | |||
197 | protected: |
||
198 | // Get a string representation for the given number and discriminator. |
||
199 | std::string lineAsString(uint32_t LineNumber, LVHalf Discriminator, |
||
200 | bool ShowZero) const; |
||
201 | |||
202 | // Get a string representation for the given number. |
||
203 | std::string referenceAsString(uint32_t LineNumber, bool Spaces) const; |
||
204 | |||
205 | // Print the Filename or Pathname. |
||
206 | // Empty implementation for those objects that do not have any user |
||
207 | // source file references, such as debug locations. |
||
208 | virtual void printFileIndex(raw_ostream &OS, bool Full = true) const {} |
||
209 | |||
210 | public: |
||
211 | LVObject() { |
||
212 | #ifndef NDEBUG |
||
213 | incID(); |
||
214 | #endif |
||
215 | }; |
||
216 | LVObject &operator=(const LVObject &) = delete; |
||
217 | virtual ~LVObject() = default; |
||
218 | |||
219 | PROPERTY(Property, IsLocation); |
||
220 | PROPERTY(Property, IsGlobalReference); |
||
221 | PROPERTY(Property, IsGeneratedName); |
||
222 | PROPERTY(Property, IsResolved); |
||
223 | PROPERTY(Property, IsResolvedName); |
||
224 | PROPERTY(Property, IsDiscarded); |
||
225 | PROPERTY(Property, IsOptimized); |
||
226 | PROPERTY(Property, IsAdded); |
||
227 | PROPERTY(Property, IsMatched); |
||
228 | PROPERTY(Property, IsMissing); |
||
229 | PROPERTY(Property, IsMissingLink); |
||
230 | PROPERTY(Property, IsInCompare); |
||
231 | PROPERTY(Property, IsFileFromReference); |
||
232 | PROPERTY(Property, IsLineFromReference); |
||
233 | PROPERTY(Property, HasMoved); |
||
234 | PROPERTY(Property, HasPattern); |
||
235 | PROPERTY(Property, IsFinalized); |
||
236 | PROPERTY(Property, IsReferenced); |
||
237 | PROPERTY(Property, HasCodeViewLocation); |
||
238 | |||
239 | // True if the scope has been named or typed or with line number. |
||
240 | virtual bool isNamed() const { return false; } |
||
241 | virtual bool isTyped() const { return false; } |
||
242 | virtual bool isFiled() const { return false; } |
||
243 | bool isLined() const { return LineNumber != 0; } |
||
244 | |||
245 | // DWARF tag, attribute or expression opcode. |
||
246 | dwarf::Tag getTag() const { return TagAttrOpcode.Tag; } |
||
247 | void setTag(dwarf::Tag Tag) { TagAttrOpcode.Tag = Tag; } |
||
248 | dwarf::Attribute getAttr() const { return TagAttrOpcode.Attr; } |
||
249 | void setAttr(dwarf::Attribute Attr) { TagAttrOpcode.Attr = Attr; } |
||
250 | LVSmall getOpcode() const { return TagAttrOpcode.Opcode; } |
||
251 | void setOpcode(LVSmall Opcode) { TagAttrOpcode.Opcode = Opcode; } |
||
252 | |||
253 | // DIE offset. |
||
254 | LVOffset getOffset() const { return Offset; } |
||
255 | void setOffset(LVOffset DieOffset) { Offset = DieOffset; } |
||
256 | |||
257 | // Level where this object is located. |
||
258 | LVLevel getLevel() const { return ScopeLevel; } |
||
259 | void setLevel(LVLevel Level) { ScopeLevel = Level; } |
||
260 | |||
261 | virtual StringRef getName() const { return StringRef(); } |
||
262 | virtual void setName(StringRef ObjectName) {} |
||
263 | |||
264 | LVElement *getParent() const { |
||
265 | assert((!Parent.Element || |
||
266 | (Parent.Element && static_cast<LVElement *>(Parent.Element))) && |
||
267 | "Invalid element"); |
||
268 | return Parent.Element; |
||
269 | } |
||
270 | LVScope *getParentScope() const { |
||
271 | assert((!Parent.Scope || |
||
272 | (Parent.Scope && static_cast<LVScope *>(Parent.Scope))) && |
||
273 | "Invalid scope"); |
||
274 | return Parent.Scope; |
||
275 | } |
||
276 | LVSymbol *getParentSymbol() const { |
||
277 | assert((!Parent.Symbol || |
||
278 | (Parent.Symbol && static_cast<LVSymbol *>(Parent.Symbol))) && |
||
279 | "Invalid symbol"); |
||
280 | return Parent.Symbol; |
||
281 | } |
||
282 | void setParent(LVScope *Scope); |
||
283 | void setParent(LVSymbol *Symbol); |
||
284 | void resetParent() { Parent = {nullptr}; } |
||
285 | |||
286 | virtual LVAddress getLowerAddress() const { return 0; } |
||
287 | virtual void setLowerAddress(LVAddress Address) {} |
||
288 | virtual LVAddress getUpperAddress() const { return 0; } |
||
289 | virtual void setUpperAddress(LVAddress Address) {} |
||
290 | |||
291 | uint32_t getLineNumber() const { return LineNumber; } |
||
292 | void setLineNumber(uint32_t Number) { LineNumber = Number; } |
||
293 | |||
294 | virtual const char *kind() const { return nullptr; } |
||
295 | |||
296 | std::string indentAsString() const; |
||
297 | std::string indentAsString(LVLevel Level) const; |
||
298 | |||
299 | // String used as padding for printing objects with no line number. |
||
300 | virtual std::string noLineAsString(bool ShowZero) const; |
||
301 | |||
302 | // Line number for display; in the case of inlined functions, we use the |
||
303 | // DW_AT_call_line attribute; otherwise use DW_AT_decl_line attribute. |
||
304 | virtual std::string lineNumberAsString(bool ShowZero = false) const { |
||
305 | return lineAsString(getLineNumber(), 0, ShowZero); |
||
306 | } |
||
307 | std::string lineNumberAsStringStripped(bool ShowZero = false) const; |
||
308 | |||
309 | // This function prints the logical view to an output stream. |
||
310 | // Split: Prints the compilation unit view to a file. |
||
311 | // Match: Prints the object only if it satisfies the patterns collected |
||
312 | // from the command line. See the '--select' option. |
||
313 | // Print: Print the object only if satisfies the conditions specified by |
||
314 | // the different '--print' options. |
||
315 | // Full: Prints full information for objects representing debug locations, |
||
316 | // aggregated scopes, compile unit, functions and namespaces. |
||
317 | virtual Error doPrint(bool Split, bool Match, bool Print, raw_ostream &OS, |
||
318 | bool Full = true) const; |
||
319 | void printAttributes(raw_ostream &OS, bool Full = true) const; |
||
320 | void printAttributes(raw_ostream &OS, bool Full, StringRef Name, |
||
321 | LVObject *Parent, StringRef Value, |
||
322 | bool UseQuotes = false, bool PrintRef = false) const; |
||
323 | |||
324 | // Mark branch as missing (current element and parents). |
||
325 | void markBranchAsMissing(); |
||
326 | |||
327 | // Prints the common information for an object (name, type, etc). |
||
328 | virtual void print(raw_ostream &OS, bool Full = true) const; |
||
329 | // Prints additional information for an object, depending on its kind |
||
330 | // (class attributes, debug ranges, files, directories, etc). |
||
331 | virtual void printExtra(raw_ostream &OS, bool Full = true) const {} |
||
332 | |||
333 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
||
334 | virtual void dump() const { print(dbgs()); } |
||
335 | #endif |
||
336 | |||
337 | uint64_t getID() const { |
||
338 | return |
||
339 | #ifndef NDEBUG |
||
340 | ID; |
||
341 | #else |
||
342 | 0; |
||
343 | #endif |
||
344 | } |
||
345 | }; |
||
346 | |||
347 | } // end namespace logicalview |
||
348 | } // end namespace llvm |
||
349 | |||
350 | #endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |