xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjCopy/Archive.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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>>
createNewArchiveMembers(const MultiFormatConfig & Config,const Archive & Ar)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.
deepWriteArchive(StringRef ArcName,ArrayRef<NewArchiveMember> NewMembers,SymtabWritingMode WriteSymtab,object::Archive::Kind Kind,bool Deterministic,bool Thin)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 
executeObjcopyOnArchive(const MultiFormatConfig & Config,const object::Archive & Ar)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