]> granicus.if.org Git - llvm/commitdiff
[COFF] Add a ResourceSectionRef method for getting resource contents
authorMartin Storsjo <martin@martin.st>
Fri, 30 Aug 2019 06:55:49 +0000 (06:55 +0000)
committerMartin Storsjo <martin@martin.st>
Fri, 30 Aug 2019 06:55:49 +0000 (06:55 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@370433 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/COFF.h
lib/Object/COFFObjectFile.cpp
test/tools/llvm-cvtres/combined.test
test/tools/llvm-cvtres/object.test
test/tools/llvm-readobj/coff-resources.test
tools/llvm-readobj/COFFDumper.cpp

index 9f2cd6d34cbd700439bc7716fadc93f8b318117d..a7427cd097243eb8780906b04cbfd8ebdd5db356 100644 (file)
@@ -1204,6 +1204,9 @@ public:
   ResourceSectionRef() = default;
   explicit ResourceSectionRef(StringRef Ref) : BBS(Ref, support::little) {}
 
+  Error load(const COFFObjectFile *O);
+  Error load(const COFFObjectFile *O, const SectionRef &S);
+
   Expected<ArrayRef<UTF16>>
   getEntryNameString(const coff_resource_dir_entry &Entry);
   Expected<const coff_resource_dir_table &>
@@ -1214,9 +1217,16 @@ public:
   Expected<const coff_resource_dir_entry &>
   getTableEntry(const coff_resource_dir_table &Table, uint32_t Index);
 
+  Expected<StringRef> getContents(const coff_resource_data_entry &Entry);
+
 private:
   BinaryByteStream BBS;
 
+  SectionRef Section;
+  const COFFObjectFile *Obj;
+
+  std::vector<const coff_relocation *> Relocs;
+
   Expected<const coff_resource_dir_table &> getTableAtOffset(uint32_t Offset);
   Expected<const coff_resource_dir_entry &>
   getTableEntryAtOffset(uint32_t Offset);
index 16d418a19fd26ae84ee8c3cdd18bc694f8883084..2c0f6dc2b1e9b3ec05be2d54f30304c71f79dcac 100644 (file)
@@ -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");
+  }
+}
index 8d01ea2ab2c3bcf9e49b7b6ca963cdbad224c68c..7efdfc4f14da024d0ae64adc444a7c8eed3fa2d4 100644 (file)
@@ -34,6 +34,8 @@ CHECK-NEXT:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 CHECK-NEXT:          DataSize: 66
 CHECK-NEXT:          Codepage: 0
 CHECK-NEXT:          Reserved: 0
+CHECK-NEXT:          Data (
+CHECK:               )
 CHECK-NEXT:        ]
 CHECK-NEXT:      ]
 CHECK-NEXT:    ]
index 42b2206dcd916f69994f25be103874ea6a5b6865..2c6eeeb2fda35b72ac7fbd7bf14f88999e6cbb18 100644 (file)
@@ -33,6 +33,8 @@ CHECK-NEXT:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 CHECK-NEXT:          DataSize: 24
 CHECK-NEXT:          Codepage: 0
 CHECK-NEXT:          Reserved: 0
+CHECK-NEXT:          Data (
+CHECK:               )
 CHECK-NEXT:        ]
 CHECK-NEXT:      ]
 CHECK-NEXT:    ]
index dee4a720d95020eab62d00185424cb6228868824..0d91755a668704f975780e3473693bb88d5539e5 100644 (file)
@@ -33,6 +33,11 @@ ZERO-NEXT:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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:          DataRVA: 0x0
 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 23c6dd03c663a72a2f078a8edf614bff99099342..9b2c6adb9d93042f86b2064c70d8074275288213 100644 (file)
@@ -1766,7 +1766,10 @@ void COFFDumper::printCOFFResources() {
     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 @@ void COFFDumper::printResourceDirectoryTable(
       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);
     }
   }
 }