Index: llvm/docs/CommandGuide/llvm-readelf.rst =================================================================== --- llvm/docs/CommandGuide/llvm-readelf.rst +++ llvm/docs/CommandGuide/llvm-readelf.rst @@ -72,9 +72,10 @@ .. option:: --elf-output-style= - Format ELF information in the specified style. Valid options are ``LLVM`` and - ``GNU``. ``LLVM`` output is an expanded and structured format, whilst ``GNU`` - (the default) output mimics the equivalent GNU :program:`readelf` output. + Format ELF information in the specified style. Valid options are ``LLVM``, + ``GNU``, and ``JSON``. ``LLVM`` output is an expanded and structured format. + ``GNU`` (the default) output mimics the equivalent GNU :program:`readelf` output. + ``JSON`` is json formatted output intended for machine consumption. .. option:: --section-groups, -g Index: llvm/docs/CommandGuide/llvm-readobj.rst =================================================================== --- llvm/docs/CommandGuide/llvm-readobj.rst +++ llvm/docs/CommandGuide/llvm-readobj.rst @@ -183,9 +183,10 @@ .. option:: --elf-output-style= - Format ELF information in the specified style. Valid options are ``LLVM`` and - ``GNU``. ``LLVM`` output (the default) is an expanded and structured format, - whilst ``GNU`` output mimics the equivalent GNU :program:`readelf` output. + Format ELF information in the specified style. Valid options are ``LLVM``, + ``GNU``, and ``JSON``. ``LLVM`` output is an expanded and structured format. + ``GNU`` (the default) output mimics the equivalent GNU :program:`readelf` output. + ``JSON`` is json formatted output intended for machine consumption. .. option:: --section-groups, -g Index: llvm/include/llvm/Support/JSONScopedPrinter.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/JSONScopedPrinter.h @@ -0,0 +1,117 @@ +//===-- JSONScopedPrinter.h ------------------------------------*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_JSONSCOPEDPRINTER_H +#define LLVM_SUPPORT_JSONSCOPEDPRINTER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +class JSONScopedPrinter : public ScopedPrinterBase { + json::OStream JOS; +public: + JSONScopedPrinter(llvm::raw_ostream &OS) + : ScopedPrinterBase(ScopedPrinterBase::SPK_JSONScopedPrinter), + JOS(OS, 2) {} + + static bool classof(const ScopedPrinterBase *SPB) { + return SPB->getKind() == SPK_JSONScopedPrinter; + } + + void printNumber(StringRef Label, uint64_t Value) override { + JOS.attribute(Label, std::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); + } + + void printNumber(StringRef Label, uint8_t Value) override { + JOS.attribute(Label, Value); + } + + 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 Label, StringRef Value) override { + JOS.attribute(Label, Value); + } + + void printString(StringRef Label, const std::string &Value) override { + JOS.attribute(Label, Value); + } + + void printString(StringRef Label, const char *Value) override { + JOS.attribute(Label, Value); + } + + template void printList(StringRef Label, const T &List) { + JOS.attributeArray(Label, [&]() { + for (const auto &Item : List) { + JOS.value(Item); + } + }); + } + + void arrayBegin() { + JOS.arrayBegin(); + } + + void arrayEnd() { + JOS.arrayEnd(); + } + + void objectBegin() { + JOS.objectBegin(); + } + + void objectEnd() { + JOS.objectEnd(); + } + + void attributeBegin(StringRef Key) { + JOS.attributeBegin(Key); + } + + void attributeEnd() { + JOS.attributeEnd(); + } +}; +} // namespace llvm + +#endif Index: llvm/include/llvm/Support/ScopedPrinter.h =================================================================== --- llvm/include/llvm/Support/ScopedPrinter.h +++ llvm/include/llvm/Support/ScopedPrinter.h @@ -67,9 +67,45 @@ return stream.str(); } -class ScopedPrinter { +class ScopedPrinterBase { public: - ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {} + enum ScopedPrinterKind { + SPK_ScopedPrinter, + SPK_JSONScopedPrinter, + }; + +private: + ScopedPrinterKind Kind; + +public: + ScopedPrinterBase(ScopedPrinterKind Kind) : Kind(Kind) {} + virtual ~ScopedPrinterBase() {} + ScopedPrinterKind getKind() const { return Kind; } + + virtual void printNumber(StringRef Label, uint64_t Value) = 0; + virtual void printNumber(StringRef Label, uint32_t Value) = 0; + virtual void printNumber(StringRef Label, uint16_t Value) = 0; + virtual void printNumber(StringRef Label, uint8_t Value) = 0; + virtual void printNumber(StringRef Label, int64_t Value) = 0; + virtual void printNumber(StringRef Label, int32_t Value) = 0; + virtual void printNumber(StringRef Label, int16_t Value) = 0; + virtual void printNumber(StringRef Label, int8_t Value) = 0; + virtual void printNumber(StringRef Label, const APSInt &Value) = 0; + virtual void printBoolean(StringRef Label, bool Value) = 0; + + virtual void printString(StringRef Label, StringRef Value) = 0; + virtual void printString(StringRef Label, const std::string &Value) = 0; + virtual void printString(StringRef Label, const char *Value) = 0; +}; + +class ScopedPrinter : public ScopedPrinterBase { +public: + ScopedPrinter(raw_ostream &OS) + : ScopedPrinterBase(SPK_ScopedPrinter), OS(OS), IndentLevel(0) {} + + static bool classof(const ScopedPrinterBase *SPB) { + return SPB->getKind() == SPK_ScopedPrinter; + } void flush() { OS.flush(); } @@ -161,43 +197,43 @@ startLine() << "]\n"; } - void printNumber(StringRef Label, uint64_t Value) { + void printNumber(StringRef Label, uint64_t Value) override { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, uint32_t Value) { + void printNumber(StringRef Label, uint32_t Value) override { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, uint16_t Value) { + void printNumber(StringRef Label, uint16_t Value) override { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, uint8_t Value) { + void printNumber(StringRef Label, uint8_t Value) override { startLine() << Label << ": " << unsigned(Value) << "\n"; } - void printNumber(StringRef Label, int64_t Value) { + void printNumber(StringRef Label, int64_t Value) override { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, int32_t Value) { + void printNumber(StringRef Label, int32_t Value) override { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, int16_t Value) { + void printNumber(StringRef Label, int16_t Value) override { startLine() << Label << ": " << Value << "\n"; } - void printNumber(StringRef Label, int8_t Value) { + void printNumber(StringRef Label, int8_t Value) override { startLine() << Label << ": " << int(Value) << "\n"; } - void printNumber(StringRef Label, const APSInt &Value) { + void printNumber(StringRef Label, const APSInt &Value) override { startLine() << Label << ": " << Value << "\n"; } - void printBoolean(StringRef Label, bool Value) { + void printBoolean(StringRef Label, bool Value) override { startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; } @@ -249,15 +285,15 @@ void printString(StringRef Value) { startLine() << Value << "\n"; } - void printString(StringRef Label, StringRef Value) { + void printString(StringRef Label, StringRef Value) override { startLine() << Label << ": " << Value << "\n"; } - void printString(StringRef Label, const std::string &Value) { + void printString(StringRef Label, const std::string &Value) override { printString(Label, StringRef(Value)); } - void printString(StringRef Label, const char* Value) { + void printString(StringRef Label, const char *Value) override { printString(Label, StringRef(Value)); } Index: llvm/test/tools/llvm-readobj/ELF/output-style.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/output-style.test +++ llvm/test/tools/llvm-readobj/ELF/output-style.test @@ -1,4 +1,4 @@ ## Error for an unknown output style. RUN: not llvm-readobj --elf-output-style=unknown 2>&1 | FileCheck %s -CHECK: error: --elf-output-style value should be either 'LLVM' or 'GNU' +CHECK: error: --elf-output-style value should be either 'LLVM', 'GNU', or 'JSON' Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -79,7 +79,7 @@ public: friend class COFFObjectDumpDelegate; COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer, Obj->getFileName()), Obj(Obj), Writer(Writer), + : ObjDumper(&Writer, Obj->getFileName()), Obj(Obj), W(Writer), Types(100) {} void printFileHeaders() override; @@ -134,7 +134,7 @@ void printFileNameForOffset(StringRef Label, uint32_t FileOffset); void printTypeIndex(StringRef FieldName, TypeIndex TI) { // Forward to CVTypeDumper for simplicity. - codeview::printTypeIndex(Writer, FieldName, TI, Types); + codeview::printTypeIndex(W, FieldName, TI, Types); } void printCodeViewSymbolsSubsection(StringRef Subsection, @@ -191,7 +191,7 @@ /// first, but if we don't see one, just assume an X64 CPU type. It is common. CPUType CompilationCPUType = CPUType::X64; - ScopedPrinter &Writer; + ScopedPrinter &W; BinaryByteStream TypeContents; LazyRandomTypeCollection Types; }; @@ -246,8 +246,9 @@ namespace llvm { std::unique_ptr createCOFFDumper(const object::COFFObjectFile &Obj, - ScopedPrinter &Writer) { - return std::make_unique(&Obj, Writer); + ScopedPrinterBase *WriterBase) { + ScopedPrinter *Writer = cast(WriterBase); + return std::make_unique(&Obj, *Writer); } } // namespace llvm Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -48,6 +48,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/JSONScopedPrinter.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MSP430AttributeParser.h" #include "llvm/Support/MSP430Attributes.h" @@ -207,16 +208,10 @@ LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) public: - ELFDumper(const object::ELFObjectFile &ObjF, ScopedPrinter &Writer); + ELFDumper(const object::ELFObjectFile &ObjF, + ScopedPrinterBase *WriterBase); - void printUnwindInfo() override; - void printNeededLibraries() override; - void printHashTable() override; - void printGnuHashTable() override; - void printLoadName() override; void printVersionInfo() override; - void printArchSpecificInfo() override; - void printStackMap() const override; const object::ELFObjectFile &getElfObject() const { return ObjF; }; @@ -261,6 +256,14 @@ virtual void printVersionDefinitionSection(const Elf_Shdr *Sec) = 0; virtual void printVersionDependencySection(const Elf_Shdr *Sec) = 0; + void printUnwindInfoHelper(ScopedPrinter &W); + void printNeededLibrariesHelper(ScopedPrinter &W); + void printHashTableHelper(ScopedPrinter &W); + void printGnuHashTableHelper(ScopedPrinter &W); + void printLoadNameHelper(ScopedPrinter &W); + void printArchSpecificInfoHelper(ScopedPrinter &W); + void printStackMapHelper(ScopedPrinter &W) const; + void printDependentLibsHelper(function_ref OnSectionStart, function_ref OnLibEntry); @@ -342,9 +345,9 @@ } void printAttributes(unsigned, std::unique_ptr, - support::endianness); - void printMipsReginfo(); - void printMipsOptions(); + support::endianness, ScopedPrinter &W); + void printMipsReginfo(ScopedPrinter &W); + void printMipsOptions(ScopedPrinter &W); std::pair findDynamic(); void loadDynamicTable(); @@ -538,13 +541,15 @@ template class GNUELFDumper : public ELFDumper { formatted_raw_ostream &OS; + ScopedPrinter &W; public: LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) GNUELFDumper(const object::ELFObjectFile &ObjF, ScopedPrinter &Writer) - : ELFDumper(ObjF, Writer), - OS(static_cast(Writer.getOStream())) { + : ELFDumper(ObjF, &Writer), + OS(static_cast(Writer.getOStream())), + W(Writer) { assert(&this->W.getOStream() == &llvm::fouts()); } @@ -573,6 +578,14 @@ void printELFLinkerOptions() override; void printStackSizes() override; + void printUnwindInfo() override; + void printNeededLibraries() override; + void printHashTable() override; + void printGnuHashTable() override; + void printLoadName() override; + void printArchSpecificInfo() override; + void printStackMap() const override; + private: void printHashHistogram(const Elf_Hash &HashTable); void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable); @@ -662,7 +675,7 @@ LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) LLVMELFDumper(const object::ELFObjectFile &ObjF, ScopedPrinter &Writer) - : ELFDumper(ObjF, Writer), W(Writer) {} + : ELFDumper(ObjF, &Writer), W(Writer) {} void printFileHeaders() override; void printGroupSections() override; @@ -685,6 +698,14 @@ void printELFLinkerOptions() override; void printStackSizes() override; + void printUnwindInfo() override; + void printNeededLibraries() override; + void printHashTable() override; + void printGnuHashTable() override; + void printLoadName() override; + void printArchSpecificInfo() override; + void printStackMap() const override; + private: void printRelrReloc(const Elf_Relr &R) override; void printRelRelaReloc(const Relocation &R, @@ -708,34 +729,103 @@ ScopedPrinter &W; }; +template class JSONELFDumper : public ELFDumper { + JSONScopedPrinter &W; + +public: + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + + JSONELFDumper(const object::ELFObjectFile &ObjF, + JSONScopedPrinter &JSONWriter) + : ELFDumper(ObjF, &JSONWriter), W(JSONWriter) {} + + void printFileHeaders() override; + void printGroupSections() override; + void printRelocations() override; + void printSectionHeaders() override; + void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override; + void printHashSymbols() override; + void printSectionDetails() override; + void printDependentLibs() override; + void printDynamicTable() override; + void printDynamicRelocations() override; + void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, + bool NonVisibilityBitsUsed) const override; + void printProgramHeaders(bool PrintProgramHeaders, + cl::boolOrDefault PrintSectionMapping) override; + void printVersionSymbolSection(const Elf_Shdr *Sec) override; + void printVersionDefinitionSection(const Elf_Shdr *Sec) override; + void printVersionDependencySection(const Elf_Shdr *Sec) override; + void printHashHistograms() override; + void printCGProfile() override; + void printBBAddrMaps() override; + void printAddrsig() override; + void printNotes() override; + void printELFLinkerOptions() override; + void printStackSizes() override; + + void printUnwindInfo() override; + void printNeededLibraries() override; + void printHashTable() override; + void printGnuHashTable() override; + void printLoadName() override; + void printArchSpecificInfo() override; + void printStackMap() const override; + +private: + void printRelrReloc(const Elf_Relr &R) override; + void printRelRelaReloc(const Relocation &R, + const RelSymbol &RelSym) override; + void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, + Optional StrTable, bool IsDynamic, + bool NonVisibilityBitsUsed) const override; + void printDynamicRelocHeader(unsigned Type, StringRef Name, + const DynRegionInfo &Reg) override; + + void printProgramHeaders() override; + void printSectionMapping() override; + + void printStackSizeEntry(uint64_t Size, + ArrayRef FuncNames) override; + void printMipsGOT(const MipsGOTParser &Parser) override; + void printMipsPLT(const MipsGOTParser &Parser) override; + void printMipsABIFlags() override; +}; + } // end anonymous namespace namespace llvm { template static std::unique_ptr -createELFDumper(const ELFObjectFile &Obj, ScopedPrinter &Writer) { +createELFDumper(const ELFObjectFile &Obj, ScopedPrinterBase *WriterBase) { + if (opts::Output == opts::JSON) { + JSONScopedPrinter *JSONWriter = cast(WriterBase); + return std::make_unique>(Obj, *JSONWriter); + } + ScopedPrinter *Writer = cast(WriterBase); if (opts::Output == opts::GNU) - return std::make_unique>(Obj, Writer); - return std::make_unique>(Obj, Writer); + return std::make_unique>(Obj, *Writer); + return std::make_unique>(Obj, *Writer); } std::unique_ptr createELFDumper(const object::ELFObjectFileBase &Obj, - ScopedPrinter &Writer) { + ScopedPrinterBase *WriterBase) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast(&Obj)) - return createELFDumper(*ELFObj, Writer); + return createELFDumper(*ELFObj, WriterBase); // Big-endian 32-bit if (const ELF32BEObjectFile *ELFObj = dyn_cast(&Obj)) - return createELFDumper(*ELFObj, Writer); + return createELFDumper(*ELFObj, WriterBase); // Little-endian 64-bit if (const ELF64LEObjectFile *ELFObj = dyn_cast(&Obj)) - return createELFDumper(*ELFObj, Writer); + return createELFDumper(*ELFObj, WriterBase); // Big-endian 64-bit - return createELFDumper(*cast(&Obj), Writer); + return createELFDumper(*cast(&Obj), WriterBase); } } // end namespace llvm @@ -1780,8 +1870,8 @@ template ELFDumper::ELFDumper(const object::ELFObjectFile &O, - ScopedPrinter &Writer) - : ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()), + ScopedPrinterBase *WriterBase) + : ObjDumper(WriterBase, O.getFileName()), ObjF(O), Obj(O.getELFFile()), FileName(O.getFileName()), DynRelRegion(O, *this), DynRelaRegion(O, *this), DynRelrRegion(O, *this), DynPLTRelRegion(O, *this), DynSymTabShndxRegion(O, *this), @@ -2366,14 +2456,15 @@ return DynamicStringTable.data() + Value; } -template void ELFDumper::printUnwindInfo() { +template +void ELFDumper::printUnwindInfoHelper(ScopedPrinter &W) { DwarfCFIEH::PrinterContext Ctx(W, ObjF); Ctx.printUnwindInformation(); } // The namespace is needed to fix the compilation with GCC older than 7.0+. namespace { -template <> void ELFDumper::printUnwindInfo() { +template <> void ELFDumper::printUnwindInfoHelper(ScopedPrinter &W) { if (Obj.getHeader().e_machine == EM_ARM) { ARM::EHABI::PrinterContext Ctx(W, Obj, ObjF.getFileName(), DotSymtabSec); @@ -2384,7 +2475,8 @@ } } // namespace -template void ELFDumper::printNeededLibraries() { +template +void ELFDumper::printNeededLibrariesHelper(ScopedPrinter &W) { ListScope D(W, "NeededLibraries"); std::vector Libs; @@ -2460,7 +2552,8 @@ return Error::success(); } -template void ELFDumper::printHashTable() { +template +void ELFDumper::printHashTableHelper(ScopedPrinter &W) { DictScope D(W, "HashTable"); if (!HashTable) return; @@ -2516,7 +2609,7 @@ } template -void ELFDumper::printGnuHashTable() { +void ELFDumper::printGnuHashTableHelper(ScopedPrinter &W) { DictScope D(W, "GnuHashTable"); if (!GnuHashTable) return; @@ -2553,20 +2646,22 @@ W.printHexList("Values", *Chains); } -template void ELFDumper::printLoadName() { +template +void ELFDumper::printLoadNameHelper(ScopedPrinter &W) { StringRef SOName = ""; if (SONameOffset) SOName = getDynamicString(*SONameOffset); W.printString("LoadName", SOName); } -template void ELFDumper::printArchSpecificInfo() { +template +void ELFDumper::printArchSpecificInfoHelper(ScopedPrinter &W) { switch (Obj.getHeader().e_machine) { case EM_ARM: if (Obj.isLE()) printAttributes(ELF::SHT_ARM_ATTRIBUTES, - std::make_unique(&W), - support::little); + std::make_unique(&W), support::little, + W); else reportUniqueWarning("attribute printing not implemented for big-endian " "ARM objects"); @@ -2575,7 +2670,7 @@ if (Obj.isLE()) printAttributes(ELF::SHT_RISCV_ATTRIBUTES, std::make_unique(&W), - support::little); + support::little, W); else reportUniqueWarning("attribute printing not implemented for big-endian " "RISC-V objects"); @@ -2583,12 +2678,12 @@ case EM_MSP430: printAttributes(ELF::SHT_MSP430_ATTRIBUTES, std::make_unique(&W), - support::little); + support::little, W); break; case EM_MIPS: { printMipsABIFlags(); - printMipsOptions(); - printMipsReginfo(); + printMipsOptions(W); + printMipsReginfo(W); MipsGOTParser Parser(*this); if (Error E = Parser.findGOT(dynamic_table(), dynamic_symbols())) reportUniqueWarning(std::move(E)); @@ -2609,7 +2704,7 @@ template void ELFDumper::printAttributes( unsigned AttrShType, std::unique_ptr AttrParser, - support::endianness Endianness) { + support::endianness Endianness, ScopedPrinter &W) { assert((AttrShType != ELF::SHT_NULL) && AttrParser && "Incomplete ELF attribute implementation"); DictScope BA(W, "BuildAttributes"); @@ -3032,7 +3127,7 @@ W.printHex("Co-Proc Mask3", Reginfo.ri_cprmask[3]); } -template void ELFDumper::printMipsReginfo() { +template void ELFDumper::printMipsReginfo(ScopedPrinter &W) { const Elf_Shdr *RegInfoSec = findSectionByName(".reginfo"); if (!RegInfoSec) { W.startLine() << "There is no .reginfo section in the file.\n"; @@ -3096,7 +3191,7 @@ return O; } -template void ELFDumper::printMipsOptions() { +template void ELFDumper::printMipsOptions(ScopedPrinter &W) { const Elf_Shdr *MipsOpts = findSectionByName(".MIPS.options"); if (!MipsOpts) { W.startLine() << "There is no .MIPS.options section in the file.\n"; @@ -3133,7 +3228,8 @@ } } -template void ELFDumper::printStackMap() const { +template +void ELFDumper::printStackMapHelper(ScopedPrinter &W) const { const Elf_Shdr *StackMapSection = findSectionByName(".llvm_stackmaps"); if (!StackMapSection) return; @@ -6098,6 +6194,34 @@ this->printNonRelocatableStackSizes(PrintHeader); } +template void GNUELFDumper::printUnwindInfo() { + ELFDumper::printUnwindInfoHelper(W); +} + +template void GNUELFDumper::printNeededLibraries() { + ELFDumper::printNeededLibrariesHelper(W); +} + +template void GNUELFDumper::printHashTable() { + ELFDumper::printHashTableHelper(W); +} + +template void GNUELFDumper::printGnuHashTable() { + ELFDumper::printGnuHashTableHelper(W); +} + +template void GNUELFDumper::printLoadName() { + ELFDumper::printLoadNameHelper(W); +} + +template void GNUELFDumper::printArchSpecificInfo() { + ELFDumper::printArchSpecificInfoHelper(W); +} + +template void GNUELFDumper::printStackMap() const { + ELFDumper::printStackMapHelper(W); +} + template void GNUELFDumper::printMipsGOT(const MipsGOTParser &Parser) { size_t Bias = ELFT::Is64Bits ? 8 : 0; @@ -7142,6 +7266,34 @@ [this](StringRef Lib, uint64_t) { W.printString(Lib); }); } +template void LLVMELFDumper::printUnwindInfo() { + ELFDumper::printUnwindInfoHelper(W); +} + +template void LLVMELFDumper::printNeededLibraries() { + ELFDumper::printNeededLibrariesHelper(W); +} + +template void LLVMELFDumper::printHashTable() { + ELFDumper::printHashTableHelper(W); +} + +template void LLVMELFDumper::printGnuHashTable() { + ELFDumper::printGnuHashTableHelper(W); +} + +template void LLVMELFDumper::printLoadName() { + ELFDumper::printLoadNameHelper(W); +} + +template void LLVMELFDumper::printArchSpecificInfo() { + ELFDumper::printArchSpecificInfoHelper(W); +} + +template void LLVMELFDumper::printStackMap() const { + ELFDumper::printStackMapHelper(W); +} + template void LLVMELFDumper::printStackSizes() { ListScope L(W, "StackSizes"); if (this->Obj.getHeader().e_type == ELF::ET_REL) @@ -7299,3 +7451,183 @@ W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1)); W.printHex("Flags 2", Flags->flags2); } + +template void JSONELFDumper::printFileHeaders() { + // TODO: Implement +} + +template void JSONELFDumper::printGroupSections() { + // TODO: Implement +} + +template void JSONELFDumper::printRelocations() { + // TODO: Implement +} + +template void JSONELFDumper::printSectionHeaders() { + // TODO: Implement +} + +template +void JSONELFDumper::printSymbols(bool PrintSymbols, + bool PrintDynamicSymbols) { + // TODO: Implement +} + +template void JSONELFDumper::printHashSymbols() { + // TODO: Implement +} + +template void JSONELFDumper::printSectionDetails() { + // TODO: Implement +} + +template void JSONELFDumper::printDependentLibs() { + // TODO: Implement +} + +template void JSONELFDumper::printDynamicTable() { + // TODO: Implement +} + +template void JSONELFDumper::printDynamicRelocations() { + // TODO: Implement +} + +template +void JSONELFDumper::printSymtabMessage(const Elf_Shdr *Symtab, + size_t Offset, + bool NonVisibilityBitsUsed) const { + // TODO: Implement +} + +template +void JSONELFDumper::printProgramHeaders( + bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) { + // TODO: Implement +} + +template +void JSONELFDumper::printVersionSymbolSection(const Elf_Shdr *Sec) { + // TODO: Implement +} + +template +void JSONELFDumper::printVersionDefinitionSection(const Elf_Shdr *Sec) { + // TODO: Implement +} + +template +void JSONELFDumper::printVersionDependencySection(const Elf_Shdr *Sec) { + // TODO: Implement +} + +template void JSONELFDumper::printHashHistograms() { + // TODO: Implement +} + +template void JSONELFDumper::printCGProfile() { + // TODO: Implement +} + +template void JSONELFDumper::printBBAddrMaps() { + // TODO: Implement +} + +template void JSONELFDumper::printAddrsig() { + // TODO: Implement +} + +template void JSONELFDumper::printNotes() { + // TODO: Implement +} + +template void JSONELFDumper::printELFLinkerOptions() { + // TODO: Implement +} + +template void JSONELFDumper::printStackSizes() { + // TODO: Implement +} + +template void JSONELFDumper::printUnwindInfo() { + // TODO: Implement +} + +template void JSONELFDumper::printNeededLibraries() { + // TODO: Implement +} + +template void JSONELFDumper::printHashTable() { + // TODO: Implement +} + +template void JSONELFDumper::printGnuHashTable() { + // TODO: Implement +} + +template void JSONELFDumper::printLoadName() { + // TODO: Implement +} + +template void JSONELFDumper::printArchSpecificInfo() { + // TODO: Implement +} + +template void JSONELFDumper::printStackMap() const { + // TODO: Implement +} + +template +void JSONELFDumper::printMipsGOT(const MipsGOTParser &Parser) { + // TODO: Implement +} + +template +void JSONELFDumper::printMipsPLT(const MipsGOTParser &Parser) { + // TODO: Implement +} + +template void JSONELFDumper::printMipsABIFlags() { + // TODO: Implement +} + +template +void JSONELFDumper::printRelrReloc(const Elf_Relr &R) { + // TODO: Implement +} + +template +void JSONELFDumper::printRelRelaReloc(const Relocation &R, + const RelSymbol &RelSym) { + // TODO: Implement +} + +template +void JSONELFDumper::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, + Optional StrTable, + bool IsDynamic, + bool NonVisibilityBitsUsed) const { + // TODO: Implement +} + +template +void JSONELFDumper::printDynamicRelocHeader(unsigned Type, StringRef Name, + const DynRegionInfo &Reg) { + // TODO: Implement +} + +template void JSONELFDumper::printProgramHeaders() { + // TODO: Implement +} + +template void JSONELFDumper::printSectionMapping() { + // TODO: Implement +} + +template +void JSONELFDumper::printStackSizeEntry(uint64_t Size, + ArrayRef FuncNames) { + // TODO: Implement +} Index: llvm/tools/llvm-readobj/MachODumper.cpp =================================================================== --- llvm/tools/llvm-readobj/MachODumper.cpp +++ llvm/tools/llvm-readobj/MachODumper.cpp @@ -27,7 +27,7 @@ class MachODumper : public ObjDumper { public: MachODumper(const MachOObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer, Obj->getFileName()), Obj(Obj) {} + : ObjDumper(&Writer, Obj->getFileName()), Obj(Obj), W(Writer) {} void printFileHeaders() override; void printSectionHeaders() override; @@ -60,6 +60,7 @@ void printSectionHeaders(const MachOObjectFile *Obj); const MachOObjectFile *Obj; + ScopedPrinter &W; }; } // namespace @@ -68,8 +69,9 @@ namespace llvm { std::unique_ptr createMachODumper(const object::MachOObjectFile &Obj, - ScopedPrinter &Writer) { - return std::make_unique(&Obj, Writer); + ScopedPrinterBase *WriterBase) { + ScopedPrinter *Writer = cast(WriterBase); + return std::make_unique(&Obj, *Writer); } } // namespace llvm Index: llvm/tools/llvm-readobj/ObjDumper.h =================================================================== --- llvm/tools/llvm-readobj/ObjDumper.h +++ llvm/tools/llvm-readobj/ObjDumper.h @@ -30,11 +30,13 @@ class MergingTypeTableBuilder; } // namespace codeview +class ScopedPrinterBase; class ScopedPrinter; +class JSONScopedPrinter; class ObjDumper { public: - ObjDumper(ScopedPrinter &Writer, StringRef ObjName); + ObjDumper(ScopedPrinterBase *WriterBase, StringRef ObjName); virtual ~ObjDumper(); virtual bool canDumpContent() { return true; } @@ -125,7 +127,7 @@ void reportUniqueWarning(const Twine &Msg) const; protected: - ScopedPrinter &W; + ScopedPrinterBase *WriterBase; private: virtual void printSymbols() {} @@ -133,23 +135,33 @@ virtual void printProgramHeaders() {} virtual void printSectionMapping() {} + void printSectionsAsString(const object::ObjectFile &Obj, + ArrayRef Sections, ScopedPrinter &W); + void printSectionsAsString(const object::ObjectFile &Obj, + ArrayRef Sections, + JSONScopedPrinter &W); + void printSectionsAsHex(const object::ObjectFile &Obj, + ArrayRef Sections, ScopedPrinter &W); + void printSectionsAsHex(const object::ObjectFile &Obj, + ArrayRef Sections, JSONScopedPrinter &W); + std::unordered_set Warnings; }; std::unique_ptr createCOFFDumper(const object::COFFObjectFile &Obj, - ScopedPrinter &Writer); + ScopedPrinterBase *WriterBase); std::unique_ptr createELFDumper(const object::ELFObjectFileBase &Obj, - ScopedPrinter &Writer); + ScopedPrinterBase *WriterBase); std::unique_ptr createMachODumper(const object::MachOObjectFile &Obj, - ScopedPrinter &Writer); + ScopedPrinterBase *WriterBase); std::unique_ptr createWasmDumper(const object::WasmObjectFile &Obj, - ScopedPrinter &Writer); + ScopedPrinterBase *WriterBase); std::unique_ptr createXCOFFDumper(const object::XCOFFObjectFile &Obj, - ScopedPrinter &Writer); + ScopedPrinterBase *WriterBase); void dumpCOFFImportFile(const object::COFFImportFile *File, ScopedPrinter &Writer); Index: llvm/tools/llvm-readobj/ObjDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ObjDumper.cpp +++ llvm/tools/llvm-readobj/ObjDumper.cpp @@ -14,8 +14,10 @@ #include "ObjDumper.h" #include "llvm-readobj.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/JSONScopedPrinter.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include @@ -26,7 +28,8 @@ return createStringError(object::object_error::parse_failed, Msg); } -ObjDumper::ObjDumper(ScopedPrinter &Writer, StringRef ObjName) : W(Writer) { +ObjDumper::ObjDumper(ScopedPrinterBase *WriterBase, StringRef ObjName) + : WriterBase(WriterBase) { // Dumper reports all non-critical errors as warnings. // It does not print the same warning more than once. WarningHandler = [=](const Twine &Msg) { @@ -78,9 +81,13 @@ CurrentWord++; continue; } - W.startLine() << format("[%6tx] ", CurrentWord - StrContent); - printAsPrintable(W.startLine(), CurrentWord, WordSize); - W.startLine() << '\n'; + if (JSONScopedPrinter *W = dyn_cast(WriterBase)) { + // TODO: implement for JSON printer + } else if (ScopedPrinter *W = dyn_cast(WriterBase)) { + W->startLine() << format("[%6tx] ", CurrentWord - StrContent); + printAsPrintable(W->startLine(), CurrentWord, WordSize); + W->startLine() << '\n'; + } CurrentWord += WordSize + 1; } } @@ -130,6 +137,25 @@ void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj, ArrayRef Sections) { + if (ScopedPrinter *W = dyn_cast(WriterBase)) { + printSectionsAsString(Obj, Sections, *W); + } else if (JSONScopedPrinter *W = dyn_cast(WriterBase)) { + printSectionsAsString(Obj, Sections, *W); + } +} + +void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj, + ArrayRef Sections) { + if (ScopedPrinter *W = dyn_cast(WriterBase)) { + printSectionsAsHex(Obj, Sections, *W); + } else if (JSONScopedPrinter *W = dyn_cast(WriterBase)) { + printSectionsAsHex(Obj, Sections, *W); + } +} + +void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj, + ArrayRef Sections, + ScopedPrinter &W) { bool First = true; for (object::SectionRef Section : getSectionRefsByNameOrIndex(Obj, Sections)) { @@ -146,8 +172,15 @@ } } +void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj, + ArrayRef Sections, + JSONScopedPrinter &W) { + // TODO: Implement +} + void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj, - ArrayRef Sections) { + ArrayRef Sections, + ScopedPrinter &W) { bool First = true; for (object::SectionRef Section : getSectionRefsByNameOrIndex(Obj, Sections)) { @@ -200,4 +233,10 @@ } } +void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj, + ArrayRef Sections, + JSONScopedPrinter &W) { + // TODO: Implement +} + } // namespace llvm Index: llvm/tools/llvm-readobj/WasmDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/WasmDumper.cpp +++ llvm/tools/llvm-readobj/WasmDumper.cpp @@ -57,7 +57,7 @@ class WasmDumper : public ObjDumper { public: WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer, Obj->getFileName()), Obj(Obj) {} + : ObjDumper(&Writer, Obj->getFileName()), Obj(Obj), W(Writer) {} void printFileHeaders() override; void printSectionHeaders() override; @@ -74,6 +74,7 @@ void printDynamicSymbols() override { llvm_unreachable("unimplemented"); } const WasmObjectFile *Obj; + ScopedPrinter &W; }; void WasmDumper::printFileHeaders() { @@ -241,8 +242,9 @@ namespace llvm { std::unique_ptr createWasmDumper(const object::WasmObjectFile &Obj, - ScopedPrinter &Writer) { - return std::make_unique(&Obj, Writer); + ScopedPrinterBase *WriterBase) { + ScopedPrinter *Writer = cast(WriterBase); + return std::make_unique(&Obj, *Writer); } } // namespace llvm Index: llvm/tools/llvm-readobj/XCOFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -27,7 +27,7 @@ public: XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) - : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {} + : ObjDumper(&Writer, Obj.getFileName()), Obj(Obj), W(Writer) {} void printFileHeaders() override; void printAuxiliaryHeader() override; @@ -53,6 +53,7 @@ void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader); void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader); const XCOFFObjectFile &Obj; + ScopedPrinter &W; }; } // anonymous namespace @@ -803,7 +804,9 @@ namespace llvm { std::unique_ptr -createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) { - return std::make_unique(XObj, Writer); +createXCOFFDumper(const object::XCOFFObjectFile &XObj, + ScopedPrinterBase *WriterBase) { + ScopedPrinter *Writer = cast(WriterBase); + return std::make_unique(XObj, *Writer); } } // 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 @@ -43,6 +43,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/JSONScopedPrinter.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/WithColor.h" @@ -235,8 +236,11 @@ 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'"); + error( + "--elf-output-style value should be either 'LLVM', 'GNU', or 'JSON'"); } opts::GnuHashTable = Args.hasArg(OPT_gnu_hash_table); opts::HashSymbols = Args.hasArg(OPT_hash_symbols); @@ -295,28 +299,29 @@ /// Creates an format-specific object file dumper. static Expected> -createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) { +createDumper(const ObjectFile &Obj, ScopedPrinterBase *WriterBase) { + if (const COFFObjectFile *COFFObj = dyn_cast(&Obj)) - return createCOFFDumper(*COFFObj, Writer); + return createCOFFDumper(*COFFObj, WriterBase); if (const ELFObjectFileBase *ELFObj = dyn_cast(&Obj)) - return createELFDumper(*ELFObj, Writer); + return createELFDumper(*ELFObj, WriterBase); if (const MachOObjectFile *MachOObj = dyn_cast(&Obj)) - return createMachODumper(*MachOObj, Writer); + return createMachODumper(*MachOObj, WriterBase); if (const WasmObjectFile *WasmObj = dyn_cast(&Obj)) - return createWasmDumper(*WasmObj, Writer); + return createWasmDumper(*WasmObj, WriterBase); if (const XCOFFObjectFile *XObj = dyn_cast(&Obj)) - return createXCOFFDumper(*XObj, Writer); + return createXCOFFDumper(*XObj, WriterBase); return createStringError(errc::invalid_argument, "unsupported object file format"); } /// Dumps the specified object file. -static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, +static void dumpObject(ObjectFile &Obj, ScopedPrinterBase *WriterBase, const Archive *A = nullptr) { std::string FileStr = A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str() @@ -328,19 +333,27 @@ toString(std::move(ContentErr)); ObjDumper *Dumper; - Expected> DumperOrErr = createDumper(Obj, Writer); + Expected> DumperOrErr = + createDumper(Obj, WriterBase); if (!DumperOrErr) reportError(DumperOrErr.takeError(), FileStr); Dumper = (*DumperOrErr).get(); - if (opts::Output == opts::LLVM || opts::InputFilenames.size() > 1 || A) { - Writer.startLine() << "\n"; - Writer.printString("File", FileStr); + if (opts::Output == opts::JSON) { + JSONScopedPrinter *JSONWriter = cast(WriterBase); + JSONWriter->objectBegin(); + JSONWriter->attributeBegin(FileStr); + JSONWriter->objectBegin(); + } else if (opts::Output == opts::LLVM || opts::InputFilenames.size() > 1 || + A) { + ScopedPrinter *Writer = cast(WriterBase); + Writer->startLine() << "\n"; + Writer->printString("File", FileStr); } if (opts::Output == opts::LLVM) { - Writer.printString("Format", Obj.getFileFormatName()); - Writer.printString("Arch", Triple::getArchTypeName(Obj.getArch())); - Writer.printString( + WriterBase->printString("Format", Obj.getFileFormatName()); + WriterBase->printString("Arch", Triple::getArchTypeName(Obj.getArch())); + WriterBase->printString( "AddressSize", std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress()))); Dumper->printLoadName(); @@ -458,10 +471,16 @@ Dumper->printStackMap(); if (opts::PrintStackSizes) Dumper->printStackSizes(); + if (opts::Output == opts::JSON) { + JSONScopedPrinter *JSONWriter = cast(WriterBase); + JSONWriter->objectEnd(); + JSONWriter->attributeEnd(); + JSONWriter->objectEnd(); + } } /// Dumps each object file in \a Arc; -static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) { +static void dumpArchive(const Archive *Arc, ScopedPrinterBase *WriterBase) { Error Err = Error::success(); for (auto &Child : Arc->children(Err)) { Expected> ChildOrErr = Child.getAsBinary(); @@ -473,14 +492,16 @@ Binary *Bin = ChildOrErr->get(); if (ObjectFile *Obj = dyn_cast(Bin)) - dumpObject(*Obj, Writer, Arc); - else if (COFFImportFile *Imp = dyn_cast(Bin)) - dumpCOFFImportFile(Imp, Writer); - else + dumpObject(*Obj, WriterBase, Arc); + else if (COFFImportFile *Imp = dyn_cast(Bin)) { + ScopedPrinter *Writer = cast(WriterBase); + dumpCOFFImportFile(Imp, *Writer); + } else { reportWarning(createStringError(errc::invalid_argument, Bin->getFileName() + " has an unsupported file type"), Arc->getFileName()); + } } if (Err) reportError(std::move(Err), Arc->getFileName()); @@ -488,29 +509,29 @@ /// Dumps each object file in \a MachO Universal Binary; static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary, - ScopedPrinter &Writer) { + ScopedPrinterBase *WriterBase) { for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) { Expected> ObjOrErr = Obj.getAsObjectFile(); if (ObjOrErr) - dumpObject(*ObjOrErr.get(), Writer); + dumpObject(*ObjOrErr.get(), WriterBase); else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) reportError(ObjOrErr.takeError(), UBinary->getFileName()); else if (Expected> AOrErr = Obj.getAsArchive()) - dumpArchive(&*AOrErr.get(), Writer); + dumpArchive(&*AOrErr.get(), WriterBase); } } /// Dumps \a WinRes, Windows Resource (.res) file; static void dumpWindowsResourceFile(WindowsResource *WinRes, - ScopedPrinter &Printer) { - WindowsRes::Dumper Dumper(WinRes, Printer); + ScopedPrinterBase *PrinterBase) { + ScopedPrinter *Printer = cast(PrinterBase); + WindowsRes::Dumper Dumper(WinRes, *Printer); if (auto Err = Dumper.printData()) reportError(std::move(Err), WinRes->getFileName()); } - /// Opens \a File and dumps it. -static void dumpInput(StringRef File, ScopedPrinter &Writer) { +static void dumpInput(StringRef File, ScopedPrinterBase *WriterBase) { ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false, /*RequiresNullTerminator=*/false); @@ -533,16 +554,17 @@ std::unique_ptr Bin = std::move(*BinaryOrErr); if (Archive *Arc = dyn_cast(Bin.get())) - dumpArchive(Arc, Writer); + dumpArchive(Arc, WriterBase); else if (MachOUniversalBinary *UBinary = dyn_cast(Bin.get())) - dumpMachOUniversalBinary(UBinary, Writer); + dumpMachOUniversalBinary(UBinary, WriterBase); else if (ObjectFile *Obj = dyn_cast(Bin.get())) - dumpObject(*Obj, Writer); - else if (COFFImportFile *Import = dyn_cast(Bin.get())) - dumpCOFFImportFile(Import, Writer); - else if (WindowsResource *WinRes = dyn_cast(Bin.get())) - dumpWindowsResourceFile(WinRes, Writer); + dumpObject(*Obj, WriterBase); + else if (COFFImportFile *Import = dyn_cast(Bin.get())) { + ScopedPrinter *Writer = cast(WriterBase); + dumpCOFFImportFile(Import, *Writer); + } else if (WindowsResource *WinRes = dyn_cast(Bin.get())) + dumpWindowsResourceFile(WinRes, WriterBase); else llvm_unreachable("unrecognized file type"); @@ -550,6 +572,13 @@ OwningBinary(std::move(Bin), std::move(Buffer))); } +std::unique_ptr createWriter() { + if (opts::Output == opts::JSON) + return std::make_unique(fouts()); + else + return std::make_unique(fouts()); +} + int main(int argc, char *argv[]) { InitLLVM X(argc, argv); BumpPtrAllocator A; @@ -610,18 +639,29 @@ opts::SectionHeaders = true; } - ScopedPrinter Writer(fouts()); + std::unique_ptr Writer = createWriter(); + + if (opts::Output == opts::JSON) { + JSONScopedPrinter *JSONWriter = cast(Writer.get()); + JSONWriter->arrayBegin(); + } + for (const std::string &I : opts::InputFilenames) - dumpInput(I, Writer); + dumpInput(I, Writer.get()); if (opts::CodeViewMergedTypes) { + ScopedPrinter *W = cast(Writer.get()); if (opts::CodeViewEnableGHash) - dumpCodeViewMergedTypes(Writer, CVTypes.GlobalIDTable.records(), + dumpCodeViewMergedTypes(*W, CVTypes.GlobalIDTable.records(), CVTypes.GlobalTypeTable.records()); else - dumpCodeViewMergedTypes(Writer, CVTypes.IDTable.records(), + dumpCodeViewMergedTypes(*W, CVTypes.IDTable.records(), CVTypes.TypeTable.records()); } + if (opts::Output == opts::JSON) { + JSONScopedPrinter *JSONWriter = cast(Writer.get()); + JSONWriter->arrayEnd(); + } return 0; }