Index: llvm/include/llvm/Object/COFF.h =================================================================== --- llvm/include/llvm/Object/COFF.h +++ llvm/include/llvm/Object/COFF.h @@ -40,6 +40,7 @@ class ExportDirectoryEntryRef; class ImportDirectoryEntryRef; class ImportedSymbolRef; +class ResourceDirTableRef; using import_directory_iterator = content_iterator; using delay_import_directory_iterator = @@ -623,6 +624,15 @@ int getOffset() const { return Data & ((1 << 12) - 1); } }; +struct coff_resource_dir_table { + support::ulittle32_t Characteristics; + support::ulittle32_t TimeDateStamp; + support::ulittle16_t MajorVersion; + support::ulittle16_t MinorVersion; + support::ulittle16_t NumberOfNameEntries; + support::ulittle16_t NumberOfIDEntries; +}; + class COFFObjectFile : public ObjectFile { private: friend class ImportDirectoryEntryRef; @@ -1038,6 +1048,24 @@ const COFFObjectFile *OwningObject = nullptr; }; +class ResourceDirTableRef { +public: + ResourceDirTableRef() = default; + ResourceDirTableRef(const coff_resource_dir_table *Table, + const COFFObjectFile *Owner) + : Table(Table), Index(0), OwningObject(Owner) {} + + std::error_code getCharacteristics(uint32_t &Characteristics) const; + std::error_code getTimeDateStamp(uint32_t &Stamp) const; + std::error_code getNumberOfIDs(uint16_t &IDs) const; + std::error_code getNumberOfNames(uint16_t &Names) const; + +private: + const coff_resource_dir_table *Table; + uint32_t Index; + const COFFObjectFile *OwningObject = nullptr; +}; + // Corresponds to `_FPO_DATA` structure in the PE/COFF spec. struct FpoData { support::ulittle32_t Offset; // ulOffStart: Offset 1st byte of function code Index: llvm/lib/Object/COFFObjectFile.cpp =================================================================== --- llvm/lib/Object/COFFObjectFile.cpp +++ llvm/lib/Object/COFFObjectFile.cpp @@ -1591,3 +1591,24 @@ Result = Header->PageRVA + Entry[Index].getOffset(); return std::error_code(); } + +std::error_code +ResourceDirTableRef::getCharacteristics(uint32_t &Characteristics) const { + Characteristics = Table->Characteristics; + return std::error_code(); +} + +std::error_code ResourceDirTableRef::getTimeDateStamp(uint32_t &Stamp) const { + Stamp = Table->TimeDateStamp; + return std::error_code(); +} + +std::error_code ResourceDirTableRef::getNumberOfNames(uint16_t &Names) const { + Names = Table->NumberOfNameEntries; + return std::error_code(); +} + +std::error_code ResourceDirTableRef::getNumberOfIDs(uint16_t &IDs) const { + IDs = Table->NumberOfIDEntries; + return std::error_code(); +} Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -78,6 +78,7 @@ void printCOFFDirectives() override; void printCOFFBaseReloc() override; void printCOFFDebugDirectory() override; + void printCOFFResources() override; void printCodeViewDebugInfo() override; void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs, llvm::codeview::TypeTableBuilder &CVTypes) override; @@ -1527,6 +1528,35 @@ } } +void COFFDumper::printCOFFResources() { + ListScope ResourcesD(W, "Resources"); + for (const SectionRef &S : Obj->sections()) { + StringRef Name; + error(S.getName(Name)); + if ((Name != ".rsrc$01") && (Name != ".rsrc$02")) + continue; + + if (Name == ".rsrc$01") { + StringRef Ref; + error(S.getContents(Ref)); + ResourceDirTableRef Table( + reinterpret_cast(Ref.data()), Obj); + uint32_t TimeDateStamp; + error(Table.getTimeDateStamp(TimeDateStamp)); + char FormattedTime[20] = { }; + time_t TDS = time_t(TimeDateStamp); + strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); + W.printHex("Time/Date Stamp", FormattedTime, TDS); + W.printBinaryBlock(".rsrc$01 Data", Ref); + } + else { + StringRef Ref; + error(S.getContents(Ref)); + W.printBinaryBlock(".rsrc$02 Data", Ref); + } + } +} + void COFFDumper::printStackMap() const { object::SectionRef StackMapSection; for (auto Sec : Obj->sections()) { Index: llvm/tools/llvm-readobj/ObjDumper.h =================================================================== --- llvm/tools/llvm-readobj/ObjDumper.h +++ llvm/tools/llvm-readobj/ObjDumper.h @@ -67,6 +67,7 @@ virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } virtual void printCOFFDebugDirectory() { } + virtual void printCOFFResources() {} virtual void printCodeViewDebugInfo() { } virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs, llvm::codeview::TypeTableBuilder &CVTypes) {} Index: llvm/tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- llvm/tools/llvm-readobj/llvm-readobj.cpp +++ llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -214,6 +214,10 @@ COFFDebugDirectory("coff-debug-directory", cl::desc("Display the PE/COFF debug directory")); + // -coff-resources + cl::opt COFFResources("coff-resources", + cl::desc("Display the PE/COFF .rsrc section (.o file only)")); + // -macho-data-in-code cl::opt MachODataInCode("macho-data-in-code", @@ -445,6 +449,8 @@ Dumper->printCOFFBaseReloc(); if (opts::COFFDebugDirectory) Dumper->printCOFFDebugDirectory(); + if (opts::COFFResources) + Dumper->printCOFFResources(); if (opts::CodeView) Dumper->printCodeViewDebugInfo(); if (opts::CodeViewMergedTypes)