xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
set(T Idx)45   void set(T Idx) { Bits[static_cast<unsigned>(Idx)] = 1; }
reset(T Idx)46   void reset(T Idx) { Bits[static_cast<unsigned>(Idx)] = 0; }
get(T Idx)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(Value, Width, false);
113   return String;
114 }
115 
116 // Get a hexadecimal string representation for the given value.
hexSquareString(uint64_t 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>
formatAttributes(const StringRef First,Args...Others)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>
addItem(MapType * Map,KeyType Key,ValueType Value)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:
add(FirstKeyType FirstKey,SecondKeyType SecondKey,ValueType Value)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 
findMap(FirstKeyType FirstKey)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 
find(FirstKeyType FirstKey,SecondKeyType SecondKey)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 
find(SecondKeyType SecondKey)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.
find()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 
formattedKind(StringRef Kind)216 inline std::string formattedKind(StringRef Kind) {
217   return (Twine("{") + Twine(Kind) + Twine("}")).str();
218 }
219 
formattedName(StringRef Name)220 inline std::string formattedName(StringRef Name) {
221   return (Twine("'") + Twine(Name) + Twine("'")).str();
222 }
223 
formattedNames(StringRef Name1,StringRef Name2)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.
getCodeViewOperationCode(uint8_t Code)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