181ad6265SDimitry Andric //===- Archive.cpp --------------------------------------------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "Archive.h" 1081ad6265SDimitry Andric #include "llvm/ObjCopy/CommonConfig.h" 1181ad6265SDimitry Andric #include "llvm/ObjCopy/MultiFormatConfig.h" 1281ad6265SDimitry Andric #include "llvm/ObjCopy/ObjCopy.h" 1381ad6265SDimitry Andric #include "llvm/Object/Error.h" 1481ad6265SDimitry Andric #include "llvm/Object/MachO.h" 1581ad6265SDimitry Andric #include "llvm/Support/FileOutputBuffer.h" 1681ad6265SDimitry Andric #include "llvm/Support/SmallVectorMemoryBuffer.h" 1781ad6265SDimitry Andric 1881ad6265SDimitry Andric namespace llvm { 1981ad6265SDimitry Andric namespace objcopy { 2081ad6265SDimitry Andric 2181ad6265SDimitry Andric using namespace llvm::object; 2281ad6265SDimitry Andric 2381ad6265SDimitry Andric Expected<std::vector<NewArchiveMember>> 2481ad6265SDimitry Andric createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) { 2581ad6265SDimitry Andric std::vector<NewArchiveMember> NewArchiveMembers; 2681ad6265SDimitry Andric Error Err = Error::success(); 2781ad6265SDimitry Andric for (const Archive::Child &Child : Ar.children(Err)) { 2881ad6265SDimitry Andric Expected<StringRef> ChildNameOrErr = Child.getName(); 2981ad6265SDimitry Andric if (!ChildNameOrErr) 3081ad6265SDimitry Andric return createFileError(Ar.getFileName(), ChildNameOrErr.takeError()); 3181ad6265SDimitry Andric 3281ad6265SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); 3381ad6265SDimitry Andric if (!ChildOrErr) 3481ad6265SDimitry Andric return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")", 3581ad6265SDimitry Andric ChildOrErr.takeError()); 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric SmallVector<char, 0> Buffer; 3881ad6265SDimitry Andric raw_svector_ostream MemStream(Buffer); 3981ad6265SDimitry Andric 4081ad6265SDimitry Andric if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) 4181ad6265SDimitry Andric return std::move(E); 4281ad6265SDimitry Andric 4381ad6265SDimitry Andric Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember( 4481ad6265SDimitry Andric Child, Config.getCommonConfig().DeterministicArchives); 4581ad6265SDimitry Andric if (!Member) 4681ad6265SDimitry Andric return createFileError(Ar.getFileName(), Member.takeError()); 4781ad6265SDimitry Andric 4881ad6265SDimitry Andric Member->Buf = std::make_unique<SmallVectorMemoryBuffer>( 4981ad6265SDimitry Andric std::move(Buffer), ChildNameOrErr.get()); 5081ad6265SDimitry Andric Member->MemberName = Member->Buf->getBufferIdentifier(); 5181ad6265SDimitry Andric NewArchiveMembers.push_back(std::move(*Member)); 5281ad6265SDimitry Andric } 5381ad6265SDimitry Andric if (Err) 5481ad6265SDimitry Andric return createFileError(Config.getCommonConfig().InputFilename, 5581ad6265SDimitry Andric std::move(Err)); 5681ad6265SDimitry Andric return std::move(NewArchiveMembers); 5781ad6265SDimitry Andric } 5881ad6265SDimitry Andric 5981ad6265SDimitry Andric // For regular archives this function simply calls llvm::writeArchive, 6081ad6265SDimitry Andric // For thin archives it writes the archive file itself as well as its members. 6181ad6265SDimitry Andric static Error deepWriteArchive(StringRef ArcName, 6281ad6265SDimitry Andric ArrayRef<NewArchiveMember> NewMembers, 63*5f757f3fSDimitry Andric SymtabWritingMode WriteSymtab, 64*5f757f3fSDimitry Andric object::Archive::Kind Kind, bool Deterministic, 65*5f757f3fSDimitry Andric bool Thin) { 6681ad6265SDimitry Andric if (Kind == object::Archive::K_BSD && !NewMembers.empty() && 6781ad6265SDimitry Andric NewMembers.front().detectKindFromObject() == object::Archive::K_DARWIN) 6881ad6265SDimitry Andric Kind = object::Archive::K_DARWIN; 6981ad6265SDimitry Andric 7081ad6265SDimitry Andric if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind, 7181ad6265SDimitry Andric Deterministic, Thin)) 7281ad6265SDimitry Andric return createFileError(ArcName, std::move(E)); 7381ad6265SDimitry Andric 7481ad6265SDimitry Andric if (!Thin) 7581ad6265SDimitry Andric return Error::success(); 7681ad6265SDimitry Andric 7781ad6265SDimitry Andric for (const NewArchiveMember &Member : NewMembers) { 7881ad6265SDimitry Andric // For regular files (as is the case for deepWriteArchive), 7981ad6265SDimitry Andric // FileOutputBuffer::create will return OnDiskBuffer. 8081ad6265SDimitry Andric // OnDiskBuffer uses a temporary file and then renames it. So in reality 8181ad6265SDimitry Andric // there is no inefficiency / duplicated in-memory buffers in this case. For 8281ad6265SDimitry Andric // now in-memory buffers can not be completely avoided since 8381ad6265SDimitry Andric // NewArchiveMember still requires them even though writeArchive does not 8481ad6265SDimitry Andric // write them on disk. 8581ad6265SDimitry Andric Expected<std::unique_ptr<FileOutputBuffer>> FB = 8681ad6265SDimitry Andric FileOutputBuffer::create(Member.MemberName, Member.Buf->getBufferSize(), 8781ad6265SDimitry Andric FileOutputBuffer::F_executable); 8881ad6265SDimitry Andric if (!FB) 8981ad6265SDimitry Andric return FB.takeError(); 9081ad6265SDimitry Andric std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 9181ad6265SDimitry Andric (*FB)->getBufferStart()); 9281ad6265SDimitry Andric if (Error E = (*FB)->commit()) 9381ad6265SDimitry Andric return E; 9481ad6265SDimitry Andric } 9581ad6265SDimitry Andric return Error::success(); 9681ad6265SDimitry Andric } 9781ad6265SDimitry Andric 9881ad6265SDimitry Andric Error executeObjcopyOnArchive(const MultiFormatConfig &Config, 9981ad6265SDimitry Andric const object::Archive &Ar) { 10081ad6265SDimitry Andric Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr = 10181ad6265SDimitry Andric createNewArchiveMembers(Config, Ar); 10281ad6265SDimitry Andric if (!NewArchiveMembersOrErr) 10381ad6265SDimitry Andric return NewArchiveMembersOrErr.takeError(); 10481ad6265SDimitry Andric const CommonConfig &CommonConfig = Config.getCommonConfig(); 10581ad6265SDimitry Andric return deepWriteArchive(CommonConfig.OutputFilename, *NewArchiveMembersOrErr, 106*5f757f3fSDimitry Andric Ar.hasSymbolTable() ? SymtabWritingMode::NormalSymtab 107*5f757f3fSDimitry Andric : SymtabWritingMode::NoSymtab, 108*5f757f3fSDimitry Andric Ar.kind(), CommonConfig.DeterministicArchives, 109*5f757f3fSDimitry Andric Ar.isThin()); 11081ad6265SDimitry Andric } 11181ad6265SDimitry Andric 11281ad6265SDimitry Andric } // end namespace objcopy 11381ad6265SDimitry Andric } // end namespace llvm 114