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/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 
82   int getIndentLevel() { return IndentLevel; }
83 
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 
140     llvm::sort(SetFlags, &flagName<TFlag>);
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) {
265     printString(Label, StringRef(Value));
266   }
267 
268   void printString(StringRef Label, const char* Value) {
269     printString(Label, StringRef(Value));
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 
303   void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value,
304                         uint32_t StartOffset) {
305     printBinaryImpl(Label, StringRef(), Value, true, StartOffset);
306   }
307 
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,
346                        bool Block, uint32_t StartOffset = 0);
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
389