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;
EnumEntryEnumEntry34   EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {}
EnumEntryEnumEntry35   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.
HexNumberHexNumber43   HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {}
HexNumberHexNumber44   HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {}
HexNumberHexNumber45   HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {}
HexNumberHexNumber46   HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {}
HexNumberHexNumber47   HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {}
HexNumberHexNumber48   HexNumber(signed long long Value)
49       : Value(static_cast<unsigned long long>(Value)) {}
HexNumberHexNumber50   HexNumber(unsigned char Value) : Value(Value) {}
HexNumberHexNumber51   HexNumber(unsigned short Value) : Value(Value) {}
HexNumberHexNumber52   HexNumber(unsigned int Value) : Value(Value) {}
HexNumberHexNumber53   HexNumber(unsigned long Value) : Value(Value) {}
HexNumberHexNumber54   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 
to_string(const T & Value)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:
ScopedPrinter(raw_ostream & OS)70   ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {}
71 
flush()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 
resetIndent()80   void resetIndent() { IndentLevel = 0; }
81 
getIndentLevel()82   int getIndentLevel() { return IndentLevel; }
83 
setPrefix(StringRef P)84   void setPrefix(StringRef P) { Prefix = P; }
85 
printIndent()86   void printIndent() {
87     OS << Prefix;
88     for (int i = 0; i < IndentLevel; ++i)
89       OS << "  ";
90   }
91 
hex(T Value)92   template <typename T> HexNumber hex(T Value) { return HexNumber(Value); }
93 
94   template <typename T, typename TEnum>
printEnum(StringRef Label,T Value,ArrayRef<EnumEntry<TEnum>> EnumValues)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 
printFlags(StringRef Label,T Value)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 
printNumber(StringRef Label,uint64_t Value)162   void printNumber(StringRef Label, uint64_t Value) {
163     startLine() << Label << ": " << Value << "\n";
164   }
165 
printNumber(StringRef Label,uint32_t Value)166   void printNumber(StringRef Label, uint32_t Value) {
167     startLine() << Label << ": " << Value << "\n";
168   }
169 
printNumber(StringRef Label,uint16_t Value)170   void printNumber(StringRef Label, uint16_t Value) {
171     startLine() << Label << ": " << Value << "\n";
172   }
173 
printNumber(StringRef Label,uint8_t Value)174   void printNumber(StringRef Label, uint8_t Value) {
175     startLine() << Label << ": " << unsigned(Value) << "\n";
176   }
177 
printNumber(StringRef Label,int64_t Value)178   void printNumber(StringRef Label, int64_t Value) {
179     startLine() << Label << ": " << Value << "\n";
180   }
181 
printNumber(StringRef Label,int32_t Value)182   void printNumber(StringRef Label, int32_t Value) {
183     startLine() << Label << ": " << Value << "\n";
184   }
185 
printNumber(StringRef Label,int16_t Value)186   void printNumber(StringRef Label, int16_t Value) {
187     startLine() << Label << ": " << Value << "\n";
188   }
189 
printNumber(StringRef Label,int8_t Value)190   void printNumber(StringRef Label, int8_t Value) {
191     startLine() << Label << ": " << int(Value) << "\n";
192   }
193 
printNumber(StringRef Label,const APSInt & Value)194   void printNumber(StringRef Label, const APSInt &Value) {
195     startLine() << Label << ": " << Value << "\n";
196   }
197 
printBoolean(StringRef Label,bool Value)198   void printBoolean(StringRef Label, bool Value) {
199     startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
200   }
201 
printVersion(StringRef Label,T...Version)202   template <typename... T> void printVersion(StringRef Label, T... Version) {
203     startLine() << Label << ": ";
204     printVersionInternal(Version...);
205     getOStream() << "\n";
206   }
207 
printList(StringRef Label,const T & List)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>
printList(StringRef Label,const T & List,const U & Printer)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 
printHexList(StringRef Label,const T & List)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 
printHex(StringRef Label,T Value)245   template <typename T> void printHex(StringRef Label, T Value) {
246     startLine() << Label << ": " << hex(Value) << "\n";
247   }
248 
printHex(StringRef Label,StringRef Str,T Value)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>
printSymbolOffset(StringRef Label,StringRef Symbol,T Value)254   void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) {
255     startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n';
256   }
257 
printString(StringRef Value)258   void printString(StringRef Value) { startLine() << Value << "\n"; }
259 
printString(StringRef Label,StringRef Value)260   void printString(StringRef Label, StringRef Value) {
261     startLine() << Label << ": " << Value << "\n";
262   }
263 
printString(StringRef Label,const std::string & Value)264   void printString(StringRef Label, const std::string &Value) {
265     printString(Label, StringRef(Value));
266   }
267 
printString(StringRef Label,const char * Value)268   void printString(StringRef Label, const char* Value) {
269     printString(Label, StringRef(Value));
270   }
271 
272   template <typename T>
printNumber(StringRef Label,StringRef Str,T Value)273   void printNumber(StringRef Label, StringRef Str, T Value) {
274     startLine() << Label << ": " << Str << " (" << Value << ")\n";
275   }
276 
printBinary(StringRef Label,StringRef Str,ArrayRef<uint8_t> Value)277   void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
278     printBinaryImpl(Label, Str, Value, false);
279   }
280 
printBinary(StringRef Label,StringRef Str,ArrayRef<char> Value)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 
printBinary(StringRef Label,ArrayRef<uint8_t> Value)287   void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
288     printBinaryImpl(Label, StringRef(), Value, false);
289   }
290 
printBinary(StringRef Label,ArrayRef<char> Value)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 
printBinary(StringRef Label,StringRef Value)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 
printBinaryBlock(StringRef Label,ArrayRef<uint8_t> Value,uint32_t StartOffset)303   void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value,
304                         uint32_t StartOffset) {
305     printBinaryImpl(Label, StringRef(), Value, true, StartOffset);
306   }
307 
printBinaryBlock(StringRef Label,ArrayRef<uint8_t> Value)308   void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
309     printBinaryImpl(Label, StringRef(), Value, true);
310   }
311 
printBinaryBlock(StringRef Label,StringRef Value)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 
printObject(StringRef Label,const T & Value)318   template <typename T> void printObject(StringRef Label, const T &Value) {
319     startLine() << Label << ": " << Value << "\n";
320   }
321 
startLine()322   raw_ostream &startLine() {
323     printIndent();
324     return OS;
325   }
326 
getOStream()327   raw_ostream &getOStream() { return OS; }
328 
329 private:
printVersionInternal(T Value)330   template <typename T> void printVersionInternal(T Value) {
331     getOStream() << Value;
332   }
333 
334   template <typename S, typename T, typename... TArgs>
printVersionInternal(S Value,T Value2,TArgs...Args)335   void printVersionInternal(S Value, T Value2, TArgs... Args) {
336     getOStream() << Value << ".";
337     printVersionInternal(Value2, Args...);
338   }
339 
340   template <typename T>
flagName(const EnumEntry<T> & lhs,const EnumEntry<T> & rhs)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 {
DelimitedScopeDelimitedScope362   explicit DelimitedScope(ScopedPrinter &W) : W(W) {
363     W.startLine() << Open << '\n';
364     W.indent();
365   }
366 
DelimitedScopeDelimitedScope367   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 
~DelimitedScopeDelimitedScope375   ~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