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