summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Object/COFFObjectFile.cpp
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2019-08-30 06:55:49 +0000
committerMartin Storsjo <martin@martin.st>2019-08-30 06:55:49 +0000
commit9438221785b110a3371cabccd47ac9887666ea35 (patch)
tree48d8e5b4b6f4292341fa9b90e0180c39f9cf4e0d /llvm/lib/Object/COFFObjectFile.cpp
parente96892a8aa4dfb2e7cd8e416b7e427a1dd03c040 (diff)
downloadbcm5719-llvm-9438221785b110a3371cabccd47ac9887666ea35.tar.gz
bcm5719-llvm-9438221785b110a3371cabccd47ac9887666ea35.zip
[COFF] Add a ResourceSectionRef method for getting resource contents
This allows llvm-readobj to print the contents of each resource when printing resources from an object file or executable, like it already does for plain .res files. This requires providing the whole COFFObjectFile to ResourceSectionRef. This supports both object files and executables. For executables, the DataRVA field is used as is to look up the right section. For object files, ideally we would need to complete linking of them and fix up all relocations to know what the DataRVA field would end up being. In practice, the only thing that makes sense for an RVA field is an ADDR32NB relocation. Thus, find a relocation pointing at this field, verify that it has the expected type, locate the symbol it points at, look up the section the symbol points at, and read from the right offset in that section. This works both for GNU windres object files (which use one single .rsrc section, with all relocations against the base of the .rsrc section, with the original value of the DataRVA field being the offset of the data from the beginning of the .rsrc section) and cvtres object files (with two separate .rsrc$01 and .rsrc$02 sections, and one symbol per data entry, with the original pre-relocated DataRVA field being set to zero). Differential Revision: https://reviews.llvm.org/D66820 llvm-svn: 370433
Diffstat (limited to 'llvm/lib/Object/COFFObjectFile.cpp')
-rw-r--r--llvm/lib/Object/COFFObjectFile.cpp117
1 files changed, 117 insertions, 0 deletions
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index 16d418a19fd..2c0f6dc2b1e 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -1744,3 +1744,120 @@ ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,
return getTableEntryAtOffset(TableOffset + sizeof(Table) +
Index * sizeof(coff_resource_dir_entry));
}
+
+Error ResourceSectionRef::load(const COFFObjectFile *O) {
+ for (const SectionRef &S : O->sections()) {
+ Expected<StringRef> 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<StringRef> Contents = Section.getContents();
+ if (!Contents)
+ return Contents.takeError();
+ BBS = BinaryByteStream(*Contents, support::little);
+ const coff_section *COFFSect = Obj->getCOFFSection(Section);
+ ArrayRef<coff_relocation> 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<StringRef>
+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<const uint8_t *>(&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<COFFSymbolRef> 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<uint8_t> 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<const char *>(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<StringRef> 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");
+ }
+}
OpenPOWER on IntegriCloud