[llvm] r302399 - Update llvm-readobj -coff-resources to display tree structure.

Eric Beckmann via llvm-commits llvm-commits at lists.llvm.org
Sun May 7 19:47:08 PDT 2017


Author: ecbeckmann
Date: Sun May  7 21:47:07 2017
New Revision: 302399

URL: http://llvm.org/viewvc/llvm-project?rev=302399&view=rev
Log:
Update llvm-readobj -coff-resources to display tree structure.

Summary: Continue making updates to llvm-readobj to display resource sections.  This is necessary for testing the up and coming cvtres tool.

Reviewers: zturner

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D32609

Added:
    llvm/trunk/test/tools/llvm-readobj/Inputs/resources/cursor_small.bmp   (with props)
    llvm/trunk/test/tools/llvm-readobj/Inputs/resources/okay_small.bmp   (with props)
    llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.rc
    llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.res   (with props)
Modified:
    llvm/trunk/include/llvm/Object/COFF.h
    llvm/trunk/include/llvm/Support/COFF.h
    llvm/trunk/lib/Object/COFFObjectFile.cpp
    llvm/trunk/test/tools/llvm-readobj/resources.test
    llvm/trunk/tools/llvm-readobj/COFFDumper.cpp

Modified: llvm/trunk/include/llvm/Object/COFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/COFF.h?rev=302399&r1=302398&r2=302399&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/COFF.h (original)
+++ llvm/trunk/include/llvm/Object/COFF.h Sun May  7 21:47:07 2017
@@ -20,6 +20,7 @@
 #include "llvm/Object/Binary.h"
 #include "llvm/Object/Error.h"
 #include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/BinaryByteStream.h"
 #include "llvm/Support/COFF.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -40,6 +41,7 @@ class DelayImportDirectoryEntryRef;
 class ExportDirectoryEntryRef;
 class ImportDirectoryEntryRef;
 class ImportedSymbolRef;
+class ResourceSectionRef;
 
 using import_directory_iterator = content_iterator<ImportDirectoryEntryRef>;
 using delay_import_directory_iterator =
@@ -623,6 +625,26 @@ struct coff_base_reloc_block_entry {
   int getOffset() const { return Data & ((1 << 12) - 1); }
 };
 
+struct coff_resource_dir_entry {
+  union {
+    support::ulittle32_t NameOffset;
+    support::ulittle32_t ID;
+    uint32_t getNameOffset() const {
+      return maskTrailingOnes<uint32_t>(31) & NameOffset;
+    }
+  } Identifier;
+  union {
+    support::ulittle32_t DataEntryOffset;
+    support::ulittle32_t SubdirOffset;
+
+    bool isSubDir() const { return SubdirOffset >> 31; }
+    uint32_t value() const {
+      return maskTrailingOnes<uint32_t>(31) & SubdirOffset;
+    }
+
+  } Offset;
+};
+
 struct coff_resource_dir_table {
   support::ulittle32_t Characteristics;
   support::ulittle32_t TimeDateStamp;
@@ -1047,6 +1069,23 @@ private:
   const COFFObjectFile *OwningObject = nullptr;
 };
 
+class ResourceSectionRef {
+public:
+  ResourceSectionRef() = default;
+  explicit ResourceSectionRef(StringRef Ref) : BBS(Ref, support::little) {}
+
+  ErrorOr<StringRef> getEntryNameString(const coff_resource_dir_entry &Entry);
+  ErrorOr<const coff_resource_dir_table &>
+  getEntrySubDir(const coff_resource_dir_entry &Entry);
+  ErrorOr<const coff_resource_dir_table &> getBaseTable();
+
+private:
+  BinaryByteStream BBS;
+
+  ErrorOr<const coff_resource_dir_table &> getTableAtOffset(uint32_t Offset);
+  ErrorOr<StringRef> getDirStringAtOffset(uint32_t Offset);
+};
+
 // Corresponds to `_FPO_DATA` structure in the PE/COFF spec.
 struct FpoData {
   support::ulittle32_t Offset; // ulOffStart: Offset 1st byte of function code

Modified: llvm/trunk/include/llvm/Support/COFF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/COFF.h?rev=302399&r1=302398&r2=302399&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/COFF.h (original)
+++ llvm/trunk/include/llvm/Support/COFF.h Sun May  7 21:47:07 2017
@@ -152,6 +152,30 @@ namespace COFF {
     IMAGE_FILE_BYTES_REVERSED_HI       = 0x8000
   };
 
+  enum ResourceTypeID {
+    RID_Cursor = 1,
+    RID_Bitmap = 2,
+    RID_Icon = 3,
+    RID_Menu = 4,
+    RID_Dialog = 5,
+    RID_String = 6,
+    RID_FontDir = 7,
+    RID_Font = 8,
+    RID_Accelerator = 9,
+    RID_RCData = 10,
+    RID_MessageTable = 11,
+    RID_Group_Cursor = 12,
+    RID_Group_Icon = 14,
+    RID_Version = 16,
+    RID_DLGInclude = 17,
+    RID_PlugPlay = 19,
+    RID_VXD = 20,
+    RID_AniCursor = 21,
+    RID_AniIcon = 22,
+    RID_HTML = 23,
+    RID_Manifest = 24,
+  };
+
   struct symbol {
     char     Name[NameSize];
     uint32_t Value;

Modified: llvm/trunk/lib/Object/COFFObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/COFFObjectFile.cpp?rev=302399&r1=302398&r2=302399&view=diff
==============================================================================
--- llvm/trunk/lib/Object/COFFObjectFile.cpp (original)
+++ llvm/trunk/lib/Object/COFFObjectFile.cpp Sun May  7 21:47:07 2017
@@ -19,7 +19,9 @@
 #include "llvm/Object/COFF.h"
 #include "llvm/Object/Error.h"
 #include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/BinaryStreamReader.h"
 #include "llvm/Support/COFF.h"
+#include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -159,8 +161,7 @@ void COFFObjectFile::moveSymbolNext(Data
 Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {
   COFFSymbolRef Symb = getCOFFSymbol(Ref);
   StringRef Result;
-  std::error_code EC = getSymbolName(Symb, Result);
-  if (EC)
+  if (std::error_code EC = getSymbolName(Symb, Result))
     return errorCodeToError(EC);
   return Result;
 }
@@ -1591,3 +1592,47 @@ std::error_code BaseRelocRef::getRVA(uin
   Result = Header->PageRVA + Entry[Index].getOffset();
   return std::error_code();
 }
+
+#define RETURN_IF_ERROR(X)                                                     \
+  if (auto EC = errorToErrorCode(X))                                           \
+    return EC;
+
+ErrorOr<StringRef> ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {
+  BinaryStreamReader Reader = BinaryStreamReader(BBS);
+  Reader.setOffset(Offset);
+  uint16_t Length;
+  RETURN_IF_ERROR(Reader.readInteger(Length));
+  ArrayRef<UTF16> RawDirString;
+  // Strings are stored as 2-byte aligned unicode characters but readFixedString
+  // assumes byte string, so we double length.
+  RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));
+  std::string DirString;
+  if (!llvm::convertUTF16ToUTF8String(RawDirString, DirString))
+    return object_error::parse_failed;
+  return DirString;
+}
+
+ErrorOr<StringRef>
+ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {
+  return getDirStringAtOffset(Entry.Identifier.getNameOffset());
+}
+
+ErrorOr<const coff_resource_dir_table &>
+ResourceSectionRef::getTableAtOffset(uint32_t Offset) {
+  const coff_resource_dir_table *Table = nullptr;
+
+  BinaryStreamReader Reader(BBS);
+  Reader.setOffset(Offset);
+  RETURN_IF_ERROR(Reader.readObject(Table));
+  assert(Table != nullptr);
+  return *Table;
+}
+
+ErrorOr<const coff_resource_dir_table &>
+ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {
+  return getTableAtOffset(Entry.Offset.value());
+}
+
+ErrorOr<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {
+  return getTableAtOffset(0);
+}

Added: llvm/trunk/test/tools/llvm-readobj/Inputs/resources/cursor_small.bmp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/Inputs/resources/cursor_small.bmp?rev=302399&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-readobj/Inputs/resources/cursor_small.bmp
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-readobj/Inputs/resources/okay_small.bmp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/Inputs/resources/okay_small.bmp?rev=302399&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-readobj/Inputs/resources/okay_small.bmp
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.rc?rev=302399&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.rc (added)
+++ llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.rc Sun May  7 21:47:07 2017
@@ -0,0 +1,44 @@
+#include "windows.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+myaccelerators ACCELERATORS
+{
+	"^C", 999, VIRTKEY, ALT
+	"D", 1100, VIRTKEY, CONTROL, SHIFT
+	"^R", 444, ASCII, NOINVERT
+}
+
+cursor BITMAP "cursor_small.bmp"
+okay BITMAP "okay_small.bmp"
+
+14432 MENU
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+{
+	MENUITEM "yu", 100
+	MENUITEM "shala", 101
+	MENUITEM "kaoya", 102
+}
+
+testdialog DIALOG 10, 10, 200, 300
+STYLE WS_POPUP | WS_BORDER
+CAPTION "Test"
+{
+	CTEXT "Continue:", 1, 10, 10, 230, 14
+	PUSHBUTTON "&OK", 2, 66, 134, 161, 13
+}
+
+12 ACCELERATORS
+{
+	"X", 164, VIRTKEY, ALT
+	"H", 5678, VIRTKEY, CONTROL, SHIFT
+	"^R", 444, ASCII, NOINVERT
+}
+
+"eat" MENU
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
+{
+	MENUITEM "fish", 100
+	MENUITEM "salad", 101
+	MENUITEM "duck", 102
+}

Added: llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.res
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.res?rev=302399&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-readobj/Inputs/resources/test_resource.res
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: llvm/trunk/test/tools/llvm-readobj/resources.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/resources.test?rev=302399&r1=302398&r2=302399&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/resources.test (original)
+++ llvm/trunk/test/tools/llvm-readobj/resources.test Sun May  7 21:47:07 2017
@@ -1,19 +1,111 @@
-RUN: llvm-readobj -coff-resources %p/Inputs/zero-string-table.obj.coff-i386 \
-RUN:   | FileCheck %s -check-prefix RESOURCE
+// Check dumping of the .rsrc section(s)
+// The input was generated with the following commands, using the original Windows
+// rc.exe and cvtres.exe:
+// > rc /fo test_resource.res /nologo test_resource.rc
+// > cvtres /machine:X86 /readonly /nologo /out:test_resource.o test_resource.res
 
-RESOURCE:      Resources [
-RESOURCE-NEXT:   Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
-RESOURCE-NEXT:   .rsrc$01 Data (
-RESOURCE-NEXT:     0000: 00000000 00000000 00000000 00000100  |................|
-RESOURCE-NEXT:     0010: 06000000 18000080 00000000 00000000  |................|
-RESOURCE-NEXT:     0020: 00000000 00000100 01000000 30000080  |............0...|
-RESOURCE-NEXT:     0030: 00000000 00000000 00000000 00000100  |................|
-RESOURCE-NEXT:     0040: 09040000 48000000 00000000 2A000000  |....H.......*...|
-RESOURCE-NEXT:     0050: 00000000 00000000                    |........|
-RESOURCE-NEXT:   )
-RESOURCE-NEXT:   .rsrc$02 Data (
-RESOURCE-NEXT:     0000: 00000500 48006500 6C006C00 6F000000  |....H.e.l.l.o...|
-RESOURCE-NEXT:     0010: 00000000 00000000 00000000 00000000  |................|
-RESOURCE-NEXT:     0020: 00000000 00000000 00000000 00000000  |................|
-RESOURCE-NEXT:   )
-RESOURCE-NEXT: ]
+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 %p/Inputs/resources/test_resource.o \
+RUN:   | FileCheck %s -check-prefix TEST_RES
+
+ZERO:      Resources [
+ZERO-NEXT:   String Name Entries: 0
+ZERO-NEXT:   ID Entries: 1
+ZERO-NEXT:   Type: kRT_STRING (ID 6) [
+ZERO-NEXT:     String Name Entries: 0
+ZERO-NEXT:     ID Entries: 1
+ZERO-NEXT:     Name: (ID 1) [
+ZERO-NEXT:       String Name Entries: 0
+ZERO-NEXT:       ID Entries: 1
+ZERO-NEXT:       Language: (ID 1033) [
+ZERO-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+ZERO-NEXT:         Major Version: 0
+ZERO-NEXT:         Minor Version: 0
+ZERO-NEXT:       ]
+ZERO-NEXT:     ]
+ZERO-NEXT:   ]
+
+
+TEST_RES:	     Resources [
+TEST_RES-NEXT:   String Name Entries: 0
+TEST_RES-NEXT:   ID Entries: 4
+TEST_RES-NEXT:   Type: kRT_BITMAP (ID 2) [
+TEST_RES-NEXT:     String Name Entries: 2
+TEST_RES-NEXT:     ID Entries: 0
+TEST_RES-NEXT:     Name: CURSOR [
+TEST_RES-NEXT:       String Name Entries: 0
+TEST_RES-NEXT:       ID Entries: 1
+TEST_RES-NEXT:       Language: (ID 1033) [
+TEST_RES-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+TEST_RES-NEXT:         Major Version: 0
+TEST_RES-NEXT:         Minor Version: 0
+TEST_RES-NEXT:       ]
+TEST_RES-NEXT:     ]
+TEST_RES-NEXT:     Name: OKAY [
+TEST_RES-NEXT:       String Name Entries: 0
+TEST_RES-NEXT:       ID Entries: 1
+TEST_RES-NEXT:       Language: (ID 1033) [
+TEST_RES-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+TEST_RES-NEXT:         Major Version: 0
+TEST_RES-NEXT:         Minor Version: 0
+TEST_RES-NEXT:       ]
+TEST_RES-NEXT:     ]
+TEST_RES-NEXT:   ]
+TEST_RES-NEXT:   Type: kRT_MENU (ID 4) [
+TEST_RES-NEXT:     String Name Entries: 1
+TEST_RES-NEXT:     ID Entries: 1
+TEST_RES-NEXT:     Name: "EAT" [
+TEST_RES-NEXT:       String Name Entries: 0
+TEST_RES-NEXT:       ID Entries: 1
+TEST_RES-NEXT:       Language: (ID 3081) [
+TEST_RES-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+TEST_RES-NEXT:         Major Version: 0
+TEST_RES-NEXT:         Minor Version: 0
+TEST_RES-NEXT:       ]
+TEST_RES-NEXT:     ]
+TEST_RES-NEXT:     Name: (ID 14432) [
+TEST_RES-NEXT:       String Name Entries: 0
+TEST_RES-NEXT:       ID Entries: 1
+TEST_RES-NEXT:       Language: (ID 2052) [
+TEST_RES-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+TEST_RES-NEXT:         Major Version: 0
+TEST_RES-NEXT:         Minor Version: 0
+TEST_RES-NEXT:       ]
+TEST_RES-NEXT:     ]
+TEST_RES-NEXT:   ]
+TEST_RES-NEXT:   Type: kRT_DIALOG (ID 5) [
+TEST_RES-NEXT:     String Name Entries: 1
+TEST_RES-NEXT:     ID Entries: 0
+TEST_RES-NEXT:     Name: TESTDIALOG [
+TEST_RES-NEXT:       String Name Entries: 0
+TEST_RES-NEXT:       ID Entries: 1
+TEST_RES-NEXT:       Language: (ID 1033) [
+TEST_RES-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+TEST_RES-NEXT:         Major Version: 0
+TEST_RES-NEXT:         Minor Version: 0
+TEST_RES-NEXT:       ]
+TEST_RES-NEXT:     ]
+TEST_RES-NEXT:   ]
+TEST_RES-NEXT:   Type: kRT_ACCELERATOR (ID 9) [
+TEST_RES-NEXT:     String Name Entries: 1
+TEST_RES-NEXT:     ID Entries: 1
+TEST_RES-NEXT:     Name: MYACCELERATORS [
+TEST_RES-NEXT:       String Name Entries: 0
+TEST_RES-NEXT:       ID Entries: 1
+TEST_RES-NEXT:       Language: (ID 1033) [
+TEST_RES-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+TEST_RES-NEXT:         Major Version: 0
+TEST_RES-NEXT:         Minor Version: 0
+TEST_RES-NEXT:       ]
+TEST_RES-NEXT:     ]
+TEST_RES-NEXT:     Name: (ID 12) [
+TEST_RES-NEXT:       String Name Entries: 0
+TEST_RES-NEXT:       ID Entries: 1
+TEST_RES-NEXT:       Language: (ID 1033) [
+TEST_RES-NEXT:         Time/Date Stamp: 1970-01-01 00:00:00 (0x0)
+TEST_RES-NEXT:         Major Version: 0
+TEST_RES-NEXT:         Minor Version: 0
+TEST_RES-NEXT:       ]
+TEST_RES-NEXT:     ]
+TEST_RES-NEXT:   ]

Modified: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=302399&r1=302398&r2=302399&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Sun May  7 21:47:07 2017
@@ -121,6 +121,10 @@ private:
                            uint32_t RelocOffset, uint32_t Offset,
                            StringRef *RelocSym = nullptr);
 
+  void printResourceDirectoryTable(ResourceSectionRef RSF,
+                                   const coff_resource_dir_table &Table,
+                                   StringRef Level);
+
   void printBinaryBlockWithRelocs(StringRef Label, const SectionRef &Sec,
                                   StringRef SectionContents, StringRef Block);
 
@@ -140,6 +144,9 @@ private:
   void printDelayImportedSymbols(
       const DelayImportDirectoryEntryRef &I,
       iterator_range<imported_symbol_iterator> Range);
+  ErrorOr<const coff_resource_dir_entry &>
+  getResourceDirectoryTableEntry(const coff_resource_dir_table &Table,
+                                 uint32_t Index);
 
   typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
 
@@ -534,6 +541,29 @@ static const EnumEntry<uint8_t> FileChec
   LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
 };
 
+static const EnumEntry<COFF::ResourceTypeID> ResourceTypeNames[]{
+    {"kRT_CURSOR (ID 1)", COFF::RID_Cursor},
+    {"kRT_BITMAP (ID 2)", COFF::RID_Bitmap},
+    {"kRT_ICON (ID 3)", COFF::RID_Icon},
+    {"kRT_MENU (ID 4)", COFF::RID_Menu},
+    {"kRT_DIALOG (ID 5)", COFF::RID_Dialog},
+    {"kRT_STRING (ID 6)", COFF::RID_String},
+    {"kRT_FONTDIR (ID 7)", COFF::RID_FontDir},
+    {"kRT_FONT (ID 8)", COFF::RID_Font},
+    {"kRT_ACCELERATOR (ID 9)", COFF::RID_Accelerator},
+    {"kRT_RCDATA (ID 10)", COFF::RID_RCData},
+    {"kRT_MESSAGETABLE (ID 11)", COFF::RID_MessageTable},
+    {"kRT_GROUP_CURSOR (ID 12)", COFF::RID_Group_Cursor},
+    {"kRT_GROUP_ICON (ID 14)", COFF::RID_Group_Icon},
+    {"kRT_VERSION (ID 16)", COFF::RID_Version},
+    {"kRT_DLGINCLUDE (ID 17)", COFF::RID_DLGInclude},
+    {"kRT_PLUGPLAY (ID 19)", COFF::RID_PlugPlay},
+    {"kRT_VXD (ID 20)", COFF::RID_VXD},
+    {"kRT_ANICURSOR (ID 21)", COFF::RID_AniCursor},
+    {"kRT_ANIICON (ID 22)", COFF::RID_AniIcon},
+    {"kRT_HTML (ID 23)", COFF::RID_HTML},
+    {"kRT_MANIFEST (ID 24)", COFF::RID_Manifest}};
+
 template <typename T>
 static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
                                         COFFSymbolRef Symbol,
@@ -1503,18 +1533,73 @@ void COFFDumper::printCOFFResources() {
     error(S.getContents(Ref));
 
     if ((Name == ".rsrc") || (Name == ".rsrc$01")) {
-      auto Table =
-          reinterpret_cast<const coff_resource_dir_table *>(Ref.data());
-      char FormattedTime[20];
-      time_t TDS = time_t(Table->TimeDateStamp);
-      strftime(FormattedTime, sizeof(FormattedTime), "%Y-%m-%d %H:%M:%S",
-               gmtime(&TDS));
-      W.printHex("Time/Date Stamp", FormattedTime, Table->TimeDateStamp);
+      ResourceSectionRef RSF(Ref);
+      auto &BaseTable = unwrapOrError(RSF.getBaseTable());
+      printResourceDirectoryTable(RSF, BaseTable, "Type");
+    }
+    if (opts::SectionData)
+      W.printBinaryBlock(Name.str() + " Data", Ref);
+  }
+}
+
+void COFFDumper::printResourceDirectoryTable(
+    ResourceSectionRef RSF, const coff_resource_dir_table &Table,
+    StringRef Level) {
+  W.printNumber("String Name Entries", Table.NumberOfNameEntries);
+  W.printNumber("ID Entries", Table.NumberOfIDEntries);
+
+  char FormattedTime[20] = {};
+  time_t TDS = time_t(Table.TimeDateStamp);
+  strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+
+  // Iterate through level in resource directory tree.
+  for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
+       i++) {
+    auto Entry = unwrapOrError(getResourceDirectoryTableEntry(Table, i));
+    StringRef Name;
+    SmallString<20> IDStr;
+    raw_svector_ostream OS(IDStr);
+    if (i < Table.NumberOfNameEntries) {
+      StringRef EntryNameString = unwrapOrError(RSF.getEntryNameString(Entry));
+      OS << ": ";
+      OS << EntryNameString.str();
+    } else {
+      if (Level == "Type") {
+        ScopedPrinter Printer(OS);
+        Printer.printEnum("", Entry.Identifier.ID,
+                          makeArrayRef(ResourceTypeNames));
+        IDStr = IDStr.slice(0, IDStr.find_first_of(")", 0) + 1);
+      } else {
+        OS << ": (ID " << Entry.Identifier.ID << ")";
+      }
+    }
+    Name = StringRef(IDStr);
+    ListScope ResourceType(W, Level.str() + Name.str());
+    if (Entry.Offset.isSubDir()) {
+      StringRef NextLevel;
+      if (Level == "Name")
+        NextLevel = "Language";
+      else
+        NextLevel = "Name";
+      auto &NextTable = unwrapOrError(RSF.getEntrySubDir(Entry));
+      printResourceDirectoryTable(RSF, NextTable, NextLevel);
+    } else {
+      W.printHex("Time/Date Stamp", FormattedTime, Table.TimeDateStamp);
+      W.printNumber("Major Version", Table.MajorVersion);
+      W.printNumber("Minor Version", Table.MinorVersion);
     }
-    W.printBinaryBlock(Name.str() + " Data", Ref);
   }
 }
 
+ErrorOr<const coff_resource_dir_entry &>
+COFFDumper::getResourceDirectoryTableEntry(const coff_resource_dir_table &Table,
+                                           uint32_t Index) {
+  if (Index >= Table.NumberOfNameEntries + Table.NumberOfIDEntries)
+    return object_error::parse_failed;
+  auto TablePtr = reinterpret_cast<const coff_resource_dir_entry *>(&Table + 1);
+  return TablePtr[Index];
+}
+
 void COFFDumper::printStackMap() const {
   object::SectionRef StackMapSection;
   for (auto Sec : Obj->sections()) {




More information about the llvm-commits mailing list