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 SymtabWritingMode WriteSymtab, 64 object::Archive::Kind Kind, bool Deterministic, 65 bool Thin) { 66 if (Kind == object::Archive::K_BSD && !NewMembers.empty() && 67 NewMembers.front().detectKindFromObject() == object::Archive::K_DARWIN) 68 Kind = object::Archive::K_DARWIN; 69 70 if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind, 71 Deterministic, Thin)) 72 return createFileError(ArcName, std::move(E)); 73 74 if (!Thin) 75 return Error::success(); 76 77 for (const NewArchiveMember &Member : NewMembers) { 78 // For regular files (as is the case for deepWriteArchive), 79 // FileOutputBuffer::create will return OnDiskBuffer. 80 // OnDiskBuffer uses a temporary file and then renames it. So in reality 81 // there is no inefficiency / duplicated in-memory buffers in this case. For 82 // now in-memory buffers can not be completely avoided since 83 // NewArchiveMember still requires them even though writeArchive does not 84 // write them on disk. 85 Expected<std::unique_ptr<FileOutputBuffer>> FB = 86 FileOutputBuffer::create(Member.MemberName, Member.Buf->getBufferSize(), 87 FileOutputBuffer::F_executable); 88 if (!FB) 89 return FB.takeError(); 90 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 91 (*FB)->getBufferStart()); 92 if (Error E = (*FB)->commit()) 93 return E; 94 } 95 return Error::success(); 96 } 97 98 Error executeObjcopyOnArchive(const MultiFormatConfig &Config, 99 const object::Archive &Ar) { 100 Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr = 101 createNewArchiveMembers(Config, Ar); 102 if (!NewArchiveMembersOrErr) 103 return NewArchiveMembersOrErr.takeError(); 104 const CommonConfig &CommonConfig = Config.getCommonConfig(); 105 return deepWriteArchive(CommonConfig.OutputFilename, *NewArchiveMembersOrErr, 106 Ar.hasSymbolTable() ? SymtabWritingMode::NormalSymtab 107 : SymtabWritingMode::NoSymtab, 108 Ar.kind(), CommonConfig.DeterministicArchives, 109 Ar.isThin()); 110 } 111 112 } // end namespace objcopy 113 } // end namespace llvm 114