diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp | 346 |
1 files changed, 68 insertions, 278 deletions
diff --git a/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp b/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp index 10717718b201..d76e1231684c 100644 --- a/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp +++ b/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp @@ -30,24 +30,15 @@ namespace object { if (auto EC = X) \ return EC; -#define UNWRAP_REF_OR_RETURN(Name, Expr) \ - auto Name##OrErr = Expr; \ - if (!Name##OrErr) \ - return Name##OrErr.takeError(); \ - const auto &Name = *Name##OrErr; - -#define UNWRAP_OR_RETURN(Name, Expr) \ - auto Name##OrErr = Expr; \ - if (!Name##OrErr) \ - return Name##OrErr.takeError(); \ - auto Name = *Name##OrErr; - const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); // COFF files seem to be inconsistent with alignment between sections, just use // 8-byte because it makes everyone happy. const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t); +uint32_t WindowsResourceParser::TreeNode::StringCount = 0; +uint32_t WindowsResourceParser::TreeNode::DataCount = 0; + WindowsResource::WindowsResource(MemoryBufferRef Source) : Binary(Binary::ID_WinRes, Source) { size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE; @@ -137,8 +128,7 @@ Error ResourceEntryRef::loadNext() { return Error::success(); } -WindowsResourceParser::WindowsResourceParser(bool MinGW) - : Root(false), MinGW(MinGW) {} +WindowsResourceParser::WindowsResourceParser() : Root(false) {} void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) { switch (TypeID) { @@ -210,122 +200,6 @@ static std::string makeDuplicateResourceError( return OS.str(); } -static void printStringOrID(const WindowsResourceParser::StringOrID &S, - raw_string_ostream &OS, bool IsType, bool IsID) { - if (S.IsString) { - std::string UTF8; - if (!convertUTF16LEToUTF8String(S.String, UTF8)) - UTF8 = "(failed conversion from UTF16)"; - OS << '\"' << UTF8 << '\"'; - } else if (IsType) - printResourceTypeName(S.ID, OS); - else if (IsID) - OS << "ID " << S.ID; - else - OS << S.ID; -} - -static std::string makeDuplicateResourceError( - const std::vector<WindowsResourceParser::StringOrID> &Context, - StringRef File1, StringRef File2) { - std::string Ret; - raw_string_ostream OS(Ret); - - OS << "duplicate resource:"; - - if (Context.size() >= 1) { - OS << " type "; - printStringOrID(Context[0], OS, /* IsType */ true, /* IsID */ true); - } - - if (Context.size() >= 2) { - OS << "/name "; - printStringOrID(Context[1], OS, /* IsType */ false, /* IsID */ true); - } - - if (Context.size() >= 3) { - OS << "/language "; - printStringOrID(Context[2], OS, /* IsType */ false, /* IsID */ false); - } - OS << ", in " << File1 << " and in " << File2; - - return OS.str(); -} - -// MinGW specific. Remove default manifests (with language zero) if there are -// other manifests present, and report an error if there are more than one -// manifest with a non-zero language code. -// GCC has the concept of a default manifest resource object, which gets -// linked in implicitly if present. This default manifest has got language -// id zero, and should be dropped silently if there's another manifest present. -// If the user resources surprisignly had a manifest with language id zero, -// we should also ignore the duplicate default manifest. -void WindowsResourceParser::cleanUpManifests( - std::vector<std::string> &Duplicates) { - auto TypeIt = Root.IDChildren.find(/* RT_MANIFEST */ 24); - if (TypeIt == Root.IDChildren.end()) - return; - - TreeNode *TypeNode = TypeIt->second.get(); - auto NameIt = - TypeNode->IDChildren.find(/* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1); - if (NameIt == TypeNode->IDChildren.end()) - return; - - TreeNode *NameNode = NameIt->second.get(); - if (NameNode->IDChildren.size() <= 1) - return; // None or one manifest present, all good. - - // If we have more than one manifest, drop the language zero one if present, - // and check again. - auto LangZeroIt = NameNode->IDChildren.find(0); - if (LangZeroIt != NameNode->IDChildren.end() && - LangZeroIt->second->IsDataNode) { - uint32_t RemovedIndex = LangZeroIt->second->DataIndex; - NameNode->IDChildren.erase(LangZeroIt); - Data.erase(Data.begin() + RemovedIndex); - Root.shiftDataIndexDown(RemovedIndex); - - // If we're now down to one manifest, all is good. - if (NameNode->IDChildren.size() <= 1) - return; - } - - // More than one non-language-zero manifest - auto FirstIt = NameNode->IDChildren.begin(); - uint32_t FirstLang = FirstIt->first; - TreeNode *FirstNode = FirstIt->second.get(); - auto LastIt = NameNode->IDChildren.rbegin(); - uint32_t LastLang = LastIt->first; - TreeNode *LastNode = LastIt->second.get(); - Duplicates.push_back( - ("duplicate non-default manifests with languages " + Twine(FirstLang) + - " in " + InputFilenames[FirstNode->Origin] + " and " + Twine(LastLang) + - " in " + InputFilenames[LastNode->Origin]) - .str()); -} - -// Ignore duplicates of manifests with language zero (the default manifest), -// in case the user has provided a manifest with that language id. See -// the function comment above for context. Only returns true if MinGW is set -// to true. -bool WindowsResourceParser::shouldIgnoreDuplicate( - const ResourceEntryRef &Entry) const { - return MinGW && !Entry.checkTypeString() && - Entry.getTypeID() == /* RT_MANIFEST */ 24 && - !Entry.checkNameString() && - Entry.getNameID() == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 && - Entry.getLanguage() == 0; -} - -bool WindowsResourceParser::shouldIgnoreDuplicate( - const std::vector<StringOrID> &Context) const { - return MinGW && Context.size() == 3 && !Context[0].IsString && - Context[0].ID == /* RT_MANIFEST */ 24 && !Context[1].IsString && - Context[1].ID == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 && - !Context[2].IsString && Context[2].ID == 0; -} - Error WindowsResourceParser::parse(WindowsResource *WR, std::vector<std::string> &Duplicates) { auto EntryOrErr = WR->getHeadEntry(); @@ -345,176 +219,112 @@ Error WindowsResourceParser::parse(WindowsResource *WR, } ResourceEntryRef Entry = EntryOrErr.get(); - uint32_t Origin = InputFilenames.size(); - InputFilenames.push_back(WR->getFileName()); bool End = false; while (!End) { + Data.push_back(Entry.getData()); - TreeNode *Node; - bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node); + bool IsNewTypeString = false; + bool IsNewNameString = false; + + TreeNode* Node; + bool IsNewNode = Root.addEntry(Entry, InputFilenames.size(), + IsNewTypeString, IsNewNameString, Node); + InputFilenames.push_back(WR->getFileName()); if (!IsNewNode) { - if (!shouldIgnoreDuplicate(Entry)) - Duplicates.push_back(makeDuplicateResourceError( - Entry, InputFilenames[Node->Origin], WR->getFileName())); + Duplicates.push_back(makeDuplicateResourceError( + Entry, InputFilenames[Node->Origin], WR->getFileName())); } + if (IsNewTypeString) + StringTable.push_back(Entry.getTypeString()); + + if (IsNewNameString) + StringTable.push_back(Entry.getNameString()); + RETURN_IF_ERROR(Entry.moveNext(End)); } return Error::success(); } -Error WindowsResourceParser::parse(ResourceSectionRef &RSR, StringRef Filename, - std::vector<std::string> &Duplicates) { - UNWRAP_REF_OR_RETURN(BaseTable, RSR.getBaseTable()); - uint32_t Origin = InputFilenames.size(); - InputFilenames.push_back(Filename); - std::vector<StringOrID> Context; - return addChildren(Root, RSR, BaseTable, Origin, Context, Duplicates); -} - void WindowsResourceParser::printTree(raw_ostream &OS) const { ScopedPrinter Writer(OS); Root.print(Writer, "Resource Tree"); } -bool WindowsResourceParser::TreeNode::addEntry( - const ResourceEntryRef &Entry, uint32_t Origin, - std::vector<std::vector<uint8_t>> &Data, - std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) { - TreeNode &TypeNode = addTypeNode(Entry, StringTable); - TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable); - return NameNode.addLanguageNode(Entry, Origin, Data, Result); +bool WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry, + uint32_t Origin, + bool &IsNewTypeString, + bool &IsNewNameString, + TreeNode *&Result) { + TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString); + TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString); + return NameNode.addLanguageNode(Entry, Origin, Result); } -Error WindowsResourceParser::addChildren(TreeNode &Node, - ResourceSectionRef &RSR, - const coff_resource_dir_table &Table, - uint32_t Origin, - std::vector<StringOrID> &Context, - std::vector<std::string> &Duplicates) { - - for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries; - i++) { - UNWRAP_REF_OR_RETURN(Entry, RSR.getTableEntry(Table, i)); - TreeNode *Child; - - if (Entry.Offset.isSubDir()) { - - // Create a new subdirectory and recurse - if (i < Table.NumberOfNameEntries) { - UNWRAP_OR_RETURN(NameString, RSR.getEntryNameString(Entry)); - Child = &Node.addNameChild(NameString, StringTable); - Context.push_back(StringOrID(NameString)); - } else { - Child = &Node.addIDChild(Entry.Identifier.ID); - Context.push_back(StringOrID(Entry.Identifier.ID)); - } - - UNWRAP_REF_OR_RETURN(NextTable, RSR.getEntrySubDir(Entry)); - Error E = - addChildren(*Child, RSR, NextTable, Origin, Context, Duplicates); - if (E) - return E; - Context.pop_back(); - - } else { - - // Data leaves are supposed to have a numeric ID as identifier (language). - if (Table.NumberOfNameEntries > 0) - return createStringError(object_error::parse_failed, - "unexpected string key for data object"); - - // Try adding a data leaf - UNWRAP_REF_OR_RETURN(DataEntry, RSR.getEntryData(Entry)); - TreeNode *Child; - Context.push_back(StringOrID(Entry.Identifier.ID)); - bool Added = Node.addDataChild(Entry.Identifier.ID, Table.MajorVersion, - Table.MinorVersion, Table.Characteristics, - Origin, Data.size(), Child); - if (Added) { - UNWRAP_OR_RETURN(Contents, RSR.getContents(DataEntry)); - Data.push_back(ArrayRef<uint8_t>( - reinterpret_cast<const uint8_t *>(Contents.data()), - Contents.size())); - } else { - if (!shouldIgnoreDuplicate(Context)) - Duplicates.push_back(makeDuplicateResourceError( - Context, InputFilenames[Child->Origin], InputFilenames.back())); - } - Context.pop_back(); - - } - } - return Error::success(); +WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) { + if (IsStringNode) + StringIndex = StringCount++; } -WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex) - : StringIndex(StringIndex) {} - WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion, uint16_t MinorVersion, uint32_t Characteristics, - uint32_t Origin, uint32_t DataIndex) - : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion), - MinorVersion(MinorVersion), Characteristics(Characteristics), - Origin(Origin) {} + uint32_t Origin) + : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion), + Characteristics(Characteristics), Origin(Origin) { + DataIndex = DataCount++; +} std::unique_ptr<WindowsResourceParser::TreeNode> -WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) { - return std::unique_ptr<TreeNode>(new TreeNode(Index)); +WindowsResourceParser::TreeNode::createStringNode() { + return std::unique_ptr<TreeNode>(new TreeNode(true)); } std::unique_ptr<WindowsResourceParser::TreeNode> WindowsResourceParser::TreeNode::createIDNode() { - return std::unique_ptr<TreeNode>(new TreeNode(0)); + return std::unique_ptr<TreeNode>(new TreeNode(false)); } std::unique_ptr<WindowsResourceParser::TreeNode> WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion, uint16_t MinorVersion, uint32_t Characteristics, - uint32_t Origin, - uint32_t DataIndex) { - return std::unique_ptr<TreeNode>(new TreeNode( - MajorVersion, MinorVersion, Characteristics, Origin, DataIndex)); + uint32_t Origin) { + return std::unique_ptr<TreeNode>( + new TreeNode(MajorVersion, MinorVersion, Characteristics, Origin)); } -WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode( - const ResourceEntryRef &Entry, - std::vector<std::vector<UTF16>> &StringTable) { +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry, + bool &IsNewTypeString) { if (Entry.checkTypeString()) - return addNameChild(Entry.getTypeString(), StringTable); + return addNameChild(Entry.getTypeString(), IsNewTypeString); else return addIDChild(Entry.getTypeID()); } -WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode( - const ResourceEntryRef &Entry, - std::vector<std::vector<UTF16>> &StringTable) { +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry, + bool &IsNewNameString) { if (Entry.checkNameString()) - return addNameChild(Entry.getNameString(), StringTable); + return addNameChild(Entry.getNameString(), IsNewNameString); else return addIDChild(Entry.getNameID()); } bool WindowsResourceParser::TreeNode::addLanguageNode( - const ResourceEntryRef &Entry, uint32_t Origin, - std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) { - bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(), - Entry.getMinorVersion(), Entry.getCharacteristics(), - Origin, Data.size(), Result); - if (Added) - Data.push_back(Entry.getData()); - return Added; + const ResourceEntryRef &Entry, uint32_t Origin, TreeNode *&Result) { + return addDataChild(Entry.getLanguage(), Entry.getMajorVersion(), + Entry.getMinorVersion(), Entry.getCharacteristics(), + Origin, Result); } bool WindowsResourceParser::TreeNode::addDataChild( uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, - uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex, - TreeNode *&Result) { - auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics, - Origin, DataIndex); + uint32_t Characteristics, uint32_t Origin, TreeNode *&Result) { + auto NewChild = + createDataNode(MajorVersion, MinorVersion, Characteristics, Origin); auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild)); Result = ElementInserted.first->second.get(); return ElementInserted.second; @@ -532,15 +342,16 @@ WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild( return *(Child->second); } -WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild( - ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) { +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addNameChild(ArrayRef<UTF16> NameRef, + bool &IsNewString) { std::string NameString; convertUTF16LEToUTF8String(NameRef, NameString); auto Child = StringChildren.find(NameString); if (Child == StringChildren.end()) { - auto NewChild = createStringNode(StringTable.size()); - StringTable.push_back(NameRef); + auto NewChild = createStringNode(); + IsNewString = true; WindowsResourceParser::TreeNode &Node = *NewChild; StringChildren.emplace(NameString, std::move(NewChild)); return Node; @@ -585,19 +396,6 @@ uint32_t WindowsResourceParser::TreeNode::getTreeSize() const { return Size; } -// Shift DataIndex of all data children with an Index greater or equal to the -// given one, to fill a gap from removing an entry from the Data vector. -void WindowsResourceParser::TreeNode::shiftDataIndexDown(uint32_t Index) { - if (IsDataNode && DataIndex >= Index) { - DataIndex--; - } else { - for (auto &Child : IDChildren) - Child.second->shiftDataIndexDown(Index); - for (auto &Child : StringChildren) - Child.second->shiftDataIndexDown(Index); - } -} - class WindowsResourceCOFFWriter { public: WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, @@ -717,14 +515,6 @@ WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) { return std::move(OutputBuffer); } -// According to COFF specification, if the Src has a size equal to Dest, -// it's okay to *not* copy the trailing zero. -static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) { - assert(Src.size() <= COFF::NameSize && - "Src is not larger than COFF::NameSize"); - strncpy(Dest, Src.data(), (size_t)COFF::NameSize); -} - void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) { // Write the COFF header. auto *Header = reinterpret_cast<coff_file_header *>(BufferStart); @@ -744,7 +534,7 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() { CurrentOffset += sizeof(coff_file_header); auto *SectionOneHeader = reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); - coffnamecpy(SectionOneHeader->Name, ".rsrc$01"); + strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize); SectionOneHeader->VirtualSize = 0; SectionOneHeader->VirtualAddress = 0; SectionOneHeader->SizeOfRawData = SectionOneSize; @@ -762,7 +552,7 @@ void WindowsResourceCOFFWriter::writeSecondSectionHeader() { CurrentOffset += sizeof(coff_section); auto *SectionTwoHeader = reinterpret_cast<coff_section *>(BufferStart + CurrentOffset); - coffnamecpy(SectionTwoHeader->Name, ".rsrc$02"); + strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize); SectionTwoHeader->VirtualSize = 0; SectionTwoHeader->VirtualAddress = 0; SectionTwoHeader->SizeOfRawData = SectionTwoSize; @@ -800,7 +590,7 @@ void WindowsResourceCOFFWriter::writeSymbolTable() { // Now write the symbol table. // First, the feat symbol. auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); - coffnamecpy(Symbol->Name.ShortName, "@feat.00"); + strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize); Symbol->Value = 0x11; Symbol->SectionNumber = 0xffff; Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; @@ -810,7 +600,7 @@ void WindowsResourceCOFFWriter::writeSymbolTable() { // Now write the .rsrc1 symbol + aux. Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); - coffnamecpy(Symbol->Name.ShortName, ".rsrc$01"); + strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize); Symbol->Value = 0; Symbol->SectionNumber = 1; Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; @@ -829,7 +619,7 @@ void WindowsResourceCOFFWriter::writeSymbolTable() { // Now write the .rsrc2 symbol + aux. Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); - coffnamecpy(Symbol->Name.ShortName, ".rsrc$02"); + strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize); Symbol->Value = 0; Symbol->SectionNumber = 2; Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; @@ -850,7 +640,7 @@ void WindowsResourceCOFFWriter::writeSymbolTable() { for (unsigned i = 0; i < Data.size(); i++) { auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>(); Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset); - coffnamecpy(Symbol->Name.ShortName, RelocationName); + memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize); Symbol->Value = DataOffsets[i]; Symbol->SectionNumber = 2; Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; |
