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 constexpr EnumEntry(StringRef N, StringRef A, T V) 36 : Name(N), AltName(A), Value(V) {} 37 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. 45 HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {} 46 HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {} 47 HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {} 48 HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {} 49 HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {} 50 HexNumber(signed long long Value) 51 : Value(static_cast<unsigned long long>(Value)) {} 52 HexNumber(unsigned char Value) : Value(Value) {} 53 HexNumber(unsigned short Value) : Value(Value) {} 54 HexNumber(unsigned int Value) : Value(Value) {} 55 HexNumber(unsigned long Value) : Value(Value) {} 56 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 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: 72 ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {} 73 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 82 void resetIndent() { IndentLevel = 0; } 83 84 int getIndentLevel() { return IndentLevel; } 85 86 void setPrefix(StringRef P) { Prefix = P; } 87 88 void printIndent() { 89 OS << Prefix; 90 for (int i = 0; i < IndentLevel; ++i) 91 OS << " "; 92 } 93 94 template <typename T> HexNumber hex(T Value) { return HexNumber(Value); } 95 96 template <typename T, typename TEnum> 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 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 164 void printNumber(StringRef Label, uint64_t Value) { 165 startLine() << Label << ": " << Value << "\n"; 166 } 167 168 void printNumber(StringRef Label, uint32_t Value) { 169 startLine() << Label << ": " << Value << "\n"; 170 } 171 172 void printNumber(StringRef Label, uint16_t Value) { 173 startLine() << Label << ": " << Value << "\n"; 174 } 175 176 void printNumber(StringRef Label, uint8_t Value) { 177 startLine() << Label << ": " << unsigned(Value) << "\n"; 178 } 179 180 void printNumber(StringRef Label, int64_t Value) { 181 startLine() << Label << ": " << Value << "\n"; 182 } 183 184 void printNumber(StringRef Label, int32_t Value) { 185 startLine() << Label << ": " << Value << "\n"; 186 } 187 188 void printNumber(StringRef Label, int16_t Value) { 189 startLine() << Label << ": " << Value << "\n"; 190 } 191 192 void printNumber(StringRef Label, int8_t Value) { 193 startLine() << Label << ": " << int(Value) << "\n"; 194 } 195 196 void printNumber(StringRef Label, const APSInt &Value) { 197 startLine() << Label << ": " << Value << "\n"; 198 } 199 200 void printBoolean(StringRef Label, bool Value) { 201 startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; 202 } 203 204 template <typename... T> void printVersion(StringRef Label, T... Version) { 205 startLine() << Label << ": "; 206 printVersionInternal(Version...); 207 getOStream() << "\n"; 208 } 209 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> 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 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 237 template <typename T> void printHex(StringRef Label, T Value) { 238 startLine() << Label << ": " << hex(Value) << "\n"; 239 } 240 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> 246 void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) { 247 startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n'; 248 } 249 250 void printString(StringRef Value) { startLine() << Value << "\n"; } 251 252 void printString(StringRef Label, StringRef Value) { 253 startLine() << Label << ": " << Value << "\n"; 254 } 255 256 void printString(StringRef Label, const std::string &Value) { 257 printString(Label, StringRef(Value)); 258 } 259 260 void printString(StringRef Label, const char* Value) { 261 printString(Label, StringRef(Value)); 262 } 263 264 template <typename T> 265 void printNumber(StringRef Label, StringRef Str, T Value) { 266 startLine() << Label << ": " << Str << " (" << Value << ")\n"; 267 } 268 269 void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) { 270 printBinaryImpl(Label, Str, Value, false); 271 } 272 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 279 void printBinary(StringRef Label, ArrayRef<uint8_t> Value) { 280 printBinaryImpl(Label, StringRef(), Value, false); 281 } 282 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 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 295 void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value, 296 uint32_t StartOffset) { 297 printBinaryImpl(Label, StringRef(), Value, true, StartOffset); 298 } 299 300 void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) { 301 printBinaryImpl(Label, StringRef(), Value, true); 302 } 303 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 310 template <typename T> void printObject(StringRef Label, const T &Value) { 311 startLine() << Label << ": " << Value << "\n"; 312 } 313 314 raw_ostream &startLine() { 315 printIndent(); 316 return OS; 317 } 318 319 raw_ostream &getOStream() { return OS; } 320 321 private: 322 template <typename T> void printVersionInternal(T Value) { 323 getOStream() << Value; 324 } 325 326 template <typename S, typename T, typename... TArgs> 327 void printVersionInternal(S Value, T Value2, TArgs... Args) { 328 getOStream() << Value << "."; 329 printVersionInternal(Value2, Args...); 330 } 331 332 template <typename T> 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 { 354 explicit DelimitedScope(ScopedPrinter &W) : W(W) { 355 W.startLine() << Open << '\n'; 356 W.indent(); 357 } 358 359 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 367 ~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