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