Index: llvm/include/llvm/Object/COFF.h =================================================================== --- llvm/include/llvm/Object/COFF.h +++ llvm/include/llvm/Object/COFF.h @@ -1204,6 +1204,9 @@ ResourceSectionRef() = default; explicit ResourceSectionRef(StringRef Ref) : BBS(Ref, support::little) {} + Error load(const COFFObjectFile *O); + Error load(const COFFObjectFile *O, const SectionRef &S); + Expected> getEntryNameString(const coff_resource_dir_entry &Entry); Expected @@ -1214,9 +1217,16 @@ Expected getTableEntry(const coff_resource_dir_table &Table, uint32_t Index); + Expected getContents(const coff_resource_data_entry &Entry); + private: BinaryByteStream BBS; + SectionRef Section; + const COFFObjectFile *Obj; + + std::vector Relocs; + Expected getTableAtOffset(uint32_t Offset); Expected getTableEntryAtOffset(uint32_t Offset); Index: llvm/lib/Object/COFFObjectFile.cpp =================================================================== --- llvm/lib/Object/COFFObjectFile.cpp +++ llvm/lib/Object/COFFObjectFile.cpp @@ -1744,3 +1744,120 @@ return getTableEntryAtOffset(TableOffset + sizeof(Table) + Index * sizeof(coff_resource_dir_entry)); } + +Error ResourceSectionRef::load(const COFFObjectFile *O) { + for (const SectionRef &S : O->sections()) { + Expected Name = S.getName(); + if (!Name) + return Name.takeError(); + + if (*Name == ".rsrc" || *Name == ".rsrc$01") + return load(O, S); + } + return createStringError(object_error::parse_failed, + "no resource section found"); +} + +Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) { + Obj = O; + Section = S; + Expected Contents = Section.getContents(); + if (!Contents) + return Contents.takeError(); + BBS = BinaryByteStream(*Contents, support::little); + const coff_section *COFFSect = Obj->getCOFFSection(Section); + ArrayRef OrigRelocs = Obj->getRelocations(COFFSect); + Relocs.reserve(OrigRelocs.size()); + for (const coff_relocation &R : OrigRelocs) + Relocs.push_back(&R); + std::sort(Relocs.begin(), Relocs.end(), + [](const coff_relocation *A, const coff_relocation *B) { + return A->VirtualAddress < B->VirtualAddress; + }); + return Error::success(); +} + +Expected +ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) { + if (!Obj) + return createStringError(object_error::parse_failed, "no object provided"); + + // Find a potential relocation at the DataRVA field (first member of + // the coff_resource_data_entry struct). + const uint8_t *EntryPtr = reinterpret_cast(&Entry); + ptrdiff_t EntryOffset = EntryPtr - BBS.data().data(); + coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0), + ulittle16_t(0)}; + auto RelocsForOffset = + std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget, + [](const coff_relocation *A, const coff_relocation *B) { + return A->VirtualAddress < B->VirtualAddress; + }); + + if (RelocsForOffset.first != RelocsForOffset.second) { + // We found a relocation with the right offset. Check that it does have + // the expected type. + const coff_relocation &R = **RelocsForOffset.first; + uint16_t RVAReloc; + switch (Obj->getMachine()) { + case COFF::IMAGE_FILE_MACHINE_I386: + RVAReloc = COFF::IMAGE_REL_I386_DIR32NB; + break; + case COFF::IMAGE_FILE_MACHINE_AMD64: + RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB; + break; + case COFF::IMAGE_FILE_MACHINE_ARMNT: + RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB; + break; + case COFF::IMAGE_FILE_MACHINE_ARM64: + RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB; + break; + default: + return createStringError(object_error::parse_failed, + "unsupported architecture"); + } + if (R.Type != RVAReloc) + return createStringError(object_error::parse_failed, + "unexpected relocation type"); + // Get the relocation's symbol + Expected Sym = Obj->getSymbol(R.SymbolTableIndex); + if (!Sym) + return Sym.takeError(); + const coff_section *Section = nullptr; + // And the symbol's section + if (std::error_code EC = Obj->getSection(Sym->getSectionNumber(), Section)) + return errorCodeToError(EC); + // Add the initial value of DataRVA to the symbol's offset to find the + // data it points at. + uint64_t Offset = Entry.DataRVA + Sym->getValue(); + ArrayRef Contents; + if (Error E = Obj->getSectionContents(Section, Contents)) + return std::move(E); + if (Offset + Entry.DataSize > Contents.size()) + return createStringError(object_error::parse_failed, + "data outside of section"); + // Return a reference to the data inside the section. + return StringRef(reinterpret_cast(Contents.data()) + Offset, + Entry.DataSize); + } else { + // Relocatable objects need a relocation for the DataRVA field. + if (Obj->isRelocatableObject()) + return createStringError(object_error::parse_failed, + "no relocation found for DataRVA"); + + // Locate the section that contains the address that DataRVA points at. + uint64_t VA = Entry.DataRVA + Obj->getImageBase(); + for (const SectionRef &S : Obj->sections()) { + if (VA >= S.getAddress() && + VA + Entry.DataSize <= S.getAddress() + S.getSize()) { + uint64_t Offset = VA - S.getAddress(); + Expected Contents = S.getContents(); + if (!Contents) + return Contents.takeError(); + return Contents->slice(Offset, Offset + Entry.DataSize); + } + } + return createStringError(object_error::parse_failed, + "address not found in image"); + } +} Index: llvm/test/tools/llvm-cvtres/combined.test =================================================================== --- llvm/test/tools/llvm-cvtres/combined.test +++ llvm/test/tools/llvm-cvtres/combined.test @@ -34,6 +34,8 @@ CHECK-NEXT: DataSize: 57 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -57,6 +59,8 @@ CHECK-NEXT: DataSize: 808 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -75,6 +79,8 @@ CHECK-NEXT: DataSize: 808 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -98,6 +104,8 @@ CHECK-NEXT: DataSize: 48 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -116,6 +124,8 @@ CHECK-NEXT: DataSize: 46 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -139,6 +149,8 @@ CHECK-NEXT: DataSize: 108 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -162,6 +174,8 @@ CHECK-NEXT: DataSize: 24 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: Language: (ID 2052) [ @@ -175,6 +189,8 @@ CHECK-NEXT: DataSize: 24 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -193,6 +209,8 @@ CHECK-NEXT: DataSize: 24 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -216,6 +234,8 @@ CHECK-NEXT: DataSize: 54 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: Language: (ID 2052) [ @@ -229,6 +249,8 @@ CHECK-NEXT: DataSize: 67 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: Language: (ID 4103) [ @@ -242,6 +264,8 @@ CHECK-NEXT: DataSize: 66 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] Index: llvm/test/tools/llvm-cvtres/object.test =================================================================== --- llvm/test/tools/llvm-cvtres/object.test +++ llvm/test/tools/llvm-cvtres/object.test @@ -33,6 +33,8 @@ CHECK-NEXT: DataSize: 57 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -56,6 +58,8 @@ CHECK-NEXT: DataSize: 808 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -74,6 +78,8 @@ CHECK-NEXT: DataSize: 808 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -97,6 +103,8 @@ CHECK-NEXT: DataSize: 48 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -115,6 +123,8 @@ CHECK-NEXT: DataSize: 46 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -138,6 +148,8 @@ CHECK-NEXT: DataSize: 108 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -161,6 +173,8 @@ CHECK-NEXT: DataSize: 24 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] @@ -179,6 +193,8 @@ CHECK-NEXT: DataSize: 24 CHECK-NEXT: Codepage: 0 CHECK-NEXT: Reserved: 0 +CHECK-NEXT: Data ( +CHECK: ) CHECK-NEXT: ] CHECK-NEXT: ] CHECK-NEXT: ] Index: llvm/test/tools/llvm-readobj/coff-resources.test =================================================================== --- llvm/test/tools/llvm-readobj/coff-resources.test +++ llvm/test/tools/llvm-readobj/coff-resources.test @@ -33,6 +33,11 @@ ZERO-NEXT: DataSize: 42 ZERO-NEXT: Codepage: 0 ZERO-NEXT: Reserved: 0 +ZERO-NEXT: Data ( +ZERO-NEXT: 0000: 00000500 48006500 6C006C00 6F000000 |....H.e.l.l.o...| +ZERO-NEXT: 0010: 00000000 00000000 00000000 00000000 |................| +ZERO-NEXT: 0020: 00000000 00000000 0000 |..........| +ZERO-NEXT: ) ZERO-NEXT: ] ZERO-NEXT: ] ZERO-NEXT: ] @@ -62,6 +67,8 @@ TEST_RES-NEXT: DataSize: 808 TEST_RES-NEXT: Codepage: 0 TEST_RES-NEXT: Reserved: 0 +TEST_RES-NEXT: Data ( +TEST_RES: ) TEST_RES-NEXT: ] TEST_RES-NEXT: ] TEST_RES-NEXT: ] @@ -80,6 +87,8 @@ TEST_RES-NEXT: DataSize: 808 TEST_RES-NEXT: Codepage: 0 TEST_RES-NEXT: Reserved: 0 +TEST_RES-NEXT: Data ( +TEST_RES: ) TEST_RES-NEXT: ] TEST_RES-NEXT: ] TEST_RES-NEXT: ] @@ -103,6 +112,8 @@ TEST_RES-NEXT: DataSize: 48 TEST_RES-NEXT: Codepage: 0 TEST_RES-NEXT: Reserved: 0 +TEST_RES-NEXT: Data ( +TEST_RES: ) TEST_RES-NEXT: ] TEST_RES-NEXT: ] TEST_RES-NEXT: ] @@ -121,6 +132,8 @@ TEST_RES-NEXT: DataSize: 46 TEST_RES-NEXT: Codepage: 0 TEST_RES-NEXT: Reserved: 0 +TEST_RES-NEXT: Data ( +TEST_RES: ) TEST_RES-NEXT: ] TEST_RES-NEXT: ] TEST_RES-NEXT: ] @@ -144,6 +157,8 @@ TEST_RES-NEXT: DataSize: 108 TEST_RES-NEXT: Codepage: 0 TEST_RES-NEXT: Reserved: 0 +TEST_RES-NEXT: Data ( +TEST_RES: ) TEST_RES-NEXT: ] TEST_RES-NEXT: ] TEST_RES-NEXT: ] @@ -167,6 +182,8 @@ TEST_RES-NEXT: DataSize: 24 TEST_RES-NEXT: Codepage: 0 TEST_RES-NEXT: Reserved: 0 +TEST_RES-NEXT: Data ( +TEST_RES: ) TEST_RES-NEXT: ] TEST_RES-NEXT: ] TEST_RES-NEXT: ] @@ -185,6 +202,8 @@ TEST_RES-NEXT: DataSize: 24 TEST_RES-NEXT: Codepage: 0 TEST_RES-NEXT: Reserved: 0 +TEST_RES-NEXT: Data ( +TEST_RES: ) TEST_RES-NEXT: ] TEST_RES-NEXT: ] TEST_RES-NEXT: ] Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -1766,7 +1766,10 @@ StringRef Ref = unwrapOrError(Obj->getFileName(), S.getContents()); if ((Name == ".rsrc") || (Name == ".rsrc$01")) { - ResourceSectionRef RSF(Ref); + ResourceSectionRef RSF; + Error E = RSF.load(Obj, S); + if (E) + reportError(std::move(E), Obj->getFileName()); auto &BaseTable = unwrapOrError(Obj->getFileName(), RSF.getBaseTable()); W.printNumber("Total Number of Resources", countTotalTableEntries(RSF, BaseTable, "Type")); @@ -1871,6 +1874,9 @@ 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); } } }