[llvm] [llvm-readobj][COFF] Add JSON Output Style (PR #95074)

Miguel A. Arroyo via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 11 22:28:57 PDT 2024


https://github.com/mayanez updated https://github.com/llvm/llvm-project/pull/95074

>From a147873b2e84d6db85eb33b7d65940f655d12b1f Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 20:17:37 -0700
Subject: [PATCH 01/12] [Support] Remove ScopedPrinter printHex specialization

* Unnecessary specialization as printHexImpl() properly handles it.
---
 llvm/include/llvm/Support/ScopedPrinter.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/llvm/include/llvm/Support/ScopedPrinter.h b/llvm/include/llvm/Support/ScopedPrinter.h
index 596b73bd27e49..ee635fbd5153d 100644
--- a/llvm/include/llvm/Support/ScopedPrinter.h
+++ b/llvm/include/llvm/Support/ScopedPrinter.h
@@ -532,13 +532,6 @@ class ScopedPrinter {
   ScopedPrinterKind Kind;
 };
 
-template <>
-inline void
-ScopedPrinter::printHex<support::ulittle16_t>(StringRef Label,
-                                              support::ulittle16_t Value) {
-  startLine() << Label << ": " << hex(Value) << "\n";
-}
-
 struct DelimitedScope;
 
 class JSONScopedPrinter : public ScopedPrinter {

>From d3ce225bbf5cb9e91b77ba30d8d6c65deb7916ae Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 20:22:52 -0700
Subject: [PATCH 02/12] [llvm-readobj][COFF] Add --coff-output-style flag

---
 llvm/docs/CommandGuide/llvm-readobj.rst             | 11 +++++++++++
 llvm/docs/ReleaseNotes.rst                          |  3 +++
 llvm/test/tools/llvm-readobj/COFF/output-style.test |  4 ++++
 llvm/tools/llvm-readobj/Opts.td                     |  1 +
 llvm/tools/llvm-readobj/llvm-readobj.cpp            | 12 ++++++++++++
 5 files changed, 31 insertions(+)
 create mode 100644 llvm/test/tools/llvm-readobj/COFF/output-style.test

diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst
index 8bd29eafbbfcf..024cfcca50489 100644
--- a/llvm/docs/CommandGuide/llvm-readobj.rst
+++ b/llvm/docs/CommandGuide/llvm-readobj.rst
@@ -347,10 +347,21 @@ The following options are implemented only for the PE/COFF file format.
 
  Display the load config.
 
+.. option:: --coff-output-style=<value>
+
+ Format COFF information in the specified style. Valid options are ``LLVM``,
+ and ``JSON``. ``LLVM`` output (the default) is an expanded and
+ structured format. ``JSON`` is JSON formatted output intended for machine consumption.
+
 .. option:: --coff-resources
 
  Display the .rsrc section.
 
+.. option:: --pretty-print
+
+ When used with :option:`--coff-output-style`, JSON output will be formatted in
+ a more readable format.
+
 XCOFF SPECIFIC OPTIONS
 ----------------------
 
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 8cdb9db087c77..1ef2961aa252b 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -286,6 +286,9 @@ Changes to the LLVM tools
   now has a map for the mapped files. (`#92835
   <https://github.com/llvm/llvm-project/pull/92835>`).
 
+* llvm-readobj now supports ``--coff-output-style=<value>``. Valid options are ``LLVM``,
+  and ``JSON``. (`#95074 <https://github.com/llvm/llvm-project/pull/95074>`)
+
 Changes to LLDB
 ---------------------------------
 
diff --git a/llvm/test/tools/llvm-readobj/COFF/output-style.test b/llvm/test/tools/llvm-readobj/COFF/output-style.test
new file mode 100644
index 0000000000000..70a1d5112b05d
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/output-style.test
@@ -0,0 +1,4 @@
+## Error for an unknown output style.
+RUN: not llvm-readobj --coff-output-style=unknown 2>&1 | FileCheck %s
+
+CHECK: error: --coff-output-style value should be either 'LLVM' or 'JSON', but was 'unknown'
\ No newline at end of file
diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td
index 7d574d875d22e..2b752b8f64a3c 100644
--- a/llvm/tools/llvm-readobj/Opts.td
+++ b/llvm/tools/llvm-readobj/Opts.td
@@ -87,6 +87,7 @@ def coff_imports : FF<"coff-imports", "Display import table">, Group<grp_coff>;
 def coff_load_config : FF<"coff-load-config", "Display load config">, Group<grp_coff>;
 def coff_resources : FF<"coff-resources", "Display .rsrc section">, Group<grp_coff>;
 def coff_tls_directory : FF<"coff-tls-directory", "Display TLS directory">, Group<grp_coff>;
+defm coff_output_style: Eq<"coff-output-style", "Specify COFF dump style: LLVM, JSON">, Group<grp_coff>;
 
 // XCOFF specific options.
 def grp_xcoff : OptionGroup<"kind">, HelpText<"OPTIONS (XCOFF specific)">;
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 9ac324cc672f0..98f0ff6b107d0 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -309,6 +309,18 @@ static void parseOptions(const opt::InputArgList &Args) {
   opts::COFFLoadConfig = Args.hasArg(OPT_coff_load_config);
   opts::COFFResources = Args.hasArg(OPT_coff_resources);
   opts::COFFTLSDirectory = Args.hasArg(OPT_coff_tls_directory);
+  if (Arg *A = Args.getLastArg(OPT_coff_output_style_EQ)) {
+    std::string OutputStyleChoice = A->getValue();
+    opts::Output = StringSwitch<opts::OutputStyleTy>(OutputStyleChoice)
+                       .Case("LLVM", opts::OutputStyleTy::LLVM)
+                       .Case("JSON", opts::OutputStyleTy::JSON)
+                       .Default(opts::OutputStyleTy::UNKNOWN);
+    if (opts::Output == opts::OutputStyleTy::UNKNOWN) {
+      error("--coff-output-style value should be either 'LLVM' or "
+            "'JSON', but was '" +
+            OutputStyleChoice + "'");
+    }
+  }
 
   // XCOFF specific options.
   opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header);

>From 69f5d58b986871ab632a5d9c5b6c916e2adf43e1 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 20:24:38 -0700
Subject: [PATCH 03/12] [llvm-readobj][COFF] Add empty JSONCOFFDumper Class

---
 llvm/tools/llvm-readobj/COFFDumper.cpp | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index b104774d37a93..3a902ba31de58 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -242,12 +242,22 @@ class COFFObjectDumpDelegate : public SymbolDumpDelegate {
   StringRef SectionContents;
 };
 
+class JSONCOFFDumper : public COFFDumper {
+public:
+  JSONCOFFDumper(const object::COFFObjectFile *ObjF, ScopedPrinter &Writer)
+      : COFFDumper(ObjF, Writer) {}
+};
+
 } // end namespace
 
 namespace llvm {
 
 std::unique_ptr<ObjDumper> createCOFFDumper(const object::COFFObjectFile &Obj,
                                             ScopedPrinter &Writer) {
+  if (opts::Output == opts::JSON) {
+    return std::make_unique<JSONCOFFDumper>(&Obj, Writer);
+  }
+
   return std::make_unique<COFFDumper>(&Obj, Writer);
 }
 

>From c8b5348ad0bf062fa98152d286b3f2c430c2ac8c Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 20:38:14 -0700
Subject: [PATCH 04/12] [llvm-readobj][COFF] JSON Style File Summary

---
 .../tools/llvm-readobj/COFF/file-summary.test | 94 +++++++++++++++++++
 .../tools/llvm-readobj/COFF/pretty-print.test | 43 +++++++++
 llvm/tools/llvm-readobj/COFFDumper.cpp        | 21 +++++
 3 files changed, 158 insertions(+)
 create mode 100644 llvm/test/tools/llvm-readobj/COFF/file-summary.test
 create mode 100644 llvm/test/tools/llvm-readobj/COFF/pretty-print.test

diff --git a/llvm/test/tools/llvm-readobj/COFF/file-summary.test b/llvm/test/tools/llvm-readobj/COFF/file-summary.test
new file mode 100644
index 0000000000000..f5614dc8eb963
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/file-summary.test
@@ -0,0 +1,94 @@
+# RUN: rm -rf %t.dir
+# RUN: mkdir -p %t.dir
+# RUN: yaml2obj %s -o %t.dir/obj
+
+## Test outputting file summary for a single file.
+# RUN: llvm-readobj --coff-output-style=JSON --pretty-print %t.dir/obj | \
+# RUN:   FileCheck %s --check-prefix=SINGLE-JSON \
+# RUN:     --match-full-lines --strict-whitespace  --implicit-check-not={{.}}
+
+#      SINGLE-JSON:[
+# SINGLE-JSON-NEXT:  {
+# SINGLE-JSON-NEXT:    "FileSummary": {
+# SINGLE-JSON-NEXT:      "File": "{{.*}}/obj",
+# SINGLE-JSON-NEXT:      "Format": "COFF-x86-64",
+# SINGLE-JSON-NEXT:      "Arch": "x86_64",
+# SINGLE-JSON-NEXT:      "AddressSize": "64"
+# SINGLE-JSON-NEXT:    }
+# SINGLE-JSON-NEXT:  }
+# SINGLE-JSON-NEXT:]
+
+## Test outputting file summary for multiple files.
+# RUN: llvm-readobj --coff-output-style=JSON --pretty-print %t.dir/obj %t.dir/obj | \
+# RUN:   FileCheck %s --check-prefix=MULTI-JSON \
+# RUN:     --match-full-lines --strict-whitespace --implicit-check-not={{.}}
+
+#      MULTI-JSON:[
+# MULTI-JSON-NEXT:  {
+# MULTI-JSON-NEXT:    "FileSummary": {
+# MULTI-JSON-NEXT:      "File": "{{.*}}/obj",
+# MULTI-JSON-NEXT:      "Format": "COFF-x86-64",
+# MULTI-JSON-NEXT:      "Arch": "x86_64",
+# MULTI-JSON-NEXT:      "AddressSize": "64"
+# MULTI-JSON-NEXT:    }
+# MULTI-JSON-NEXT:  },
+# MULTI-JSON-NEXT:  {
+# MULTI-JSON-NEXT:    "FileSummary": {
+# MULTI-JSON-NEXT:      "File": "{{.*}}/obj",
+# MULTI-JSON-NEXT:      "Format": "COFF-x86-64",
+# MULTI-JSON-NEXT:      "Arch": "x86_64",
+# MULTI-JSON-NEXT:      "AddressSize": "64"
+# MULTI-JSON-NEXT:    }
+# MULTI-JSON-NEXT:  }
+# MULTI-JSON-NEXT:]
+
+## Test outputting file summary for an archive with a single file.
+# RUN: rm -f %t.archive-single
+# RUN: llvm-ar rc %t.archive-single %t.dir/obj
+# RUN: llvm-readobj --coff-output-style=JSON --pretty-print %t.archive-single | \
+# RUN:   FileCheck %s --check-prefix=ARCH-SINGLE-JSON \
+# RUN:     --match-full-lines --strict-whitespace --implicit-check-not={{.}}
+
+#      ARCH-SINGLE-JSON:[
+# ARCH-SINGLE-JSON-NEXT:  {
+# ARCH-SINGLE-JSON-NEXT:    "FileSummary": {
+# ARCH-SINGLE-JSON-NEXT:      "File": "{{.*}}.archive-single(obj)",
+# ARCH-SINGLE-JSON-NEXT:      "Format": "COFF-x86-64",
+# ARCH-SINGLE-JSON-NEXT:      "Arch": "x86_64",
+# ARCH-SINGLE-JSON-NEXT:      "AddressSize": "64"
+# ARCH-SINGLE-JSON-NEXT:    }
+# ARCH-SINGLE-JSON-NEXT:  }
+# ARCH-SINGLE-JSON-NEXT:]
+
+## Test outputting file summary for an archive with multiple files.
+# RUN: rm -f %t.archive-multiple
+# RUN: llvm-ar rc %t.archive-multiple %t.dir/obj %t.dir/obj
+# RUN: llvm-readobj --coff-output-style=JSON --pretty-print %t.archive-multiple | \
+# RUN:   FileCheck %s --check-prefix=ARCH-MULTI-JSON \
+# RUN:     --match-full-lines --strict-whitespace --implicit-check-not={{.}}
+
+#      ARCH-MULTI-JSON:[
+# ARCH-MULTI-JSON-NEXT:  {
+# ARCH-MULTI-JSON-NEXT:    "FileSummary": {
+# ARCH-MULTI-JSON-NEXT:      "File": "{{.*}}.archive-multiple(obj)",
+# ARCH-MULTI-JSON-NEXT:      "Format": "COFF-x86-64",
+# ARCH-MULTI-JSON-NEXT:      "Arch": "x86_64",
+# ARCH-MULTI-JSON-NEXT:      "AddressSize": "64"
+# ARCH-MULTI-JSON-NEXT:    }
+# ARCH-MULTI-JSON-NEXT:  },
+# ARCH-MULTI-JSON-NEXT:  {
+# ARCH-MULTI-JSON-NEXT:    "FileSummary": {
+# ARCH-MULTI-JSON-NEXT:      "File": "{{.*}}.archive-multiple(obj)",
+# ARCH-MULTI-JSON-NEXT:      "Format": "COFF-x86-64",
+# ARCH-MULTI-JSON-NEXT:      "Arch": "x86_64",
+# ARCH-MULTI-JSON-NEXT:      "AddressSize": "64"
+# ARCH-MULTI-JSON-NEXT:    }
+# ARCH-MULTI-JSON-NEXT:  }
+# ARCH-MULTI-JSON-NEXT:]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+symbols:
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-readobj/COFF/pretty-print.test b/llvm/test/tools/llvm-readobj/COFF/pretty-print.test
new file mode 100644
index 0000000000000..8fe627bb88e83
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/pretty-print.test
@@ -0,0 +1,43 @@
+## Test the JSON pretty-print flag.
+#
+# RUN: yaml2obj %s -o %t.pretty
+
+## Test JSON with pretty-print off.
+# RUN: llvm-readobj --coff-output-style=JSON %t.pretty | \
+# RUN:   FileCheck %s --check-prefix=NO-PRETTY \
+# RUN:     --strict-whitespace
+
+#      NO-PRETTY:[
+# NO-PRETTY-SAME:{
+# NO-PRETTY-SAME:"FileSummary":{
+# NO-PRETTY-SAME:"File":"{{.*}}.pretty",
+# NO-PRETTY-SAME:"Format":"COFF-x86-64",
+# NO-PRETTY-SAME:"Arch":"x86_64",
+# NO-PRETTY-SAME:"AddressSize":"64"
+# NO-PRETTY-SAME:}
+# NO-PRETTY-SAME:}
+# NO-PRETTY-SAME:]
+
+## Test JSON with pretty-print on.
+# RUN: llvm-readobj --coff-output-style=JSON --pretty-print %t.pretty | \
+# RUN:   FileCheck %s --check-prefix=PRETTY \
+# RUN:     --match-full-lines --strict-whitespace
+
+#      PRETTY:[
+# PRETTY-NEXT:  {
+# PRETTY-NEXT:    "FileSummary": {
+# PRETTY-NEXT:      "File": "{{.*}}.pretty",
+# PRETTY-NEXT:      "Format": "COFF-x86-64",
+# PRETTY-NEXT:      "Arch": "x86_64",
+# PRETTY-NEXT:      "AddressSize": "64"
+# PRETTY-NEXT:    }
+# PRETTY-NEXT:  }
+# PRETTY-NEXT:]
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+symbols:
+
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 3a902ba31de58..b67006cfd7f4b 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -246,6 +246,13 @@ class JSONCOFFDumper : public COFFDumper {
 public:
   JSONCOFFDumper(const object::COFFObjectFile *ObjF, ScopedPrinter &Writer)
       : COFFDumper(ObjF, Writer) {}
+
+  void printFileSummary(StringRef FileStr, ObjectFile &Obj,
+                        ArrayRef<std::string> InputFilenames,
+                        const Archive *A) override;
+
+private:
+  std::unique_ptr<DictScope> FileScope;
 };
 
 } // end namespace
@@ -2244,3 +2251,17 @@ void COFFDumper::printCOFFTLSDirectory(
                ArrayRef(ImageSectionCharacteristics),
                COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK));
 }
+
+void JSONCOFFDumper::printFileSummary(StringRef FileStr, ObjectFile &Obj,
+                                      ArrayRef<std::string> InputFilenames,
+                                      const Archive *A) {
+  FileScope = std::make_unique<DictScope>(this->W);
+  DictScope D(this->W, "FileSummary");
+  this->W.printString("File", FileStr);
+  this->W.printString("Format", Obj.getFileFormatName());
+  this->W.printString("Arch", Triple::getArchTypeName(Obj.getArch()));
+  this->W.printString("AddressSize",
+                      std::string(formatv("{0}", 8 * Obj.getBytesInAddress())));
+  this->printLoadName();
+}
+}
\ No newline at end of file

>From 75cc9ccfe3d7b0d24b3d7001f1ea88d0aa384758 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 20:58:44 -0700
Subject: [PATCH 05/12] [llvm-readobj][COFF] JSON Style --coff-basereloc

---
 .../tools/llvm-readobj/COFF/basereloc.test    | 29 +++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/llvm/test/tools/llvm-readobj/COFF/basereloc.test b/llvm/test/tools/llvm-readobj/COFF/basereloc.test
index 3256a3a4adb8e..d4c7b2ee2fd76 100644
--- a/llvm/test/tools/llvm-readobj/COFF/basereloc.test
+++ b/llvm/test/tools/llvm-readobj/COFF/basereloc.test
@@ -22,3 +22,32 @@ CHECK-NEXT:     Address: 0x1000
 CHECK-NEXT:   }
 CHECK-NEXT: ]
 
+
+RUN: llvm-readobj --coff-basereloc --coff-output-style=JSON --pretty-print %p/Inputs/basereloc.obj.coff-i386 | FileCheck %s --check-prefix JSON
+
+     JSON:    "BaseReloc": [
+JSON-NEXT:      {
+JSON-NEXT:        "Entry": {
+JSON-NEXT:          "Type": "HIGHLOW",
+JSON-NEXT:          "Address": 4100
+JSON-NEXT:        }
+JSON-NEXT:      },
+JSON-NEXT:      {
+JSON-NEXT:        "Entry": {
+JSON-NEXT:          "Type": "HIGHLOW",
+JSON-NEXT:          "Address": 4106
+JSON-NEXT:        }
+JSON-NEXT:      },
+JSON-NEXT:      {
+JSON-NEXT:        "Entry": {
+JSON-NEXT:          "Type": "HIGHLOW",
+JSON-NEXT:          "Address": 4112
+JSON-NEXT:        }
+JSON-NEXT:      },
+JSON-NEXT:      {
+JSON-NEXT:        "Entry": {
+JSON-NEXT:          "Type": "ABSOLUTE",
+JSON-NEXT:          "Address": 4096
+JSON-NEXT:        }
+JSON-NEXT:      }
+JSON-NEXT:    ]

>From a3cebb2facd041dac7ca77afa60a60b2d6d29f65 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 21:01:48 -0700
Subject: [PATCH 06/12] [llvm-readobj][COFF] JSON Style --coff-debug-directory

---
 .../llvm-readobj/COFF/debug-directory.test    | 72 +++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/llvm/test/tools/llvm-readobj/COFF/debug-directory.test b/llvm/test/tools/llvm-readobj/COFF/debug-directory.test
index 88295679a290a..1dd7bf639e9c6 100644
--- a/llvm/test/tools/llvm-readobj/COFF/debug-directory.test
+++ b/llvm/test/tools/llvm-readobj/COFF/debug-directory.test
@@ -32,3 +32,75 @@ CHECK:       0010: C0000000                             |....|
 CHECK:     )
 CHECK:   }
 CHECK: ]
+
+RUN: llvm-readobj --coff-debug-directory --coff-output-style=JSON --pretty-print %p/Inputs/has_pdb.exe | FileCheck %s --check-prefix JSON
+
+     JSON:    "DebugDirectory": [
+JSON-NEXT:      {
+JSON-NEXT:        "DebugEntry": {
+JSON-NEXT:          "Characteristics": 0,
+JSON-NEXT:          "TimeDateStamp": {
+JSON-NEXT:            "Name": "2016-06-01 22:53:16",
+JSON-NEXT:            "Value": 1464821596
+JSON-NEXT:          },
+JSON-NEXT:          "MajorVersion": 0,
+JSON-NEXT:          "MinorVersion": 0,
+JSON-NEXT:          "Type": {
+JSON-NEXT:            "Name": "CodeView",
+JSON-NEXT:            "Value": 2
+JSON-NEXT:          },
+JSON-NEXT:          "SizeOfData": 54,
+JSON-NEXT:          "AddressOfRawData": 372840,
+JSON-NEXT:          "PointerToRawData": 369256,
+JSON-NEXT:          "PDBInfo": {
+JSON-NEXT:            "PDBSignature": 1396986706,
+JSON-NEXT:            "PDBGUID": "{42408396-0781-409D-901B-4A3C0D4F5632}",
+JSON-NEXT:            "PDBAge": 3,
+JSON-NEXT:            "PDBFileName": "D:\\src\\llvm\\build\\has_pdb.pdb"
+JSON-NEXT:          }
+JSON-NEXT:        }
+JSON-NEXT:      },
+JSON-NEXT:      {
+JSON-NEXT:        "DebugEntry": {
+JSON-NEXT:          "Characteristics": 0,
+JSON-NEXT:          "TimeDateStamp": {
+JSON-NEXT:            "Name": "2016-06-01 22:53:16",
+JSON-NEXT:            "Value": 1464821596
+JSON-NEXT:          },
+JSON-NEXT:          "MajorVersion": 0,
+JSON-NEXT:          "MinorVersion": 0,
+JSON-NEXT:          "Type": {
+JSON-NEXT:            "Name": "VCFeature",
+JSON-NEXT:            "Value": 12
+JSON-NEXT:          },
+JSON-NEXT:          "SizeOfData": 20,
+JSON-NEXT:          "AddressOfRawData": 372896,
+JSON-NEXT:          "PointerToRawData": 369312,
+JSON-NEXT:          "RawData": {
+JSON-NEXT:            "Offset": 0,
+JSON-NEXT:            "Bytes": [
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              193,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              193,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              192,
+JSON-NEXT:              0,
+JSON-NEXT:              0,
+JSON-NEXT:              0
+JSON-NEXT:            ]
+JSON-NEXT:          }
+JSON-NEXT:        }
+JSON-NEXT:      }
+JSON-NEXT:    ]
\ No newline at end of file

>From b87a797844140d82cd3e24d2722275efdc05895c Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 21:01:21 -0700
Subject: [PATCH 07/12] [llvm-readobj][COFF] JSON Style --coff-directives

---
 llvm/test/tools/llvm-readobj/COFF/directives.test | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/test/tools/llvm-readobj/COFF/directives.test b/llvm/test/tools/llvm-readobj/COFF/directives.test
index a932583b4e0d9..ae98926f20417 100644
--- a/llvm/test/tools/llvm-readobj/COFF/directives.test
+++ b/llvm/test/tools/llvm-readobj/COFF/directives.test
@@ -1,2 +1,4 @@
 RUN: llvm-readobj --coff-directives %p/Inputs/directives.obj.coff-x86_64 | FileCheck %s
+RUN: llvm-readobj --coff-directives --coff-output-style=JSON --pretty-print %p/Inputs/directives.obj.coff-x86_64 | FileCheck %s --check-prefix JSON
 CHECK: Directive(s): /DEFAULTLIB:"LIBCMT" /DEFAULTLIB:"OLDNAMES" 
+JSON: "Directive(s)": "   /DEFAULTLIB:\"LIBCMT\" /DEFAULTLIB:\"OLDNAMES\" "

>From e7961835a40a70f1825f4983ff07414d6c58643f Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 21:00:14 -0700
Subject: [PATCH 08/12] [llvm-readobj][COFF] JSON Style --coff-exports

---
 llvm/test/tools/llvm-readobj/COFF/exports.test | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/llvm/test/tools/llvm-readobj/COFF/exports.test b/llvm/test/tools/llvm-readobj/COFF/exports.test
index 48ff57289eeab..71c5a8a90cc27 100644
--- a/llvm/test/tools/llvm-readobj/COFF/exports.test
+++ b/llvm/test/tools/llvm-readobj/COFF/exports.test
@@ -2,6 +2,10 @@ RUN: llvm-readobj --coff-exports %p/Inputs/export-x86.dll | FileCheck %s -check-
 RUN: llvm-readobj --coff-exports %p/Inputs/export-x64.dll | FileCheck %s -check-prefixes=CHECK,CHECK-X64
 RUN: llvm-readobj --coff-exports %p/Inputs/export-arm.dll | FileCheck %s -check-prefixes=CHECK,CHECK-ARM
 
+RUN: llvm-readobj --coff-exports --coff-output-style=JSON --pretty-print %p/Inputs/export-x86.dll | FileCheck %s -check-prefixes=JSON,JSON-X86
+RUN: llvm-readobj --coff-exports --coff-output-style=JSON --pretty-print %p/Inputs/export-x64.dll | FileCheck %s -check-prefixes=JSON,JSON-X64
+RUN: llvm-readobj --coff-exports --coff-output-style=JSON --pretty-print %p/Inputs/export-arm.dll | FileCheck %s -check-prefixes=JSON,JSON-ARM
+
 CHECK: Export {
 CHECK:   Ordinal: 1
 CHECK:   Name: function
@@ -9,3 +13,11 @@ CHECK-X86:   RVA: 0x1000
 CHECK-X64:   RVA: 0x1000
 CHECK-ARM:   RVA: 0x1001
 CHECK: }
+
+JSON:    "Export": {
+JSON:      "Ordinal": 1,
+JSON:      "Name": "function",
+JSON-X86:      "RVA": 4096
+JSON-X64:      "RVA": 4096
+JSON-ARM:      "RVA": 4097
+JSON:    }

>From 722d42b6825d745f4c6ba2cbee0f1673b51dc022 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 20:49:30 -0700
Subject: [PATCH 09/12] [llvm-readobj][COFF] JSON Style --coff-imports

---
 .../test/tools/llvm-readobj/COFF/imports.test | 171 ++++++++++++++++++
 llvm/tools/llvm-readobj/COFFDumper.cpp        |  61 ++++++-
 2 files changed, 227 insertions(+), 5 deletions(-)

diff --git a/llvm/test/tools/llvm-readobj/COFF/imports.test b/llvm/test/tools/llvm-readobj/COFF/imports.test
index 58512f42adcdf..2e4c64be14187 100644
--- a/llvm/test/tools/llvm-readobj/COFF/imports.test
+++ b/llvm/test/tools/llvm-readobj/COFF/imports.test
@@ -1,5 +1,7 @@
 RUN: llvm-readobj --coff-imports %p/Inputs/imports.exe.coff-i386 | FileCheck -check-prefix=X86 %s
 RUN: llvm-readobj --coff-imports %p/Inputs/imports.exe.coff-x86-64 | FileCheck -check-prefix=X64  %s
+RUN: llvm-readobj --coff-imports --coff-output-style=JSON --pretty-print %p/Inputs/imports.exe.coff-i386 | FileCheck -check-prefix=X86-JSON %s
+RUN: llvm-readobj --coff-imports --coff-output-style=JSON --pretty-print %p/Inputs/imports.exe.coff-x86-64 --coff-output-style=JSON --pretty-print | FileCheck -check-prefixes=X64-JSON  %s
 
 X86:      Import {
 X86-NEXT:   Name: KERNEL32.dll
@@ -44,6 +46,91 @@ X86-NEXT:     Address: 0x401052
 X86-NEXT:   }
 X86-NEXT: }
 
+     X86-JSON:    "Import": {
+X86-JSON-NEXT:      "Name": "KERNEL32.dll",
+X86-JSON-NEXT:      "ImportLookupTableRVA": 8456,
+X86-JSON-NEXT:      "ImportAddressTableRVA": 8192,
+X86-JSON-NEXT:      "Symbols": [
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "ExitProcess",
+X86-JSON-NEXT:          "Ordinal": 337
+X86-JSON-NEXT:        },
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "GetProcAddress",
+X86-JSON-NEXT:          "Ordinal": 669
+X86-JSON-NEXT:        },
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "FreeLibrary",
+X86-JSON-NEXT:          "Ordinal": 414
+X86-JSON-NEXT:        },
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "GetLastError",
+X86-JSON-NEXT:          "Ordinal": 592
+X86-JSON-NEXT:        },
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "RaiseException",
+X86-JSON-NEXT:          "Ordinal": 1087
+X86-JSON-NEXT:        },
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "LoadLibraryExA",
+X86-JSON-NEXT:          "Ordinal": 934
+X86-JSON-NEXT:        }
+X86-JSON-NEXT:      ]
+X86-JSON-NEXT:    },
+X86-JSON-NEXT:    "Import": {
+X86-JSON-NEXT:      "Name": "USER32.dll",
+X86-JSON-NEXT:      "ImportLookupTableRVA": 8484,
+X86-JSON-NEXT:      "ImportAddressTableRVA": 8220,
+X86-JSON-NEXT:      "Symbols": [
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "MessageBoxA",
+X86-JSON-NEXT:          "Ordinal": 582
+X86-JSON-NEXT:        }
+X86-JSON-NEXT:      ]
+X86-JSON-NEXT:    },
+X86-JSON-NEXT:    "Import": {
+X86-JSON-NEXT:      "Name": "mydll.dll",
+X86-JSON-NEXT:      "ImportLookupTableRVA": 8492,
+X86-JSON-NEXT:      "ImportAddressTableRVA": 8228,
+X86-JSON-NEXT:      "Symbols": [
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "Func1",
+X86-JSON-NEXT:          "Ordinal": 0
+X86-JSON-NEXT:        },
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "Func2",
+X86-JSON-NEXT:          "Ordinal": 1
+X86-JSON-NEXT:        },
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "",
+X86-JSON-NEXT:          "Ordinal": 3
+X86-JSON-NEXT:        }
+X86-JSON-NEXT:      ]
+X86-JSON-NEXT:    },
+X86-JSON-NEXT:    "DelayImport": {
+X86-JSON-NEXT:      "Name": "lazyload.dll",
+X86-JSON-NEXT:      "Attributes": 1,
+X86-JSON-NEXT:      "ModuleHandle": 12316,
+X86-JSON-NEXT:      "ImportAddressTable": 12304,
+X86-JSON-NEXT:      "ImportNameTable": 8336,
+X86-JSON-NEXT:      "BoundDelayImportTable": 8364,
+X86-JSON-NEXT:      "UnloadDelayImportTable": 0,
+X86-JSON-NEXT:      "Symbols": [
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "Func5",
+X86-JSON-NEXT:          "Ordinal": 0,
+X86-JSON-NEXT:          "Address": 4198515
+X86-JSON-NEXT:        },
+X86-JSON-NEXT:        {
+X86-JSON-NEXT:          "Name": "Func4",
+X86-JSON-NEXT:          "Ordinal": 0,
+X86-JSON-NEXT:          "Address": 4198482
+X86-JSON-NEXT:        }
+X86-JSON-NEXT:      ]
+X86-JSON-NEXT:    }
+X86-JSON-NEXT:  }
+
+
 X64:      Import {
 X64-NEXT:   Name: KERNEL32.dll
 X64-NEXT:   ImportLookupTableRVA: 0x2170
@@ -86,3 +173,87 @@ X64-NEXT:     Symbol: Func4 (0)
 X64-NEXT:     Address: 0x140001066
 X64-NEXT:   }
 X64-NEXT: }
+
+     X64-JSON:    "Import": {
+X64-JSON-NEXT:      "Name": "KERNEL32.dll",
+X64-JSON-NEXT:      "ImportLookupTableRVA": 8560,
+X64-JSON-NEXT:      "ImportAddressTableRVA": 8192,
+X64-JSON-NEXT:      "Symbols": [
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "ExitProcess",
+X64-JSON-NEXT:          "Ordinal": 343
+X64-JSON-NEXT:        },
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "GetProcAddress",
+X64-JSON-NEXT:          "Ordinal": 676
+X64-JSON-NEXT:        },
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "FreeLibrary",
+X64-JSON-NEXT:          "Ordinal": 420
+X64-JSON-NEXT:        },
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "GetLastError",
+X64-JSON-NEXT:          "Ordinal": 598
+X64-JSON-NEXT:        },
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "RaiseException",
+X64-JSON-NEXT:          "Ordinal": 1091
+X64-JSON-NEXT:        },
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "LoadLibraryExA",
+X64-JSON-NEXT:          "Ordinal": 937
+X64-JSON-NEXT:        }
+X64-JSON-NEXT:      ]
+X64-JSON-NEXT:    },
+X64-JSON-NEXT:    "Import": {
+X64-JSON-NEXT:      "Name": "USER32.dll",
+X64-JSON-NEXT:      "ImportLookupTableRVA": 8616,
+X64-JSON-NEXT:      "ImportAddressTableRVA": 8248,
+X64-JSON-NEXT:      "Symbols": [
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "MessageBoxA",
+X64-JSON-NEXT:          "Ordinal": 586
+X64-JSON-NEXT:        }
+X64-JSON-NEXT:      ]
+X64-JSON-NEXT:    },
+X64-JSON-NEXT:    "Import": {
+X64-JSON-NEXT:      "Name": "mydll.dll",
+X64-JSON-NEXT:      "ImportLookupTableRVA": 8632,
+X64-JSON-NEXT:      "ImportAddressTableRVA": 8264,
+X64-JSON-NEXT:      "Symbols": [
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "Func1",
+X64-JSON-NEXT:          "Ordinal": 0
+X64-JSON-NEXT:        },
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "Func2",
+X64-JSON-NEXT:          "Ordinal": 1
+X64-JSON-NEXT:        },
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "",
+X64-JSON-NEXT:          "Ordinal": 3
+X64-JSON-NEXT:        }
+X64-JSON-NEXT:      ]
+X64-JSON-NEXT:    },
+X64-JSON-NEXT:    "DelayImport": {
+X64-JSON-NEXT:      "Name": "lazyload.dll",
+X64-JSON-NEXT:      "Attributes": 1,
+X64-JSON-NEXT:      "ModuleHandle": 12328,
+X64-JSON-NEXT:      "ImportAddressTable": 12304,
+X64-JSON-NEXT:      "ImportNameTable": 8416,
+X64-JSON-NEXT:      "BoundDelayImportTable": 8456,
+X64-JSON-NEXT:      "UnloadDelayImportTable": 0,
+X64-JSON-NEXT:      "Symbols": [
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "Func5",
+X64-JSON-NEXT:          "Ordinal": 0,
+X64-JSON-NEXT:          "Address": 5368713457
+X64-JSON-NEXT:        },
+X64-JSON-NEXT:        {
+X64-JSON-NEXT:          "Name": "Func4",
+X64-JSON-NEXT:          "Ordinal": 0,
+X64-JSON-NEXT:          "Address": 5368713318
+X64-JSON-NEXT:        }
+X64-JSON-NEXT:      ]
+X64-JSON-NEXT:    }
+X64-JSON-NEXT:  }
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index b67006cfd7f4b..38f9f4e0cceeb 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -108,8 +108,13 @@ class COFFDumper : public ObjDumper {
   void printStackMap() const override;
   void printAddrsig() override;
   void printCGProfile() override;
+  virtual void
+  printImportedSymbols(iterator_range<imported_symbol_iterator> Range);
+  virtual void
+  printDelayImportedSymbols(const DelayImportDirectoryEntryRef &I,
+                            iterator_range<imported_symbol_iterator> Range);
 
-private:
+protected:
   StringRef getSymbolName(uint32_t Index);
   void printSymbols(bool ExtraSymInfo) override;
   void printDynamicSymbols() override;
@@ -174,10 +179,6 @@ class COFFDumper : public ObjDumper {
   std::error_code resolveSymbolName(const coff_section *Section,
                                     StringRef SectionContents,
                                     const void *RelocPtr, StringRef &Name);
-  void printImportedSymbols(iterator_range<imported_symbol_iterator> Range);
-  void printDelayImportedSymbols(
-      const DelayImportDirectoryEntryRef &I,
-      iterator_range<imported_symbol_iterator> Range);
 
   typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
 
@@ -250,6 +251,11 @@ class JSONCOFFDumper : public COFFDumper {
   void printFileSummary(StringRef FileStr, ObjectFile &Obj,
                         ArrayRef<std::string> InputFilenames,
                         const Archive *A) override;
+  void
+  printImportedSymbols(iterator_range<imported_symbol_iterator> Range) override;
+  void printDelayImportedSymbols(
+      const DelayImportDirectoryEntryRef &I,
+      iterator_range<imported_symbol_iterator> Range) override;
 
 private:
   std::unique_ptr<DictScope> FileScope;
@@ -2264,4 +2270,49 @@ void JSONCOFFDumper::printFileSummary(StringRef FileStr, ObjectFile &Obj,
                       std::string(formatv("{0}", 8 * Obj.getBytesInAddress())));
   this->printLoadName();
 }
+
+void JSONCOFFDumper::printImportedSymbols(
+    iterator_range<imported_symbol_iterator> Range) {
+
+  ListScope SymbolsScope(W, "Symbols");
+  for (const ImportedSymbolRef &I : Range) {
+    DictScope SymbolScope(W);
+    StringRef Sym;
+    if (Error E = I.getSymbolName(Sym))
+      reportError(std::move(E), Obj->getFileName());
+
+    uint16_t Ordinal;
+    if (Error E = I.getOrdinal(Ordinal))
+      reportError(std::move(E), Obj->getFileName());
+
+    W.printString("Name", Sym);
+    W.printNumber("Ordinal", Ordinal);
+  }
+}
+
+void JSONCOFFDumper::printDelayImportedSymbols(
+    const DelayImportDirectoryEntryRef &I,
+    iterator_range<imported_symbol_iterator> Range) {
+  int Index = 0;
+
+  ListScope SymbolsScope(W, "Symbols");
+  for (const ImportedSymbolRef &S : Range) {
+    DictScope SymbolScope(W);
+    StringRef Sym;
+    if (Error E = S.getSymbolName(Sym))
+      reportError(std::move(E), Obj->getFileName());
+
+    uint16_t Ordinal;
+    if (Error E = S.getOrdinal(Ordinal))
+      reportError(std::move(E), Obj->getFileName());
+
+    uint64_t Addr;
+    if (Error E = I.getImportAddress(Index++, Addr))
+      reportError(std::move(E), Obj->getFileName());
+
+    W.printString("Name", Sym);
+    W.printNumber("Ordinal", Ordinal);
+    W.printHex("Address", Addr);
+  }
+}
 }
\ No newline at end of file

>From ccd78e11ca371aaa46c99fd0ecf42bd5d7d35dc3 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 20:50:40 -0700
Subject: [PATCH 10/12] [llvm-readobj][COFF] JSON Style --coff-load-config

---
 .../tools/llvm-readobj/COFF/load-config.test  | 93 ++++++++++++++++++-
 .../test/tools/yaml2obj/COFF/load-config.yaml | 10 +-
 llvm/tools/llvm-readobj/COFFDumper.cpp        | 28 +++++-
 3 files changed, 117 insertions(+), 14 deletions(-)

diff --git a/llvm/test/tools/llvm-readobj/COFF/load-config.test b/llvm/test/tools/llvm-readobj/COFF/load-config.test
index 63ba11a940ad8..6f81c310b92d4 100644
--- a/llvm/test/tools/llvm-readobj/COFF/load-config.test
+++ b/llvm/test/tools/llvm-readobj/COFF/load-config.test
@@ -1,11 +1,12 @@
 RUN: llvm-readobj --coff-load-config %S/Inputs/coff-load-config-x86.dll | FileCheck %s --check-prefix=X86
 RUN: llvm-readobj --coff-load-config %S/Inputs/coff-load-config-x64.dll | FileCheck %s --check-prefix=X64
+RUN: llvm-readobj --coff-load-config --coff-output-style=JSON --pretty-print %S/Inputs/coff-load-config-x64.dll | FileCheck %s --check-prefix=JSON-X64
 
 RUN: llvm-readobj --coff-load-config %S/Inputs/coff-load-config-data-end.exe | FileCheck %s --check-prefix=DATAEND
 
 RUN: llvm-readobj --coff-load-config %S/Inputs/coff-no-load-config.exe | FileCheck %s --check-prefix=NOCONFIG
 
-X86: LoadConfig [
+X86: LoadConfig {
 X86:   Size: 0x5C
 X86:   TimeDateStamp: 1970-01-01 00:00:00 (0x0)
 X86:   MajorVersion: 0x0
@@ -37,7 +38,7 @@ X86:     CF_LONGJUMP_TABLE_PRESENT (0x10000)
 X86:     DELAYLOAD_IAT_IN_ITS_OWN_SECTION (0x2000)
 X86:     PROTECT_DELAYLOAD_IAT (0x1000)
 X86:   ]
-X86: ]
+X86: }
 X86: SEHTable [
 X86:   0x10001BE0
 X86:   0x10001E30
@@ -56,7 +57,7 @@ X86:   0x10001BE0
 X86:   0x10001DC0
 X86: ]
 
-X64: LoadConfig [
+X64: LoadConfig {
 X64:   Size: 0x94
 X64:   TimeDateStamp: 1970-01-01 00:00:00 (0x0)
 X64:   MajorVersion: 0x0
@@ -88,7 +89,7 @@ X64:    CF_LONGJUMP_TABLE_PRESENT (0x10000)
 X64:    DELAYLOAD_IAT_IN_ITS_OWN_SECTION (0x2000)
 X64:    PROTECT_DELAYLOAD_IAT (0x1000)
 X64:  ]
-X64: ]
+X64: }
 X64-NOT: SEHTable
 X64: GuardFidTable [
 X64:   0x180001000
@@ -108,3 +109,87 @@ DATAEND-NEXT: ]
 
 NOCONFIG: Format: COFF-x86-64
 NOCONFIG-NOT: LoadConfig
+
+     JSON-X64:    "LoadConfig": {
+JSON-X64-NEXT:      "Size": 148,
+JSON-X64-NEXT:      "TimeDateStamp": {
+JSON-X64-NEXT:        "Name": "1970-01-01 00:00:00",
+JSON-X64-NEXT:        "Value": 0
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      "MajorVersion": 0,
+JSON-X64-NEXT:      "MinorVersion": 0,
+JSON-X64-NEXT:      "GlobalFlagsClear": 0,
+JSON-X64-NEXT:      "GlobalFlagsSet": 0,
+JSON-X64-NEXT:      "CriticalSectionDefaultTimeout": 0,
+JSON-X64-NEXT:      "DeCommitFreeBlockThreshold": 0,
+JSON-X64-NEXT:      "DeCommitTotalFreeThreshold": 0,
+JSON-X64-NEXT:      "LockPrefixTable": 0,
+JSON-X64-NEXT:      "MaximumAllocationSize": 0,
+JSON-X64-NEXT:      "VirtualMemoryThreshold": 0,
+JSON-X64-NEXT:      "ProcessHeapFlags": 0,
+JSON-X64-NEXT:      "ProcessAffinityMask": 0,
+JSON-X64-NEXT:      "CSDVersion": 0,
+JSON-X64-NEXT:      "DependentLoadFlags": 0,
+JSON-X64-NEXT:      "EditList": 0,
+JSON-X64-NEXT:      "SecurityCookie": 6442463256,
+JSON-X64-NEXT:      "SEHandlerTable": 0,
+JSON-X64-NEXT:      "SEHandlerCount": 0,
+JSON-X64-NEXT:      "GuardCFCheckFunction": 6442459392,
+JSON-X64-NEXT:      "GuardCFCheckDispatch": 6442459400,
+JSON-X64-NEXT:      "GuardCFFunctionTable": 6442459480,
+JSON-X64-NEXT:      "GuardCFFunctionCount": 9,
+JSON-X64-NEXT:      "GuardFlags": {
+JSON-X64-NEXT:        "Value": 79104,
+JSON-X64-NEXT:        "Flags": [
+JSON-X64-NEXT:          {
+JSON-X64-NEXT:            "Name": "CF_FUNCTION_TABLE_PRESENT",
+JSON-X64-NEXT:            "Value": 1024
+JSON-X64-NEXT:          },
+JSON-X64-NEXT:          {
+JSON-X64-NEXT:            "Name": "CF_INSTRUMENTED",
+JSON-X64-NEXT:            "Value": 256
+JSON-X64-NEXT:          },
+JSON-X64-NEXT:          {
+JSON-X64-NEXT:            "Name": "CF_LONGJUMP_TABLE_PRESENT",
+JSON-X64-NEXT:            "Value": 65536
+JSON-X64-NEXT:          },
+JSON-X64-NEXT:          {
+JSON-X64-NEXT:            "Name": "DELAYLOAD_IAT_IN_ITS_OWN_SECTION",
+JSON-X64-NEXT:            "Value": 8192
+JSON-X64-NEXT:          },
+JSON-X64-NEXT:          {
+JSON-X64-NEXT:            "Name": "PROTECT_DELAYLOAD_IAT",
+JSON-X64-NEXT:            "Value": 4096
+JSON-X64-NEXT:          }
+JSON-X64-NEXT:        ]
+JSON-X64-NEXT:      }
+JSON-X64-NEXT:    },
+JSON-X64-NEXT:    "GuardFidTable": [
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442455040
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442455120
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442455152
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442455264
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442455312
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442456160
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442457456
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442457936
+JSON-X64-NEXT:      },
+JSON-X64-NEXT:      {
+JSON-X64-NEXT:        "Address": 6442458512
+JSON-X64-NEXT:      }
+JSON-X64-NEXT:    ]
diff --git a/llvm/test/tools/yaml2obj/COFF/load-config.yaml b/llvm/test/tools/yaml2obj/COFF/load-config.yaml
index 36c66e6d69271..fe5e258a83180 100644
--- a/llvm/test/tools/yaml2obj/COFF/load-config.yaml
+++ b/llvm/test/tools/yaml2obj/COFF/load-config.yaml
@@ -5,7 +5,7 @@
 # ALL:      Format: COFF-x86-64
 # ALL-NEXT: Arch: x86_64
 # ALL-NEXT: AddressSize: 64bit
-# ALL-NEXT: LoadConfig [
+# ALL-NEXT: LoadConfig {
 # ALL-NEXT:   Size: 0x150
 # ALL-NEXT:   TimeDateStamp: 1970-01-01 00:00:01 (0x1)
 # ALL-NEXT:   MajorVersion: 0x2
@@ -48,7 +48,7 @@
 # ALL-NEXT:   VolatileMetadataPointer: 0x2
 # ALL-NEXT:   GuardEHContinuationTable: 0x0
 # ALL-NEXT:   GuardEHContinuationCount: 0
-# ALL-NEXT: ]
+# ALL-NEXT: }
 
 --- !COFF
 OptionalHeader:
@@ -125,7 +125,7 @@ symbols: []
 # RUN: yaml2obj --docnum=2 %s -o %t
 # RUN: llvm-readobj --coff-load-config %t | FileCheck %s --check-prefix=LOADCFG32
 
-# LOADCFG32: LoadConfig [
+# LOADCFG32: LoadConfig {
 # LOADCFG32:   MaximumAllocationSize: 0x100000
 # LOADCFG32:   VirtualMemoryThreshold: 0x2000000
 # LOADCFG32:   CHPEMetadataPointer: 0
@@ -161,12 +161,12 @@ symbols: []
 # DEF: Format: COFF-x86-64
 # DEF: Arch: x86_64
 # DEF: AddressSize: 64bit
-# DEF: LoadConfig [
+# DEF: LoadConfig {
 # DEF:   Size: 0x138
 # DEF:   MajorVersion: 0x0
 # DEF:   MinorVersion: 0x0
 # DEF:   GuardEHContinuationCount: 0
-# DEF: ]
+# DEF: }
 
 --- !COFF
 OptionalHeader:
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 38f9f4e0cceeb..83738a2bd8c4f 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -113,6 +113,10 @@ class COFFDumper : public ObjDumper {
   virtual void
   printDelayImportedSymbols(const DelayImportDirectoryEntryRef &I,
                             iterator_range<imported_symbol_iterator> Range);
+  typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *);
+  virtual void printRVATable(uint64_t TableVA, uint64_t Count,
+                             uint64_t EntrySize,
+                             PrintExtraCB PrintExtra = nullptr);
 
 protected:
   StringRef getSymbolName(uint32_t Index);
@@ -131,10 +135,6 @@ class COFFDumper : public ObjDumper {
   void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables);
   template <typename IntTy>
   void printCOFFTLSDirectory(const coff_tls_directory<IntTy> *TlsTable);
-  typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *);
-  void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
-                     PrintExtraCB PrintExtra = nullptr);
-
   void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section);
   void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section);
   StringRef getFileNameForFileOffset(uint32_t FileOffset);
@@ -256,6 +256,8 @@ class JSONCOFFDumper : public COFFDumper {
   void printDelayImportedSymbols(
       const DelayImportDirectoryEntryRef &I,
       iterator_range<imported_symbol_iterator> Range) override;
+  void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
+                     PrintExtraCB PrintExtra = nullptr) override;
 
 private:
   std::unique_ptr<DictScope> FileScope;
@@ -1002,7 +1004,7 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
   if (!Conf)
     return;
 
-  ListScope LS(W, "LoadConfig");
+  DictScope LS(W, "LoadConfig");
   char FormattedTime[20] = {};
   time_t TDS = Conf->TimeDateStamp;
   strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
@@ -2315,4 +2317,20 @@ void JSONCOFFDumper::printDelayImportedSymbols(
     W.printHex("Address", Addr);
   }
 }
+
+void JSONCOFFDumper::printRVATable(uint64_t TableVA, uint64_t Count,
+                                   uint64_t EntrySize,
+                                   PrintExtraCB PrintExtra) {
+  uintptr_t TableStart, TableEnd;
+  if (Error E = Obj->getVaPtr(TableVA, TableStart))
+    reportError(std::move(E), Obj->getFileName());
+  if (Error E = Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd))
+    reportError(std::move(E), Obj->getFileName());
+  TableEnd++;
+  for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) {
+    DictScope D(W);
+    uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I);
+    W.printHex("Address", Obj->getImageBase() + RVA);
+  }
+}
 }
\ No newline at end of file

>From a6d737fbc00f324e8be086718df2c45c5c9f76c8 Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 21:04:33 -0700
Subject: [PATCH 11/12] [llvm-readobj][COFF] JSON Style --coff-resources

---
 .../tools/llvm-readobj/COFF/resources.test    | 386 ++++++++++++++++++
 llvm/tools/llvm-readobj/COFFDumper.cpp        | 178 ++++++++
 2 files changed, 564 insertions(+)

diff --git a/llvm/test/tools/llvm-readobj/COFF/resources.test b/llvm/test/tools/llvm-readobj/COFF/resources.test
index 0d91755a66870..520a7ca70f20c 100644
--- a/llvm/test/tools/llvm-readobj/COFF/resources.test
+++ b/llvm/test/tools/llvm-readobj/COFF/resources.test
@@ -6,8 +6,12 @@
 
 RUN: llvm-readobj --coff-resources --section-data %p/Inputs/zero-string-table.obj.coff-i386 \
 RUN:   | FileCheck %s -check-prefix ZERO
+RUN: llvm-readobj --coff-resources --coff-output-style=JSON --pretty-print %p/Inputs/zero-string-table.obj.coff-i386 \
+RUN:   | FileCheck %s -check-prefix JSON-ZERO
 RUN: llvm-readobj --coff-resources %p/Inputs/resources/test_resource.obj.coff \
 RUN:   | FileCheck %s -check-prefix TEST_RES
+RUN: llvm-readobj --coff-resources --coff-output-style=JSON --pretty-print %p/Inputs/resources/test_resource.obj.coff \
+RUN:   | FileCheck %s -check-prefix JSON-TEST_RES
 
 ZERO:     Resources [
 ZERO-NEXT:  Total Number of Resources: 1
@@ -43,6 +47,107 @@ ZERO-NEXT:      ]
 ZERO-NEXT:    ]
 ZERO-NEXT:  ]
 
+JSON-ZERO:         "Resource Sections": [
+JSON-ZERO-NEXT:      {
+JSON-ZERO-NEXT:        "Name": ".rsrc$01",
+JSON-ZERO-NEXT:        "Total Number of Resources": 1,
+JSON-ZERO-NEXT:        "Base Table Address": 392,
+JSON-ZERO-NEXT:        "Resource Type Table": {
+JSON-ZERO-NEXT:          "Number of String Entries": 0,
+JSON-ZERO-NEXT:          "Number of ID Entries": 1,
+JSON-ZERO-NEXT:          "Entries": [
+JSON-ZERO-NEXT:            {
+JSON-ZERO-NEXT:              "Table Offset": 24,
+JSON-ZERO-NEXT:              "Type": 6,
+JSON-ZERO-NEXT:              "Resource Name Table": {
+JSON-ZERO-NEXT:                "Number of String Entries": 0,
+JSON-ZERO-NEXT:                "Number of ID Entries": 1,
+JSON-ZERO-NEXT:                "Entries": [
+JSON-ZERO-NEXT:                  {
+JSON-ZERO-NEXT:                    "Table Offset": 48,
+JSON-ZERO-NEXT:                    "Name": "",
+JSON-ZERO-NEXT:                    "ID": 1,
+JSON-ZERO-NEXT:                    "Resource Language Table": {
+JSON-ZERO-NEXT:                      "Number of String Entries": 0,
+JSON-ZERO-NEXT:                      "Number of ID Entries": 1,
+JSON-ZERO-NEXT:                      "Entries": [
+JSON-ZERO-NEXT:                        {
+JSON-ZERO-NEXT:                          "Entry Offset": 72,
+JSON-ZERO-NEXT:                          "Time/Date Stamp": {
+JSON-ZERO-NEXT:                            "Name": "1970-01-01 00:00:00",
+JSON-ZERO-NEXT:                            "Value": 0
+JSON-ZERO-NEXT:                          },
+JSON-ZERO-NEXT:                          "Major Version": 0,
+JSON-ZERO-NEXT:                          "Minor Version": 0,
+JSON-ZERO-NEXT:                          "Characteristics": 0,
+JSON-ZERO-NEXT:                          "Data": {
+JSON-ZERO-NEXT:                            "DataRVA": 0,
+JSON-ZERO-NEXT:                            "DataSize": 42,
+JSON-ZERO-NEXT:                            "Codepage": 0,
+JSON-ZERO-NEXT:                            "Reserved": 0,
+JSON-ZERO-NEXT:                            "Data": {
+JSON-ZERO-NEXT:                              "Offset": 0,
+JSON-ZERO-NEXT:                              "Bytes": [
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                5,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                72,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                101,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                108,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                108,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                111,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0,
+JSON-ZERO-NEXT:                                0
+JSON-ZERO-NEXT:                              ]
+JSON-ZERO-NEXT:                            }
+JSON-ZERO-NEXT:                          }
+JSON-ZERO-NEXT:                        }
+JSON-ZERO-NEXT:                      ]
+JSON-ZERO-NEXT:                    }
+JSON-ZERO-NEXT:                  }
+JSON-ZERO-NEXT:                ]
+JSON-ZERO-NEXT:              }
+JSON-ZERO-NEXT:            }
+JSON-ZERO-NEXT:          ]
+JSON-ZERO-NEXT:        }
+JSON-ZERO-NEXT:      },
+JSON-ZERO-NEXT:      {
+JSON-ZERO-NEXT:        "Name": ".rsrc$02"
+JSON-ZERO-NEXT:      }
+JSON-ZERO-NEXT:    ]
+
 TEST_RES:     Resources [
 TEST_RES-NEXT:  Total Number of Resources: 7
 TEST_RES-NEXT:  Base Table Address: 0x1C0  
@@ -208,3 +313,284 @@ TEST_RES-NEXT:        ]
 TEST_RES-NEXT:      ]
 TEST_RES-NEXT:    ]
 TEST_RES-NEXT:  ]
+
+JSON-TEST_RES:    "Resource Sections": [
+JSON-TEST_RES-NEXT:      {
+JSON-TEST_RES-NEXT:        "Name": ".rsrc$01",
+JSON-TEST_RES-NEXT:        "Total Number of Resources": 7,
+JSON-TEST_RES-NEXT:        "Base Table Address": 448,
+JSON-TEST_RES-NEXT:        "Resource Type Table": {
+JSON-TEST_RES-NEXT:          "Number of String Entries": 0,
+JSON-TEST_RES-NEXT:          "Number of ID Entries": 4,
+JSON-TEST_RES-NEXT:          "Entries": [
+JSON-TEST_RES-NEXT:            {
+JSON-TEST_RES-NEXT:              "Table Offset": 48,
+JSON-TEST_RES-NEXT:              "Type": 2,
+JSON-TEST_RES-NEXT:              "Resource Name Table": {
+JSON-TEST_RES-NEXT:                "Number of String Entries": 2,
+JSON-TEST_RES-NEXT:                "Number of ID Entries": 0,
+JSON-TEST_RES-NEXT:                "Entries": [
+JSON-TEST_RES-NEXT:                  {
+JSON-TEST_RES-NEXT:                    "Table Offset": 168,
+JSON-TEST_RES-NEXT:                    "Name": "CURSOR",
+JSON-TEST_RES-NEXT:                    "ID": 0,
+JSON-TEST_RES-NEXT:                    "Resource Language Table": {
+JSON-TEST_RES-NEXT:                      "Number of String Entries": 0,
+JSON-TEST_RES-NEXT:                      "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                      "Entries": [
+JSON-TEST_RES-NEXT:                        {
+JSON-TEST_RES-NEXT:                          "Entry Offset": 336,
+JSON-TEST_RES-NEXT:                          "Time/Date Stamp": {
+JSON-TEST_RES-NEXT:                            "Name": "1970-01-01 00:00:00",
+JSON-TEST_RES-NEXT:                            "Value": 0
+JSON-TEST_RES-NEXT:                          },
+JSON-TEST_RES-NEXT:                          "Major Version": 0,
+JSON-TEST_RES-NEXT:                          "Minor Version": 0,
+JSON-TEST_RES-NEXT:                          "Characteristics": 0,
+JSON-TEST_RES-NEXT:                          "Data": {
+JSON-TEST_RES-NEXT:                            "DataRVA": 0,
+JSON-TEST_RES-NEXT:                            "DataSize": 808,
+JSON-TEST_RES-NEXT:                            "Codepage": 0,
+JSON-TEST_RES-NEXT:                            "Reserved": 0,
+JSON-TEST_RES-NEXT:                            "Data": {
+JSON-TEST_RES-NEXT:                              "Offset": 0,
+JSON-TEST_RES-NEXT:                              "Bytes": [
+JSON-TEST_RES:                                   ]
+JSON-TEST_RES-NEXT:                            }
+JSON-TEST_RES-NEXT:                          }
+JSON-TEST_RES-NEXT:                        }
+JSON-TEST_RES-NEXT:                      ]
+JSON-TEST_RES-NEXT:                    }
+JSON-TEST_RES-NEXT:                  },
+JSON-TEST_RES-NEXT:                  {
+JSON-TEST_RES-NEXT:                    "Table Offset": 192,
+JSON-TEST_RES-NEXT:                    "Name": "OKAY",
+JSON-TEST_RES-NEXT:                    "ID": 0,
+JSON-TEST_RES-NEXT:                    "Resource Language Table": {
+JSON-TEST_RES-NEXT:                      "Number of String Entries": 0,
+JSON-TEST_RES-NEXT:                      "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                      "Entries": [
+JSON-TEST_RES-NEXT:                        {
+JSON-TEST_RES-NEXT:                          "Entry Offset": 352,
+JSON-TEST_RES-NEXT:                          "Time/Date Stamp": {
+JSON-TEST_RES-NEXT:                            "Name": "1970-01-01 00:00:00",
+JSON-TEST_RES-NEXT:                            "Value": 0
+JSON-TEST_RES-NEXT:                          },
+JSON-TEST_RES-NEXT:                          "Major Version": 0,
+JSON-TEST_RES-NEXT:                          "Minor Version": 0,
+JSON-TEST_RES-NEXT:                          "Characteristics": 0,
+JSON-TEST_RES-NEXT:                          "Data": {
+JSON-TEST_RES-NEXT:                            "DataRVA": 0,
+JSON-TEST_RES-NEXT:                            "DataSize": 808,
+JSON-TEST_RES-NEXT:                            "Codepage": 0,
+JSON-TEST_RES-NEXT:                            "Reserved": 0,
+JSON-TEST_RES-NEXT:                            "Data": {
+JSON-TEST_RES-NEXT:                              "Offset": 0,
+JSON-TEST_RES-NEXT:                              "Bytes": [
+JSON-TEST_RES:                                   ]
+JSON-TEST_RES-NEXT:                            }
+JSON-TEST_RES-NEXT:                          }
+JSON-TEST_RES-NEXT:                        }
+JSON-TEST_RES-NEXT:                      ]
+JSON-TEST_RES-NEXT:                    }
+JSON-TEST_RES-NEXT:                  }
+JSON-TEST_RES-NEXT:                ]
+JSON-TEST_RES-NEXT:              }
+JSON-TEST_RES-NEXT:            },
+JSON-TEST_RES-NEXT:            {
+JSON-TEST_RES-NEXT:              "Table Offset": 80,
+JSON-TEST_RES-NEXT:              "Type": 4,
+JSON-TEST_RES-NEXT:              "Resource Name Table": {
+JSON-TEST_RES-NEXT:                "Number of String Entries": 1,
+JSON-TEST_RES-NEXT:                "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                "Entries": [
+JSON-TEST_RES-NEXT:                  {
+JSON-TEST_RES-NEXT:                    "Table Offset": 216,
+JSON-TEST_RES-NEXT:                    "Name": "\"EAT\"",
+JSON-TEST_RES-NEXT:                    "ID": 0,
+JSON-TEST_RES-NEXT:                    "Resource Language Table": {
+JSON-TEST_RES-NEXT:                      "Number of String Entries": 0,
+JSON-TEST_RES-NEXT:                      "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                      "Entries": [
+JSON-TEST_RES-NEXT:                        {
+JSON-TEST_RES-NEXT:                          "Entry Offset": 368,
+JSON-TEST_RES-NEXT:                          "Time/Date Stamp": {
+JSON-TEST_RES-NEXT:                            "Name": "1970-01-01 00:00:00",
+JSON-TEST_RES-NEXT:                            "Value": 0
+JSON-TEST_RES-NEXT:                          },
+JSON-TEST_RES-NEXT:                          "Major Version": 0,
+JSON-TEST_RES-NEXT:                          "Minor Version": 0,
+JSON-TEST_RES-NEXT:                          "Characteristics": 0,
+JSON-TEST_RES-NEXT:                          "Data": {
+JSON-TEST_RES-NEXT:                            "DataRVA": 0,
+JSON-TEST_RES-NEXT:                            "DataSize": 48,
+JSON-TEST_RES-NEXT:                            "Codepage": 0,
+JSON-TEST_RES-NEXT:                            "Reserved": 0,
+JSON-TEST_RES-NEXT:                            "Data": {
+JSON-TEST_RES-NEXT:                              "Offset": 0,
+JSON-TEST_RES-NEXT:                              "Bytes": [
+JSON-TEST_RES:                                   ]
+JSON-TEST_RES-NEXT:                            }
+JSON-TEST_RES-NEXT:                          }
+JSON-TEST_RES-NEXT:                        }
+JSON-TEST_RES-NEXT:                      ]
+JSON-TEST_RES-NEXT:                    }
+JSON-TEST_RES-NEXT:                  },
+JSON-TEST_RES-NEXT:                  {
+JSON-TEST_RES-NEXT:                    "Table Offset": 240,
+JSON-TEST_RES-NEXT:                    "Name": "",
+JSON-TEST_RES-NEXT:                    "ID": 14432,
+JSON-TEST_RES-NEXT:                    "Resource Language Table": {
+JSON-TEST_RES-NEXT:                      "Number of String Entries": 0,
+JSON-TEST_RES-NEXT:                      "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                      "Entries": [
+JSON-TEST_RES-NEXT:                        {
+JSON-TEST_RES-NEXT:                          "Entry Offset": 384,
+JSON-TEST_RES-NEXT:                          "Time/Date Stamp": {
+JSON-TEST_RES-NEXT:                            "Name": "1970-01-01 00:00:00",
+JSON-TEST_RES-NEXT:                            "Value": 0
+JSON-TEST_RES-NEXT:                          },
+JSON-TEST_RES-NEXT:                          "Major Version": 0,
+JSON-TEST_RES-NEXT:                          "Minor Version": 0,
+JSON-TEST_RES-NEXT:                          "Characteristics": 0,
+JSON-TEST_RES-NEXT:                          "Data": {
+JSON-TEST_RES-NEXT:                            "DataRVA": 0,
+JSON-TEST_RES-NEXT:                            "DataSize": 46,
+JSON-TEST_RES-NEXT:                            "Codepage": 0,
+JSON-TEST_RES-NEXT:                            "Reserved": 0,
+JSON-TEST_RES-NEXT:                            "Data": {
+JSON-TEST_RES-NEXT:                              "Offset": 0,
+JSON-TEST_RES-NEXT:                              "Bytes": [
+JSON-TEST_RES:                                   ]
+JSON-TEST_RES-NEXT:                            }
+JSON-TEST_RES-NEXT:                          }
+JSON-TEST_RES-NEXT:                        }
+JSON-TEST_RES-NEXT:                      ]
+JSON-TEST_RES-NEXT:                    }
+JSON-TEST_RES-NEXT:                  }
+JSON-TEST_RES-NEXT:                ]
+JSON-TEST_RES-NEXT:              }
+JSON-TEST_RES-NEXT:            },
+JSON-TEST_RES-NEXT:            {
+JSON-TEST_RES-NEXT:              "Table Offset": 112,
+JSON-TEST_RES-NEXT:              "Type": 5,
+JSON-TEST_RES-NEXT:              "Resource Name Table": {
+JSON-TEST_RES-NEXT:                "Number of String Entries": 1,
+JSON-TEST_RES-NEXT:                "Number of ID Entries": 0,
+JSON-TEST_RES-NEXT:                "Entries": [
+JSON-TEST_RES-NEXT:                  {
+JSON-TEST_RES-NEXT:                    "Table Offset": 264,
+JSON-TEST_RES-NEXT:                    "Name": "TESTDIALOG",
+JSON-TEST_RES-NEXT:                    "ID": 0,
+JSON-TEST_RES-NEXT:                    "Resource Language Table": {
+JSON-TEST_RES-NEXT:                      "Number of String Entries": 0,
+JSON-TEST_RES-NEXT:                      "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                      "Entries": [
+JSON-TEST_RES-NEXT:                        {
+JSON-TEST_RES-NEXT:                          "Entry Offset": 400,
+JSON-TEST_RES-NEXT:                          "Time/Date Stamp": {
+JSON-TEST_RES-NEXT:                            "Name": "1970-01-01 00:00:00",
+JSON-TEST_RES-NEXT:                            "Value": 0
+JSON-TEST_RES-NEXT:                          },
+JSON-TEST_RES-NEXT:                          "Major Version": 0,
+JSON-TEST_RES-NEXT:                          "Minor Version": 0,
+JSON-TEST_RES-NEXT:                          "Characteristics": 0,
+JSON-TEST_RES-NEXT:                          "Data": {
+JSON-TEST_RES-NEXT:                            "DataRVA": 0,
+JSON-TEST_RES-NEXT:                            "DataSize": 108,
+JSON-TEST_RES-NEXT:                            "Codepage": 0,
+JSON-TEST_RES-NEXT:                            "Reserved": 0,
+JSON-TEST_RES-NEXT:                            "Data": {
+JSON-TEST_RES-NEXT:                              "Offset": 0,
+JSON-TEST_RES-NEXT:                              "Bytes": [
+JSON-TEST_RES:                                   ]
+JSON-TEST_RES-NEXT:                            }
+JSON-TEST_RES-NEXT:                          }
+JSON-TEST_RES-NEXT:                        }
+JSON-TEST_RES-NEXT:                      ]
+JSON-TEST_RES-NEXT:                    }
+JSON-TEST_RES-NEXT:                  }
+JSON-TEST_RES-NEXT:                ]
+JSON-TEST_RES-NEXT:              }
+JSON-TEST_RES-NEXT:            },
+JSON-TEST_RES-NEXT:            {
+JSON-TEST_RES-NEXT:              "Table Offset": 136,
+JSON-TEST_RES-NEXT:              "Type": 9,
+JSON-TEST_RES-NEXT:              "Resource Name Table": {
+JSON-TEST_RES-NEXT:                "Number of String Entries": 1,
+JSON-TEST_RES-NEXT:                "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                "Entries": [
+JSON-TEST_RES-NEXT:                  {
+JSON-TEST_RES-NEXT:                    "Table Offset": 288,
+JSON-TEST_RES-NEXT:                    "Name": "MYACCELERATORS",
+JSON-TEST_RES-NEXT:                    "ID": 0,
+JSON-TEST_RES-NEXT:                    "Resource Language Table": {
+JSON-TEST_RES-NEXT:                      "Number of String Entries": 0,
+JSON-TEST_RES-NEXT:                      "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                      "Entries": [
+JSON-TEST_RES-NEXT:                        {
+JSON-TEST_RES-NEXT:                          "Entry Offset": 416,
+JSON-TEST_RES-NEXT:                          "Time/Date Stamp": {
+JSON-TEST_RES-NEXT:                            "Name": "1970-01-01 00:00:00",
+JSON-TEST_RES-NEXT:                            "Value": 0
+JSON-TEST_RES-NEXT:                          },
+JSON-TEST_RES-NEXT:                          "Major Version": 0,
+JSON-TEST_RES-NEXT:                          "Minor Version": 0,
+JSON-TEST_RES-NEXT:                          "Characteristics": 0,
+JSON-TEST_RES-NEXT:                          "Data": {
+JSON-TEST_RES-NEXT:                            "DataRVA": 0,
+JSON-TEST_RES-NEXT:                            "DataSize": 24,
+JSON-TEST_RES-NEXT:                            "Codepage": 0,
+JSON-TEST_RES-NEXT:                            "Reserved": 0,
+JSON-TEST_RES-NEXT:                            "Data": {
+JSON-TEST_RES-NEXT:                              "Offset": 0,
+JSON-TEST_RES-NEXT:                              "Bytes": [
+JSON-TEST_RES:                                   ]
+JSON-TEST_RES-NEXT:                            }
+JSON-TEST_RES-NEXT:                          }
+JSON-TEST_RES-NEXT:                        }
+JSON-TEST_RES-NEXT:                      ]
+JSON-TEST_RES-NEXT:                    }
+JSON-TEST_RES-NEXT:                  },
+JSON-TEST_RES-NEXT:                  {
+JSON-TEST_RES-NEXT:                    "Table Offset": 312,
+JSON-TEST_RES-NEXT:                    "Name": "",
+JSON-TEST_RES-NEXT:                    "ID": 12,
+JSON-TEST_RES-NEXT:                    "Resource Language Table": {
+JSON-TEST_RES-NEXT:                      "Number of String Entries": 0,
+JSON-TEST_RES-NEXT:                      "Number of ID Entries": 1,
+JSON-TEST_RES-NEXT:                      "Entries": [
+JSON-TEST_RES-NEXT:                        {
+JSON-TEST_RES-NEXT:                          "Entry Offset": 432,
+JSON-TEST_RES-NEXT:                          "Time/Date Stamp": {
+JSON-TEST_RES-NEXT:                            "Name": "1970-01-01 00:00:00",
+JSON-TEST_RES-NEXT:                            "Value": 0
+JSON-TEST_RES-NEXT:                          },
+JSON-TEST_RES-NEXT:                          "Major Version": 0,
+JSON-TEST_RES-NEXT:                          "Minor Version": 0,
+JSON-TEST_RES-NEXT:                          "Characteristics": 0,
+JSON-TEST_RES-NEXT:                          "Data": {
+JSON-TEST_RES-NEXT:                            "DataRVA": 0,
+JSON-TEST_RES-NEXT:                            "DataSize": 24,
+JSON-TEST_RES-NEXT:                            "Codepage": 0,
+JSON-TEST_RES-NEXT:                            "Reserved": 0,
+JSON-TEST_RES-NEXT:                            "Data": {
+JSON-TEST_RES-NEXT:                              "Offset": 0,
+JSON-TEST_RES-NEXT:                              "Bytes": [
+JSON-TEST_RES:                                   ]
+JSON-TEST_RES-NEXT:                            }
+JSON-TEST_RES-NEXT:                          }
+JSON-TEST_RES-NEXT:                        }
+JSON-TEST_RES-NEXT:                      ]
+JSON-TEST_RES-NEXT:                    }
+JSON-TEST_RES-NEXT:                  }
+JSON-TEST_RES-NEXT:                ]
+JSON-TEST_RES-NEXT:              }
+JSON-TEST_RES-NEXT:            }
+JSON-TEST_RES-NEXT:          ]
+JSON-TEST_RES-NEXT:        }
+JSON-TEST_RES-NEXT:      },
+JSON-TEST_RES-NEXT:      {
+JSON-TEST_RES-NEXT:        "Name": ".rsrc$02"
+JSON-TEST_RES-NEXT:      }
+JSON-TEST_RES-NEXT:    ]
\ No newline at end of file
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 83738a2bd8c4f..8926656b6386a 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -54,6 +54,7 @@
 #include "llvm/Support/Win64EH.h"
 #include "llvm/Support/raw_ostream.h"
 #include <ctime>
+#include <functional>
 
 using namespace llvm;
 using namespace llvm::object;
@@ -256,10 +257,28 @@ class JSONCOFFDumper : public COFFDumper {
   void printDelayImportedSymbols(
       const DelayImportDirectoryEntryRef &I,
       iterator_range<imported_symbol_iterator> Range) override;
+  void printCOFFResources() override;
   void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
                      PrintExtraCB PrintExtra = nullptr) override;
 
 private:
+  using ResourceEntryTy =
+      std::pair<std::string,
+                std::reference_wrapper<const coff_resource_dir_entry>>;
+  std::vector<ResourceEntryTy>
+  getResourceTableEntries(ResourceSectionRef RSF,
+                          const coff_resource_dir_table &Table,
+                          bool SubDirEntriesOnly = true);
+  void printResourceDirectoryTable(const coff_resource_dir_table &Table);
+  void
+  printResourceDirectoryTypeTable(ResourceSectionRef RSF,
+                                  const coff_resource_dir_table &TypeTable);
+  void
+  printResourceDirectoryNameTable(ResourceSectionRef RSF,
+                                  const coff_resource_dir_table &NameTable);
+  void printResourceDirectoryLanguageTable(
+      ResourceSectionRef RSF, const coff_resource_dir_table &LanguageTable);
+
   std::unique_ptr<DictScope> FileScope;
 };
 
@@ -2333,4 +2352,163 @@ void JSONCOFFDumper::printRVATable(uint64_t TableVA, uint64_t Count,
     W.printHex("Address", Obj->getImageBase() + RVA);
   }
 }
+
+void JSONCOFFDumper::printCOFFResources() {
+  ListScope ResourcesD(W, "Resource Sections");
+  for (const SectionRef &S : Obj->sections()) {
+    StringRef Name = unwrapOrError(Obj->getFileName(), S.getName());
+    if (!Name.starts_with(".rsrc"))
+      continue;
+
+    DictScope D(W);
+    W.printString("Name", Name);
+    StringRef Ref = unwrapOrError(Obj->getFileName(), S.getContents());
+
+    if ((Name == ".rsrc") || (Name == ".rsrc$01")) {
+      ResourceSectionRef RSF;
+      Error E = RSF.load(Obj, S);
+      if (E)
+        reportError(std::move(E), Obj->getFileName());
+      auto &TypeTable = unwrapOrError(Obj->getFileName(), RSF.getBaseTable());
+      W.printNumber("Total Number of Resources",
+                    countTotalTableEntries(RSF, TypeTable, "Type"));
+      W.printHex("Base Table Address",
+                 Obj->getCOFFSection(S)->PointerToRawData);
+      printResourceDirectoryTypeTable(RSF, TypeTable);
+    }
+    if (opts::SectionData)
+      W.printBinaryBlock("Data", Ref);
+  }
+}
+
+std::vector<JSONCOFFDumper::ResourceEntryTy>
+JSONCOFFDumper::getResourceTableEntries(ResourceSectionRef RSF,
+                                        const coff_resource_dir_table &Table,
+                                        bool SubDirEntriesOnly) {
+  std::vector<ResourceEntryTy> TableEntries;
+  for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
+       ++i) {
+    auto &Entry =
+        unwrapOrError(Obj->getFileName(), RSF.getTableEntry(Table, i));
+
+    std::string Name;
+
+    if (i < Table.NumberOfNameEntries) {
+      ArrayRef<UTF16> RawEntryNameString =
+          unwrapOrError(Obj->getFileName(), RSF.getEntryNameString(Entry));
+      std::vector<UTF16> EndianCorrectedNameString;
+      if (llvm::sys::IsBigEndianHost) {
+        EndianCorrectedNameString.resize(RawEntryNameString.size() + 1);
+        std::copy(RawEntryNameString.begin(), RawEntryNameString.end(),
+                  EndianCorrectedNameString.begin() + 1);
+        EndianCorrectedNameString[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
+        RawEntryNameString = ArrayRef(EndianCorrectedNameString);
+      }
+      if (!llvm::convertUTF16ToUTF8String(RawEntryNameString, Name))
+        reportError(errorCodeToError(object_error::parse_failed),
+                    Obj->getFileName());
+    }
+
+    if (Entry.Offset.isSubDir()) {
+      TableEntries.push_back({Name, Entry});
+      if (SubDirEntriesOnly)
+        continue;
+    }
+
+    TableEntries.push_back({Name, Entry});
+  }
+
+  return TableEntries;
+}
+
+void JSONCOFFDumper::printResourceDirectoryTable(
+    const coff_resource_dir_table &Table) {
+  W.printNumber("Number of String Entries", Table.NumberOfNameEntries);
+  W.printNumber("Number of ID Entries", Table.NumberOfIDEntries);
+}
+
+void JSONCOFFDumper::printResourceDirectoryLanguageTable(
+    ResourceSectionRef RSF, const coff_resource_dir_table &LanguageTable) {
+  DictScope D(W, "Resource Language Table");
+  printResourceDirectoryTable(LanguageTable);
+
+  std::vector<ResourceEntryTy> LanguageTableEntries =
+      getResourceTableEntries(RSF, LanguageTable, false);
+
+  ListScope LLS(W, "Entries");
+  for (auto &LTP : LanguageTableEntries) {
+    const auto &LanguageTableEntry = LTP.second.get();
+
+    DictScope LD(W);
+    W.printHex("Entry Offset", LanguageTableEntry.Offset.value());
+    char FormattedTime[20] = {};
+    time_t TDS = time_t(LanguageTable.TimeDateStamp);
+    strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+    W.printHex("Time/Date Stamp", FormattedTime, LanguageTable.TimeDateStamp);
+    W.printNumber("Major Version", LanguageTable.MajorVersion);
+    W.printNumber("Minor Version", LanguageTable.MinorVersion);
+    W.printNumber("Characteristics", LanguageTable.Characteristics);
+    DictScope DataScope(W, "Data");
+    auto &DataEntry =
+        unwrapOrError(Obj->getFileName(), RSF.getEntryData(LanguageTableEntry));
+    W.printHex("DataRVA", DataEntry.DataRVA);
+    W.printNumber("DataSize", DataEntry.DataSize);
+    W.printNumber("Codepage", DataEntry.Codepage);
+    W.printNumber("Reserved", DataEntry.Reserved);
+    StringRef Contents =
+        unwrapOrError(Obj->getFileName(), RSF.getContents(DataEntry));
+    W.printBinaryBlock("Data", Contents);
+  }
+}
+
+void JSONCOFFDumper::printResourceDirectoryNameTable(
+    ResourceSectionRef RSF, const coff_resource_dir_table &NameTable) {
+  DictScope D(W, "Resource Name Table");
+  printResourceDirectoryTable(NameTable);
+
+  std::vector<ResourceEntryTy> NameTableEntries =
+      getResourceTableEntries(RSF, NameTable);
+
+  ListScope NLS(W, "Entries");
+  for (auto &NTP : NameTableEntries) {
+    auto &Name = NTP.first;
+    const auto &NameTableEntry = NTP.second.get();
+    DictScope ND(W);
+
+    W.printHex("Table Offset", NameTableEntry.Offset.value());
+    W.printString("Name", Name);
+
+    // The ID can be ignored if name is non-empty. We emit the "ID" so data is
+    // consistent.
+    auto ID = !Name.empty() ? 0 : NameTableEntry.Identifier.ID;
+    W.printNumber("ID", ID);
+
+    auto &LanguageTable =
+        unwrapOrError(Obj->getFileName(), RSF.getEntrySubDir(NameTableEntry));
+    printResourceDirectoryLanguageTable(RSF, LanguageTable);
+  }
+}
+
+void JSONCOFFDumper::printResourceDirectoryTypeTable(
+    ResourceSectionRef RSF, const coff_resource_dir_table &TypeTable) {
+  DictScope D(W, "Resource Type Table");
+
+  printResourceDirectoryTable(TypeTable);
+
+  ListScope LS(W, "Entries");
+  std::vector<ResourceEntryTy> TypeTableEntries =
+      getResourceTableEntries(RSF, TypeTable);
+
+  for (auto &TTP : TypeTableEntries) {
+    const auto &TypeTableEntry = TTP.second.get();
+
+    DictScope TD(W);
+    W.printHex("Table Offset", TypeTableEntry.Offset.value());
+    W.printNumber("Type", TypeTableEntry.Identifier.ID);
+
+    auto &NameTable =
+        unwrapOrError(Obj->getFileName(), RSF.getEntrySubDir(TypeTableEntry));
+
+    printResourceDirectoryNameTable(RSF, NameTable);
+  }
 }
\ No newline at end of file

>From 8aeaa56546d9240d3e60cd30652f28b8592b5a5f Mon Sep 17 00:00:00 2001
From: Miguel Arroyo <miguel.arroyo at rockstargames.com>
Date: Tue, 11 Jun 2024 20:58:15 -0700
Subject: [PATCH 12/12] [llvm-readobj][COFF] JSON Style --coff-tls-directory

---
 .../tools/llvm-readobj/COFF/tls-directory.test  | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/llvm/test/tools/llvm-readobj/COFF/tls-directory.test b/llvm/test/tools/llvm-readobj/COFF/tls-directory.test
index b32bd7a12fb52..ab124c10386b4 100644
--- a/llvm/test/tools/llvm-readobj/COFF/tls-directory.test
+++ b/llvm/test/tools/llvm-readobj/COFF/tls-directory.test
@@ -87,6 +87,23 @@ symbols:         []
 # X86-64-NEXT:   ]
 # X86-64-NEXT: }
 
+# RUN: llvm-readobj --coff-tls-directory --coff-output-style=JSON --pretty-print %t.64.exe | FileCheck %s --check-prefix JSON-X64 
+
+# JSON-X64:       "TLSDirectory": {
+# JSON-X64-NEXT:      "StartAddressOfRawData": 5368725504,
+# JSON-X64-NEXT:      "EndAddressOfRawData": 5368725512,
+# JSON-X64-NEXT:      "AddressOfIndex": 5368717312,
+# JSON-X64-NEXT:      "AddressOfCallBacks": 0,
+# JSON-X64-NEXT:      "SizeOfZeroFill": 0,
+# JSON-X64-NEXT:      "Characteristics": {
+# JSON-X64-NEXT:        "Value": 3145728,
+# JSON-X64-NEXT:        "Flags": [
+# JSON-X64-NEXT:          {
+# JSON-X64-NEXT:            "Name": "IMAGE_SCN_ALIGN_4BYTES",
+# JSON-X64-NEXT:            "Value": 3145728
+# JSON-X64-NEXT:          }
+# JSON-X64-NEXT:        ]
+# JSON-X64-NEXT:      }
 
 ## Test that the output of --coff-tls-directory errors on malformed input.
 



More information about the llvm-commits mailing list