1 | //===-- LVSupport.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 support functions. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H |
14 | #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H |
15 | |
16 | #include "llvm/ADT/SmallBitVector.h" |
17 | #include "llvm/ADT/Twine.h" |
18 | #include "llvm/DebugInfo/LogicalView/Core/LVStringPool.h" |
19 | #include "llvm/Support/Debug.h" |
20 | #include "llvm/Support/Format.h" |
21 | #include "llvm/Support/Path.h" |
22 | #include "llvm/Support/raw_ostream.h" |
23 | #include <cctype> |
24 | #include <map> |
25 | #include <sstream> |
26 | |
27 | namespace llvm { |
28 | namespace logicalview { |
29 | |
30 | // Returns the unique string pool instance. |
31 | LVStringPool &getStringPool(); |
32 | |
33 | using LVStringRefs = std::vector<StringRef>; |
34 | using LVLexicalComponent = std::tuple<StringRef, StringRef>; |
35 | using LVLexicalIndex = |
36 | std::tuple<LVStringRefs::size_type, LVStringRefs::size_type>; |
37 | |
38 | // Used to record specific characteristics about the objects. |
39 | template <typename T> class LVProperties { |
40 | SmallBitVector Bits = SmallBitVector(static_cast<unsigned>(T::LastEntry) + 1); |
41 | |
42 | public: |
43 | LVProperties() = default; |
44 | |
45 | void set(T Idx) { Bits[static_cast<unsigned>(Idx)] = 1; } |
46 | void reset(T Idx) { Bits[static_cast<unsigned>(Idx)] = 0; } |
47 | bool get(T Idx) const { return Bits[static_cast<unsigned>(Idx)]; } |
48 | }; |
49 | |
50 | // Generate get, set and reset 'bool' functions for LVProperties instances. |
51 | // FAMILY: instance name. |
52 | // ENUM: enumeration instance. |
53 | // FIELD: enumerator instance. |
54 | // F1, F2, F3: optional 'set' functions to be called. |
55 | #define BOOL_BIT(FAMILY, ENUM, FIELD) \ |
56 | bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \ |
57 | void set##FIELD() { FAMILY.set(ENUM::FIELD); } \ |
58 | void reset##FIELD() { FAMILY.reset(ENUM::FIELD); } |
59 | |
60 | #define BOOL_BIT_1(FAMILY, ENUM, FIELD, F1) \ |
61 | bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \ |
62 | void set##FIELD() { \ |
63 | FAMILY.set(ENUM::FIELD); \ |
64 | set##F1(); \ |
65 | } \ |
66 | void reset##FIELD() { FAMILY.reset(ENUM::FIELD); } |
67 | |
68 | #define BOOL_BIT_2(FAMILY, ENUM, FIELD, F1, F2) \ |
69 | bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \ |
70 | void set##FIELD() { \ |
71 | FAMILY.set(ENUM::FIELD); \ |
72 | set##F1(); \ |
73 | set##F2(); \ |
74 | } \ |
75 | void reset##FIELD() { FAMILY.reset(ENUM::FIELD); } |
76 | |
77 | #define BOOL_BIT_3(FAMILY, ENUM, FIELD, F1, F2, F3) \ |
78 | bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \ |
79 | void set##FIELD() { \ |
80 | FAMILY.set(ENUM::FIELD); \ |
81 | set##F1(); \ |
82 | set##F2(); \ |
83 | set##F3(); \ |
84 | } \ |
85 | void reset##FIELD() { FAMILY.reset(ENUM::FIELD); } |
86 | |
87 | // Generate get, set and reset functions for 'properties'. |
88 | #define PROPERTY(ENUM, FIELD) BOOL_BIT(Properties, ENUM, FIELD) |
89 | #define PROPERTY_1(ENUM, FIELD, F1) BOOL_BIT_1(Properties, ENUM, FIELD, F1) |
90 | #define PROPERTY_2(ENUM, FIELD, F1, F2) \ |
91 | BOOL_BIT_2(Properties, ENUM, FIELD, F1, F2) |
92 | #define PROPERTY_3(ENUM, FIELD, F1, F2, F3) \ |
93 | BOOL_BIT_3(Properties, ENUM, FIELD, F1, F2, F3) |
94 | |
95 | // Generate get, set and reset functions for 'kinds'. |
96 | #define KIND(ENUM, FIELD) BOOL_BIT(Kinds, ENUM, FIELD) |
97 | #define KIND_1(ENUM, FIELD, F1) BOOL_BIT_1(Kinds, ENUM, FIELD, F1) |
98 | #define KIND_2(ENUM, FIELD, F1, F2) BOOL_BIT_2(Kinds, ENUM, FIELD, F1, F2) |
99 | #define KIND_3(ENUM, FIELD, F1, F2, F3) \ |
100 | BOOL_BIT_3(Kinds, ENUM, FIELD, F1, F2, F3) |
101 | |
102 | const int HEX_WIDTH = 12; |
103 | inline FormattedNumber hexValue(uint64_t N, unsigned Width = HEX_WIDTH, |
104 | bool Upper = false) { |
105 | return format_hex(N, Width, Upper); |
106 | } |
107 | |
108 | // Output the hexadecimal representation of 'Value' using '[0x%08x]' format. |
109 | inline std::string hexString(uint64_t Value, size_t Width = HEX_WIDTH) { |
110 | std::string String; |
111 | raw_string_ostream Stream(String); |
112 | Stream << hexValue(N: Value, Width, Upper: false); |
113 | return Stream.str(); |
114 | } |
115 | |
116 | // Get a hexadecimal string representation for the given value. |
117 | inline std::string hexSquareString(uint64_t Value) { |
118 | return (Twine("[" ) + Twine(hexString(Value)) + Twine("]" )).str(); |
119 | } |
120 | |
121 | // Return a string with the First and Others separated by spaces. |
122 | template <typename... Args> |
123 | std::string formatAttributes(const StringRef First, Args... Others) { |
124 | const auto List = {First, Others...}; |
125 | std::stringstream Stream; |
126 | size_t Size = 0; |
127 | for (const StringRef &Item : List) { |
128 | Stream << (Size ? " " : "" ) << Item.str(); |
129 | Size = Item.size(); |
130 | } |
131 | Stream << (Size ? " " : "" ); |
132 | return Stream.str(); |
133 | } |
134 | |
135 | // Add an item to a map with second being a small vector. |
136 | template <typename MapType, typename KeyType, typename ValueType> |
137 | void addItem(MapType *Map, KeyType Key, ValueType Value) { |
138 | (*Map)[Key].push_back(Value); |
139 | } |
140 | |
141 | // Double map data structure. |
142 | template <typename FirstKeyType, typename SecondKeyType, typename ValueType> |
143 | class LVDoubleMap { |
144 | static_assert(std::is_pointer<ValueType>::value, |
145 | "ValueType must be a pointer." ); |
146 | using LVSecondMapType = std::map<SecondKeyType, ValueType>; |
147 | using LVFirstMapType = |
148 | std::map<FirstKeyType, std::unique_ptr<LVSecondMapType>>; |
149 | using LVAuxMapType = std::map<SecondKeyType, FirstKeyType>; |
150 | using LVValueTypes = std::vector<ValueType>; |
151 | LVFirstMapType FirstMap; |
152 | LVAuxMapType AuxMap; |
153 | |
154 | public: |
155 | void add(FirstKeyType FirstKey, SecondKeyType SecondKey, ValueType Value) { |
156 | typename LVFirstMapType::iterator FirstIter = FirstMap.find(FirstKey); |
157 | if (FirstIter == FirstMap.end()) { |
158 | auto SecondMapSP = std::make_unique<LVSecondMapType>(); |
159 | SecondMapSP->emplace(SecondKey, Value); |
160 | FirstMap.emplace(FirstKey, std::move(SecondMapSP)); |
161 | } else { |
162 | LVSecondMapType *SecondMap = FirstIter->second.get(); |
163 | if (SecondMap->find(SecondKey) == SecondMap->end()) |
164 | SecondMap->emplace(SecondKey, Value); |
165 | } |
166 | |
167 | typename LVAuxMapType::iterator AuxIter = AuxMap.find(SecondKey); |
168 | if (AuxIter == AuxMap.end()) { |
169 | AuxMap.emplace(SecondKey, FirstKey); |
170 | } |
171 | } |
172 | |
173 | LVSecondMapType *findMap(FirstKeyType FirstKey) const { |
174 | typename LVFirstMapType::const_iterator FirstIter = FirstMap.find(FirstKey); |
175 | if (FirstIter == FirstMap.end()) |
176 | return nullptr; |
177 | |
178 | return FirstIter->second.get(); |
179 | } |
180 | |
181 | ValueType find(FirstKeyType FirstKey, SecondKeyType SecondKey) const { |
182 | LVSecondMapType *SecondMap = findMap(FirstKey); |
183 | if (!SecondMap) |
184 | return nullptr; |
185 | |
186 | typename LVSecondMapType::const_iterator SecondIter = |
187 | SecondMap->find(SecondKey); |
188 | return (SecondIter != SecondMap->end()) ? SecondIter->second : nullptr; |
189 | } |
190 | |
191 | ValueType find(SecondKeyType SecondKey) const { |
192 | typename LVAuxMapType::const_iterator AuxIter = AuxMap.find(SecondKey); |
193 | if (AuxIter == AuxMap.end()) |
194 | return nullptr; |
195 | return find(AuxIter->second, SecondKey); |
196 | } |
197 | |
198 | // Return a vector with all the 'ValueType' values. |
199 | LVValueTypes find() const { |
200 | LVValueTypes Values; |
201 | if (FirstMap.empty()) |
202 | return Values; |
203 | for (typename LVFirstMapType::const_reference FirstEntry : FirstMap) { |
204 | LVSecondMapType &SecondMap = *FirstEntry.second; |
205 | for (typename LVSecondMapType::const_reference SecondEntry : SecondMap) |
206 | Values.push_back(SecondEntry.second); |
207 | } |
208 | return Values; |
209 | } |
210 | }; |
211 | |
212 | // Unified and flattened pathnames. |
213 | std::string transformPath(StringRef Path); |
214 | std::string flattenedFilePath(StringRef Path); |
215 | |
216 | inline std::string formattedKind(StringRef Kind) { |
217 | return (Twine("{" ) + Twine(Kind) + Twine("}" )).str(); |
218 | } |
219 | |
220 | inline std::string formattedName(StringRef Name) { |
221 | return (Twine("'" ) + Twine(Name) + Twine("'" )).str(); |
222 | } |
223 | |
224 | inline std::string formattedNames(StringRef Name1, StringRef Name2) { |
225 | return (Twine("'" ) + Twine(Name1) + Twine(Name2) + Twine("'" )).str(); |
226 | } |
227 | |
228 | // The given string represents a symbol or type name with optional enclosing |
229 | // scopes, such as: name, name<..>, scope::name, scope::..::name, etc. |
230 | // The string can have multiple references to template instantiations. |
231 | // It returns the inner most component. |
232 | LVLexicalComponent getInnerComponent(StringRef Name); |
233 | LVStringRefs getAllLexicalComponents(StringRef Name); |
234 | std::string getScopedName(const LVStringRefs &Components, |
235 | StringRef BaseName = {}); |
236 | |
237 | // These are the values assigned to the debug location record IDs. |
238 | // See DebugInfo/CodeView/CodeViewSymbols.def. |
239 | // S_DEFRANGE 0x113f |
240 | // S_DEFRANGE_SUBFIELD 0x1140 |
241 | // S_DEFRANGE_REGISTER 0x1141 |
242 | // S_DEFRANGE_FRAMEPOINTER_REL 0x1142 |
243 | // S_DEFRANGE_SUBFIELD_REGISTER 0x1143 |
244 | // S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE 0x1144 |
245 | // S_DEFRANGE_REGISTER_REL 0x1145 |
246 | // When recording CodeView debug location, the above values are truncated |
247 | // to a uint8_t value in order to fit the 'OpCode' used for the logical |
248 | // debug location operations. |
249 | // Return the original CodeView enum value. |
250 | inline uint16_t getCodeViewOperationCode(uint8_t Code) { return 0x1100 | Code; } |
251 | |
252 | } // end namespace logicalview |
253 | } // end namespace llvm |
254 | |
255 | #endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H |
256 | |