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