LCOV - code coverage report
Current view: top level - lib/Object - WindowsResource.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 324 329 98.5 %
Date: 2018-02-19 03:08:00 Functions: 41 41 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file implements the .res file class.
      11             : //
      12             : //===----------------------------------------------------------------------===//
      13             : 
      14             : #include "llvm/Object/WindowsResource.h"
      15             : #include "llvm/Object/COFF.h"
      16             : #include "llvm/Support/FileOutputBuffer.h"
      17             : #include "llvm/Support/FormatVariadic.h"
      18             : #include "llvm/Support/MathExtras.h"
      19             : #include <ctime>
      20             : #include <queue>
      21             : #include <system_error>
      22             : 
      23             : using namespace llvm;
      24             : using namespace object;
      25             : 
      26             : namespace llvm {
      27             : namespace object {
      28             : 
      29             : #define RETURN_IF_ERROR(X)                                                     \
      30             :   if (auto EC = X)                                                             \
      31             :     return EC;
      32             : 
      33             : const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
      34             : 
      35             : // COFF files seem to be inconsistent with alignment between sections, just use
      36             : // 8-byte because it makes everyone happy.
      37             : const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
      38             : 
      39             : uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
      40             : uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
      41             : 
      42          28 : WindowsResource::WindowsResource(MemoryBufferRef Source)
      43          28 :     : Binary(Binary::ID_WinRes, Source) {
      44             :   size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
      45          56 :   BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
      46             :                          support::little);
      47          28 : }
      48             : 
      49             : Expected<std::unique_ptr<WindowsResource>>
      50          28 : WindowsResource::createWindowsResource(MemoryBufferRef Source) {
      51          28 :   if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
      52             :     return make_error<GenericBinaryError>(
      53             :         "File too small to be a resource file",
      54             :         object_error::invalid_file_type);
      55          28 :   std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
      56             :   return std::move(Ret);
      57             : }
      58             : 
      59          33 : Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
      60          33 :   if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix))
      61             :     return make_error<EmptyResError>(".res contains no entries",
      62             :                                      object_error::unexpected_eof);
      63          66 :   return ResourceEntryRef::create(BinaryStreamRef(BBS), this);
      64             : }
      65             : 
      66          33 : ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
      67          33 :                                    const WindowsResource *Owner)
      68         165 :     : Reader(Ref) {}
      69             : 
      70             : Expected<ResourceEntryRef>
      71          33 : ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) {
      72          66 :   auto Ref = ResourceEntryRef(BSR, Owner);
      73          66 :   if (auto E = Ref.loadNext())
      74             :     return std::move(E);
      75             :   return Ref;
      76             : }
      77             : 
      78         187 : Error ResourceEntryRef::moveNext(bool &End) {
      79             :   // Reached end of all the entries.
      80         187 :   if (Reader.bytesRemaining() == 0) {
      81          33 :     End = true;
      82             :     return Error::success();
      83             :   }
      84         308 :   RETURN_IF_ERROR(loadNext());
      85             : 
      86             :   return Error::success();
      87             : }
      88             : 
      89         374 : static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
      90             :                             ArrayRef<UTF16> &Str, bool &IsString) {
      91             :   uint16_t IDFlag;
      92         748 :   RETURN_IF_ERROR(Reader.readInteger(IDFlag));
      93         374 :   IsString = IDFlag != 0xffff;
      94             : 
      95         374 :   if (IsString) {
      96         127 :     Reader.setOffset(
      97         127 :         Reader.getOffset() -
      98             :         sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
      99         254 :     RETURN_IF_ERROR(Reader.readWideString(Str));
     100             :   } else
     101         494 :     RETURN_IF_ERROR(Reader.readInteger(ID));
     102             : 
     103             :   return Error::success();
     104             : }
     105             : 
     106         187 : Error ResourceEntryRef::loadNext() {
     107             :   const WinResHeaderPrefix *Prefix;
     108         374 :   RETURN_IF_ERROR(Reader.readObject(Prefix));
     109             : 
     110         374 :   if (Prefix->HeaderSize < MIN_HEADER_SIZE)
     111             :     return make_error<GenericBinaryError>("Header size is too small.",
     112             :                                           object_error::parse_failed);
     113             : 
     114         374 :   RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
     115             : 
     116         374 :   RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
     117             : 
     118         374 :   RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
     119             : 
     120         374 :   RETURN_IF_ERROR(Reader.readObject(Suffix));
     121             : 
     122         561 :   RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
     123             : 
     124         374 :   RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
     125             : 
     126             :   return Error::success();
     127             : }
     128             : 
     129          22 : WindowsResourceParser::WindowsResourceParser() : Root(false) {}
     130             : 
     131          14 : Error WindowsResourceParser::parse(WindowsResource *WR) {
     132          28 :   auto EntryOrErr = WR->getHeadEntry();
     133          14 :   if (!EntryOrErr) {
     134             :     auto E = EntryOrErr.takeError();
     135             :     if (E.isA<EmptyResError>()) {
     136             :       // Check if the .res file contains no entries.  In this case we don't have
     137             :       // to throw an error but can rather just return without parsing anything.
     138             :       // This applies for files which have a valid PE header magic and the
     139             :       // mandatory empty null resource entry.  Files which do not fit this
     140             :       // criteria would have already been filtered out by
     141             :       // WindowsResource::createWindowsResource().
     142           0 :       consumeError(std::move(E));
     143             :       return Error::success();
     144             :     }
     145             :     return E;
     146             :   }
     147             : 
     148          14 :   ResourceEntryRef Entry = EntryOrErr.get();
     149          14 :   bool End = false;
     150          97 :   while (!End) {
     151         166 :     Data.push_back(Entry.getData());
     152             : 
     153          83 :     bool IsNewTypeString = false;
     154          83 :     bool IsNewNameString = false;
     155             : 
     156          83 :     Root.addEntry(Entry, IsNewTypeString, IsNewNameString);
     157             : 
     158          83 :     if (IsNewTypeString)
     159          18 :       StringTable.push_back(Entry.getTypeString());
     160             : 
     161          83 :     if (IsNewNameString)
     162         112 :       StringTable.push_back(Entry.getNameString());
     163             : 
     164         166 :     RETURN_IF_ERROR(Entry.moveNext(End));
     165             :   }
     166             : 
     167             :   return Error::success();
     168             : }
     169             : 
     170           4 : void WindowsResourceParser::printTree(raw_ostream &OS) const {
     171             :   ScopedPrinter Writer(OS);
     172           8 :   Root.print(Writer, "Resource Tree");
     173           4 : }
     174             : 
     175          83 : void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry,
     176             :                                                bool &IsNewTypeString,
     177             :                                                bool &IsNewNameString) {
     178          83 :   TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString);
     179          83 :   TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);
     180          83 :   NameNode.addLanguageNode(Entry);
     181          83 : }
     182             : 
     183         276 : WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
     184         138 :   if (IsStringNode)
     185          65 :     StringIndex = StringCount++;
     186         138 : }
     187             : 
     188          83 : WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
     189             :                                           uint16_t MinorVersion,
     190          83 :                                           uint32_t Characteristics)
     191             :     : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
     192         166 :       Characteristics(Characteristics) {
     193          83 :     DataIndex = DataCount++;
     194          83 : }
     195             : 
     196             : std::unique_ptr<WindowsResourceParser::TreeNode>
     197          65 : WindowsResourceParser::TreeNode::createStringNode() {
     198         130 :   return std::unique_ptr<TreeNode>(new TreeNode(true));
     199             : }
     200             : 
     201             : std::unique_ptr<WindowsResourceParser::TreeNode>
     202          62 : WindowsResourceParser::TreeNode::createIDNode() {
     203         124 :   return std::unique_ptr<TreeNode>(new TreeNode(false));
     204             : }
     205             : 
     206             : std::unique_ptr<WindowsResourceParser::TreeNode>
     207          83 : WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
     208             :                                                 uint16_t MinorVersion,
     209             :                                                 uint32_t Characteristics) {
     210             :   return std::unique_ptr<TreeNode>(
     211         166 :       new TreeNode(MajorVersion, MinorVersion, Characteristics));
     212             : }
     213             : 
     214             : WindowsResourceParser::TreeNode &
     215          83 : WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry,
     216             :                                              bool &IsNewTypeString) {
     217          83 :   if (Entry.checkTypeString())
     218           9 :     return addChild(Entry.getTypeString(), IsNewTypeString);
     219             :   else
     220          74 :     return addChild(Entry.getTypeID());
     221             : }
     222             : 
     223             : WindowsResourceParser::TreeNode &
     224          83 : WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry,
     225             :                                              bool &IsNewNameString) {
     226          83 :   if (Entry.checkNameString())
     227          62 :     return addChild(Entry.getNameString(), IsNewNameString);
     228             :   else
     229          21 :     return addChild(Entry.getNameID());
     230             : }
     231             : 
     232             : WindowsResourceParser::TreeNode &
     233          83 : WindowsResourceParser::TreeNode::addLanguageNode(
     234             :     const ResourceEntryRef &Entry) {
     235             :   return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(),
     236         332 :                   Entry.getMinorVersion(), Entry.getCharacteristics());
     237             : }
     238             : 
     239         178 : WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild(
     240             :     uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion,
     241             :     uint32_t Characteristics) {
     242             :   auto Child = IDChildren.find(ID);
     243         178 :   if (Child == IDChildren.end()) {
     244             :     auto NewChild =
     245             :         IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics)
     246         145 :                    : createIDNode();
     247             :     WindowsResourceParser::TreeNode &Node = *NewChild;
     248             :     IDChildren.emplace(ID, std::move(NewChild));
     249             :     return Node;
     250             :   } else
     251          33 :     return *(Child->second);
     252             : }
     253             : 
     254             : WindowsResourceParser::TreeNode &
     255          71 : WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef,
     256             :                                           bool &IsNewString) {
     257             :   std::string NameString;
     258             :   ArrayRef<UTF16> CorrectedName;
     259             :   std::vector<UTF16> EndianCorrectedName;
     260             :   if (sys::IsBigEndianHost) {
     261             :     EndianCorrectedName.resize(NameRef.size() + 1);
     262             :     std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1);
     263             :     EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
     264             :     CorrectedName = makeArrayRef(EndianCorrectedName);
     265             :   } else
     266          71 :     CorrectedName = NameRef;
     267          71 :   convertUTF16ToUTF8String(CorrectedName, NameString);
     268             : 
     269             :   auto Child = StringChildren.find(NameString);
     270          71 :   if (Child == StringChildren.end()) {
     271          65 :     auto NewChild = createStringNode();
     272          65 :     IsNewString = true;
     273             :     WindowsResourceParser::TreeNode &Node = *NewChild;
     274             :     StringChildren.emplace(NameString, std::move(NewChild));
     275             :     return Node;
     276             :   } else
     277           6 :     return *(Child->second);
     278             : }
     279             : 
     280          94 : void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
     281             :                                             StringRef Name) const {
     282         188 :   ListScope NodeScope(Writer, Name);
     283         123 :   for (auto const &Child : StringChildren) {
     284          29 :     Child.second->print(Writer, Child.first);
     285             :   }
     286         155 :   for (auto const &Child : IDChildren) {
     287         183 :     Child.second->print(Writer, to_string(Child.first));
     288             :   }
     289          94 : }
     290             : 
     291             : // This function returns the size of the entire resource tree, including
     292             : // directory tables, directory entries, and data entries.  It does not include
     293             : // the directory strings or the relocations of the .rsrc section.
     294         221 : uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
     295         221 :   uint32_t Size = (IDChildren.size() + StringChildren.size()) *
     296         221 :                   sizeof(coff_resource_dir_entry);
     297             : 
     298             :   // Reached a node pointing to a data entry.
     299         221 :   if (IsDataNode) {
     300          83 :     Size += sizeof(coff_resource_data_entry);
     301          83 :     return Size;
     302             :   }
     303             : 
     304             :   // If the node does not point to data, it must have a directory table pointing
     305             :   // to other nodes.
     306         138 :   Size += sizeof(coff_resource_dir_table);
     307             : 
     308         203 :   for (auto const &Child : StringChildren) {
     309          65 :     Size += Child.second->getTreeSize();
     310             :   }
     311         283 :   for (auto const &Child : IDChildren) {
     312         145 :     Size += Child.second->getTreeSize();
     313             :   }
     314             :   return Size;
     315             : }
     316             : 
     317          22 : class WindowsResourceCOFFWriter {
     318             : public:
     319             :   WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,
     320             :                             const WindowsResourceParser &Parser, Error &E);
     321             :   std::unique_ptr<MemoryBuffer> write();
     322             : 
     323             : private:
     324             :   void performFileLayout();
     325             :   void performSectionOneLayout();
     326             :   void performSectionTwoLayout();
     327             :   void writeCOFFHeader();
     328             :   void writeFirstSectionHeader();
     329             :   void writeSecondSectionHeader();
     330             :   void writeFirstSection();
     331             :   void writeSecondSection();
     332             :   void writeSymbolTable();
     333             :   void writeStringTable();
     334             :   void writeDirectoryTree();
     335             :   void writeDirectoryStringTable();
     336             :   void writeFirstSectionRelocations();
     337             :   std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
     338             :   char *BufferStart;
     339             :   uint64_t CurrentOffset = 0;
     340             :   COFF::MachineTypes MachineType;
     341             :   const WindowsResourceParser::TreeNode &Resources;
     342             :   const ArrayRef<std::vector<uint8_t>> Data;
     343             :   uint64_t FileSize;
     344             :   uint32_t SymbolTableOffset;
     345             :   uint32_t SectionOneSize;
     346             :   uint32_t SectionOneOffset;
     347             :   uint32_t SectionOneRelocations;
     348             :   uint32_t SectionTwoSize;
     349             :   uint32_t SectionTwoOffset;
     350             :   const ArrayRef<std::vector<UTF16>> StringTable;
     351             :   std::vector<uint32_t> StringTableOffsets;
     352             :   std::vector<uint32_t> DataOffsets;
     353             :   std::vector<uint32_t> RelocationAddresses;
     354             : };
     355             : 
     356          11 : WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
     357             :     COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
     358          11 :     Error &E)
     359             :     : MachineType(MachineType), Resources(Parser.getTree()),
     360          44 :       Data(Parser.getData()), StringTable(Parser.getStringTable()) {
     361          11 :   performFileLayout();
     362             : 
     363          22 :   OutputBuffer = WritableMemoryBuffer::getNewMemBuffer(FileSize);
     364          11 : }
     365             : 
     366          11 : void WindowsResourceCOFFWriter::performFileLayout() {
     367             :   // Add size of COFF header.
     368             :   FileSize = COFF::Header16Size;
     369             : 
     370             :   // one .rsrc section header for directory tree, another for resource data.
     371          11 :   FileSize += 2 * COFF::SectionSize;
     372             : 
     373          11 :   performSectionOneLayout();
     374          11 :   performSectionTwoLayout();
     375             : 
     376             :   // We have reached the address of the symbol table.
     377          11 :   SymbolTableOffset = FileSize;
     378             : 
     379          11 :   FileSize += COFF::Symbol16Size;     // size of the @feat.00 symbol.
     380          11 :   FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
     381          11 :   FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
     382          11 :   FileSize += 4; // four null bytes for the string table.
     383          11 : }
     384             : 
     385          11 : void WindowsResourceCOFFWriter::performSectionOneLayout() {
     386          11 :   SectionOneOffset = FileSize;
     387             : 
     388          11 :   SectionOneSize = Resources.getTreeSize();
     389          11 :   uint32_t CurrentStringOffset = SectionOneSize;
     390             :   uint32_t TotalStringTableSize = 0;
     391         152 :   for (auto const &String : StringTable) {
     392          65 :     StringTableOffsets.push_back(CurrentStringOffset);
     393         130 :     uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
     394          65 :     CurrentStringOffset += StringSize;
     395          65 :     TotalStringTableSize += StringSize;
     396             :   }
     397          22 :   SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
     398             : 
     399             :   // account for the relocations of section one.
     400          11 :   SectionOneRelocations = FileSize + SectionOneSize;
     401          11 :   FileSize += SectionOneSize;
     402          11 :   FileSize +=
     403          11 :       Data.size() * COFF::RelocationSize; // one relocation for each resource.
     404          11 :   FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
     405          11 : }
     406             : 
     407          11 : void WindowsResourceCOFFWriter::performSectionTwoLayout() {
     408             :   // add size of .rsrc$2 section, which contains all resource data on 8-byte
     409             :   // alignment.
     410          11 :   SectionTwoOffset = FileSize;
     411          11 :   SectionTwoSize = 0;
     412         188 :   for (auto const &Entry : Data) {
     413          83 :     DataOffsets.push_back(SectionTwoSize);
     414         166 :     SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
     415             :   }
     416          11 :   FileSize += SectionTwoSize;
     417          11 :   FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
     418          11 : }
     419             : 
     420             : static std::time_t getTime() {
     421          11 :   std::time_t Now = time(nullptr);
     422          11 :   if (Now < 0 || !isUInt<32>(Now))
     423             :     return UINT32_MAX;
     424             :   return Now;
     425             : }
     426             : 
     427          11 : std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() {
     428          11 :   BufferStart = OutputBuffer->getBufferStart();
     429             : 
     430          11 :   writeCOFFHeader();
     431          11 :   writeFirstSectionHeader();
     432          11 :   writeSecondSectionHeader();
     433          11 :   writeFirstSection();
     434          11 :   writeSecondSection();
     435          11 :   writeSymbolTable();
     436          11 :   writeStringTable();
     437             : 
     438          11 :   return std::move(OutputBuffer);
     439             : }
     440             : 
     441          11 : void WindowsResourceCOFFWriter::writeCOFFHeader() {
     442             :   // Write the COFF header.
     443          11 :   auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
     444          11 :   Header->Machine = MachineType;
     445             :   Header->NumberOfSections = 2;
     446          11 :   Header->TimeDateStamp = getTime();
     447          11 :   Header->PointerToSymbolTable = SymbolTableOffset;
     448             :   // One symbol for every resource plus 2 for each section and @feat.00
     449          11 :   Header->NumberOfSymbols = Data.size() + 5;
     450             :   Header->SizeOfOptionalHeader = 0;
     451             :   Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
     452          11 : }
     453             : 
     454          11 : void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
     455             :   // Write the first section header.
     456          11 :   CurrentOffset += sizeof(coff_file_header);
     457          11 :   auto *SectionOneHeader =
     458          11 :       reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
     459          11 :   strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize);
     460             :   SectionOneHeader->VirtualSize = 0;
     461             :   SectionOneHeader->VirtualAddress = 0;
     462          11 :   SectionOneHeader->SizeOfRawData = SectionOneSize;
     463          11 :   SectionOneHeader->PointerToRawData = SectionOneOffset;
     464          11 :   SectionOneHeader->PointerToRelocations = SectionOneRelocations;
     465             :   SectionOneHeader->PointerToLinenumbers = 0;
     466          11 :   SectionOneHeader->NumberOfRelocations = Data.size();
     467             :   SectionOneHeader->NumberOfLinenumbers = 0;
     468             :   SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
     469             :   SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
     470          11 : }
     471             : 
     472          11 : void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
     473             :   // Write the second section header.
     474          11 :   CurrentOffset += sizeof(coff_section);
     475          11 :   auto *SectionTwoHeader =
     476          11 :       reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
     477          11 :   strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize);
     478             :   SectionTwoHeader->VirtualSize = 0;
     479             :   SectionTwoHeader->VirtualAddress = 0;
     480          11 :   SectionTwoHeader->SizeOfRawData = SectionTwoSize;
     481          11 :   SectionTwoHeader->PointerToRawData = SectionTwoOffset;
     482             :   SectionTwoHeader->PointerToRelocations = 0;
     483             :   SectionTwoHeader->PointerToLinenumbers = 0;
     484             :   SectionTwoHeader->NumberOfRelocations = 0;
     485             :   SectionTwoHeader->NumberOfLinenumbers = 0;
     486             :   SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
     487             :   SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
     488          11 : }
     489             : 
     490          11 : void WindowsResourceCOFFWriter::writeFirstSection() {
     491             :   // Write section one.
     492          11 :   CurrentOffset += sizeof(coff_section);
     493             : 
     494          11 :   writeDirectoryTree();
     495          11 :   writeDirectoryStringTable();
     496          11 :   writeFirstSectionRelocations();
     497             : 
     498          22 :   CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
     499          11 : }
     500             : 
     501          11 : void WindowsResourceCOFFWriter::writeSecondSection() {
     502             :   // Now write the .rsrc$02 section.
     503         188 :   for (auto const &RawDataEntry : Data) {
     504          83 :     std::copy(RawDataEntry.begin(), RawDataEntry.end(),
     505          83 :               BufferStart + CurrentOffset);
     506         166 :     CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
     507             :   }
     508             : 
     509          22 :   CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
     510          11 : }
     511             : 
     512          11 : void WindowsResourceCOFFWriter::writeSymbolTable() {
     513             :   // Now write the symbol table.
     514             :   // First, the feat symbol.
     515          11 :   auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
     516          11 :   strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize);
     517             :   Symbol->Value = 0x11;
     518             :   Symbol->SectionNumber = 0xffff;
     519             :   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
     520          11 :   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
     521          11 :   Symbol->NumberOfAuxSymbols = 0;
     522          11 :   CurrentOffset += sizeof(coff_symbol16);
     523             : 
     524             :   // Now write the .rsrc1 symbol + aux.
     525          11 :   Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
     526          11 :   strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize);
     527             :   Symbol->Value = 0;
     528             :   Symbol->SectionNumber = 1;
     529             :   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
     530          11 :   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
     531          11 :   Symbol->NumberOfAuxSymbols = 1;
     532          11 :   CurrentOffset += sizeof(coff_symbol16);
     533          11 :   auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
     534             :                                                               CurrentOffset);
     535          11 :   Aux->Length = SectionOneSize;
     536          11 :   Aux->NumberOfRelocations = Data.size();
     537             :   Aux->NumberOfLinenumbers = 0;
     538             :   Aux->CheckSum = 0;
     539             :   Aux->NumberLowPart = 0;
     540          11 :   Aux->Selection = 0;
     541          11 :   CurrentOffset += sizeof(coff_aux_section_definition);
     542             : 
     543             :   // Now write the .rsrc2 symbol + aux.
     544          11 :   Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
     545          11 :   strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize);
     546             :   Symbol->Value = 0;
     547             :   Symbol->SectionNumber = 2;
     548             :   Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
     549          11 :   Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
     550          11 :   Symbol->NumberOfAuxSymbols = 1;
     551          11 :   CurrentOffset += sizeof(coff_symbol16);
     552          11 :   Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
     553             :                                                         CurrentOffset);
     554          11 :   Aux->Length = SectionTwoSize;
     555             :   Aux->NumberOfRelocations = 0;
     556             :   Aux->NumberOfLinenumbers = 0;
     557             :   Aux->CheckSum = 0;
     558             :   Aux->NumberLowPart = 0;
     559          11 :   Aux->Selection = 0;
     560          11 :   CurrentOffset += sizeof(coff_aux_section_definition);
     561             : 
     562             :   // Now write a symbol for each relocation.
     563         177 :   for (unsigned i = 0; i < Data.size(); i++) {
     564         249 :     auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
     565          83 :     Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
     566          83 :     memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize);
     567         166 :     Symbol->Value = DataOffsets[i];
     568             :     Symbol->SectionNumber = 2;
     569             :     Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
     570          83 :     Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
     571          83 :     Symbol->NumberOfAuxSymbols = 0;
     572          83 :     CurrentOffset += sizeof(coff_symbol16);
     573             :   }
     574          11 : }
     575             : 
     576          11 : void WindowsResourceCOFFWriter::writeStringTable() {
     577             :   // Just 4 null bytes for the string table.
     578          11 :   auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
     579          11 :   memset(COFFStringTable, 0, 4);
     580          11 : }
     581             : 
     582          11 : void WindowsResourceCOFFWriter::writeDirectoryTree() {
     583             :   // Traverse parsed resource tree breadth-first and write the corresponding
     584             :   // COFF objects.
     585             :   std::queue<const WindowsResourceParser::TreeNode *> Queue;
     586          22 :   Queue.push(&Resources);
     587             :   uint32_t NextLevelOffset =
     588          22 :       sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
     589             :                                          Resources.getIDChildren().size()) *
     590          11 :                                             sizeof(coff_resource_dir_entry);
     591             :   std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
     592             :   uint32_t CurrentRelativeOffset = 0;
     593             : 
     594         149 :   while (!Queue.empty()) {
     595         138 :     auto CurrentNode = Queue.front();
     596             :     Queue.pop();
     597         276 :     auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
     598         138 :                                                               CurrentOffset);
     599         138 :     Table->Characteristics = CurrentNode->getCharacteristics();
     600             :     Table->TimeDateStamp = 0;
     601         138 :     Table->MajorVersion = CurrentNode->getMajorVersion();
     602         138 :     Table->MinorVersion = CurrentNode->getMinorVersion();
     603             :     auto &IDChildren = CurrentNode->getIDChildren();
     604             :     auto &StringChildren = CurrentNode->getStringChildren();
     605         138 :     Table->NumberOfNameEntries = StringChildren.size();
     606         138 :     Table->NumberOfIDEntries = IDChildren.size();
     607         138 :     CurrentOffset += sizeof(coff_resource_dir_table);
     608         138 :     CurrentRelativeOffset += sizeof(coff_resource_dir_table);
     609             : 
     610             :     // Write the directory entries immediately following each directory table.
     611         203 :     for (auto const &Child : StringChildren) {
     612         130 :       auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
     613          65 :                                                                 CurrentOffset);
     614          65 :       Entry->Identifier.setNameOffset(
     615          65 :           StringTableOffsets[Child.second->getStringIndex()]);
     616          65 :       if (Child.second->checkIsDataNode()) {
     617             :         Entry->Offset.DataEntryOffset = NextLevelOffset;
     618           0 :         NextLevelOffset += sizeof(coff_resource_data_entry);
     619           0 :         DataEntriesTreeOrder.push_back(Child.second.get());
     620             :       } else {
     621          65 :         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
     622          65 :         NextLevelOffset += sizeof(coff_resource_dir_table) +
     623          65 :                            (Child.second->getStringChildren().size() +
     624             :                             Child.second->getIDChildren().size()) *
     625             :                                sizeof(coff_resource_dir_entry);
     626         130 :         Queue.push(Child.second.get());
     627             :       }
     628          65 :       CurrentOffset += sizeof(coff_resource_dir_entry);
     629          65 :       CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
     630             :     }
     631         283 :     for (auto const &Child : IDChildren) {
     632         290 :       auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
     633         145 :                                                                 CurrentOffset);
     634         145 :       Entry->Identifier.ID = Child.first;
     635         145 :       if (Child.second->checkIsDataNode()) {
     636             :         Entry->Offset.DataEntryOffset = NextLevelOffset;
     637          83 :         NextLevelOffset += sizeof(coff_resource_data_entry);
     638         166 :         DataEntriesTreeOrder.push_back(Child.second.get());
     639             :       } else {
     640          62 :         Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
     641          62 :         NextLevelOffset += sizeof(coff_resource_dir_table) +
     642          62 :                            (Child.second->getStringChildren().size() +
     643             :                             Child.second->getIDChildren().size()) *
     644             :                                sizeof(coff_resource_dir_entry);
     645         124 :         Queue.push(Child.second.get());
     646             :       }
     647         145 :       CurrentOffset += sizeof(coff_resource_dir_entry);
     648         145 :       CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
     649             :     }
     650             :   }
     651             : 
     652          11 :   RelocationAddresses.resize(Data.size());
     653             :   // Now write all the resource data entries.
     654          94 :   for (auto DataNodes : DataEntriesTreeOrder) {
     655         166 :     auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
     656          83 :                                                                CurrentOffset);
     657         166 :     RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
     658             :     Entry->DataRVA = 0; // Set to zero because it is a relocation.
     659         249 :     Entry->DataSize = Data[DataNodes->getDataIndex()].size();
     660             :     Entry->Codepage = 0;
     661             :     Entry->Reserved = 0;
     662          83 :     CurrentOffset += sizeof(coff_resource_data_entry);
     663          83 :     CurrentRelativeOffset += sizeof(coff_resource_data_entry);
     664             :   }
     665          11 : }
     666             : 
     667          11 : void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
     668             :   // Now write the directory string table for .rsrc$01
     669             :   uint32_t TotalStringTableSize = 0;
     670         152 :   for (auto &String : StringTable) {
     671          65 :     uint16_t Length = String.size();
     672          65 :     support::endian::write16le(BufferStart + CurrentOffset, Length);
     673          65 :     CurrentOffset += sizeof(uint16_t);
     674          65 :     auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
     675          65 :     std::copy(String.begin(), String.end(), Start);
     676          65 :     CurrentOffset += Length * sizeof(UTF16);
     677          65 :     TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
     678             :   }
     679          11 :   CurrentOffset +=
     680          11 :       alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
     681          11 : }
     682             : 
     683          11 : void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
     684             : 
     685             :   // Now write the relocations for .rsrc$01
     686             :   // Five symbols already in table before we start, @feat.00 and 2 for each
     687             :   // .rsrc section.
     688             :   uint32_t NextSymbolIndex = 5;
     689         177 :   for (unsigned i = 0; i < Data.size(); i++) {
     690          83 :     auto *Reloc =
     691          83 :         reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
     692         166 :     Reloc->VirtualAddress = RelocationAddresses[i];
     693          83 :     Reloc->SymbolTableIndex = NextSymbolIndex++;
     694          83 :     switch (MachineType) {
     695           8 :     case COFF::IMAGE_FILE_MACHINE_ARMNT:
     696             :       Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
     697             :       break;
     698          59 :     case COFF::IMAGE_FILE_MACHINE_AMD64:
     699             :       Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
     700             :       break;
     701           8 :     case COFF::IMAGE_FILE_MACHINE_I386:
     702             :       Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
     703             :       break;
     704           8 :     case COFF::IMAGE_FILE_MACHINE_ARM64:
     705             :       Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
     706             :       break;
     707           0 :     default:
     708           0 :       llvm_unreachable("unknown machine type");
     709             :     }
     710          83 :     CurrentOffset += sizeof(coff_relocation);
     711             :   }
     712          11 : }
     713             : 
     714             : Expected<std::unique_ptr<MemoryBuffer>>
     715          11 : writeWindowsResourceCOFF(COFF::MachineTypes MachineType,
     716             :                          const WindowsResourceParser &Parser) {
     717             :   Error E = Error::success();
     718          22 :   WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
     719          11 :   if (E)
     720             :     return std::move(E);
     721          22 :   return Writer.write();
     722             : }
     723             : 
     724             : } // namespace object
     725             : } // namespace llvm

Generated by: LCOV version 1.13