From efef15a0c784839d179727afadc7352435e94a6c Mon Sep 17 00:00:00 2001 From: Eric Beckmann Date: Mon, 8 May 2017 02:47:07 +0000 Subject: [PATCH] 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 llvm-svn: 302399 --- llvm/include/llvm/Object/COFF.h | 39 +++++++ llvm/include/llvm/Support/COFF.h | 24 ++++ llvm/lib/Object/COFFObjectFile.cpp | 49 +++++++- .../llvm-readobj/Inputs/resources/cursor_small.bmp | Bin 0 -> 822 bytes .../llvm-readobj/Inputs/resources/okay_small.bmp | Bin 0 -> 822 bytes .../llvm-readobj/Inputs/resources/test_resource.rc | 44 +++++++ .../Inputs/resources/test_resource.res | Bin 0 -> 2200 bytes llvm/test/tools/llvm-readobj/resources.test | 128 ++++++++++++++++++--- llvm/tools/llvm-readobj/COFFDumper.cpp | 101 ++++++++++++++-- 9 files changed, 357 insertions(+), 28 deletions(-) create mode 100644 llvm/test/tools/llvm-readobj/Inputs/resources/cursor_small.bmp create mode 100644 llvm/test/tools/llvm-readobj/Inputs/resources/okay_small.bmp create mode 100644 llvm/test/tools/llvm-readobj/Inputs/resources/test_resource.rc create mode 100644 llvm/test/tools/llvm-readobj/Inputs/resources/test_resource.res diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h index 1b6aaf4..94fc103 100644 --- a/llvm/include/llvm/Object/COFF.h +++ b/llvm/include/llvm/Object/COFF.h @@ -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; 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(31) & NameOffset; + } + } Identifier; + union { + support::ulittle32_t DataEntryOffset; + support::ulittle32_t SubdirOffset; + + bool isSubDir() const { return SubdirOffset >> 31; } + uint32_t value() const { + return maskTrailingOnes(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 getEntryNameString(const coff_resource_dir_entry &Entry); + ErrorOr + getEntrySubDir(const coff_resource_dir_entry &Entry); + ErrorOr getBaseTable(); + +private: + BinaryByteStream BBS; + + ErrorOr getTableAtOffset(uint32_t Offset); + ErrorOr 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 diff --git a/llvm/include/llvm/Support/COFF.h b/llvm/include/llvm/Support/COFF.h index 8d2a2ac..bc2098e 100644 --- a/llvm/include/llvm/Support/COFF.h +++ b/llvm/include/llvm/Support/COFF.h @@ -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; diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp index 1866aba..39762e1 100644 --- a/llvm/lib/Object/COFFObjectFile.cpp +++ b/llvm/lib/Object/COFFObjectFile.cpp @@ -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(DataRefImpl &Ref) const { Expected 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(uint32_t &Result) const { Result = Header->PageRVA + Entry[Index].getOffset(); return std::error_code(); } + +#define RETURN_IF_ERROR(X) \ + if (auto EC = errorToErrorCode(X)) \ + return EC; + +ErrorOr ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) { + BinaryStreamReader Reader = BinaryStreamReader(BBS); + Reader.setOffset(Offset); + uint16_t Length; + RETURN_IF_ERROR(Reader.readInteger(Length)); + ArrayRef 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 +ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) { + return getDirStringAtOffset(Entry.Identifier.getNameOffset()); +} + +ErrorOr +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 +ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) { + return getTableAtOffset(Entry.Offset.value()); +} + +ErrorOr ResourceSectionRef::getBaseTable() { + return getTableAtOffset(0); +} diff --git a/llvm/test/tools/llvm-readobj/Inputs/resources/cursor_small.bmp b/llvm/test/tools/llvm-readobj/Inputs/resources/cursor_small.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ce513261bc2c223d317d9fded11bec5c3b9e725b GIT binary patch literal 822 zcmc)F!HR-V6b4|2*$=avN0=w*0cJmsBP6IHM(DyoB6LyVLI{O$WfGwvSO{+1L_~{F zibT{v1eY_1?yO?Q+RcR{c+U49y&s>gXY6`f@O+1Q{i!GH?b^p+?!BNw4GjDGkJIUN zNRn)~+c=Ild|#3zG-X*<*Y*8=PY^^yWHcJdvJ4T9;{aQhMNw44enn9rG8hbIvsqb| z-ENm*mUO&wkH=vc7DXY7q96#!Ly)HFo2;g3u=aF1#c@0w4w2`1zSryBNc4(+ zBZ{KK;cz~mkH_P3x$O7*zhY>brV0C#BmtbJ>3Y4MOeTL}=r0zFs;aUq%kw-4g6VYH zfMI0Yc3sz(%LVRh7)CROsq4DnH=E6TKEI0rc%HZ0?HtE>1cUK?f3;dYh=IW!@8WN7 CMZZ4) literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/Inputs/resources/okay_small.bmp b/llvm/test/tools/llvm-readobj/Inputs/resources/okay_small.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e4005bf5ef97c42f4f43c8ea816aa948b0498260 GIT binary patch literal 822 zcmZ?rHDhJ~12Z700mK4O%*Y@C7H0s;AK`;whyVk_|6v3cJYLDTSpp3uUdYGgMW9NC z>&7y-J#YVfH2eK}ARCB)g80< zzyJRYeYb>w`nNL}V5t53`G5ca6HxzU7XuQS^ZN+_^}la3pdvi#=RaBjltn{$!V_1x H4Q6owcR8P# literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/Inputs/resources/test_resource.rc b/llvm/test/tools/llvm-readobj/Inputs/resources/test_resource.rc new file mode 100644 index 0000000..fd61652 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/Inputs/resources/test_resource.rc @@ -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 +} diff --git a/llvm/test/tools/llvm-readobj/Inputs/resources/test_resource.res b/llvm/test/tools/llvm-readobj/Inputs/resources/test_resource.res new file mode 100644 index 0000000000000000000000000000000000000000..c577ecc3d6333761ae52a556093568e136f97edd GIT binary patch literal 2200 zcmdUxUr1AN6vw}t3o=ryhwz~X@gaN=8Pr2WFa42{jG`RnThfZ8$cLIZ@V~P3K|w?u zG;P7cCfFWA#Y{<7_dNckcb2^ZT5$`}@JU zX8=$@l_W(u-6Q$5&Qm2R8`n{Z3%JCq6y?-gv?_3e&)dIZ^vKqwjAO_`Fbl}RWt7v~ zisSgG0gC7=mUC*E%OJ;#EGgNYqlnJDpQ?d)8w%syxr!+9?4>P#k+ z%Fp-r_baPyZEeHD!#2xyf+S;1m@9*pDQ~1u# zPK(8oMk=QA8mp_TD=RC(U@#B}OioUAcX$65rgL<3l=(L{HVAKSZqCik4Gs?O2h%?> zF%gT!LZMJN9G;(_9~v4`fw?p_H5HG?qtPh$>vFl&VXn^1%#dGLSQr}{%Lo&2yWLAm zOViWS2Z70WJf7Lv*#pAFxW|mJs3}n^lB8utUSnlerb+|q~^NUVA6{CLw({ zL>w9TuobECBK|okNg4Rq2kaWQL?8p7@L}&z;a~aRay4zJoacV$_AmQOSUm-DJ?U6e z_s)u9(&y<8i|39QVTMUIAK)1tp$bo^Kr$u{GZ{H+kHqO%rIMW2_XqnvTSdwTg@IOxm4Rg|3A>E(L*l<$rX qh1{3;M^Gq&Dcp;aNHKXg@?5IrlM*hm59P#+w8WVi`NsEoa=;HpTc=9^ literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-readobj/resources.test b/llvm/test/tools/llvm-readobj/resources.test index 46ee8b9..6e9e39d 100644 --- a/llvm/test/tools/llvm-readobj/resources.test +++ b/llvm/test/tools/llvm-readobj/resources.test @@ -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: ] diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index 3f4b6c7..64fd60e 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -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 Range); + ErrorOr + getResourceDirectoryTableEntry(const coff_resource_dir_table &Table, + uint32_t Index); typedef DenseMap > RelocMapTy; @@ -534,6 +541,29 @@ static const EnumEntry FileChecksumKindNames[] = { LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256), }; +static const EnumEntry 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 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(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 +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(&Table + 1); + return TablePtr[Index]; +} + void COFFDumper::printStackMap() const { object::SectionRef StackMapSection; for (auto Sec : Obj->sections()) { -- 2.7.4