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