LLVM 20.0.0git
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
22using namespace llvm;
23using namespace object;
24
25namespace llvm {
26namespace object {
27
28#define RETURN_IF_ERROR(X) \
29 if (auto EC = X) \
30 return EC;
31
32#define UNWRAP_REF_OR_RETURN(Name, Expr) \
33 auto Name##OrErr = Expr; \
34 if (!Name##OrErr) \
35 return Name##OrErr.takeError(); \
36 const auto &Name = *Name##OrErr;
37
38#define UNWRAP_OR_RETURN(Name, Expr) \
39 auto Name##OrErr = Expr; \
40 if (!Name##OrErr) \
41 return Name##OrErr.takeError(); \
42 auto Name = *Name##OrErr;
43
44const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
45
46// COFF files seem to be inconsistent with alignment between sections, just use
47// 8-byte because it makes everyone happy.
49
50WindowsResource::WindowsResource(MemoryBufferRef Source)
51 : Binary(Binary::ID_WinRes, Source) {
52 size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
53 BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
55}
56
57// static
60 if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
61 return make_error<GenericBinaryError>(
62 Source.getBufferIdentifier() + ": too small to be a resource file",
63 object_error::invalid_file_type);
64 std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
65 return std::move(Ret);
66}
67
69 if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix))
70 return make_error<EmptyResError>(getFileName() + " contains no entries",
71 object_error::unexpected_eof);
72 return ResourceEntryRef::create(BinaryStreamRef(BBS), this);
73}
74
75ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
76 const WindowsResource *Owner)
77 : Reader(Ref), Owner(Owner) {}
78
80ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) {
81 auto Ref = ResourceEntryRef(BSR, Owner);
82 if (auto E = Ref.loadNext())
83 return E;
84 return Ref;
85}
86
88 // Reached end of all the entries.
89 if (Reader.bytesRemaining() == 0) {
90 End = true;
91 return Error::success();
92 }
93 RETURN_IF_ERROR(loadNext());
94
95 return Error::success();
96}
97
99 ArrayRef<UTF16> &Str, bool &IsString) {
100 uint16_t IDFlag;
101 RETURN_IF_ERROR(Reader.readInteger(IDFlag));
102 IsString = IDFlag != 0xffff;
103
104 if (IsString) {
105 Reader.setOffset(
106 Reader.getOffset() -
107 sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
108 RETURN_IF_ERROR(Reader.readWideString(Str));
109 } else
111
112 return Error::success();
113}
114
115Error ResourceEntryRef::loadNext() {
116 const WinResHeaderPrefix *Prefix;
117 RETURN_IF_ERROR(Reader.readObject(Prefix));
118
119 if (Prefix->HeaderSize < MIN_HEADER_SIZE)
120 return make_error<GenericBinaryError>(Owner->getFileName() +
121 ": header size too small",
123
124 RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
125
126 RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
127
129
130 RETURN_IF_ERROR(Reader.readObject(Suffix));
131
132 RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
133
135
136 return Error::success();
137}
138
140 : Root(false), MinGW(MinGW) {}
141
143 switch (TypeID) {
144 case 1: OS << "CURSOR (ID 1)"; break;
145 case 2: OS << "BITMAP (ID 2)"; break;
146 case 3: OS << "ICON (ID 3)"; break;
147 case 4: OS << "MENU (ID 4)"; break;
148 case 5: OS << "DIALOG (ID 5)"; break;
149 case 6: OS << "STRINGTABLE (ID 6)"; break;
150 case 7: OS << "FONTDIR (ID 7)"; break;
151 case 8: OS << "FONT (ID 8)"; break;
152 case 9: OS << "ACCELERATOR (ID 9)"; break;
153 case 10: OS << "RCDATA (ID 10)"; break;
154 case 11: OS << "MESSAGETABLE (ID 11)"; break;
155 case 12: OS << "GROUP_CURSOR (ID 12)"; break;
156 case 14: OS << "GROUP_ICON (ID 14)"; break;
157 case 16: OS << "VERSIONINFO (ID 16)"; break;
158 case 17: OS << "DLGINCLUDE (ID 17)"; break;
159 case 19: OS << "PLUGPLAY (ID 19)"; break;
160 case 20: OS << "VXD (ID 20)"; break;
161 case 21: OS << "ANICURSOR (ID 21)"; break;
162 case 22: OS << "ANIICON (ID 22)"; break;
163 case 23: OS << "HTML (ID 23)"; break;
164 case 24: OS << "MANIFEST (ID 24)"; break;
165 default: OS << "ID " << TypeID; break;
166 }
167}
168
169static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) {
171 return convertUTF16ToUTF8String(Src, Out);
172
173 std::vector<UTF16> EndianCorrectedSrc;
174 EndianCorrectedSrc.resize(Src.size() + 1);
175 llvm::copy(Src, EndianCorrectedSrc.begin() + 1);
176 EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
177 return convertUTF16ToUTF8String(ArrayRef(EndianCorrectedSrc), Out);
178}
179
180static std::string makeDuplicateResourceError(
181 const ResourceEntryRef &Entry, StringRef File1, StringRef File2) {
182 std::string Ret;
184
185 OS << "duplicate resource:";
186
187 OS << " type ";
188 if (Entry.checkTypeString()) {
189 std::string UTF8;
190 if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8))
191 UTF8 = "(failed conversion from UTF16)";
192 OS << '\"' << UTF8 << '\"';
193 } else
194 printResourceTypeName(Entry.getTypeID(), OS);
195
196 OS << "/name ";
197 if (Entry.checkNameString()) {
198 std::string UTF8;
199 if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8))
200 UTF8 = "(failed conversion from UTF16)";
201 OS << '\"' << UTF8 << '\"';
202 } else {
203 OS << "ID " << Entry.getNameID();
204 }
205
206 OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in "
207 << File2;
208
209 return OS.str();
210}
211
213 raw_string_ostream &OS, bool IsType, bool IsID) {
214 if (S.IsString) {
215 std::string UTF8;
217 UTF8 = "(failed conversion from UTF16)";
218 OS << '\"' << UTF8 << '\"';
219 } else if (IsType)
221 else if (IsID)
222 OS << "ID " << S.ID;
223 else
224 OS << S.ID;
225}
226
227static std::string makeDuplicateResourceError(
228 const std::vector<WindowsResourceParser::StringOrID> &Context,
229 StringRef File1, StringRef File2) {
230 std::string Ret;
232
233 OS << "duplicate resource:";
234
235 if (Context.size() >= 1) {
236 OS << " type ";
237 printStringOrID(Context[0], OS, /* IsType */ true, /* IsID */ true);
238 }
239
240 if (Context.size() >= 2) {
241 OS << "/name ";
242 printStringOrID(Context[1], OS, /* IsType */ false, /* IsID */ true);
243 }
244
245 if (Context.size() >= 3) {
246 OS << "/language ";
247 printStringOrID(Context[2], OS, /* IsType */ false, /* IsID */ false);
248 }
249 OS << ", in " << File1 << " and in " << File2;
250
251 return OS.str();
252}
253
254// MinGW specific. Remove default manifests (with language zero) if there are
255// other manifests present, and report an error if there are more than one
256// manifest with a non-zero language code.
257// GCC has the concept of a default manifest resource object, which gets
258// linked in implicitly if present. This default manifest has got language
259// id zero, and should be dropped silently if there's another manifest present.
260// If the user resources surprisignly had a manifest with language id zero,
261// we should also ignore the duplicate default manifest.
263 std::vector<std::string> &Duplicates) {
264 auto TypeIt = Root.IDChildren.find(/* RT_MANIFEST */ 24);
265 if (TypeIt == Root.IDChildren.end())
266 return;
267
268 TreeNode *TypeNode = TypeIt->second.get();
269 auto NameIt =
270 TypeNode->IDChildren.find(/* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1);
271 if (NameIt == TypeNode->IDChildren.end())
272 return;
273
274 TreeNode *NameNode = NameIt->second.get();
275 if (NameNode->IDChildren.size() <= 1)
276 return; // None or one manifest present, all good.
277
278 // If we have more than one manifest, drop the language zero one if present,
279 // and check again.
280 auto LangZeroIt = NameNode->IDChildren.find(0);
281 if (LangZeroIt != NameNode->IDChildren.end() &&
282 LangZeroIt->second->IsDataNode) {
283 uint32_t RemovedIndex = LangZeroIt->second->DataIndex;
284 NameNode->IDChildren.erase(LangZeroIt);
285 Data.erase(Data.begin() + RemovedIndex);
286 Root.shiftDataIndexDown(RemovedIndex);
287
288 // If we're now down to one manifest, all is good.
289 if (NameNode->IDChildren.size() <= 1)
290 return;
291 }
292
293 // More than one non-language-zero manifest
294 auto FirstIt = NameNode->IDChildren.begin();
295 uint32_t FirstLang = FirstIt->first;
296 TreeNode *FirstNode = FirstIt->second.get();
297 auto LastIt = NameNode->IDChildren.rbegin();
298 uint32_t LastLang = LastIt->first;
299 TreeNode *LastNode = LastIt->second.get();
300 Duplicates.push_back(
301 ("duplicate non-default manifests with languages " + Twine(FirstLang) +
302 " in " + InputFilenames[FirstNode->Origin] + " and " + Twine(LastLang) +
303 " in " + InputFilenames[LastNode->Origin])
304 .str());
305}
306
307// Ignore duplicates of manifests with language zero (the default manifest),
308// in case the user has provided a manifest with that language id. See
309// the function comment above for context. Only returns true if MinGW is set
310// to true.
311bool WindowsResourceParser::shouldIgnoreDuplicate(
312 const ResourceEntryRef &Entry) const {
313 return MinGW && !Entry.checkTypeString() &&
314 Entry.getTypeID() == /* RT_MANIFEST */ 24 &&
315 !Entry.checkNameString() &&
316 Entry.getNameID() == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
317 Entry.getLanguage() == 0;
318}
319
320bool WindowsResourceParser::shouldIgnoreDuplicate(
321 const std::vector<StringOrID> &Context) const {
322 return MinGW && Context.size() == 3 && !Context[0].IsString &&
323 Context[0].ID == /* RT_MANIFEST */ 24 && !Context[1].IsString &&
324 Context[1].ID == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
325 !Context[2].IsString && Context[2].ID == 0;
326}
327
329 std::vector<std::string> &Duplicates) {
330 auto EntryOrErr = WR->getHeadEntry();
331 if (!EntryOrErr) {
332 auto E = EntryOrErr.takeError();
333 if (E.isA<EmptyResError>()) {
334 // Check if the .res file contains no entries. In this case we don't have
335 // to throw an error but can rather just return without parsing anything.
336 // This applies for files which have a valid PE header magic and the
337 // mandatory empty null resource entry. Files which do not fit this
338 // criteria would have already been filtered out by
339 // WindowsResource::createWindowsResource().
340 consumeError(std::move(E));
341 return Error::success();
342 }
343 return E;
344 }
345
346 ResourceEntryRef Entry = EntryOrErr.get();
347 uint32_t Origin = InputFilenames.size();
348 InputFilenames.push_back(std::string(WR->getFileName()));
349 bool End = false;
350 while (!End) {
351
352 TreeNode *Node;
353 bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node);
354 if (!IsNewNode) {
355 if (!shouldIgnoreDuplicate(Entry))
356 Duplicates.push_back(makeDuplicateResourceError(
357 Entry, InputFilenames[Node->Origin], WR->getFileName()));
358 }
359
360 RETURN_IF_ERROR(Entry.moveNext(End));
361 }
362
363 return Error::success();
364}
365
367 std::vector<std::string> &Duplicates) {
368 UNWRAP_REF_OR_RETURN(BaseTable, RSR.getBaseTable());
369 uint32_t Origin = InputFilenames.size();
370 InputFilenames.push_back(std::string(Filename));
371 std::vector<StringOrID> Context;
372 return addChildren(Root, RSR, BaseTable, Origin, Context, Duplicates);
373}
374
376 ScopedPrinter Writer(OS);
377 Root.print(Writer, "Resource Tree");
378}
379
380bool WindowsResourceParser::TreeNode::addEntry(
381 const ResourceEntryRef &Entry, uint32_t Origin,
382 std::vector<std::vector<uint8_t>> &Data,
383 std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) {
384 TreeNode &TypeNode = addTypeNode(Entry, StringTable);
385 TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable);
386 return NameNode.addLanguageNode(Entry, Origin, Data, Result);
387}
388
389Error WindowsResourceParser::addChildren(TreeNode &Node,
391 const coff_resource_dir_table &Table,
392 uint32_t Origin,
393 std::vector<StringOrID> &Context,
394 std::vector<std::string> &Duplicates) {
395
396 for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
397 i++) {
398 UNWRAP_REF_OR_RETURN(Entry, RSR.getTableEntry(Table, i));
399 TreeNode *Child;
400
401 if (Entry.Offset.isSubDir()) {
402
403 // Create a new subdirectory and recurse
404 if (i < Table.NumberOfNameEntries) {
405 UNWRAP_OR_RETURN(NameString, RSR.getEntryNameString(Entry));
406 Child = &Node.addNameChild(NameString, StringTable);
407 Context.push_back(StringOrID(NameString));
408 } else {
409 Child = &Node.addIDChild(Entry.Identifier.ID);
410 Context.push_back(StringOrID(Entry.Identifier.ID));
411 }
412
413 UNWRAP_REF_OR_RETURN(NextTable, RSR.getEntrySubDir(Entry));
414 Error E =
415 addChildren(*Child, RSR, NextTable, Origin, Context, Duplicates);
416 if (E)
417 return E;
418 Context.pop_back();
419
420 } else {
421
422 // Data leaves are supposed to have a numeric ID as identifier (language).
423 if (Table.NumberOfNameEntries > 0)
425 "unexpected string key for data object");
426
427 // Try adding a data leaf
428 UNWRAP_REF_OR_RETURN(DataEntry, RSR.getEntryData(Entry));
429 TreeNode *Child;
430 Context.push_back(StringOrID(Entry.Identifier.ID));
431 bool Added = Node.addDataChild(Entry.Identifier.ID, Table.MajorVersion,
432 Table.MinorVersion, Table.Characteristics,
433 Origin, Data.size(), Child);
434 if (Added) {
435 UNWRAP_OR_RETURN(Contents, RSR.getContents(DataEntry));
436 Data.push_back(ArrayRef<uint8_t>(
437 reinterpret_cast<const uint8_t *>(Contents.data()),
438 Contents.size()));
439 } else {
440 if (!shouldIgnoreDuplicate(Context))
441 Duplicates.push_back(makeDuplicateResourceError(
442 Context, InputFilenames[Child->Origin], InputFilenames.back()));
443 }
444 Context.pop_back();
445
446 }
447 }
448 return Error::success();
449}
450
451WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex)
452 : StringIndex(StringIndex) {}
453
454WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
455 uint16_t MinorVersion,
457 uint32_t Origin, uint32_t DataIndex)
458 : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion),
459 MinorVersion(MinorVersion), Characteristics(Characteristics),
460 Origin(Origin) {}
461
462std::unique_ptr<WindowsResourceParser::TreeNode>
463WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) {
464 return std::unique_ptr<TreeNode>(new TreeNode(Index));
465}
466
467std::unique_ptr<WindowsResourceParser::TreeNode>
468WindowsResourceParser::TreeNode::createIDNode() {
469 return std::unique_ptr<TreeNode>(new TreeNode(0));
470}
471
472std::unique_ptr<WindowsResourceParser::TreeNode>
473WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
474 uint16_t MinorVersion,
476 uint32_t Origin,
477 uint32_t DataIndex) {
478 return std::unique_ptr<TreeNode>(new TreeNode(
479 MajorVersion, MinorVersion, Characteristics, Origin, DataIndex));
480}
481
482WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode(
483 const ResourceEntryRef &Entry,
484 std::vector<std::vector<UTF16>> &StringTable) {
485 if (Entry.checkTypeString())
486 return addNameChild(Entry.getTypeString(), StringTable);
487 else
488 return addIDChild(Entry.getTypeID());
489}
490
491WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode(
492 const ResourceEntryRef &Entry,
493 std::vector<std::vector<UTF16>> &StringTable) {
494 if (Entry.checkNameString())
495 return addNameChild(Entry.getNameString(), StringTable);
496 else
497 return addIDChild(Entry.getNameID());
498}
499
500bool WindowsResourceParser::TreeNode::addLanguageNode(
501 const ResourceEntryRef &Entry, uint32_t Origin,
502 std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) {
503 bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
504 Entry.getMinorVersion(), Entry.getCharacteristics(),
505 Origin, Data.size(), Result);
506 if (Added)
507 Data.push_back(Entry.getData());
508 return Added;
509}
510
511bool WindowsResourceParser::TreeNode::addDataChild(
512 uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
513 uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex,
514 TreeNode *&Result) {
515 auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics,
516 Origin, DataIndex);
517 auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild));
518 Result = ElementInserted.first->second.get();
519 return ElementInserted.second;
520}
521
522WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild(
523 uint32_t ID) {
524 auto Child = IDChildren.find(ID);
525 if (Child == IDChildren.end()) {
526 auto NewChild = createIDNode();
528 IDChildren.emplace(ID, std::move(NewChild));
529 return Node;
530 } else
531 return *(Child->second);
532}
533
534WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild(
535 ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) {
536 std::string NameString;
537 convertUTF16LEToUTF8String(NameRef, NameString);
538
539 auto Child = StringChildren.find(NameString);
540 if (Child == StringChildren.end()) {
541 auto NewChild = createStringNode(StringTable.size());
542 StringTable.push_back(NameRef);
544 StringChildren.emplace(NameString, std::move(NewChild));
545 return Node;
546 } else
547 return *(Child->second);
548}
549
551 StringRef Name) const {
552 ListScope NodeScope(Writer, Name);
553 for (auto const &Child : StringChildren) {
554 Child.second->print(Writer, Child.first);
555 }
556 for (auto const &Child : IDChildren) {
557 Child.second->print(Writer, to_string(Child.first));
558 }
559}
560
561// This function returns the size of the entire resource tree, including
562// directory tables, directory entries, and data entries. It does not include
563// the directory strings or the relocations of the .rsrc section.
565 uint32_t Size = (IDChildren.size() + StringChildren.size()) *
567
568 // Reached a node pointing to a data entry.
569 if (IsDataNode) {
571 return Size;
572 }
573
574 // If the node does not point to data, it must have a directory table pointing
575 // to other nodes.
576 Size += sizeof(coff_resource_dir_table);
577
578 for (auto const &Child : StringChildren) {
579 Size += Child.second->getTreeSize();
580 }
581 for (auto const &Child : IDChildren) {
582 Size += Child.second->getTreeSize();
583 }
584 return Size;
585}
586
587// Shift DataIndex of all data children with an Index greater or equal to the
588// given one, to fill a gap from removing an entry from the Data vector.
589void WindowsResourceParser::TreeNode::shiftDataIndexDown(uint32_t Index) {
590 if (IsDataNode && DataIndex >= Index) {
591 DataIndex--;
592 } else {
593 for (auto &Child : IDChildren)
594 Child.second->shiftDataIndexDown(Index);
595 for (auto &Child : StringChildren)
596 Child.second->shiftDataIndexDown(Index);
597 }
598}
599
601public:
604 std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp);
605
606private:
607 void performFileLayout();
608 void performSectionOneLayout();
609 void performSectionTwoLayout();
610 void writeCOFFHeader(uint32_t TimeDateStamp);
611 void writeFirstSectionHeader();
612 void writeSecondSectionHeader();
613 void writeFirstSection();
614 void writeSecondSection();
615 void writeSymbolTable();
616 void writeStringTable();
617 void writeDirectoryTree();
618 void writeDirectoryStringTable();
619 void writeFirstSectionRelocations();
620 std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
621 char *BufferStart;
622 uint64_t CurrentOffset = 0;
623 COFF::MachineTypes MachineType;
624 const WindowsResourceParser::TreeNode &Resources;
626 uint64_t FileSize;
627 uint32_t SymbolTableOffset;
628 uint32_t SectionOneSize;
629 uint32_t SectionOneOffset;
630 uint32_t SectionOneRelocations;
631 uint32_t SectionTwoSize;
632 uint32_t SectionTwoOffset;
634 std::vector<uint32_t> StringTableOffsets;
635 std::vector<uint32_t> DataOffsets;
636 std::vector<uint32_t> RelocationAddresses;
637};
638
641 Error &E)
642 : MachineType(MachineType), Resources(Parser.getTree()),
644 performFileLayout();
645
647 FileSize, "internal .obj file created from .res files");
648}
649
650void WindowsResourceCOFFWriter::performFileLayout() {
651 // Add size of COFF header.
652 FileSize = COFF::Header16Size;
653
654 // one .rsrc section header for directory tree, another for resource data.
655 FileSize += 2 * COFF::SectionSize;
656
657 performSectionOneLayout();
658 performSectionTwoLayout();
659
660 // We have reached the address of the symbol table.
661 SymbolTableOffset = FileSize;
662
663 FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol.
664 FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
665 FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
666 FileSize += 4; // four null bytes for the string table.
667}
668
669void WindowsResourceCOFFWriter::performSectionOneLayout() {
670 SectionOneOffset = FileSize;
671
672 SectionOneSize = Resources.getTreeSize();
673 uint32_t CurrentStringOffset = SectionOneSize;
674 uint32_t TotalStringTableSize = 0;
675 for (auto const &String : StringTable) {
676 StringTableOffsets.push_back(CurrentStringOffset);
677 uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
678 CurrentStringOffset += StringSize;
679 TotalStringTableSize += StringSize;
680 }
681 SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
682
683 // account for the relocations of section one.
684 SectionOneRelocations = FileSize + SectionOneSize;
685 FileSize += SectionOneSize;
686 FileSize +=
687 Data.size() * COFF::RelocationSize; // one relocation for each resource.
688 FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
689}
690
691void WindowsResourceCOFFWriter::performSectionTwoLayout() {
692 // add size of .rsrc$2 section, which contains all resource data on 8-byte
693 // alignment.
694 SectionTwoOffset = FileSize;
695 SectionTwoSize = 0;
696 for (auto const &Entry : Data) {
697 DataOffsets.push_back(SectionTwoSize);
698 SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
699 }
700 FileSize += SectionTwoSize;
701 FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
702}
703
704std::unique_ptr<MemoryBuffer>
706 BufferStart = OutputBuffer->getBufferStart();
707
708 writeCOFFHeader(TimeDateStamp);
709 writeFirstSectionHeader();
710 writeSecondSectionHeader();
711 writeFirstSection();
712 writeSecondSection();
713 writeSymbolTable();
714 writeStringTable();
715
716 return std::move(OutputBuffer);
717}
718
719// According to COFF specification, if the Src has a size equal to Dest,
720// it's okay to *not* copy the trailing zero.
721static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) {
722 assert(Src.size() <= COFF::NameSize &&
723 "Src is larger than COFF::NameSize");
724 assert((Src.size() == COFF::NameSize || Dest[Src.size()] == '\0') &&
725 "Dest not zeroed upon initialization");
726 memcpy(Dest, Src.data(), Src.size());
727}
728
729void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) {
730 // Write the COFF header.
731 auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
732 Header->Machine = MachineType;
733 Header->NumberOfSections = 2;
734 Header->TimeDateStamp = TimeDateStamp;
735 Header->PointerToSymbolTable = SymbolTableOffset;
736 // One symbol for every resource plus 2 for each section and 1 for @feat.00
737 Header->NumberOfSymbols = Data.size() + 5;
738 Header->SizeOfOptionalHeader = 0;
739 // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it.
740 Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
741}
742
743void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
744 // Write the first section header.
745 CurrentOffset += sizeof(coff_file_header);
746 auto *SectionOneHeader =
747 reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
748 coffnamecpy(SectionOneHeader->Name, ".rsrc$01");
749 SectionOneHeader->VirtualSize = 0;
750 SectionOneHeader->VirtualAddress = 0;
751 SectionOneHeader->SizeOfRawData = SectionOneSize;
752 SectionOneHeader->PointerToRawData = SectionOneOffset;
753 SectionOneHeader->PointerToRelocations = SectionOneRelocations;
754 SectionOneHeader->PointerToLinenumbers = 0;
755 SectionOneHeader->NumberOfRelocations = Data.size();
756 SectionOneHeader->NumberOfLinenumbers = 0;
757 SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
758 SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
759}
760
761void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
762 // Write the second section header.
763 CurrentOffset += sizeof(coff_section);
764 auto *SectionTwoHeader =
765 reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
766 coffnamecpy(SectionTwoHeader->Name, ".rsrc$02");
767 SectionTwoHeader->VirtualSize = 0;
768 SectionTwoHeader->VirtualAddress = 0;
769 SectionTwoHeader->SizeOfRawData = SectionTwoSize;
770 SectionTwoHeader->PointerToRawData = SectionTwoOffset;
771 SectionTwoHeader->PointerToRelocations = 0;
772 SectionTwoHeader->PointerToLinenumbers = 0;
773 SectionTwoHeader->NumberOfRelocations = 0;
774 SectionTwoHeader->NumberOfLinenumbers = 0;
775 SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
776 SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
777}
778
779void WindowsResourceCOFFWriter::writeFirstSection() {
780 // Write section one.
781 CurrentOffset += sizeof(coff_section);
782
783 writeDirectoryTree();
784 writeDirectoryStringTable();
785 writeFirstSectionRelocations();
786
787 CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
788}
789
790void WindowsResourceCOFFWriter::writeSecondSection() {
791 // Now write the .rsrc$02 section.
792 for (auto const &RawDataEntry : Data) {
793 llvm::copy(RawDataEntry, BufferStart + CurrentOffset);
794 CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
795 }
796
797 CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
798}
799
800void WindowsResourceCOFFWriter::writeSymbolTable() {
801 // Now write the symbol table.
802 // First, the feat symbol.
803 auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
804 coffnamecpy(Symbol->Name.ShortName, "@feat.00");
805 Symbol->Value = 0x11;
806 Symbol->SectionNumber = 0xffff;
808 Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
809 Symbol->NumberOfAuxSymbols = 0;
810 CurrentOffset += sizeof(coff_symbol16);
811
812 // Now write the .rsrc1 symbol + aux.
813 Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
814 coffnamecpy(Symbol->Name.ShortName, ".rsrc$01");
815 Symbol->Value = 0;
816 Symbol->SectionNumber = 1;
818 Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
819 Symbol->NumberOfAuxSymbols = 1;
820 CurrentOffset += sizeof(coff_symbol16);
821 auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
822 CurrentOffset);
823 Aux->Length = SectionOneSize;
824 Aux->NumberOfRelocations = Data.size();
825 Aux->NumberOfLinenumbers = 0;
826 Aux->CheckSum = 0;
827 Aux->NumberLowPart = 0;
828 Aux->Selection = 0;
829 CurrentOffset += sizeof(coff_aux_section_definition);
830
831 // Now write the .rsrc2 symbol + aux.
832 Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
833 coffnamecpy(Symbol->Name.ShortName, ".rsrc$02");
834 Symbol->Value = 0;
835 Symbol->SectionNumber = 2;
837 Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
838 Symbol->NumberOfAuxSymbols = 1;
839 CurrentOffset += sizeof(coff_symbol16);
840 Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
841 CurrentOffset);
842 Aux->Length = SectionTwoSize;
843 Aux->NumberOfRelocations = 0;
844 Aux->NumberOfLinenumbers = 0;
845 Aux->CheckSum = 0;
846 Aux->NumberLowPart = 0;
847 Aux->Selection = 0;
848 CurrentOffset += sizeof(coff_aux_section_definition);
849
850 // Now write a symbol for each relocation.
851 for (unsigned i = 0; i < Data.size(); i++) {
852 auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
853 Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
854 coffnamecpy(Symbol->Name.ShortName, RelocationName);
855 Symbol->Value = DataOffsets[i];
856 Symbol->SectionNumber = 2;
858 Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
859 Symbol->NumberOfAuxSymbols = 0;
860 CurrentOffset += sizeof(coff_symbol16);
861 }
862}
863
864void WindowsResourceCOFFWriter::writeStringTable() {
865 // Just 4 null bytes for the string table.
866 auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
867 memset(COFFStringTable, 0, 4);
868}
869
870void WindowsResourceCOFFWriter::writeDirectoryTree() {
871 // Traverse parsed resource tree breadth-first and write the corresponding
872 // COFF objects.
873 std::queue<const WindowsResourceParser::TreeNode *> Queue;
874 Queue.push(&Resources);
875 uint32_t NextLevelOffset =
876 sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
877 Resources.getIDChildren().size()) *
879 std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
880 uint32_t CurrentRelativeOffset = 0;
881
882 while (!Queue.empty()) {
883 auto CurrentNode = Queue.front();
884 Queue.pop();
885 auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
886 CurrentOffset);
887 Table->Characteristics = CurrentNode->getCharacteristics();
888 Table->TimeDateStamp = 0;
889 Table->MajorVersion = CurrentNode->getMajorVersion();
890 Table->MinorVersion = CurrentNode->getMinorVersion();
891 auto &IDChildren = CurrentNode->getIDChildren();
892 auto &StringChildren = CurrentNode->getStringChildren();
893 Table->NumberOfNameEntries = StringChildren.size();
894 Table->NumberOfIDEntries = IDChildren.size();
895 CurrentOffset += sizeof(coff_resource_dir_table);
896 CurrentRelativeOffset += sizeof(coff_resource_dir_table);
897
898 // Write the directory entries immediately following each directory table.
899 for (auto const &Child : StringChildren) {
900 auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
901 CurrentOffset);
902 Entry->Identifier.setNameOffset(
903 StringTableOffsets[Child.second->getStringIndex()]);
904 if (Child.second->checkIsDataNode()) {
905 Entry->Offset.DataEntryOffset = NextLevelOffset;
906 NextLevelOffset += sizeof(coff_resource_data_entry);
907 DataEntriesTreeOrder.push_back(Child.second.get());
908 } else {
909 Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
910 NextLevelOffset += sizeof(coff_resource_dir_table) +
911 (Child.second->getStringChildren().size() +
912 Child.second->getIDChildren().size()) *
914 Queue.push(Child.second.get());
915 }
916 CurrentOffset += sizeof(coff_resource_dir_entry);
917 CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
918 }
919 for (auto const &Child : IDChildren) {
920 auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
921 CurrentOffset);
922 Entry->Identifier.ID = Child.first;
923 if (Child.second->checkIsDataNode()) {
924 Entry->Offset.DataEntryOffset = NextLevelOffset;
925 NextLevelOffset += sizeof(coff_resource_data_entry);
926 DataEntriesTreeOrder.push_back(Child.second.get());
927 } else {
928 Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
929 NextLevelOffset += sizeof(coff_resource_dir_table) +
930 (Child.second->getStringChildren().size() +
931 Child.second->getIDChildren().size()) *
933 Queue.push(Child.second.get());
934 }
935 CurrentOffset += sizeof(coff_resource_dir_entry);
936 CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
937 }
938 }
939
940 RelocationAddresses.resize(Data.size());
941 // Now write all the resource data entries.
942 for (const auto *DataNodes : DataEntriesTreeOrder) {
943 auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
944 CurrentOffset);
945 RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
946 Entry->DataRVA = 0; // Set to zero because it is a relocation.
947 Entry->DataSize = Data[DataNodes->getDataIndex()].size();
948 Entry->Codepage = 0;
949 Entry->Reserved = 0;
950 CurrentOffset += sizeof(coff_resource_data_entry);
951 CurrentRelativeOffset += sizeof(coff_resource_data_entry);
952 }
953}
954
955void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
956 // Now write the directory string table for .rsrc$01
957 uint32_t TotalStringTableSize = 0;
958 for (auto &String : StringTable) {
959 uint16_t Length = String.size();
960 support::endian::write16le(BufferStart + CurrentOffset, Length);
961 CurrentOffset += sizeof(uint16_t);
962 auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
963 llvm::copy(String, Start);
964 CurrentOffset += Length * sizeof(UTF16);
965 TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
966 }
967 CurrentOffset +=
968 alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
969}
970
971void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
972
973 // Now write the relocations for .rsrc$01
974 // Five symbols already in table before we start, @feat.00 and 2 for each
975 // .rsrc section.
976 uint32_t NextSymbolIndex = 5;
977 for (unsigned i = 0; i < Data.size(); i++) {
978 auto *Reloc =
979 reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
980 Reloc->VirtualAddress = RelocationAddresses[i];
981 Reloc->SymbolTableIndex = NextSymbolIndex++;
982 switch (getMachineArchType(MachineType)) {
983 case Triple::thumb:
984 Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
985 break;
986 case Triple::x86_64:
987 Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
988 break;
989 case Triple::x86:
990 Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB;
991 break;
992 case Triple::aarch64:
993 Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
994 break;
995 default:
996 llvm_unreachable("unknown machine type");
997 }
998 CurrentOffset += sizeof(coff_relocation);
999 }
1000}
1001
1005 uint32_t TimeDateStamp) {
1006 Error E = Error::success();
1007 WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
1008 if (E)
1009 return E;
1010 return Writer.write(TimeDateStamp);
1011}
1012
1013} // namespace object
1014} // namespace llvm
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef< MemberData > Members, StringRef StringTable, uint64_t MembersOffset, unsigned NumSyms, uint64_t PrevMemberOffset=0, uint64_t NextMemberOffset=0, bool Is64Bit=false)
basic Basic Alias true
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define RETURN_IF_ERROR(Expr)
COFFYAML::WeakExternalCharacteristics Characteristics
Definition: COFFYAML.cpp:350
static Expected< StringRef > getFileName(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID)
#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED
Definition: ConvertUTF.h:143
std::string Name
uint64_t Size
bool End
Definition: ELF_riscv.cpp:480
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
#define UNWRAP_OR_RETURN(Name, Expr)
#define UNWRAP_REF_OR_RETURN(Name, Expr)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:168
An implementation of BinaryStream which holds its entire data set in a single contiguous buffer.
Provides read only access to a subclass of BinaryStream.
Error readObject(const T *&Dest)
Get a pointer to an object of type T from the underlying stream, as if by memcpy, and store the resul...
Error readWideString(ArrayRef< UTF16 > &Dest)
Similar to readCString, however read a null-terminated UTF16 string instead.
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream's offset.
uint64_t bytesRemaining() const
Error padToAlignment(uint32_t Align)
void setOffset(uint64_t Off)
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Get a reference to a NumElements element array of objects of type T from the underlying stream as if ...
BinaryStreamRef is to BinaryStream what ArrayRef is to an Array.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
A table of densely packed, null-terminated strings indexed by offset.
Definition: StringTable.h:31
constexpr size_t size() const
Returns the byte size of the table.
Definition: StringTable.h:86
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
TypeID
Definitions of all of the base types for the Type system.
Definition: Type.h:54
static std::unique_ptr< WritableMemoryBuffer > getNewMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new zero-initialized MemoryBuffer of the specified size.
StringRef getFileName() const
Definition: Binary.cpp:41
Expected< const coff_resource_dir_table & > getBaseTable()
Expected< const coff_resource_dir_table & > getEntrySubDir(const coff_resource_dir_entry &Entry)
Expected< const coff_resource_data_entry & > getEntryData(const coff_resource_dir_entry &Entry)
Expected< ArrayRef< UTF16 > > getEntryNameString(const coff_resource_dir_entry &Entry)
Expected< StringRef > getContents(const coff_resource_data_entry &Entry)
Expected< const coff_resource_dir_entry & > getTableEntry(const coff_resource_dir_table &Table, uint32_t Index)
WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, Error &E)
std::unique_ptr< MemoryBuffer > write(uint32_t TimeDateStamp)
const Children< std::string > & getStringChildren() const
const Children< uint32_t > & getIDChildren() const
void print(ScopedPrinter &Writer, StringRef Name) const
void cleanUpManifests(std::vector< std::string > &Duplicates)
const TreeNode & getTree() const
void printTree(raw_ostream &OS) const
ArrayRef< std::vector< uint8_t > > getData() const
ArrayRef< std::vector< UTF16 > > getStringTable() const
Error parse(WindowsResource *WR, std::vector< std::string > &Duplicates)
Expected< ResourceEntryRef > getHeadEntry()
static Expected< std::unique_ptr< WindowsResource > > createWindowsResource(MemoryBufferRef Source)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
MachineTypes
Definition: COFF.h:92
@ IMAGE_SCN_MEM_READ
Definition: COFF.h:335
@ IMAGE_SCN_CNT_INITIALIZED_DATA
Definition: COFF.h:303
@ IMAGE_REL_ARM64_ADDR32NB
Definition: COFF.h:402
@ NameSize
Definition: COFF.h:57
@ Header16Size
Definition: COFF.h:55
@ Symbol16Size
Definition: COFF.h:58
@ SectionSize
Definition: COFF.h:60
@ RelocationSize
Definition: COFF.h:61
@ IMAGE_REL_AMD64_ADDR32NB
Definition: COFF.h:363
@ IMAGE_SYM_CLASS_STATIC
Static.
Definition: COFF.h:224
@ IMAGE_REL_ARM_ADDR32NB
Definition: COFF.h:382
@ IMAGE_REL_I386_DIR32NB
Definition: COFF.h:350
@ Entry
Definition: COFF.h:844
@ IMAGE_FILE_32BIT_MACHINE
Machine is based on a 32bit word architecture.
Definition: COFF.h:159
@ IMAGE_SYM_DTYPE_NULL
No complex type; simple scalar variable.
Definition: COFF.h:273
const uint32_t MIN_HEADER_SIZE
static void printStringOrID(const WindowsResourceParser::StringOrID &S, raw_string_ostream &OS, bool IsType, bool IsID)
Expected< std::unique_ptr< MemoryBuffer > > writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, uint32_t TimeDateStamp)
const size_t WIN_RES_NULL_ENTRY_SIZE
const uint32_t WIN_RES_DATA_ALIGNMENT
void printResourceTypeName(uint16_t TypeID, raw_ostream &OS)
const uint32_t WIN_RES_HEADER_ALIGNMENT
static std::string makeDuplicateResourceError(const ResourceEntryRef &Entry, StringRef File1, StringRef File2)
static void coffnamecpy(char(&Dest)[COFF::NameSize], StringRef Src)
const size_t WIN_RES_MAGIC_SIZE
static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, ArrayRef< UTF16 > &Str, bool &IsString)
static bool convertUTF16LEToUTF8String(ArrayRef< UTF16 > Src, std::string &Out)
coff_symbol< support::ulittle16_t > coff_symbol16
Definition: COFF.h:269
static void writeStringTable(std::vector< uint8_t > &B, ArrayRef< const std::string_view > Strings)
const uint32_t SECTION_ALIGNMENT
void write16le(void *P, uint16_t V)
Definition: Endian.h:465
constexpr bool IsBigEndianHost
Definition: SwapByteOrder.h:26
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Length
Definition: DWP.cpp:480
std::string to_string(const T &Value)
Definition: ScopedPrinter.h:85
unsigned short UTF16
Definition: ConvertUTF.h:129
Triple::ArchType getMachineArchType(T machine)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1291
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
Definition: DWP.cpp:625
bool convertUTF16ToUTF8String(ArrayRef< char > SrcBytes, std::string &Out)
Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
@ Ref
The access may reference the value stored in memory.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
OutputIt copy(R &&Range, OutputIt Out)
Definition: STLExtras.h:1841
unsigned char UTF8
Definition: ConvertUTF.h:130
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1069
support::ulittle32_t VirtualAddress
Definition: COFF.h:479
Definition: COFF.h:822
Definition: COFF.h:799
support::ulittle16_t NumberOfNameEntries
Definition: COFF.h:834
support::ulittle32_t Characteristics
Definition: COFF.h:830
support::ulittle16_t NumberOfIDEntries
Definition: COFF.h:835
support::ulittle32_t TimeDateStamp
Definition: COFF.h:831
support::ulittle16_t MinorVersion
Definition: COFF.h:833
support::ulittle16_t MajorVersion
Definition: COFF.h:832