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

Generated by: LCOV version 1.13