Index: llvm/include/llvm/Support/ScopedPrinter.h =================================================================== --- llvm/include/llvm/Support/ScopedPrinter.h +++ llvm/include/llvm/Support/ScopedPrinter.h @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" #include @@ -57,6 +58,29 @@ uint64_t Value; }; +struct FlagEntry { + FlagEntry(StringRef Name, char Value) + : Name(Name), Value(static_cast(Value)) {} + FlagEntry(StringRef Name, signed char Value) + : Name(Name), Value(static_cast(Value)) {} + FlagEntry(StringRef Name, signed short Value) + : Name(Name), Value(static_cast(Value)) {} + FlagEntry(StringRef Name, signed int Value) + : Name(Name), Value(static_cast(Value)) {} + FlagEntry(StringRef Name, signed long Value) + : Name(Name), Value(static_cast(Value)) {} + FlagEntry(StringRef Name, signed long long Value) + : Name(Name), Value(static_cast(Value)) {} + FlagEntry(StringRef Name, unsigned char Value) : Name(Name), Value(Value) {} + FlagEntry(StringRef Name, unsigned short Value) : Name(Name), Value(Value) {} + FlagEntry(StringRef Name, unsigned int Value) : Name(Name), Value(Value) {} + FlagEntry(StringRef Name, unsigned long Value) : Name(Name), Value(Value) {} + FlagEntry(StringRef Name, unsigned long long Value) + : Name(Name), Value(Value) {} + StringRef Name; + uint64_t Value; +}; + raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value); std::string to_hexString(uint64_t Value, bool UpperCase = true); @@ -69,7 +93,21 @@ class ScopedPrinter { public: - ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {} + enum ScopedPrinterKind { + Standard, + JSON, + }; + + ScopedPrinter(raw_ostream &OS, ScopedPrinterKind Kind = Standard) + : OS(OS), IndentLevel(0), Kind(Kind) {} + + ScopedPrinterKind getKind() const { return Kind; } + + static bool classof(const ScopedPrinter *SP) { + return SP->getKind() == Standard; + } + + virtual ~ScopedPrinter() {} void flush() { OS.flush(); } @@ -107,9 +145,9 @@ } if (Found) { - startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n"; + printHex(Label, Name, Value); } else { - startLine() << Label << ": " << hex(Value) << "\n"; + printHex(Label, Value); } } @@ -117,9 +155,7 @@ void printFlags(StringRef Label, T Value, ArrayRef> Flags, TFlag EnumMask1 = {}, TFlag EnumMask2 = {}, TFlag EnumMask3 = {}) { - typedef EnumEntry FlagEntry; - typedef SmallVector FlagVector; - FlagVector SetFlags; + SmallVector SetFlags; for (const auto &Flag : Flags) { if (Flag.Value == 0) @@ -135,17 +171,12 @@ bool IsEnum = (Flag.Value & EnumMask) != 0; if ((!IsEnum && (Value & Flag.Value) == Flag.Value) || (IsEnum && (Value & EnumMask) == Flag.Value)) { - SetFlags.push_back(Flag); + SetFlags.emplace_back(Flag.Name, Flag.Value); } } - llvm::sort(SetFlags, &flagName); - - startLine() << Label << " [ (" << hex(Value) << ")\n"; - for (const auto &Flag : SetFlags) { - startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n"; - } - startLine() << "]\n"; + llvm::sort(SetFlags, &flagName); + printFlagsInternal(Label, hex(Value), SetFlags); } template void printFlags(StringRef Label, T Value) { @@ -161,43 +192,43 @@ startLine() << "]\n"; } - void printNumber(StringRef Label, uint64_t Value) { + virtual void printNumber(StringRef Label, uint64_t Value) { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, uint32_t Value) { + virtual void printNumber(StringRef Label, uint32_t Value) { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, uint16_t Value) { + virtual void printNumber(StringRef Label, uint16_t Value) { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, uint8_t Value) { + virtual void printNumber(StringRef Label, uint8_t Value) { startLine() << Label << ": " << unsigned(Value) << "\n"; } - void printNumber(StringRef Label, int64_t Value) { + virtual void printNumber(StringRef Label, int64_t Value) { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, int32_t Value) { + virtual void printNumber(StringRef Label, int32_t Value) { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, int16_t Value) { + virtual void printNumber(StringRef Label, int16_t Value) { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, int8_t Value) { + virtual void printNumber(StringRef Label, int8_t Value) { startLine() << Label << ": " << int(Value) << "\n"; } - void printNumber(StringRef Label, const APSInt &Value) { + virtual void printNumber(StringRef Label, const APSInt &Value) { startLine() << Label << ": " << Value << "\n"; } - void printBoolean(StringRef Label, bool Value) { + virtual void printBoolean(StringRef Label, bool Value) { startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; } @@ -208,11 +239,11 @@ } template void printList(StringRef Label, const T &List) { - startLine() << Label << ": ["; - ListSeparator LS; - for (const auto &Item : List) - OS << LS << Item; - OS << "]\n"; + SmallVector StringList; + for (const auto &Item : List) { + StringList.emplace_back(to_string(Item)); + } + printListInternal(Label, StringList); } template @@ -227,29 +258,29 @@ } template void printHexList(StringRef Label, const T &List) { - startLine() << Label << ": ["; - ListSeparator LS; - for (const auto &Item : List) - OS << LS << hex(Item); - OS << "]\n"; + SmallVector HexList; + for (const auto &Item : List) { + HexList.emplace_back(Item); + } + printHexListInternal(Label, HexList); } template void printHex(StringRef Label, T Value) { - startLine() << Label << ": " << hex(Value) << "\n"; + printHexInternal(Label, hex(Value)); } template void printHex(StringRef Label, StringRef Str, T Value) { - startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n"; + printHexInternal(Label, Str, hex(Value)); } template void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) { - startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n'; + printSymbolOffsetInternal(Label, Symbol, hex(Value)); } - void printString(StringRef Value) { startLine() << Value << "\n"; } + virtual void printString(StringRef Value) { startLine() << Value << "\n"; } - void printString(StringRef Label, StringRef Value) { + virtual void printString(StringRef Label, StringRef Value) { startLine() << Label << ": " << Value << "\n"; } @@ -257,13 +288,13 @@ printString(Label, StringRef(Value)); } - void printString(StringRef Label, const char* Value) { + void printString(StringRef Label, const char *Value) { printString(Label, StringRef(Value)); } template void printNumber(StringRef Label, StringRef Str, T Value) { - startLine() << Label << ": " << Str << " (" << Value << ")\n"; + printNumberInternal(Label, Str, to_string(Value)); } void printBinary(StringRef Label, StringRef Str, ArrayRef Value) { @@ -311,12 +342,48 @@ startLine() << Label << ": " << Value << "\n"; } - raw_ostream &startLine() { + virtual void objectBegin() { + startLine() << "{\n"; + indent(); + } + + virtual void objectBegin(StringRef Label) { + startLine() << Label; + if (!Label.empty()) + OS << ' '; + OS << "{\n"; + indent(); + } + + virtual void objectEnd() { + unindent(); + startLine() << "}\n"; + } + + virtual void arrayBegin() { + startLine() << "[\n"; + indent(); + } + + virtual void arrayBegin(StringRef Label) { + startLine() << Label; + if (!Label.empty()) + OS << ' '; + OS << "[\n"; + indent(); + } + + virtual void arrayEnd() { + unindent(); + startLine() << "]\n"; + } + + virtual raw_ostream &startLine() { printIndent(); return OS; } - raw_ostream &getOStream() { return OS; } + virtual raw_ostream &getOStream() { return OS; } private: template void printVersionInternal(T Value) { @@ -329,17 +396,64 @@ printVersionInternal(Value2, Args...); } - template - static bool flagName(const EnumEntry &lhs, const EnumEntry &rhs) { + static bool flagName(const FlagEntry &lhs, const FlagEntry &rhs) { return lhs.Name < rhs.Name; } - void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef Value, - bool Block, uint32_t StartOffset = 0); + virtual void printBinaryImpl(StringRef Label, StringRef Str, + ArrayRef Value, bool Block, + uint32_t StartOffset = 0); + + virtual void printFlagsInternal(StringRef Label, HexNumber Value, + ArrayRef Flags) { + startLine() << Label << " [ (" << Value << ")\n"; + for (const auto &Flag : Flags) { + startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n"; + } + startLine() << "]\n"; + } + + virtual void printListInternal(StringRef Label, + const ArrayRef List) { + startLine() << Label << ": ["; + ListSeparator LS; + for (const auto &Item : List) + OS << LS << Item; + OS << "]\n"; + } + + virtual void printHexListInternal(StringRef Label, + const ArrayRef List) { + startLine() << Label << ": ["; + ListSeparator LS; + for (const auto &Item : List) + OS << LS << hex(Item); + OS << "]\n"; + } + + virtual void printHexInternal(StringRef Label, HexNumber Value) { + startLine() << Label << ": " << Value << "\n"; + } + + virtual void printHexInternal(StringRef Label, StringRef Str, + HexNumber Value) { + startLine() << Label << ": " << Str << " (" << Value << ")\n"; + } + + virtual void printSymbolOffsetInternal(StringRef Label, StringRef Symbol, + HexNumber Value) { + startLine() << Label << ": " << Symbol << '+' << Value << '\n'; + } + + virtual void printNumberInternal(StringRef Label, StringRef Str, + StringRef Value) { + startLine() << Label << ": " << Str << " (" << Value << ")\n"; + } raw_ostream &OS; int IndentLevel; StringRef Prefix; + ScopedPrinterKind Kind; }; template <> @@ -349,31 +463,230 @@ startLine() << Label << ": " << hex(Value) << "\n"; } -template -struct DelimitedScope { - explicit DelimitedScope(ScopedPrinter &W) : W(W) { - W.startLine() << Open << '\n'; - W.indent(); +class JSONScopedPrinter : public ScopedPrinter { + + enum Scope { + Array, + Object, + }; + enum ScopeKind { + Standard, + Attribute, + NestedAttribute, + }; + struct ScopeContext { + Scope Context; + ScopeKind Kind; + ScopeContext(Scope Context, ScopeKind Kind = ScopeKind::Standard) + : Context(Context), Kind(Kind) {} + }; + SmallVector ScopeHistory; + json::OStream JOS; + +public: + JSONScopedPrinter(llvm::raw_ostream &OS) + : ScopedPrinter(OS, ScopedPrinter::ScopedPrinterKind::JSON), JOS(OS, 2) {} + + static bool classof(const ScopedPrinter *SP) { return SP->getKind() == JSON; } + + void printNumber(StringRef Label, uint64_t Value) override { + JOS.attribute(Label, to_string(Value)); + } + + void printNumber(StringRef Label, uint32_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, uint16_t Value) override { + JOS.attribute(Label, Value); } - DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) { - W.startLine() << N; - if (!N.empty()) - W.getOStream() << ' '; - W.getOStream() << Open << '\n'; - W.indent(); + void printNumber(StringRef Label, uint8_t Value) override { + JOS.attribute(Label, Value); } - ~DelimitedScope() { - W.unindent(); - W.startLine() << Close << '\n'; + void printNumber(StringRef Label, int64_t Value) override { + JOS.attribute(Label, Value); } + void printNumber(StringRef Label, int32_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int16_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int8_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, const APSInt &Value) override { + SmallString<64> StringValue; + Value.toString(StringValue); + JOS.attribute(Label, StringValue); + } + + void printBoolean(StringRef Label, bool Value) override { + JOS.attribute(Label, Value); + } + + void printString(StringRef Value) override { JOS.value(Value); } + + void printString(StringRef Label, StringRef Value) override { + JOS.attribute(Label, Value); + } + + void objectBegin() override { + JOS.objectBegin(); + ScopeHistory.emplace_back(Scope::Object, ScopeKind::Standard); + } + + void objectBegin(StringRef Label) override { + ScopeContext ScopeCtx{Scope::Object, ScopeKind::Attribute}; + if (ScopeHistory.back().Context == Scope::Array) { + JOS.objectBegin(); + ScopeCtx.Kind = ScopeKind::NestedAttribute; + } + JOS.attributeBegin(Label); + JOS.objectBegin(); + ScopeHistory.emplace_back(ScopeCtx); + } + + void objectEnd() override { + ScopeContext ScopeCtx = ScopeHistory.back(); + if (ScopeCtx.Context == Scope::Object) { + JOS.objectEnd(); + if (ScopeCtx.Kind == ScopeKind::Attribute || + ScopeCtx.Kind == ScopeKind::NestedAttribute) + JOS.attributeEnd(); + if (ScopeCtx.Kind == ScopeKind::NestedAttribute) + JOS.objectEnd(); + } + ScopeHistory.pop_back(); + } + + void arrayBegin() override { + JOS.arrayBegin(); + ScopeHistory.emplace_back(Scope::Array, ScopeKind::Standard); + } + + void arrayBegin(StringRef Label) override { + ScopeContext ScopeCtx{Scope::Array, ScopeKind::Attribute}; + if (ScopeHistory.back().Context == Scope::Array) { + JOS.objectBegin(); + ScopeCtx.Kind = ScopeKind::NestedAttribute; + } + JOS.attributeBegin(Label); + JOS.arrayBegin(); + ScopeHistory.emplace_back(ScopeCtx); + } + + void arrayEnd() override { + ScopeContext ScopeCtx = ScopeHistory.back(); + if (ScopeCtx.Context == Scope::Array) { + JOS.arrayEnd(); + if (ScopeCtx.Kind == ScopeKind::Attribute || + ScopeCtx.Kind == ScopeKind::NestedAttribute) + JOS.attributeEnd(); + if (ScopeCtx.Kind == ScopeKind::NestedAttribute) + JOS.objectEnd(); + } + ScopeHistory.pop_back(); + } + + raw_ostream &startLine() override { + raw_ostream &OS = JOS.rawValueBegin(); + JOS.rawValueEnd(); + return OS; + } + + raw_ostream &getOStream() override { + raw_ostream &OS = JOS.rawValueBegin(); + JOS.rawValueEnd(); + return OS; + } + +private: + void printFlagsInternal(StringRef Label, HexNumber Value, + ArrayRef Flags) override { + JOS.attributeArray(Label, [&]() { + for (const auto &Flag : Flags) { + JOS.value(Flag.Name); + } + }); + } + + void printListInternal(StringRef Label, + const ArrayRef List) override { + JOS.attributeArray(Label, [&]() { + for (const auto &Item : List) { + JOS.value(Item); + } + }); + } + + void printHexListInternal(StringRef Label, + const ArrayRef List) override { + JOS.attributeArray(Label, [&]() { + for (const auto &Item : List) { + JOS.value(to_hexString(Item.Value)); + } + }); + } + + void printHexInternal(StringRef Label, HexNumber Value) override { + JOS.attribute(Label, "0x" + to_hexString(Value.Value)); + } + + void printHexInternal(StringRef Label, StringRef Str, + HexNumber Value) override { + JOS.attribute(Label, Str); + JOS.attribute(Label.str() + "_raw", "0x" + to_hexString(Value.Value)); + } + + void printSymbolOffsetInternal(StringRef Label, StringRef Symbol, + HexNumber Value) override { + JOS.attribute(Label, Symbol.str() + "+0x" + to_hexString(Value.Value)); + } + + void printNumberInternal(StringRef Label, StringRef Str, + StringRef Value) override { + JOS.attribute(Label, Str); + JOS.attribute(Label.str() + "_raw", Value); + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef Value, + bool Block, uint32_t StartOffset = 0) override { + // TODO: Implement + } +}; + +struct DelimitedScope { + DelimitedScope(ScopedPrinter &W) : W(W) {} + virtual ~DelimitedScope(){}; ScopedPrinter &W; }; -using DictScope = DelimitedScope<'{', '}'>; -using ListScope = DelimitedScope<'[', ']'>; +struct DictScope : DelimitedScope { + explicit DictScope(ScopedPrinter &W) : DelimitedScope(W) { W.objectBegin(); } + + DictScope(ScopedPrinter &W, StringRef N) : DelimitedScope(W) { + W.objectBegin(N); + } + + ~DictScope() { W.objectEnd(); } +}; + +struct ListScope : DelimitedScope { + explicit ListScope(ScopedPrinter &W) : DelimitedScope(W) { W.arrayBegin(); } + + ListScope(ScopedPrinter &W, StringRef N) : DelimitedScope(W) { + W.arrayBegin(N); + } + + ~ListScope() { W.arrayEnd(); } +}; } // namespace llvm Index: llvm/tools/llvm-readobj/llvm-readobj.h =================================================================== --- llvm/tools/llvm-readobj/llvm-readobj.h +++ llvm/tools/llvm-readobj/llvm-readobj.h @@ -39,7 +39,7 @@ extern bool RawRelr; extern bool CodeViewSubsectionBytes; extern bool Demangle; -enum OutputStyleTy { LLVM, GNU }; +enum OutputStyleTy { LLVM, GNU, JSON }; extern OutputStyleTy Output; } // namespace opts Index: llvm/tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- llvm/tools/llvm-readobj/llvm-readobj.cpp +++ llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -235,6 +235,8 @@ opts::Output = opts::OutputStyleTy::LLVM; else if (V == "GNU") opts::Output = opts::OutputStyleTy::GNU; + else if (V == "JSON") + opts::Output = opts::OutputStyleTy::JSON; else error("--elf-output-style value should be either 'LLVM' or 'GNU'"); } @@ -550,6 +552,13 @@ OwningBinary(std::move(Bin), std::move(Buffer))); } +std::unique_ptr createWriter() { + if (opts::Output == opts::JSON) { + return std::make_unique(fouts()); + } + return std::make_unique(fouts()); +} + int main(int argc, char *argv[]) { InitLLVM X(argc, argv); BumpPtrAllocator A; @@ -610,16 +619,20 @@ opts::SectionHeaders = true; } - ScopedPrinter Writer(fouts()); + std::unique_ptr Writer = createWriter(); + std::unique_ptr D; + if (opts::Output == opts::JSON) + D = std::make_unique(*Writer.get()); + for (const std::string &I : opts::InputFilenames) - dumpInput(I, Writer); + dumpInput(I, *Writer.get()); if (opts::CodeViewMergedTypes) { if (opts::CodeViewEnableGHash) - dumpCodeViewMergedTypes(Writer, CVTypes.GlobalIDTable.records(), + dumpCodeViewMergedTypes(*Writer.get(), CVTypes.GlobalIDTable.records(), CVTypes.GlobalTypeTable.records()); else - dumpCodeViewMergedTypes(Writer, CVTypes.IDTable.records(), + dumpCodeViewMergedTypes(*Writer.get(), CVTypes.IDTable.records(), CVTypes.TypeTable.records()); }