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 SymtabWritingMode WriteSymtab, 63 object::Archive::Kind Kind, bool Deterministic, 64 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() ? SymtabWritingMode::NormalSymtab 106 : SymtabWritingMode::NoSymtab, 107 Ar.kind(), CommonConfig.DeterministicArchives, 108 Ar.isThin()); 109 } 110 111 } // end namespace objcopy 112 } // end namespace llvm 113