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