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