LLVM  10.0.0svn
WindowsResource.cpp
Go to the documentation of this file.
1 //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the .res file class.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "llvm/Object/COFF.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 WindowsResource::WindowsResource(MemoryBufferRef Source)
43  : Binary(Binary::ID_WinRes, Source) {
44  size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
45  BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
47 }
48 
49 // static
53  return make_error<GenericBinaryError>(
54  Source.getBufferIdentifier() + ": too small to be a resource file",
56  std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
57  return std::move(Ret);
58 }
59 
61  if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix))
62  return make_error<EmptyResError>(getFileName() + " contains no entries",
64  return ResourceEntryRef::create(BinaryStreamRef(BBS), this);
65 }
66 
67 ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
68  const WindowsResource *Owner)
69  : Reader(Ref), Owner(Owner) {}
70 
72 ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) {
73  auto Ref = ResourceEntryRef(BSR, Owner);
74  if (auto E = Ref.loadNext())
75  return std::move(E);
76  return Ref;
77 }
78 
80  // Reached end of all the entries.
81  if (Reader.bytesRemaining() == 0) {
82  End = true;
83  return Error::success();
84  }
85  RETURN_IF_ERROR(loadNext());
86 
87  return Error::success();
88 }
89 
90 static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
91  ArrayRef<UTF16> &Str, bool &IsString) {
92  uint16_t IDFlag;
93  RETURN_IF_ERROR(Reader.readInteger(IDFlag));
94  IsString = IDFlag != 0xffff;
95 
96  if (IsString) {
97  Reader.setOffset(
98  Reader.getOffset() -
99  sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
100  RETURN_IF_ERROR(Reader.readWideString(Str));
101  } else
102  RETURN_IF_ERROR(Reader.readInteger(ID));
103 
104  return Error::success();
105 }
106 
107 Error ResourceEntryRef::loadNext() {
108  const WinResHeaderPrefix *Prefix;
109  RETURN_IF_ERROR(Reader.readObject(Prefix));
110 
111  if (Prefix->HeaderSize < MIN_HEADER_SIZE)
112  return make_error<GenericBinaryError>(Owner->getFileName() +
113  ": header size too small",
115 
116  RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
117 
118  RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
119 
120  RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
121 
122  RETURN_IF_ERROR(Reader.readObject(Suffix));
123 
124  RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
125 
126  RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
127 
128  return Error::success();
129 }
130 
132 
134  switch (TypeID) {
135  case 1: OS << "CURSOR (ID 1)"; break;
136  case 2: OS << "BITMAP (ID 2)"; break;
137  case 3: OS << "ICON (ID 3)"; break;
138  case 4: OS << "MENU (ID 4)"; break;
139  case 5: OS << "DIALOG (ID 5)"; break;
140  case 6: OS << "STRINGTABLE (ID 6)"; break;
141  case 7: OS << "FONTDIR (ID 7)"; break;
142  case 8: OS << "FONT (ID 8)"; break;
143  case 9: OS << "ACCELERATOR (ID 9)"; break;
144  case 10: OS << "RCDATA (ID 10)"; break;
145  case 11: OS << "MESSAGETABLE (ID 11)"; break;
146  case 12: OS << "GROUP_CURSOR (ID 12)"; break;
147  case 14: OS << "GROUP_ICON (ID 14)"; break;
148  case 16: OS << "VERSIONINFO (ID 16)"; break;
149  case 17: OS << "DLGINCLUDE (ID 17)"; break;
150  case 19: OS << "PLUGPLAY (ID 19)"; break;
151  case 20: OS << "VXD (ID 20)"; break;
152  case 21: OS << "ANICURSOR (ID 21)"; break;
153  case 22: OS << "ANIICON (ID 22)"; break;
154  case 23: OS << "HTML (ID 23)"; break;
155  case 24: OS << "MANIFEST (ID 24)"; break;
156  default: OS << "ID " << TypeID; break;
157  }
158 }
159 
160 static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) {
162  return convertUTF16ToUTF8String(Src, Out);
163 
164  std::vector<UTF16> EndianCorrectedSrc;
165  EndianCorrectedSrc.resize(Src.size() + 1);
166  llvm::copy(Src, EndianCorrectedSrc.begin() + 1);
167  EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
168  return convertUTF16ToUTF8String(makeArrayRef(EndianCorrectedSrc), Out);
169 }
170 
171 static std::string makeDuplicateResourceError(
172  const ResourceEntryRef &Entry, StringRef File1, StringRef File2) {
173  std::string Ret;
174  raw_string_ostream OS(Ret);
175 
176  OS << "duplicate resource:";
177 
178  OS << " type ";
179  if (Entry.checkTypeString()) {
180  std::string UTF8;
182  UTF8 = "(failed conversion from UTF16)";
183  OS << '\"' << UTF8 << '\"';
184  } else
185  printResourceTypeName(Entry.getTypeID(), OS);
186 
187  OS << "/name ";
188  if (Entry.checkNameString()) {
189  std::string UTF8;
191  UTF8 = "(failed conversion from UTF16)";
192  OS << '\"' << UTF8 << '\"';
193  } else {
194  OS << "ID " << Entry.getNameID();
195  }
196 
197  OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in "
198  << File2;
199 
200  return OS.str();
201 }
202 
204  std::vector<std::string> &Duplicates) {
205  auto EntryOrErr = WR->getHeadEntry();
206  if (!EntryOrErr) {
207  auto E = EntryOrErr.takeError();
208  if (E.isA<EmptyResError>()) {
209  // Check if the .res file contains no entries. In this case we don't have
210  // to throw an error but can rather just return without parsing anything.
211  // This applies for files which have a valid PE header magic and the
212  // mandatory empty null resource entry. Files which do not fit this
213  // criteria would have already been filtered out by
214  // WindowsResource::createWindowsResource().
215  consumeError(std::move(E));
216  return Error::success();
217  }
218  return E;
219  }
220 
221  ResourceEntryRef Entry = EntryOrErr.get();
222  bool End = false;
223  while (!End) {
224  Data.push_back(Entry.getData());
225 
226  bool IsNewTypeString = false;
227  bool IsNewNameString = false;
228 
229  TreeNode* Node;
230  bool IsNewNode = Root.addEntry(Entry, InputFilenames.size(),
231  IsNewTypeString, IsNewNameString, Node);
232  InputFilenames.push_back(WR->getFileName());
233  if (!IsNewNode) {
234  Duplicates.push_back(makeDuplicateResourceError(
235  Entry, InputFilenames[Node->Origin], WR->getFileName()));
236  }
237 
238  if (IsNewTypeString)
239  StringTable.push_back(Entry.getTypeString());
240 
241  if (IsNewNameString)
242  StringTable.push_back(Entry.getNameString());
243 
244  RETURN_IF_ERROR(Entry.moveNext(End));
245  }
246 
247  return Error::success();
248 }
249 
251  ScopedPrinter Writer(OS);
252  Root.print(Writer, "Resource Tree");
253 }
254 
255 bool WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry,
256  uint32_t Origin,
257  bool &IsNewTypeString,
258  bool &IsNewNameString,
259  TreeNode *&Result) {
260  TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString);
261  TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);
262  return NameNode.addLanguageNode(Entry, Origin, Result);
263 }
264 
265 WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
266  if (IsStringNode)
267  StringIndex = StringCount++;
268 }
269 
270 WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
271  uint16_t MinorVersion,
273  uint32_t Origin)
274  : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
275  Characteristics(Characteristics), Origin(Origin) {
276  DataIndex = DataCount++;
277 }
278 
279 std::unique_ptr<WindowsResourceParser::TreeNode>
280 WindowsResourceParser::TreeNode::createStringNode() {
281  return std::unique_ptr<TreeNode>(new TreeNode(true));
282 }
283 
284 std::unique_ptr<WindowsResourceParser::TreeNode>
285 WindowsResourceParser::TreeNode::createIDNode() {
286  return std::unique_ptr<TreeNode>(new TreeNode(false));
287 }
288 
289 std::unique_ptr<WindowsResourceParser::TreeNode>
290 WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
291  uint16_t MinorVersion,
292  uint32_t Characteristics,
293  uint32_t Origin) {
294  return std::unique_ptr<TreeNode>(
295  new TreeNode(MajorVersion, MinorVersion, Characteristics, Origin));
296 }
297 
299 WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry,
300  bool &IsNewTypeString) {
301  if (Entry.checkTypeString())
302  return addNameChild(Entry.getTypeString(), IsNewTypeString);
303  else
304  return addIDChild(Entry.getTypeID());
305 }
306 
308 WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry,
309  bool &IsNewNameString) {
310  if (Entry.checkNameString())
311  return addNameChild(Entry.getNameString(), IsNewNameString);
312  else
313  return addIDChild(Entry.getNameID());
314 }
315 
316 bool WindowsResourceParser::TreeNode::addLanguageNode(
317  const ResourceEntryRef &Entry, uint32_t Origin, TreeNode *&Result) {
318  return addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
319  Entry.getMinorVersion(), Entry.getCharacteristics(),
320  Origin, Result);
321 }
322 
323 bool WindowsResourceParser::TreeNode::addDataChild(
324  uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
325  uint32_t Characteristics, uint32_t Origin, TreeNode *&Result) {
326  auto NewChild =
327  createDataNode(MajorVersion, MinorVersion, Characteristics, Origin);
328  auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild));
329  Result = ElementInserted.first->second.get();
330  return ElementInserted.second;
331 }
332 
333 WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild(
334  uint32_t ID) {
335  auto Child = IDChildren.find(ID);
336  if (Child == IDChildren.end()) {
337  auto NewChild = createIDNode();
338  WindowsResourceParser::TreeNode &Node = *NewChild;
339  IDChildren.emplace(ID, std::move(NewChild));
340  return Node;
341  } else
342  return *(Child->second);
343 }
344 
346 WindowsResourceParser::TreeNode::addNameChild(ArrayRef<UTF16> NameRef,
347  bool &IsNewString) {
348  std::string NameString;
349  convertUTF16LEToUTF8String(NameRef, NameString);
350 
351  auto Child = StringChildren.find(NameString);
352  if (Child == StringChildren.end()) {
353  auto NewChild = createStringNode();
354  IsNewString = true;
355  WindowsResourceParser::TreeNode &Node = *NewChild;
356  StringChildren.emplace(NameString, std::move(NewChild));
357  return Node;
358  } else
359  return *(Child->second);
360 }
361 
363  StringRef Name) const {
364  ListScope NodeScope(Writer, Name);
365  for (auto const &Child : StringChildren) {
366  Child.second->print(Writer, Child.first);
367  }
368  for (auto const &Child : IDChildren) {
369  Child.second->print(Writer, to_string(Child.first));
370  }
371 }
372 
373 // This function returns the size of the entire resource tree, including
374 // directory tables, directory entries, and data entries. It does not include
375 // the directory strings or the relocations of the .rsrc section.
377  uint32_t Size = (IDChildren.size() + StringChildren.size()) *
378  sizeof(coff_resource_dir_entry);
379 
380  // Reached a node pointing to a data entry.
381  if (IsDataNode) {
382  Size += sizeof(coff_resource_data_entry);
383  return Size;
384  }
385 
386  // If the node does not point to data, it must have a directory table pointing
387  // to other nodes.
388  Size += sizeof(coff_resource_dir_table);
389 
390  for (auto const &Child : StringChildren) {
391  Size += Child.second->getTreeSize();
392  }
393  for (auto const &Child : IDChildren) {
394  Size += Child.second->getTreeSize();
395  }
396  return Size;
397 }
398 
400 public:
403  std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp);
404 
405 private:
406  void performFileLayout();
407  void performSectionOneLayout();
408  void performSectionTwoLayout();
409  void writeCOFFHeader(uint32_t TimeDateStamp);
410  void writeFirstSectionHeader();
411  void writeSecondSectionHeader();
412  void writeFirstSection();
413  void writeSecondSection();
414  void writeSymbolTable();
415  void writeStringTable();
416  void writeDirectoryTree();
417  void writeDirectoryStringTable();
418  void writeFirstSectionRelocations();
419  std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
420  char *BufferStart;
421  uint64_t CurrentOffset = 0;
422  COFF::MachineTypes MachineType;
423  const WindowsResourceParser::TreeNode &Resources;
425  uint64_t FileSize;
426  uint32_t SymbolTableOffset;
427  uint32_t SectionOneSize;
428  uint32_t SectionOneOffset;
429  uint32_t SectionOneRelocations;
430  uint32_t SectionTwoSize;
431  uint32_t SectionTwoOffset;
432  const ArrayRef<std::vector<UTF16>> StringTable;
433  std::vector<uint32_t> StringTableOffsets;
434  std::vector<uint32_t> DataOffsets;
435  std::vector<uint32_t> RelocationAddresses;
436 };
437 
439  COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
440  Error &E)
441  : MachineType(MachineType), Resources(Parser.getTree()),
442  Data(Parser.getData()), StringTable(Parser.getStringTable()) {
443  performFileLayout();
444 
446  FileSize, "internal .obj file created from .res files");
447 }
448 
449 void WindowsResourceCOFFWriter::performFileLayout() {
450  // Add size of COFF header.
451  FileSize = COFF::Header16Size;
452 
453  // one .rsrc section header for directory tree, another for resource data.
454  FileSize += 2 * COFF::SectionSize;
455 
456  performSectionOneLayout();
457  performSectionTwoLayout();
458 
459  // We have reached the address of the symbol table.
460  SymbolTableOffset = FileSize;
461 
462  FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol.
463  FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
464  FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
465  FileSize += 4; // four null bytes for the string table.
466 }
467 
468 void WindowsResourceCOFFWriter::performSectionOneLayout() {
469  SectionOneOffset = FileSize;
470 
471  SectionOneSize = Resources.getTreeSize();
472  uint32_t CurrentStringOffset = SectionOneSize;
473  uint32_t TotalStringTableSize = 0;
474  for (auto const &String : StringTable) {
475  StringTableOffsets.push_back(CurrentStringOffset);
476  uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
477  CurrentStringOffset += StringSize;
478  TotalStringTableSize += StringSize;
479  }
480  SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
481 
482  // account for the relocations of section one.
483  SectionOneRelocations = FileSize + SectionOneSize;
484  FileSize += SectionOneSize;
485  FileSize +=
486  Data.size() * COFF::RelocationSize; // one relocation for each resource.
487  FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
488 }
489 
490 void WindowsResourceCOFFWriter::performSectionTwoLayout() {
491  // add size of .rsrc$2 section, which contains all resource data on 8-byte
492  // alignment.
493  SectionTwoOffset = FileSize;
494  SectionTwoSize = 0;
495  for (auto const &Entry : Data) {
496  DataOffsets.push_back(SectionTwoSize);
497  SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
498  }
499  FileSize += SectionTwoSize;
500  FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
501 }
502 
503 std::unique_ptr<MemoryBuffer>
505  BufferStart = OutputBuffer->getBufferStart();
506 
507  writeCOFFHeader(TimeDateStamp);
508  writeFirstSectionHeader();
509  writeSecondSectionHeader();
510  writeFirstSection();
511  writeSecondSection();
512  writeSymbolTable();
513  writeStringTable();
514 
515  return std::move(OutputBuffer);
516 }
517 
518 void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) {
519  // Write the COFF header.
520  auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
521  Header->Machine = MachineType;
522  Header->NumberOfSections = 2;
523  Header->TimeDateStamp = TimeDateStamp;
524  Header->PointerToSymbolTable = SymbolTableOffset;
525  // One symbol for every resource plus 2 for each section and 1 for @feat.00
526  Header->NumberOfSymbols = Data.size() + 5;
527  Header->SizeOfOptionalHeader = 0;
528  // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it.
529  Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
530 }
531 
532 void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
533  // Write the first section header.
534  CurrentOffset += sizeof(coff_file_header);
535  auto *SectionOneHeader =
536  reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
537  strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize);
538  SectionOneHeader->VirtualSize = 0;
539  SectionOneHeader->VirtualAddress = 0;
540  SectionOneHeader->SizeOfRawData = SectionOneSize;
541  SectionOneHeader->PointerToRawData = SectionOneOffset;
542  SectionOneHeader->PointerToRelocations = SectionOneRelocations;
543  SectionOneHeader->PointerToLinenumbers = 0;
544  SectionOneHeader->NumberOfRelocations = Data.size();
545  SectionOneHeader->NumberOfLinenumbers = 0;
546  SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
547  SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
548 }
549 
550 void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
551  // Write the second section header.
552  CurrentOffset += sizeof(coff_section);
553  auto *SectionTwoHeader =
554  reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
555  strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize);
556  SectionTwoHeader->VirtualSize = 0;
557  SectionTwoHeader->VirtualAddress = 0;
558  SectionTwoHeader->SizeOfRawData = SectionTwoSize;
559  SectionTwoHeader->PointerToRawData = SectionTwoOffset;
560  SectionTwoHeader->PointerToRelocations = 0;
561  SectionTwoHeader->PointerToLinenumbers = 0;
562  SectionTwoHeader->NumberOfRelocations = 0;
563  SectionTwoHeader->NumberOfLinenumbers = 0;
564  SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
565  SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
566 }
567 
568 void WindowsResourceCOFFWriter::writeFirstSection() {
569  // Write section one.
570  CurrentOffset += sizeof(coff_section);
571 
572  writeDirectoryTree();
573  writeDirectoryStringTable();
574  writeFirstSectionRelocations();
575 
576  CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
577 }
578 
579 void WindowsResourceCOFFWriter::writeSecondSection() {
580  // Now write the .rsrc$02 section.
581  for (auto const &RawDataEntry : Data) {
582  llvm::copy(RawDataEntry, BufferStart + CurrentOffset);
583  CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
584  }
585 
586  CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
587 }
588 
589 void WindowsResourceCOFFWriter::writeSymbolTable() {
590  // Now write the symbol table.
591  // First, the feat symbol.
592  auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
593  strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize);
594  Symbol->Value = 0x11;
595  Symbol->SectionNumber = 0xffff;
597  Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
598  Symbol->NumberOfAuxSymbols = 0;
599  CurrentOffset += sizeof(coff_symbol16);
600 
601  // Now write the .rsrc1 symbol + aux.
602  Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
603  strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize);
604  Symbol->Value = 0;
605  Symbol->SectionNumber = 1;
607  Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
608  Symbol->NumberOfAuxSymbols = 1;
609  CurrentOffset += sizeof(coff_symbol16);
610  auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
611  CurrentOffset);
612  Aux->Length = SectionOneSize;
613  Aux->NumberOfRelocations = Data.size();
614  Aux->NumberOfLinenumbers = 0;
615  Aux->CheckSum = 0;
616  Aux->NumberLowPart = 0;
617  Aux->Selection = 0;
618  CurrentOffset += sizeof(coff_aux_section_definition);
619 
620  // Now write the .rsrc2 symbol + aux.
621  Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
622  strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize);
623  Symbol->Value = 0;
624  Symbol->SectionNumber = 2;
626  Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
627  Symbol->NumberOfAuxSymbols = 1;
628  CurrentOffset += sizeof(coff_symbol16);
629  Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
630  CurrentOffset);
631  Aux->Length = SectionTwoSize;
632  Aux->NumberOfRelocations = 0;
633  Aux->NumberOfLinenumbers = 0;
634  Aux->CheckSum = 0;
635  Aux->NumberLowPart = 0;
636  Aux->Selection = 0;
637  CurrentOffset += sizeof(coff_aux_section_definition);
638 
639  // Now write a symbol for each relocation.
640  for (unsigned i = 0; i < Data.size(); i++) {
641  auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
642  Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
643  memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize);
644  Symbol->Value = DataOffsets[i];
645  Symbol->SectionNumber = 2;
646  Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
647  Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
648  Symbol->NumberOfAuxSymbols = 0;
649  CurrentOffset += sizeof(coff_symbol16);
650  }
651 }
652 
653 void WindowsResourceCOFFWriter::writeStringTable() {
654  // Just 4 null bytes for the string table.
655  auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
656  memset(COFFStringTable, 0, 4);
657 }
658 
659 void WindowsResourceCOFFWriter::writeDirectoryTree() {
660  // Traverse parsed resource tree breadth-first and write the corresponding
661  // COFF objects.
662  std::queue<const WindowsResourceParser::TreeNode *> Queue;
663  Queue.push(&Resources);
664  uint32_t NextLevelOffset =
665  sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
666  Resources.getIDChildren().size()) *
667  sizeof(coff_resource_dir_entry);
668  std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
669  uint32_t CurrentRelativeOffset = 0;
670 
671  while (!Queue.empty()) {
672  auto CurrentNode = Queue.front();
673  Queue.pop();
674  auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
675  CurrentOffset);
676  Table->Characteristics = CurrentNode->getCharacteristics();
677  Table->TimeDateStamp = 0;
678  Table->MajorVersion = CurrentNode->getMajorVersion();
679  Table->MinorVersion = CurrentNode->getMinorVersion();
680  auto &IDChildren = CurrentNode->getIDChildren();
681  auto &StringChildren = CurrentNode->getStringChildren();
682  Table->NumberOfNameEntries = StringChildren.size();
683  Table->NumberOfIDEntries = IDChildren.size();
684  CurrentOffset += sizeof(coff_resource_dir_table);
685  CurrentRelativeOffset += sizeof(coff_resource_dir_table);
686 
687  // Write the directory entries immediately following each directory table.
688  for (auto const &Child : StringChildren) {
689  auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
690  CurrentOffset);
691  Entry->Identifier.setNameOffset(
692  StringTableOffsets[Child.second->getStringIndex()]);
693  if (Child.second->checkIsDataNode()) {
694  Entry->Offset.DataEntryOffset = NextLevelOffset;
695  NextLevelOffset += sizeof(coff_resource_data_entry);
696  DataEntriesTreeOrder.push_back(Child.second.get());
697  } else {
698  Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
699  NextLevelOffset += sizeof(coff_resource_dir_table) +
700  (Child.second->getStringChildren().size() +
701  Child.second->getIDChildren().size()) *
702  sizeof(coff_resource_dir_entry);
703  Queue.push(Child.second.get());
704  }
705  CurrentOffset += sizeof(coff_resource_dir_entry);
706  CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
707  }
708  for (auto const &Child : IDChildren) {
709  auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
710  CurrentOffset);
711  Entry->Identifier.ID = Child.first;
712  if (Child.second->checkIsDataNode()) {
713  Entry->Offset.DataEntryOffset = NextLevelOffset;
714  NextLevelOffset += sizeof(coff_resource_data_entry);
715  DataEntriesTreeOrder.push_back(Child.second.get());
716  } else {
717  Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
718  NextLevelOffset += sizeof(coff_resource_dir_table) +
719  (Child.second->getStringChildren().size() +
720  Child.second->getIDChildren().size()) *
721  sizeof(coff_resource_dir_entry);
722  Queue.push(Child.second.get());
723  }
724  CurrentOffset += sizeof(coff_resource_dir_entry);
725  CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
726  }
727  }
728 
729  RelocationAddresses.resize(Data.size());
730  // Now write all the resource data entries.
731  for (auto DataNodes : DataEntriesTreeOrder) {
732  auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
733  CurrentOffset);
734  RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
735  Entry->DataRVA = 0; // Set to zero because it is a relocation.
736  Entry->DataSize = Data[DataNodes->getDataIndex()].size();
737  Entry->Codepage = 0;
738  Entry->Reserved = 0;
739  CurrentOffset += sizeof(coff_resource_data_entry);
740  CurrentRelativeOffset += sizeof(coff_resource_data_entry);
741  }
742 }
743 
744 void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
745  // Now write the directory string table for .rsrc$01
746  uint32_t TotalStringTableSize = 0;
747  for (auto &String : StringTable) {
748  uint16_t Length = String.size();
749  support::endian::write16le(BufferStart + CurrentOffset, Length);
750  CurrentOffset += sizeof(uint16_t);
751  auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
752  llvm::copy(String, Start);
753  CurrentOffset += Length * sizeof(UTF16);
754  TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
755  }
756  CurrentOffset +=
757  alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
758 }
759 
760 void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
761 
762  // Now write the relocations for .rsrc$01
763  // Five symbols already in table before we start, @feat.00 and 2 for each
764  // .rsrc section.
765  uint32_t NextSymbolIndex = 5;
766  for (unsigned i = 0; i < Data.size(); i++) {
767  auto *Reloc =
768  reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
769  Reloc->VirtualAddress = RelocationAddresses[i];
770  Reloc->SymbolTableIndex = NextSymbolIndex++;
771  switch (MachineType) {
773  Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
774  break;
776  Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
777  break;
779  Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
780  break;
782  Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
783  break;
784  default:
785  llvm_unreachable("unknown machine type");
786  }
787  CurrentOffset += sizeof(coff_relocation);
788  }
789 }
790 
794  uint32_t TimeDateStamp) {
795  Error E = Error::success();
796  WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
797  if (E)
798  return std::move(E);
799  return Writer.write(TimeDateStamp);
800 }
801 
802 } // namespace object
803 } // namespace llvm
coff_symbol< support::ulittle16_t > coff_symbol16
Definition: COFF.h:265
const size_t WIN_RES_NULL_ENTRY_SIZE
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:218
support::ulittle16_t Machine
Definition: COFF.h:76
An implementation of BinaryStream which holds its entire data set in a single contiguous buffer...
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream&#39;s offset.
iterator begin() const
Definition: ArrayRef.h:136
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
Expected< std::unique_ptr< MemoryBuffer > > writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, uint32_t TimeDateStamp)
Error readWideString(ArrayRef< UTF16 > &Dest)
Similar to readCString, however read a null-terminated UTF16 string instead.
StringRef getFileName() const
Definition: Binary.cpp:41
support::ulittle32_t HeaderSize
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
Definition: MathExtras.h:689
unsigned short UTF16
Definition: ConvertUTF.h:110
No complex type; simple scalar variable.
Definition: COFF.h:259
constexpr bool IsBigEndianHost
Definition: Host.h:46
static std::string makeDuplicateResourceError(const ResourceEntryRef &Entry, StringRef File1, StringRef File2)
MachineTypes
Definition: COFF.h:93
Machine is based on a 32bit word architecture.
Definition: COFF.h:145
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:450
const uint32_t SECTION_ALIGNMENT
void write16le(void *P, uint16_t V)
Definition: Endian.h:417
const Children< uint32_t > & getIDChildren() const
The access may reference the value stored in memory.
TypeID
Definitions of all of the base types for the Type system.
Definition: Type.h:54
#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED
Definition: ConvertUTF.h:124
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
unsigned char UTF8
Definition: ConvertUTF.h:111
static std::unique_ptr< WritableMemoryBuffer > getNewMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new zero-initialized MemoryBuffer of the specified size.
static Expected< std::unique_ptr< WindowsResource > > createWindowsResource(MemoryBufferRef Source)
Expected< ResourceEntryRef > getHeadEntry()
const uint32_t MIN_HEADER_SIZE
std::unique_ptr< MemoryBuffer > write(uint32_t TimeDateStamp)
size_t getBufferSize() const
Definition: MemoryBuffer.h:278
WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, Error &E)
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:148
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Definition: COFF.h:740
ArrayRef< uint8_t > getData() const
Type::TypeID TypeID
ArrayRef< UTF16 > getTypeString() const
static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, ArrayRef< UTF16 > &Str, bool &IsString)
static void write(bool isBE, void *P, T V)
void printTree(raw_ostream &OS) const
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:981
support::ulittle32_t VirtualAddress
Definition: COFF.h:472
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void setOffset(uint32_t Off)
const ArrayRef< std::vector< UTF16 > > getStringTable() const
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
const uint32_t WIN_RES_HEADER_ALIGNMENT
const ArrayRef< std::vector< uint8_t > > getData() const
BinaryStreamRef is to BinaryStream what ArrayRef is to an Array.
Bit scan reverse.
MemoryBufferRef Data
Definition: Binary.h:37
StringRef getBufferIdentifier() const
Definition: MemoryBuffer.h:274
bool convertUTF16ToUTF8String(ArrayRef< char > SrcBytes, std::string &Out)
Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
const size_t WIN_RES_MAGIC_SIZE
Definition: COFF.h:717
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef< MemberData > Members, StringRef StringTable)
Error parse(WindowsResource *WR, std::vector< std::string > &Duplicates)
COFFYAML::WeakExternalCharacteristics Characteristics
Definition: COFFYAML.cpp:325
static void writeStringTable(std::vector< uint8_t > &B, ArrayRef< const std::string > Strings)
uint32_t getLength() override
Return the number of bytes of data in this stream.
static bool convertUTF16LEToUTF8String(ArrayRef< UTF16 > Src, std::string &Out)
ArrayRef< UTF16 > getNameString() const
uint32_t Size
Definition: Profile.cpp:46
void printResourceTypeName(uint16_t TypeID, raw_ostream &OS)
const std::string to_string(const T &Value)
Definition: ScopedPrinter.h:61
const uint32_t WIN_RES_DATA_ALIGNMENT
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:482
#define RETURN_IF_ERROR(X)
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
void print(ScopedPrinter &Writer, StringRef Name) const
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
support::ulittle32_t Characteristics
Definition: COFF.h:748
const TreeNode & getTree() const
OutputIt copy(R &&Range, OutputIt Out)
Definition: STLExtras.h:1244
const Children< std::string > & getStringChildren() const