147
|
1 //===-- ScopedPrinter.h ----------------------------------------*- C++ -*--===//
|
120
|
2 //
|
147
|
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
|
120
|
6 //
|
|
7 //===----------------------------------------------------------------------===//
|
|
8
|
|
9 #ifndef LLVM_SUPPORT_SCOPEDPRINTER_H
|
|
10 #define LLVM_SUPPORT_SCOPEDPRINTER_H
|
|
11
|
|
12 #include "llvm/ADT/APSInt.h"
|
|
13 #include "llvm/ADT/ArrayRef.h"
|
|
14 #include "llvm/ADT/SmallVector.h"
|
|
15 #include "llvm/ADT/StringRef.h"
|
|
16 #include "llvm/Support/DataTypes.h"
|
|
17 #include "llvm/Support/Endian.h"
|
|
18 #include "llvm/Support/raw_ostream.h"
|
|
19 #include <algorithm>
|
|
20
|
|
21 namespace llvm {
|
|
22
|
|
23 template <typename T> struct EnumEntry {
|
|
24 StringRef Name;
|
|
25 // While Name suffices in most of the cases, in certain cases
|
|
26 // GNU style and LLVM style of ELFDumper do not
|
|
27 // display same string for same enum. The AltName if initialized appropriately
|
|
28 // will hold the string that GNU style emits.
|
|
29 // Example:
|
|
30 // "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to
|
|
31 // "Advanced Micro Devices X86-64" on GNU style
|
|
32 StringRef AltName;
|
|
33 T Value;
|
|
34 EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {}
|
|
35 EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {}
|
|
36 };
|
|
37
|
|
38 struct HexNumber {
|
|
39 // To avoid sign-extension we have to explicitly cast to the appropriate
|
|
40 // unsigned type. The overloads are here so that every type that is implicitly
|
|
41 // convertible to an integer (including enums and endian helpers) can be used
|
|
42 // without requiring type traits or call-site changes.
|
|
43 HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {}
|
|
44 HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {}
|
|
45 HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {}
|
|
46 HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {}
|
|
47 HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {}
|
|
48 HexNumber(signed long long Value)
|
|
49 : Value(static_cast<unsigned long long>(Value)) {}
|
|
50 HexNumber(unsigned char Value) : Value(Value) {}
|
|
51 HexNumber(unsigned short Value) : Value(Value) {}
|
|
52 HexNumber(unsigned int Value) : Value(Value) {}
|
|
53 HexNumber(unsigned long Value) : Value(Value) {}
|
|
54 HexNumber(unsigned long long Value) : Value(Value) {}
|
|
55 uint64_t Value;
|
|
56 };
|
|
57
|
|
58 raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value);
|
|
59 const std::string to_hexString(uint64_t Value, bool UpperCase = true);
|
|
60
|
|
61 template <class T> const std::string to_string(const T &Value) {
|
|
62 std::string number;
|
|
63 llvm::raw_string_ostream stream(number);
|
|
64 stream << Value;
|
|
65 return stream.str();
|
|
66 }
|
|
67
|
|
68 class ScopedPrinter {
|
|
69 public:
|
|
70 ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {}
|
|
71
|
|
72 void flush() { OS.flush(); }
|
|
73
|
|
74 void indent(int Levels = 1) { IndentLevel += Levels; }
|
|
75
|
|
76 void unindent(int Levels = 1) {
|
|
77 IndentLevel = std::max(0, IndentLevel - Levels);
|
|
78 }
|
|
79
|
|
80 void resetIndent() { IndentLevel = 0; }
|
|
81
|
147
|
82 int getIndentLevel() { return IndentLevel; }
|
|
83
|
120
|
84 void setPrefix(StringRef P) { Prefix = P; }
|
|
85
|
|
86 void printIndent() {
|
|
87 OS << Prefix;
|
|
88 for (int i = 0; i < IndentLevel; ++i)
|
|
89 OS << " ";
|
|
90 }
|
|
91
|
|
92 template <typename T> HexNumber hex(T Value) { return HexNumber(Value); }
|
|
93
|
|
94 template <typename T, typename TEnum>
|
|
95 void printEnum(StringRef Label, T Value,
|
|
96 ArrayRef<EnumEntry<TEnum>> EnumValues) {
|
|
97 StringRef Name;
|
|
98 bool Found = false;
|
|
99 for (const auto &EnumItem : EnumValues) {
|
|
100 if (EnumItem.Value == Value) {
|
|
101 Name = EnumItem.Name;
|
|
102 Found = true;
|
|
103 break;
|
|
104 }
|
|
105 }
|
|
106
|
|
107 if (Found) {
|
|
108 startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
|
|
109 } else {
|
|
110 startLine() << Label << ": " << hex(Value) << "\n";
|
|
111 }
|
|
112 }
|
|
113
|
|
114 template <typename T, typename TFlag>
|
|
115 void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
|
|
116 TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
|
|
117 TFlag EnumMask3 = {}) {
|
|
118 typedef EnumEntry<TFlag> FlagEntry;
|
|
119 typedef SmallVector<FlagEntry, 10> FlagVector;
|
|
120 FlagVector SetFlags;
|
|
121
|
|
122 for (const auto &Flag : Flags) {
|
|
123 if (Flag.Value == 0)
|
|
124 continue;
|
|
125
|
|
126 TFlag EnumMask{};
|
|
127 if (Flag.Value & EnumMask1)
|
|
128 EnumMask = EnumMask1;
|
|
129 else if (Flag.Value & EnumMask2)
|
|
130 EnumMask = EnumMask2;
|
|
131 else if (Flag.Value & EnumMask3)
|
|
132 EnumMask = EnumMask3;
|
|
133 bool IsEnum = (Flag.Value & EnumMask) != 0;
|
|
134 if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
|
|
135 (IsEnum && (Value & EnumMask) == Flag.Value)) {
|
|
136 SetFlags.push_back(Flag);
|
|
137 }
|
|
138 }
|
|
139
|
147
|
140 llvm::sort(SetFlags, &flagName<TFlag>);
|
120
|
141
|
|
142 startLine() << Label << " [ (" << hex(Value) << ")\n";
|
|
143 for (const auto &Flag : SetFlags) {
|
|
144 startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n";
|
|
145 }
|
|
146 startLine() << "]\n";
|
|
147 }
|
|
148
|
|
149 template <typename T> void printFlags(StringRef Label, T Value) {
|
|
150 startLine() << Label << " [ (" << hex(Value) << ")\n";
|
|
151 uint64_t Flag = 1;
|
|
152 uint64_t Curr = Value;
|
|
153 while (Curr > 0) {
|
|
154 if (Curr & 1)
|
|
155 startLine() << " " << hex(Flag) << "\n";
|
|
156 Curr >>= 1;
|
|
157 Flag <<= 1;
|
|
158 }
|
|
159 startLine() << "]\n";
|
|
160 }
|
|
161
|
|
162 void printNumber(StringRef Label, uint64_t Value) {
|
|
163 startLine() << Label << ": " << Value << "\n";
|
|
164 }
|
|
165
|
|
166 void printNumber(StringRef Label, uint32_t Value) {
|
|
167 startLine() << Label << ": " << Value << "\n";
|
|
168 }
|
|
169
|
|
170 void printNumber(StringRef Label, uint16_t Value) {
|
|
171 startLine() << Label << ": " << Value << "\n";
|
|
172 }
|
|
173
|
|
174 void printNumber(StringRef Label, uint8_t Value) {
|
|
175 startLine() << Label << ": " << unsigned(Value) << "\n";
|
|
176 }
|
|
177
|
|
178 void printNumber(StringRef Label, int64_t Value) {
|
|
179 startLine() << Label << ": " << Value << "\n";
|
|
180 }
|
|
181
|
|
182 void printNumber(StringRef Label, int32_t Value) {
|
|
183 startLine() << Label << ": " << Value << "\n";
|
|
184 }
|
|
185
|
|
186 void printNumber(StringRef Label, int16_t Value) {
|
|
187 startLine() << Label << ": " << Value << "\n";
|
|
188 }
|
|
189
|
|
190 void printNumber(StringRef Label, int8_t Value) {
|
|
191 startLine() << Label << ": " << int(Value) << "\n";
|
|
192 }
|
|
193
|
|
194 void printNumber(StringRef Label, const APSInt &Value) {
|
|
195 startLine() << Label << ": " << Value << "\n";
|
|
196 }
|
|
197
|
|
198 void printBoolean(StringRef Label, bool Value) {
|
|
199 startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
|
|
200 }
|
|
201
|
|
202 template <typename... T> void printVersion(StringRef Label, T... Version) {
|
|
203 startLine() << Label << ": ";
|
|
204 printVersionInternal(Version...);
|
|
205 getOStream() << "\n";
|
|
206 }
|
|
207
|
|
208 template <typename T> void printList(StringRef Label, const T &List) {
|
|
209 startLine() << Label << ": [";
|
|
210 bool Comma = false;
|
|
211 for (const auto &Item : List) {
|
|
212 if (Comma)
|
|
213 OS << ", ";
|
|
214 OS << Item;
|
|
215 Comma = true;
|
|
216 }
|
|
217 OS << "]\n";
|
|
218 }
|
|
219
|
|
220 template <typename T, typename U>
|
|
221 void printList(StringRef Label, const T &List, const U &Printer) {
|
|
222 startLine() << Label << ": [";
|
|
223 bool Comma = false;
|
|
224 for (const auto &Item : List) {
|
|
225 if (Comma)
|
|
226 OS << ", ";
|
|
227 Printer(OS, Item);
|
|
228 Comma = true;
|
|
229 }
|
|
230 OS << "]\n";
|
|
231 }
|
|
232
|
|
233 template <typename T> void printHexList(StringRef Label, const T &List) {
|
|
234 startLine() << Label << ": [";
|
|
235 bool Comma = false;
|
|
236 for (const auto &Item : List) {
|
|
237 if (Comma)
|
|
238 OS << ", ";
|
|
239 OS << hex(Item);
|
|
240 Comma = true;
|
|
241 }
|
|
242 OS << "]\n";
|
|
243 }
|
|
244
|
|
245 template <typename T> void printHex(StringRef Label, T Value) {
|
|
246 startLine() << Label << ": " << hex(Value) << "\n";
|
|
247 }
|
|
248
|
|
249 template <typename T> void printHex(StringRef Label, StringRef Str, T Value) {
|
|
250 startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
|
|
251 }
|
|
252
|
|
253 template <typename T>
|
|
254 void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) {
|
|
255 startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n';
|
|
256 }
|
|
257
|
|
258 void printString(StringRef Value) { startLine() << Value << "\n"; }
|
|
259
|
|
260 void printString(StringRef Label, StringRef Value) {
|
|
261 startLine() << Label << ": " << Value << "\n";
|
|
262 }
|
|
263
|
|
264 void printString(StringRef Label, const std::string &Value) {
|
134
|
265 printString(Label, StringRef(Value));
|
|
266 }
|
|
267
|
|
268 void printString(StringRef Label, const char* Value) {
|
|
269 printString(Label, StringRef(Value));
|
120
|
270 }
|
|
271
|
|
272 template <typename T>
|
|
273 void printNumber(StringRef Label, StringRef Str, T Value) {
|
|
274 startLine() << Label << ": " << Str << " (" << Value << ")\n";
|
|
275 }
|
|
276
|
|
277 void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
|
|
278 printBinaryImpl(Label, Str, Value, false);
|
|
279 }
|
|
280
|
|
281 void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
|
|
282 auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
|
|
283 Value.size());
|
|
284 printBinaryImpl(Label, Str, V, false);
|
|
285 }
|
|
286
|
|
287 void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
|
|
288 printBinaryImpl(Label, StringRef(), Value, false);
|
|
289 }
|
|
290
|
|
291 void printBinary(StringRef Label, ArrayRef<char> Value) {
|
|
292 auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
|
|
293 Value.size());
|
|
294 printBinaryImpl(Label, StringRef(), V, false);
|
|
295 }
|
|
296
|
|
297 void printBinary(StringRef Label, StringRef Value) {
|
|
298 auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
|
|
299 Value.size());
|
|
300 printBinaryImpl(Label, StringRef(), V, false);
|
|
301 }
|
|
302
|
121
|
303 void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value,
|
|
304 uint32_t StartOffset) {
|
|
305 printBinaryImpl(Label, StringRef(), Value, true, StartOffset);
|
|
306 }
|
|
307
|
120
|
308 void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
|
|
309 printBinaryImpl(Label, StringRef(), Value, true);
|
|
310 }
|
|
311
|
|
312 void printBinaryBlock(StringRef Label, StringRef Value) {
|
|
313 auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
|
|
314 Value.size());
|
|
315 printBinaryImpl(Label, StringRef(), V, true);
|
|
316 }
|
|
317
|
|
318 template <typename T> void printObject(StringRef Label, const T &Value) {
|
|
319 startLine() << Label << ": " << Value << "\n";
|
|
320 }
|
|
321
|
|
322 raw_ostream &startLine() {
|
|
323 printIndent();
|
|
324 return OS;
|
|
325 }
|
|
326
|
|
327 raw_ostream &getOStream() { return OS; }
|
|
328
|
|
329 private:
|
|
330 template <typename T> void printVersionInternal(T Value) {
|
|
331 getOStream() << Value;
|
|
332 }
|
|
333
|
|
334 template <typename S, typename T, typename... TArgs>
|
|
335 void printVersionInternal(S Value, T Value2, TArgs... Args) {
|
|
336 getOStream() << Value << ".";
|
|
337 printVersionInternal(Value2, Args...);
|
|
338 }
|
|
339
|
|
340 template <typename T>
|
|
341 static bool flagName(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
|
|
342 return lhs.Name < rhs.Name;
|
|
343 }
|
|
344
|
|
345 void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
|
121
|
346 bool Block, uint32_t StartOffset = 0);
|
120
|
347
|
|
348 raw_ostream &OS;
|
|
349 int IndentLevel;
|
|
350 StringRef Prefix;
|
|
351 };
|
|
352
|
|
353 template <>
|
|
354 inline void
|
|
355 ScopedPrinter::printHex<support::ulittle16_t>(StringRef Label,
|
|
356 support::ulittle16_t Value) {
|
|
357 startLine() << Label << ": " << hex(Value) << "\n";
|
|
358 }
|
|
359
|
|
360 template<char Open, char Close>
|
|
361 struct DelimitedScope {
|
|
362 explicit DelimitedScope(ScopedPrinter &W) : W(W) {
|
|
363 W.startLine() << Open << '\n';
|
|
364 W.indent();
|
|
365 }
|
|
366
|
|
367 DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) {
|
|
368 W.startLine() << N;
|
|
369 if (!N.empty())
|
|
370 W.getOStream() << ' ';
|
|
371 W.getOStream() << Open << '\n';
|
|
372 W.indent();
|
|
373 }
|
|
374
|
|
375 ~DelimitedScope() {
|
|
376 W.unindent();
|
|
377 W.startLine() << Close << '\n';
|
|
378 }
|
|
379
|
|
380 ScopedPrinter &W;
|
|
381 };
|
|
382
|
|
383 using DictScope = DelimitedScope<'{', '}'>;
|
|
384 using ListScope = DelimitedScope<'[', ']'>;
|
|
385
|
|
386 } // namespace llvm
|
|
387
|
|
388 #endif
|