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