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