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