]> granicus.if.org Git - llvm/commitdiff
[llvm-readobj] Dump the COFF image load config
authorReid Kleckner <rnk@google.com>
Thu, 22 Jun 2017 01:10:29 +0000 (01:10 +0000)
committerReid Kleckner <rnk@google.com>
Thu, 22 Jun 2017 01:10:29 +0000 (01:10 +0000)
This includes the safe SEH tables and the control flow guard function
table. LLD will emit the guard table soon, and I need a tool that dumps
them for testing.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305979 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/COFF.h
lib/Object/COFFObjectFile.cpp
test/tools/llvm-readobj/Inputs/coff-load-config-x64.dll [new file with mode: 0644]
test/tools/llvm-readobj/Inputs/coff-load-config-x86.dll [new file with mode: 0644]
test/tools/llvm-readobj/coff-load-config.test [new file with mode: 0644]
tools/llvm-readobj/COFFDumper.cpp
tools/llvm-readobj/ObjDumper.h
tools/llvm-readobj/llvm-readobj.cpp

index ae695a529597bc782d749759de76fa7484ba9c7e..bf0172822d3fcdf20796a881f17f5f5ca7c609cb 100644 (file)
@@ -562,8 +562,26 @@ struct coff_tls_directory {
 using coff_tls_directory32 = coff_tls_directory<support::little32_t>;
 using coff_tls_directory64 = coff_tls_directory<support::little64_t>;
 
+/// Bits in control flow guard flags as we understand them.
+enum class coff_guard_flags : uint32_t {
+  CFInstrumented = 0x00000100,
+  HasFidTable = 0x00000400,
+  ProtectDelayLoadIAT = 0x00001000,
+  DelayLoadIATSection = 0x00002000, // Delay load in separate section
+  HasLongJmpTable = 0x00010000,
+  FidTableHasFlags = 0x10000000, // Indicates that fid tables are 5 bytes
+};
+
+struct coff_load_config_code_integrity {
+  support::ulittle16_t Flags;
+  support::ulittle16_t Catalog;
+  support::ulittle32_t CatalogOffset;
+  support::ulittle32_t Reserved;
+};
+
+/// 32-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY32)
 struct coff_load_configuration32 {
-  support::ulittle32_t Characteristics;
+  support::ulittle32_t Size;
   support::ulittle32_t TimeDateStamp;
   support::ulittle16_t MajorVersion;
   support::ulittle16_t MinorVersion;
@@ -578,34 +596,81 @@ struct coff_load_configuration32 {
   support::ulittle32_t ProcessAffinityMask;
   support::ulittle32_t ProcessHeapFlags;
   support::ulittle16_t CSDVersion;
-  support::ulittle16_t Reserved;
+  support::ulittle16_t DependentLoadFlags;
   support::ulittle32_t EditList;
   support::ulittle32_t SecurityCookie;
   support::ulittle32_t SEHandlerTable;
   support::ulittle32_t SEHandlerCount;
+
+  // Added in MSVC 2015 for /guard:cf.
+  support::ulittle32_t GuardCFCheckFunction;
+  support::ulittle32_t GuardCFCheckDispatch;
+  support::ulittle32_t GuardCFFunctionTable;
+  support::ulittle32_t GuardCFFunctionCount;
+  support::ulittle32_t GuardFlags; // coff_guard_flags
+
+  // Added in MSVC 2017
+  coff_load_config_code_integrity CodeIntegrity;
+  support::ulittle32_t GuardAddressTakenIatEntryTable;
+  support::ulittle32_t GuardAddressTakenIatEntryCount;
+  support::ulittle32_t GuardLongJumpTargetTable;
+  support::ulittle32_t GuardLongJumpTargetCount;
+  support::ulittle32_t DynamicValueRelocTable;
+  support::ulittle32_t CHPEMetadataPointer;
+  support::ulittle32_t GuardRFFailureRoutine;
+  support::ulittle32_t GuardRFFailureRoutineFunctionPointer;
+  support::ulittle32_t DynamicValueRelocTableOffset;
+  support::ulittle16_t DynamicValueRelocTableSection;
+  support::ulittle16_t Reserved2;
+  support::ulittle32_t GuardRFVerifyStackPointerFunctionPointer;
+  support::ulittle32_t HotPatchTableOffset;
 };
 
+/// 64-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY64)
 struct coff_load_configuration64 {
-  support::ulittle32_t Characteristics;
+  support::ulittle32_t Size;
   support::ulittle32_t TimeDateStamp;
   support::ulittle16_t MajorVersion;
   support::ulittle16_t MinorVersion;
   support::ulittle32_t GlobalFlagsClear;
   support::ulittle32_t GlobalFlagsSet;
   support::ulittle32_t CriticalSectionDefaultTimeout;
-  support::ulittle32_t DeCommitFreeBlockThreshold;
-  support::ulittle32_t DeCommitTotalFreeThreshold;
-  support::ulittle32_t LockPrefixTable;
-  support::ulittle32_t MaximumAllocationSize;
-  support::ulittle32_t VirtualMemoryThreshold;
-  support::ulittle32_t ProcessAffinityMask;
+  support::ulittle64_t DeCommitFreeBlockThreshold;
+  support::ulittle64_t DeCommitTotalFreeThreshold;
+  support::ulittle64_t LockPrefixTable;
+  support::ulittle64_t MaximumAllocationSize;
+  support::ulittle64_t VirtualMemoryThreshold;
+  support::ulittle64_t ProcessAffinityMask;
   support::ulittle32_t ProcessHeapFlags;
   support::ulittle16_t CSDVersion;
-  support::ulittle16_t Reserved;
-  support::ulittle32_t EditList;
+  support::ulittle16_t DependentLoadFlags;
+  support::ulittle64_t EditList;
   support::ulittle64_t SecurityCookie;
   support::ulittle64_t SEHandlerTable;
   support::ulittle64_t SEHandlerCount;
+
+  // Added in MSVC 2015 for /guard:cf.
+  support::ulittle64_t GuardCFCheckFunction;
+  support::ulittle64_t GuardCFCheckDispatch;
+  support::ulittle64_t GuardCFFunctionTable;
+  support::ulittle64_t GuardCFFunctionCount;
+  support::ulittle32_t GuardFlags;
+
+  // Added in MSVC 2017
+  coff_load_config_code_integrity CodeIntegrity;
+  support::ulittle64_t GuardAddressTakenIatEntryTable;
+  support::ulittle64_t GuardAddressTakenIatEntryCount;
+  support::ulittle64_t GuardLongJumpTargetTable;
+  support::ulittle64_t GuardLongJumpTargetCount;
+  support::ulittle64_t DynamicValueRelocTable;
+  support::ulittle64_t CHPEMetadataPointer;
+  support::ulittle64_t GuardRFFailureRoutine;
+  support::ulittle64_t GuardRFFailureRoutineFunctionPointer;
+  support::ulittle32_t DynamicValueRelocTableOffset;
+  support::ulittle16_t DynamicValueRelocTableSection;
+  support::ulittle16_t Reserved2;
+  support::ulittle64_t GuardRFVerifyStackPointerFunctionPointer;
+  support::ulittle32_t HotPatchTableOffset;
 };
 
 struct coff_runtime_function_x64 {
@@ -684,6 +749,8 @@ private:
   const coff_base_reloc_block_header *BaseRelocEnd;
   const debug_directory *DebugDirectoryBegin;
   const debug_directory *DebugDirectoryEnd;
+  // Either coff_load_configuration32 or coff_load_configuration64.
+  const void *LoadConfig;
 
   std::error_code getString(uint32_t offset, StringRef &Res) const;
 
@@ -698,6 +765,7 @@ private:
   std::error_code initExportTablePtr();
   std::error_code initBaseRelocPtr();
   std::error_code initDebugDirectoryPtr();
+  std::error_code initLoadConfigPtr();
 
 public:
   uintptr_t getSymbolTable() const {
@@ -775,6 +843,16 @@ public:
     return getRawNumberOfSymbols();
   }
 
+  const coff_load_configuration32 *getLoadConfig32() const {
+    assert(!is64());
+    return reinterpret_cast<const coff_load_configuration32 *>(LoadConfig);
+  }
+
+  const coff_load_configuration64 *getLoadConfig64() const {
+    assert(is64());
+    return reinterpret_cast<const coff_load_configuration64 *>(LoadConfig);
+  }
+
 protected:
   void moveSymbolNext(DataRefImpl &Symb) const override;
   Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
index 579c8dde366a073bcd5d2d9eaa7d1e882dbf022e..9a760d86e7e2224aba074d889c2975dc37274e34 100644 (file)
@@ -650,6 +650,23 @@ std::error_code COFFObjectFile::initDebugDirectoryPtr() {
   return std::error_code();
 }
 
+std::error_code COFFObjectFile::initLoadConfigPtr() {
+  // Get the RVA of the debug directory. Do nothing if it does not exist.
+  const data_directory *DataEntry;
+  if (getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataEntry))
+    return std::error_code();
+
+  // Do nothing if the RVA is NULL.
+  if (DataEntry->RelativeVirtualAddress == 0)
+    return std::error_code();
+  uintptr_t IntPtr = 0;
+  if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+    return EC;
+
+  LoadConfig = (const void *)IntPtr;
+  return std::error_code();
+}
+
 COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
     : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
       COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
@@ -784,6 +801,9 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
   if ((EC = initDebugDirectoryPtr()))
     return;
 
+  if ((EC = initLoadConfigPtr()))
+    return;
+
   EC = std::error_code();
 }
 
diff --git a/test/tools/llvm-readobj/Inputs/coff-load-config-x64.dll b/test/tools/llvm-readobj/Inputs/coff-load-config-x64.dll
new file mode 100644 (file)
index 0000000..26101f9
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/coff-load-config-x64.dll differ
diff --git a/test/tools/llvm-readobj/Inputs/coff-load-config-x86.dll b/test/tools/llvm-readobj/Inputs/coff-load-config-x86.dll
new file mode 100644 (file)
index 0000000..c334c7b
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/coff-load-config-x86.dll differ
diff --git a/test/tools/llvm-readobj/coff-load-config.test b/test/tools/llvm-readobj/coff-load-config.test
new file mode 100644 (file)
index 0000000..97bd2e0
--- /dev/null
@@ -0,0 +1,87 @@
+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
+
+X86: LoadConfig [
+X86:   Size: 0x5C
+X86:   TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+X86:   MajorVersion: 0x0
+X86:   MinorVersion: 0x0
+X86:   GlobalFlagsClear: 0x0
+X86:   GlobalFlagsSet: 0x0
+X86:   CriticalSectionDefaultTimeout: 0x0
+X86:   DeCommitFreeBlockThreshold: 0x0
+X86:   DeCommitTotalFreeThreshold: 0x0
+X86:   LockPrefixTable: 0x0
+X86:   MaximumAllocationSize: 0x0
+X86:   VirtualMemoryThreshold: 0x0
+X86:   ProcessHeapFlags: 0x0
+X86:   ProcessAffinityMask: 0x0
+X86:   CSDVersion: 0x0
+X86:   DependentLoadFlags: 0x0
+X86:   EditList: 0x0
+X86:   SecurityCookie: 0x10003004
+X86:   SEHandlerTable: 0x100021C0
+X86:   SEHandlerCount: 2
+X86:   GuardCFCheckFunction: 0x1000207C
+X86:   GuardCFCheckDispatch: 0x0
+X86:   GuardCFFunctionTable: 0x100020A4
+X86:   GuardCFFunctionCount: 11
+X86:   GuardFlags: 0x13500
+X86: ]
+X86: SEHTable [
+X86:   0x10001BE0
+X86:   0x10001E30
+X86: ]
+X86: GuardFidTable [
+X86:   0x10001000
+X86:   0x10001040
+X86:   0x10001060
+X86:   0x10001100
+X86:   0x10001120
+X86:   0x10001150
+X86:   0x10001460
+X86:   0x100019B0
+X86:   0x10001B40
+X86:   0x10001BE0
+X86:   0x10001DC0
+X86: ]
+
+X64: LoadConfig [
+X64:   Size: 0x94
+X64:   TimeDateStamp: 1970-01-01 00:00:00 (0x0)
+X64:   MajorVersion: 0x0
+X64:   MinorVersion: 0x0
+X64:   GlobalFlagsClear: 0x0
+X64:   GlobalFlagsSet: 0x0
+X64:   CriticalSectionDefaultTimeout: 0x0
+X64:   DeCommitFreeBlockThreshold: 0x0
+X64:   DeCommitTotalFreeThreshold: 0x0
+X64:   LockPrefixTable: 0x0
+X64:   MaximumAllocationSize: 0x0
+X64:   VirtualMemoryThreshold: 0x0
+X64:   ProcessHeapFlags: 0x0
+X64:   ProcessAffinityMask: 0x0
+X64:   CSDVersion: 0x0
+X64:   DependentLoadFlags: 0x0
+X64:   EditList: 0x0
+X64:   SecurityCookie: 0x180003018
+X64:   SEHandlerTable: 0
+X64:   SEHandlerCount: 0
+X64:   GuardCFCheckFunction: 0x180002100
+X64:   GuardCFCheckDispatch: 0x180002108
+X64:   GuardCFFunctionTable: 0x180002158
+X64:   GuardCFFunctionCount: 9
+X64:   GuardFlags: 0x13500
+X64: ]
+X64-NOT: SEHTable
+X64: GuardFidTable [
+X64:   0x180001000
+X64:   0x180001050
+X64:   0x180001070
+X64:   0x1800010E0
+X64:   0x180001110
+X64:   0x180001460
+X64:   0x180001970
+X64:   0x180001B50
+X64:   0x180001D90
+X64: ]
index bb30180325e212f553ef348bc670e55fc9803d6b..373c528feeafe7b6adeb7bf991d545237e28adaf 100644 (file)
@@ -68,6 +68,14 @@ using namespace llvm::Win64EH;
 
 namespace {
 
+struct LoadConfigTables {
+  uint64_t SEHTableVA = 0;
+  uint64_t SEHTableCount = 0;
+  uint32_t GuardFlags = 0;
+  uint64_t GuardFidTableVA = 0;
+  uint64_t GuardFidTableCount = 0;
+};
+
 class COFFDumper : public ObjDumper {
 public:
   friend class COFFObjectDumpDelegate;
@@ -86,6 +94,7 @@ public:
   void printCOFFBaseReloc() override;
   void printCOFFDebugDirectory() override;
   void printCOFFResources() override;
+  void printCOFFLoadConfig() override;
   void printCodeViewDebugInfo() override;
   void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
                           llvm::codeview::TypeTableBuilder &CVTypes) override;
@@ -100,6 +109,11 @@ private:
   template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
   void printBaseOfDataField(const pe32_header *Hdr);
   void printBaseOfDataField(const pe32plus_header *Hdr);
+  template <typename T>
+  void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables);
+  typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *);
+  void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
+                     PrintExtraCB PrintExtra = 0);
 
   void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section);
   void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section);
@@ -745,6 +759,125 @@ void COFFDumper::printCOFFDebugDirectory() {
   }
 }
 
+void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count,
+                               uint64_t EntrySize, PrintExtraCB PrintExtra) {
+  uintptr_t TableStart, TableEnd;
+  error(Obj->getVaPtr(TableVA, TableStart));
+  error(Obj->getVaPtr(TableVA + Count * EntrySize, TableEnd));
+  for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) {
+    uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I);
+    raw_ostream &OS = W.startLine();
+    OS << "0x" << utohexstr(Obj->getImageBase() + RVA);
+    if (PrintExtra)
+      PrintExtra(OS, reinterpret_cast<const uint8_t *>(I));
+    OS << '\n';
+  }
+}
+
+void COFFDumper::printCOFFLoadConfig() {
+  LoadConfigTables Tables;
+  if (Obj->is64())
+    printCOFFLoadConfig(Obj->getLoadConfig64(), Tables);
+  else
+    printCOFFLoadConfig(Obj->getLoadConfig32(), Tables);
+
+  if (Tables.SEHTableVA) {
+    ListScope LS(W, "SEHTable");
+    printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4);
+  }
+
+  if (Tables.GuardFidTableVA) {
+    ListScope LS(W, "GuardFidTable");
+    if (Tables.GuardFlags & uint32_t(coff_guard_flags::FidTableHasFlags)) {
+      auto PrintGuardFlags = [](raw_ostream &OS, const uint8_t *Entry) {
+        uint8_t Flags = *reinterpret_cast<const uint8_t *>(Entry + 4);
+        if (Flags)
+          OS << " flags " << utohexstr(Flags);
+      };
+      printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 5,
+                    PrintGuardFlags);
+    } else {
+      printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 4);
+    }
+  }
+}
+
+template <typename T>
+void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
+  ListScope LS(W, "LoadConfig");
+  char FormattedTime[20] = {};
+  time_t TDS = Conf->TimeDateStamp;
+  strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+  W.printHex("Size", Conf->Size);
+
+  // Print everything before SecurityCookie. The vast majority of images today
+  // have all these fields.
+  if (Conf->Size < offsetof(T, SEHandlerTable))
+    return;
+  W.printHex("TimeDateStamp", FormattedTime, TDS);
+  W.printHex("MajorVersion", Conf->MajorVersion);
+  W.printHex("MinorVersion", Conf->MinorVersion);
+  W.printHex("GlobalFlagsClear", Conf->GlobalFlagsClear);
+  W.printHex("GlobalFlagsSet", Conf->GlobalFlagsSet);
+  W.printHex("CriticalSectionDefaultTimeout",
+             Conf->CriticalSectionDefaultTimeout);
+  W.printHex("DeCommitFreeBlockThreshold", Conf->DeCommitFreeBlockThreshold);
+  W.printHex("DeCommitTotalFreeThreshold", Conf->DeCommitTotalFreeThreshold);
+  W.printHex("LockPrefixTable", Conf->LockPrefixTable);
+  W.printHex("MaximumAllocationSize", Conf->MaximumAllocationSize);
+  W.printHex("VirtualMemoryThreshold", Conf->VirtualMemoryThreshold);
+  W.printHex("ProcessHeapFlags", Conf->ProcessHeapFlags);
+  W.printHex("ProcessAffinityMask", Conf->ProcessAffinityMask);
+  W.printHex("CSDVersion", Conf->CSDVersion);
+  W.printHex("DependentLoadFlags", Conf->DependentLoadFlags);
+  W.printHex("EditList", Conf->EditList);
+  W.printHex("SecurityCookie", Conf->SecurityCookie);
+
+  // Print the safe SEH table if present.
+  if (Conf->Size < offsetof(coff_load_configuration32, GuardCFCheckFunction))
+    return;
+  W.printHex("SEHandlerTable", Conf->SEHandlerTable);
+  W.printNumber("SEHandlerCount", Conf->SEHandlerCount);
+
+  Tables.SEHTableVA = Conf->SEHandlerTable;
+  Tables.SEHTableCount = Conf->SEHandlerCount;
+
+  // Print everything before CodeIntegrity. (2015)
+  if (Conf->Size < offsetof(T, CodeIntegrity))
+    return;
+  W.printHex("GuardCFCheckFunction", Conf->GuardCFCheckFunction);
+  W.printHex("GuardCFCheckDispatch", Conf->GuardCFCheckDispatch);
+  W.printHex("GuardCFFunctionTable", Conf->GuardCFFunctionTable);
+  W.printNumber("GuardCFFunctionCount", Conf->GuardCFFunctionCount);
+  W.printHex("GuardFlags", Conf->GuardFlags);
+
+  Tables.GuardFidTableVA = Conf->GuardCFFunctionTable;
+  Tables.GuardFidTableCount = Conf->GuardCFFunctionCount;
+  Tables.GuardFlags = Conf->GuardFlags;
+
+  // Print the rest. (2017)
+  if (Conf->Size < sizeof(T))
+    return;
+  W.printHex("GuardAddressTakenIatEntryTable",
+             Conf->GuardAddressTakenIatEntryTable);
+  W.printNumber("GuardAddressTakenIatEntryCount",
+                Conf->GuardAddressTakenIatEntryCount);
+  W.printHex("GuardLongJumpTargetTable", Conf->GuardLongJumpTargetTable);
+  W.printNumber("GuardLongJumpTargetCount", Conf->GuardLongJumpTargetCount);
+  W.printHex("DynamicValueRelocTable", Conf->DynamicValueRelocTable);
+  W.printHex("CHPEMetadataPointer", Conf->CHPEMetadataPointer);
+  W.printHex("GuardRFFailureRoutine", Conf->GuardRFFailureRoutine);
+  W.printHex("GuardRFFailureRoutineFunctionPointer",
+             Conf->GuardRFFailureRoutineFunctionPointer);
+  W.printHex("DynamicValueRelocTableOffset",
+             Conf->DynamicValueRelocTableOffset);
+  W.printNumber("DynamicValueRelocTableSection",
+                Conf->DynamicValueRelocTableSection);
+  W.printHex("GuardRFVerifyStackPointerFunctionPointer",
+             Conf->GuardRFVerifyStackPointerFunctionPointer);
+  W.printHex("HotPatchTableOffset", Conf->HotPatchTableOffset);
+}
+
 void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
   W.printHex("BaseOfData", Hdr->BaseOfData);
 }
index 48f825c527c16a73ee6a101713befbe3e91e0b5e..43883c2d21766b39f1694849680533b2b51b1827 100644 (file)
@@ -68,6 +68,7 @@ public:
   virtual void printCOFFBaseReloc() { }
   virtual void printCOFFDebugDirectory() { }
   virtual void printCOFFResources() {}
+  virtual void printCOFFLoadConfig() { }
   virtual void printCodeViewDebugInfo() { }
   virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
                                   llvm::codeview::TypeTableBuilder &CVTypes) {}
index cd7244a8f9707a05e75db21b9e92e8e8762276b8..51991a3f067ba7de763493858e1a48a2f65d160e 100644 (file)
@@ -218,6 +218,11 @@ namespace opts {
   cl::opt<bool> COFFResources("coff-resources",
                               cl::desc("Display the PE/COFF .rsrc section"));
 
+  // -coff-load-config
+  cl::opt<bool>
+  COFFLoadConfig("coff-load-config",
+                 cl::desc("Display the PE/COFF load config"));
+
   // -macho-data-in-code
   cl::opt<bool>
   MachODataInCode("macho-data-in-code",
@@ -444,6 +449,8 @@ static void dumpObject(const ObjectFile *Obj) {
       Dumper->printCOFFDebugDirectory();
     if (opts::COFFResources)
       Dumper->printCOFFResources();
+    if (opts::COFFLoadConfig)
+      Dumper->printCOFFLoadConfig();
     if (opts::CodeView)
       Dumper->printCodeViewDebugInfo();
     if (opts::CodeViewMergedTypes)