1f75da0c8SAlexey Lapshin //===- Archive.cpp --------------------------------------------------------===// 2f75da0c8SAlexey Lapshin // 3f75da0c8SAlexey Lapshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f75da0c8SAlexey Lapshin // See https://llvm.org/LICENSE.txt for license information. 5f75da0c8SAlexey Lapshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f75da0c8SAlexey Lapshin // 7f75da0c8SAlexey Lapshin //===----------------------------------------------------------------------===// 8f75da0c8SAlexey Lapshin 9f75da0c8SAlexey Lapshin #include "Archive.h" 10f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/CommonConfig.h" 11f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/MultiFormatConfig.h" 12f75da0c8SAlexey Lapshin #include "llvm/ObjCopy/ObjCopy.h" 13f75da0c8SAlexey Lapshin #include "llvm/Object/Error.h" 14f75da0c8SAlexey Lapshin #include "llvm/Support/FileOutputBuffer.h" 15f75da0c8SAlexey Lapshin #include "llvm/Support/SmallVectorMemoryBuffer.h" 16f75da0c8SAlexey Lapshin 17f75da0c8SAlexey Lapshin namespace llvm { 18f75da0c8SAlexey Lapshin namespace objcopy { 19f75da0c8SAlexey Lapshin 20f75da0c8SAlexey Lapshin using namespace llvm::object; 21f75da0c8SAlexey Lapshin 22f75da0c8SAlexey Lapshin Expected<std::vector<NewArchiveMember>> 23f75da0c8SAlexey Lapshin createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { 24f75da0c8SAlexey Lapshin std::vector<NewArchiveMember> NewArchiveMembers; 25f75da0c8SAlexey Lapshin Error Err = Error::success(); 26f75da0c8SAlexey Lapshin for (const Archive::Child &Child : Ar.children(Err)) { 27f75da0c8SAlexey Lapshin Expected<StringRef> ChildNameOrErr = Child.getName(); 28f75da0c8SAlexey Lapshin if (!ChildNameOrErr) 29f75da0c8SAlexey Lapshin return createFileError(Ar.getFileName(), ChildNameOrErr.takeError()); 30f75da0c8SAlexey Lapshin 31f75da0c8SAlexey Lapshin Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); 32f75da0c8SAlexey Lapshin if (!ChildOrErr) 33f75da0c8SAlexey Lapshin return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")", 34f75da0c8SAlexey Lapshin ChildOrErr.takeError()); 35f75da0c8SAlexey Lapshin 36f75da0c8SAlexey Lapshin SmallVector<char, 0> Buffer; 37f75da0c8SAlexey Lapshin raw_svector_ostream MemStream(Buffer); 38f75da0c8SAlexey Lapshin 39f75da0c8SAlexey Lapshin if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) 40f75da0c8SAlexey Lapshin return std::move(E); 41f75da0c8SAlexey Lapshin 42f75da0c8SAlexey Lapshin Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember( 43f75da0c8SAlexey Lapshin Child, Config.getCommonConfig().DeterministicArchives); 44f75da0c8SAlexey Lapshin if (!Member) 45f75da0c8SAlexey Lapshin return createFileError(Ar.getFileName(), Member.takeError()); 46f75da0c8SAlexey Lapshin 47f75da0c8SAlexey Lapshin Member->Buf = std::make_unique<SmallVectorMemoryBuffer>( 48f75da0c8SAlexey Lapshin std::move(Buffer), ChildNameOrErr.get()); 49f75da0c8SAlexey Lapshin Member->MemberName = Member->Buf->getBufferIdentifier(); 50f75da0c8SAlexey Lapshin NewArchiveMembers.push_back(std::move(*Member)); 51f75da0c8SAlexey Lapshin } 52f75da0c8SAlexey Lapshin if (Err) 53f75da0c8SAlexey Lapshin return createFileError(Config.getCommonConfig().InputFilename, 54f75da0c8SAlexey Lapshin std::move(Err)); 55f75da0c8SAlexey Lapshin return std::move(NewArchiveMembers); 56f75da0c8SAlexey Lapshin } 57f75da0c8SAlexey Lapshin 58f75da0c8SAlexey Lapshin // For regular archives this function simply calls llvm::writeArchive, 59f75da0c8SAlexey Lapshin // For thin archives it writes the archive file itself as well as its members. 60f75da0c8SAlexey Lapshin static Error deepWriteArchive(StringRef ArcName, 61f75da0c8SAlexey Lapshin ArrayRef<NewArchiveMember> NewMembers, 62*f740bcb3Szhijian SymtabWritingMode WriteSymtab, 63*f740bcb3Szhijian object::Archive::Kind Kind, bool Deterministic, 64*f740bcb3Szhijian bool Thin) { 6506624305SKeith Smiley if (Kind == object::Archive::K_BSD && !NewMembers.empty() && 6606624305SKeith Smiley NewMembers.front().detectKindFromObject() == object::Archive::K_DARWIN) 6706624305SKeith Smiley Kind = object::Archive::K_DARWIN; 6806624305SKeith Smiley 69f75da0c8SAlexey Lapshin if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind, 70f75da0c8SAlexey Lapshin Deterministic, Thin)) 71f75da0c8SAlexey Lapshin return createFileError(ArcName, std::move(E)); 72f75da0c8SAlexey Lapshin 73f75da0c8SAlexey Lapshin if (!Thin) 74f75da0c8SAlexey Lapshin return Error::success(); 75f75da0c8SAlexey Lapshin 76f75da0c8SAlexey Lapshin for (const NewArchiveMember &Member : NewMembers) { 77f75da0c8SAlexey Lapshin // For regular files (as is the case for deepWriteArchive), 78f75da0c8SAlexey Lapshin // FileOutputBuffer::create will return OnDiskBuffer. 79f75da0c8SAlexey Lapshin // OnDiskBuffer uses a temporary file and then renames it. So in reality 80f75da0c8SAlexey Lapshin // there is no inefficiency / duplicated in-memory buffers in this case. For 81f75da0c8SAlexey Lapshin // now in-memory buffers can not be completely avoided since 82f75da0c8SAlexey Lapshin // NewArchiveMember still requires them even though writeArchive does not 83f75da0c8SAlexey Lapshin // write them on disk. 84f75da0c8SAlexey Lapshin Expected<std::unique_ptr<FileOutputBuffer>> FB = 85f75da0c8SAlexey Lapshin FileOutputBuffer::create(Member.MemberName, Member.Buf->getBufferSize(), 86f75da0c8SAlexey Lapshin FileOutputBuffer::F_executable); 87f75da0c8SAlexey Lapshin if (!FB) 88f75da0c8SAlexey Lapshin return FB.takeError(); 89f75da0c8SAlexey Lapshin std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 90f75da0c8SAlexey Lapshin (*FB)->getBufferStart()); 91f75da0c8SAlexey Lapshin if (Error E = (*FB)->commit()) 92f75da0c8SAlexey Lapshin return E; 93f75da0c8SAlexey Lapshin } 94f75da0c8SAlexey Lapshin return Error::success(); 95f75da0c8SAlexey Lapshin } 96f75da0c8SAlexey Lapshin 97f75da0c8SAlexey Lapshin Error executeObjcopyOnArchive(const MultiFormatConfig &Config, 98f75da0c8SAlexey Lapshin const object::Archive &Ar) { 99f75da0c8SAlexey Lapshin Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr = 100f75da0c8SAlexey Lapshin createNewArchiveMembers(Config, Ar); 101f75da0c8SAlexey Lapshin if (!NewArchiveMembersOrErr) 102f75da0c8SAlexey Lapshin return NewArchiveMembersOrErr.takeError(); 103f75da0c8SAlexey Lapshin const CommonConfig &CommonConfig = Config.getCommonConfig(); 104f75da0c8SAlexey Lapshin return deepWriteArchive(CommonConfig.OutputFilename, *NewArchiveMembersOrErr, 105*f740bcb3Szhijian Ar.hasSymbolTable() ? SymtabWritingMode::NormalSymtab 106*f740bcb3Szhijian : SymtabWritingMode::NoSymtab, 107*f740bcb3Szhijian Ar.kind(), CommonConfig.DeterministicArchives, 108*f740bcb3Szhijian Ar.isThin()); 109f75da0c8SAlexey Lapshin } 110f75da0c8SAlexey Lapshin 111f75da0c8SAlexey Lapshin } // end namespace objcopy 112f75da0c8SAlexey Lapshin } // end namespace llvm 113