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