1353358Sdim//===-- ScopedPrinter.h ----------------------------------------*- C++ -*--===// 2303231Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6303231Sdim// 7303231Sdim//===----------------------------------------------------------------------===// 8303231Sdim 9303231Sdim#ifndef LLVM_SUPPORT_SCOPEDPRINTER_H 10303231Sdim#define LLVM_SUPPORT_SCOPEDPRINTER_H 11303231Sdim 12303231Sdim#include "llvm/ADT/APSInt.h" 13303231Sdim#include "llvm/ADT/ArrayRef.h" 14303231Sdim#include "llvm/ADT/SmallVector.h" 15303231Sdim#include "llvm/ADT/StringRef.h" 16303231Sdim#include "llvm/Support/DataTypes.h" 17303231Sdim#include "llvm/Support/Endian.h" 18303231Sdim#include "llvm/Support/raw_ostream.h" 19303231Sdim#include <algorithm> 20303231Sdim 21303231Sdimnamespace llvm { 22303231Sdim 23303231Sdimtemplate <typename T> struct EnumEntry { 24303231Sdim StringRef Name; 25303231Sdim // While Name suffices in most of the cases, in certain cases 26303231Sdim // GNU style and LLVM style of ELFDumper do not 27303231Sdim // display same string for same enum. The AltName if initialized appropriately 28303231Sdim // will hold the string that GNU style emits. 29303231Sdim // Example: 30303231Sdim // "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to 31303231Sdim // "Advanced Micro Devices X86-64" on GNU style 32303231Sdim StringRef AltName; 33303231Sdim T Value; 34303231Sdim EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {} 35303231Sdim EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {} 36303231Sdim}; 37303231Sdim 38303231Sdimstruct HexNumber { 39303231Sdim // To avoid sign-extension we have to explicitly cast to the appropriate 40303231Sdim // unsigned type. The overloads are here so that every type that is implicitly 41303231Sdim // convertible to an integer (including enums and endian helpers) can be used 42303231Sdim // without requiring type traits or call-site changes. 43303231Sdim HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {} 44303231Sdim HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {} 45303231Sdim HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {} 46303231Sdim HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {} 47303231Sdim HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {} 48303231Sdim HexNumber(signed long long Value) 49303231Sdim : Value(static_cast<unsigned long long>(Value)) {} 50303231Sdim HexNumber(unsigned char Value) : Value(Value) {} 51303231Sdim HexNumber(unsigned short Value) : Value(Value) {} 52303231Sdim HexNumber(unsigned int Value) : Value(Value) {} 53303231Sdim HexNumber(unsigned long Value) : Value(Value) {} 54303231Sdim HexNumber(unsigned long long Value) : Value(Value) {} 55303231Sdim uint64_t Value; 56303231Sdim}; 57303231Sdim 58303231Sdimraw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value); 59303231Sdimconst std::string to_hexString(uint64_t Value, bool UpperCase = true); 60303231Sdim 61303231Sdimtemplate <class T> const std::string to_string(const T &Value) { 62303231Sdim std::string number; 63303231Sdim llvm::raw_string_ostream stream(number); 64303231Sdim stream << Value; 65303231Sdim return stream.str(); 66303231Sdim} 67303231Sdim 68303231Sdimclass ScopedPrinter { 69303231Sdimpublic: 70303231Sdim ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {} 71303231Sdim 72303231Sdim void flush() { OS.flush(); } 73303231Sdim 74303231Sdim void indent(int Levels = 1) { IndentLevel += Levels; } 75303231Sdim 76303231Sdim void unindent(int Levels = 1) { 77303231Sdim IndentLevel = std::max(0, IndentLevel - Levels); 78303231Sdim } 79303231Sdim 80303231Sdim void resetIndent() { IndentLevel = 0; } 81303231Sdim 82341825Sdim int getIndentLevel() { return IndentLevel; } 83341825Sdim 84303231Sdim void setPrefix(StringRef P) { Prefix = P; } 85303231Sdim 86303231Sdim void printIndent() { 87303231Sdim OS << Prefix; 88303231Sdim for (int i = 0; i < IndentLevel; ++i) 89303231Sdim OS << " "; 90303231Sdim } 91303231Sdim 92303231Sdim template <typename T> HexNumber hex(T Value) { return HexNumber(Value); } 93303231Sdim 94303231Sdim template <typename T, typename TEnum> 95303231Sdim void printEnum(StringRef Label, T Value, 96303231Sdim ArrayRef<EnumEntry<TEnum>> EnumValues) { 97303231Sdim StringRef Name; 98303231Sdim bool Found = false; 99303231Sdim for (const auto &EnumItem : EnumValues) { 100303231Sdim if (EnumItem.Value == Value) { 101303231Sdim Name = EnumItem.Name; 102303231Sdim Found = true; 103303231Sdim break; 104303231Sdim } 105303231Sdim } 106303231Sdim 107303231Sdim if (Found) { 108303231Sdim startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n"; 109303231Sdim } else { 110303231Sdim startLine() << Label << ": " << hex(Value) << "\n"; 111303231Sdim } 112303231Sdim } 113303231Sdim 114303231Sdim template <typename T, typename TFlag> 115303231Sdim void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags, 116303231Sdim TFlag EnumMask1 = {}, TFlag EnumMask2 = {}, 117303231Sdim TFlag EnumMask3 = {}) { 118303231Sdim typedef EnumEntry<TFlag> FlagEntry; 119303231Sdim typedef SmallVector<FlagEntry, 10> FlagVector; 120303231Sdim FlagVector SetFlags; 121303231Sdim 122303231Sdim for (const auto &Flag : Flags) { 123303231Sdim if (Flag.Value == 0) 124303231Sdim continue; 125303231Sdim 126303231Sdim TFlag EnumMask{}; 127303231Sdim if (Flag.Value & EnumMask1) 128303231Sdim EnumMask = EnumMask1; 129303231Sdim else if (Flag.Value & EnumMask2) 130303231Sdim EnumMask = EnumMask2; 131303231Sdim else if (Flag.Value & EnumMask3) 132303231Sdim EnumMask = EnumMask3; 133303231Sdim bool IsEnum = (Flag.Value & EnumMask) != 0; 134303231Sdim if ((!IsEnum && (Value & Flag.Value) == Flag.Value) || 135303231Sdim (IsEnum && (Value & EnumMask) == Flag.Value)) { 136303231Sdim SetFlags.push_back(Flag); 137303231Sdim } 138303231Sdim } 139303231Sdim 140344779Sdim llvm::sort(SetFlags, &flagName<TFlag>); 141303231Sdim 142303231Sdim startLine() << Label << " [ (" << hex(Value) << ")\n"; 143303231Sdim for (const auto &Flag : SetFlags) { 144303231Sdim startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n"; 145303231Sdim } 146303231Sdim startLine() << "]\n"; 147303231Sdim } 148303231Sdim 149303231Sdim template <typename T> void printFlags(StringRef Label, T Value) { 150303231Sdim startLine() << Label << " [ (" << hex(Value) << ")\n"; 151303231Sdim uint64_t Flag = 1; 152303231Sdim uint64_t Curr = Value; 153303231Sdim while (Curr > 0) { 154303231Sdim if (Curr & 1) 155303231Sdim startLine() << " " << hex(Flag) << "\n"; 156303231Sdim Curr >>= 1; 157303231Sdim Flag <<= 1; 158303231Sdim } 159303231Sdim startLine() << "]\n"; 160303231Sdim } 161303231Sdim 162303231Sdim void printNumber(StringRef Label, uint64_t Value) { 163303231Sdim startLine() << Label << ": " << Value << "\n"; 164303231Sdim } 165303231Sdim 166303231Sdim void printNumber(StringRef Label, uint32_t Value) { 167303231Sdim startLine() << Label << ": " << Value << "\n"; 168303231Sdim } 169303231Sdim 170303231Sdim void printNumber(StringRef Label, uint16_t Value) { 171303231Sdim startLine() << Label << ": " << Value << "\n"; 172303231Sdim } 173303231Sdim 174303231Sdim void printNumber(StringRef Label, uint8_t Value) { 175303231Sdim startLine() << Label << ": " << unsigned(Value) << "\n"; 176303231Sdim } 177303231Sdim 178303231Sdim void printNumber(StringRef Label, int64_t Value) { 179303231Sdim startLine() << Label << ": " << Value << "\n"; 180303231Sdim } 181303231Sdim 182303231Sdim void printNumber(StringRef Label, int32_t Value) { 183303231Sdim startLine() << Label << ": " << Value << "\n"; 184303231Sdim } 185303231Sdim 186303231Sdim void printNumber(StringRef Label, int16_t Value) { 187303231Sdim startLine() << Label << ": " << Value << "\n"; 188303231Sdim } 189303231Sdim 190303231Sdim void printNumber(StringRef Label, int8_t Value) { 191303231Sdim startLine() << Label << ": " << int(Value) << "\n"; 192303231Sdim } 193303231Sdim 194303231Sdim void printNumber(StringRef Label, const APSInt &Value) { 195303231Sdim startLine() << Label << ": " << Value << "\n"; 196303231Sdim } 197303231Sdim 198303231Sdim void printBoolean(StringRef Label, bool Value) { 199303231Sdim startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; 200303231Sdim } 201303231Sdim 202303231Sdim template <typename... T> void printVersion(StringRef Label, T... Version) { 203303231Sdim startLine() << Label << ": "; 204303231Sdim printVersionInternal(Version...); 205303231Sdim getOStream() << "\n"; 206303231Sdim } 207303231Sdim 208303231Sdim template <typename T> void printList(StringRef Label, const T &List) { 209303231Sdim startLine() << Label << ": ["; 210303231Sdim bool Comma = false; 211303231Sdim for (const auto &Item : List) { 212303231Sdim if (Comma) 213303231Sdim OS << ", "; 214303231Sdim OS << Item; 215303231Sdim Comma = true; 216303231Sdim } 217303231Sdim OS << "]\n"; 218303231Sdim } 219303231Sdim 220303231Sdim template <typename T, typename U> 221303231Sdim void printList(StringRef Label, const T &List, const U &Printer) { 222303231Sdim startLine() << Label << ": ["; 223303231Sdim bool Comma = false; 224303231Sdim for (const auto &Item : List) { 225303231Sdim if (Comma) 226303231Sdim OS << ", "; 227303231Sdim Printer(OS, Item); 228303231Sdim Comma = true; 229303231Sdim } 230303231Sdim OS << "]\n"; 231303231Sdim } 232303231Sdim 233303231Sdim template <typename T> void printHexList(StringRef Label, const T &List) { 234303231Sdim startLine() << Label << ": ["; 235303231Sdim bool Comma = false; 236303231Sdim for (const auto &Item : List) { 237303231Sdim if (Comma) 238303231Sdim OS << ", "; 239303231Sdim OS << hex(Item); 240303231Sdim Comma = true; 241303231Sdim } 242303231Sdim OS << "]\n"; 243303231Sdim } 244303231Sdim 245303231Sdim template <typename T> void printHex(StringRef Label, T Value) { 246303231Sdim startLine() << Label << ": " << hex(Value) << "\n"; 247303231Sdim } 248303231Sdim 249303231Sdim template <typename T> void printHex(StringRef Label, StringRef Str, T Value) { 250303231Sdim startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n"; 251303231Sdim } 252303231Sdim 253303231Sdim template <typename T> 254303231Sdim void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) { 255303231Sdim startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n'; 256303231Sdim } 257303231Sdim 258303231Sdim void printString(StringRef Value) { startLine() << Value << "\n"; } 259303231Sdim 260303231Sdim void printString(StringRef Label, StringRef Value) { 261303231Sdim startLine() << Label << ": " << Value << "\n"; 262303231Sdim } 263303231Sdim 264303231Sdim void printString(StringRef Label, const std::string &Value) { 265341825Sdim printString(Label, StringRef(Value)); 266303231Sdim } 267303231Sdim 268341825Sdim void printString(StringRef Label, const char* Value) { 269341825Sdim printString(Label, StringRef(Value)); 270341825Sdim } 271341825Sdim 272303231Sdim template <typename T> 273303231Sdim void printNumber(StringRef Label, StringRef Str, T Value) { 274303231Sdim startLine() << Label << ": " << Str << " (" << Value << ")\n"; 275303231Sdim } 276303231Sdim 277303231Sdim void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) { 278303231Sdim printBinaryImpl(Label, Str, Value, false); 279303231Sdim } 280303231Sdim 281303231Sdim void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) { 282303231Sdim auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), 283303231Sdim Value.size()); 284303231Sdim printBinaryImpl(Label, Str, V, false); 285303231Sdim } 286303231Sdim 287303231Sdim void printBinary(StringRef Label, ArrayRef<uint8_t> Value) { 288303231Sdim printBinaryImpl(Label, StringRef(), Value, false); 289303231Sdim } 290303231Sdim 291303231Sdim void printBinary(StringRef Label, ArrayRef<char> Value) { 292303231Sdim auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), 293303231Sdim Value.size()); 294303231Sdim printBinaryImpl(Label, StringRef(), V, false); 295303231Sdim } 296303231Sdim 297303231Sdim void printBinary(StringRef Label, StringRef Value) { 298303231Sdim auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), 299303231Sdim Value.size()); 300303231Sdim printBinaryImpl(Label, StringRef(), V, false); 301303231Sdim } 302303231Sdim 303321369Sdim void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value, 304321369Sdim uint32_t StartOffset) { 305321369Sdim printBinaryImpl(Label, StringRef(), Value, true, StartOffset); 306321369Sdim } 307321369Sdim 308303231Sdim void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) { 309303231Sdim printBinaryImpl(Label, StringRef(), Value, true); 310303231Sdim } 311303231Sdim 312303231Sdim void printBinaryBlock(StringRef Label, StringRef Value) { 313303231Sdim auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), 314303231Sdim Value.size()); 315303231Sdim printBinaryImpl(Label, StringRef(), V, true); 316303231Sdim } 317303231Sdim 318303231Sdim template <typename T> void printObject(StringRef Label, const T &Value) { 319303231Sdim startLine() << Label << ": " << Value << "\n"; 320303231Sdim } 321303231Sdim 322303231Sdim raw_ostream &startLine() { 323303231Sdim printIndent(); 324303231Sdim return OS; 325303231Sdim } 326303231Sdim 327303231Sdim raw_ostream &getOStream() { return OS; } 328303231Sdim 329303231Sdimprivate: 330303231Sdim template <typename T> void printVersionInternal(T Value) { 331303231Sdim getOStream() << Value; 332303231Sdim } 333303231Sdim 334303231Sdim template <typename S, typename T, typename... TArgs> 335303231Sdim void printVersionInternal(S Value, T Value2, TArgs... Args) { 336303231Sdim getOStream() << Value << "."; 337303231Sdim printVersionInternal(Value2, Args...); 338303231Sdim } 339303231Sdim 340303231Sdim template <typename T> 341303231Sdim static bool flagName(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) { 342303231Sdim return lhs.Name < rhs.Name; 343303231Sdim } 344303231Sdim 345303231Sdim void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value, 346321369Sdim bool Block, uint32_t StartOffset = 0); 347303231Sdim 348303231Sdim raw_ostream &OS; 349303231Sdim int IndentLevel; 350303231Sdim StringRef Prefix; 351303231Sdim}; 352303231Sdim 353303231Sdimtemplate <> 354303231Sdiminline void 355303231SdimScopedPrinter::printHex<support::ulittle16_t>(StringRef Label, 356303231Sdim support::ulittle16_t Value) { 357303231Sdim startLine() << Label << ": " << hex(Value) << "\n"; 358303231Sdim} 359303231Sdim 360303231Sdimtemplate<char Open, char Close> 361303231Sdimstruct DelimitedScope { 362303231Sdim explicit DelimitedScope(ScopedPrinter &W) : W(W) { 363303231Sdim W.startLine() << Open << '\n'; 364303231Sdim W.indent(); 365303231Sdim } 366303231Sdim 367303231Sdim DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) { 368303231Sdim W.startLine() << N; 369303231Sdim if (!N.empty()) 370303231Sdim W.getOStream() << ' '; 371303231Sdim W.getOStream() << Open << '\n'; 372303231Sdim W.indent(); 373303231Sdim } 374303231Sdim 375303231Sdim ~DelimitedScope() { 376303231Sdim W.unindent(); 377303231Sdim W.startLine() << Close << '\n'; 378303231Sdim } 379303231Sdim 380303231Sdim ScopedPrinter &W; 381303231Sdim}; 382303231Sdim 383303231Sdimusing DictScope = DelimitedScope<'{', '}'>; 384303231Sdimusing ListScope = DelimitedScope<'[', ']'>; 385303231Sdim 386303231Sdim} // namespace llvm 387303231Sdim 388303231Sdim#endif 389