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