]> git.proxmox.com Git - rustc.git/blame - src/rustllvm/ArchiveWrapper.cpp
New upstream version 1.42.0+dfsg1
[rustc.git] / src / rustllvm / ArchiveWrapper.cpp
CommitLineData
c1a9b12d
SL
1#include "rustllvm.h"
2
3#include "llvm/Object/Archive.h"
c1a9b12d 4#include "llvm/Object/ArchiveWriter.h"
3b2f2976 5#include "llvm/Support/Path.h"
c1a9b12d
SL
6
7using namespace llvm;
8using namespace llvm::object;
9
5bcae85e 10struct RustArchiveMember {
32a655c1
SL
11 const char *Filename;
12 const char *Name;
13 Archive::Child Child;
c1a9b12d 14
32a655c1
SL
15 RustArchiveMember()
16 : Filename(nullptr), Name(nullptr),
32a655c1 17 Child(nullptr, nullptr, nullptr)
32a655c1
SL
18 {
19 }
5bcae85e 20 ~RustArchiveMember() {}
c1a9b12d
SL
21};
22
5bcae85e 23struct RustArchiveIterator {
32a655c1
SL
24 bool First;
25 Archive::child_iterator Cur;
26 Archive::child_iterator End;
532ac7d7
XL
27 std::unique_ptr<Error> Err;
28
29 RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End,
30 std::unique_ptr<Error> Err)
31 : First(true),
32 Cur(Cur),
33 End(End),
34 Err(std::move(Err)) {}
5bcae85e
SL
35};
36
37enum class LLVMRustArchiveKind {
32a655c1
SL
38 Other,
39 GNU,
32a655c1
SL
40 BSD,
41 COFF,
5bcae85e
SL
42};
43
32a655c1
SL
44static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
45 switch (Kind) {
46 case LLVMRustArchiveKind::GNU:
47 return Archive::K_GNU;
32a655c1
SL
48 case LLVMRustArchiveKind::BSD:
49 return Archive::K_BSD;
50 case LLVMRustArchiveKind::COFF:
51 return Archive::K_COFF;
52 default:
ff7c6d11 53 report_fatal_error("Bad ArchiveKind.");
5bcae85e
SL
54 }
55}
56
57typedef OwningBinary<Archive> *LLVMRustArchiveRef;
58typedef RustArchiveMember *LLVMRustArchiveMemberRef;
59typedef Archive::Child *LLVMRustArchiveChildRef;
60typedef Archive::Child const *LLVMRustArchiveChildConstRef;
61typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
62
32a655c1
SL
63extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
64 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
65 MemoryBuffer::getFile(Path, -1, false);
66 if (!BufOr) {
67 LLVMRustSetLastError(BufOr.getError().message().c_str());
68 return nullptr;
69 }
c1a9b12d 70
32a655c1 71 Expected<std::unique_ptr<Archive>> ArchiveOr =
32a655c1 72 Archive::create(BufOr.get()->getMemBufferRef());
c1a9b12d 73
32a655c1 74 if (!ArchiveOr) {
32a655c1 75 LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
32a655c1
SL
76 return nullptr;
77 }
c1a9b12d 78
32a655c1
SL
79 OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
80 std::move(ArchiveOr.get()), std::move(BufOr.get()));
c1a9b12d 81
32a655c1 82 return Ret;
c1a9b12d
SL
83}
84
32a655c1
SL
85extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
86 delete RustArchive;
c1a9b12d
SL
87}
88
5bcae85e 89extern "C" LLVMRustArchiveIteratorRef
32a655c1
SL
90LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
91 Archive *Archive = RustArchive->getBinary();
dfeec247
XL
92#if LLVM_VERSION_GE(10, 0)
93 std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success());
94#else
532ac7d7 95 std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success());
dfeec247 96#endif
532ac7d7
XL
97 auto Cur = Archive->child_begin(*Err);
98 if (*Err) {
99 LLVMRustSetLastError(toString(std::move(*Err)).c_str());
32a655c1
SL
100 return nullptr;
101 }
532ac7d7
XL
102 auto End = Archive->child_end();
103 return new RustArchiveIterator(Cur, End, std::move(Err));
c1a9b12d
SL
104}
105
5bcae85e 106extern "C" LLVMRustArchiveChildConstRef
32a655c1
SL
107LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
108 if (RAI->Cur == RAI->End)
109 return nullptr;
110
111 // Advancing the iterator validates the next child, and this can
112 // uncover an error. LLVM requires that we check all Errors,
113 // so we only advance the iterator if we actually need to fetch
114 // the next child.
115 // This means we must not advance the iterator in the *first* call,
116 // but instead advance it *before* fetching the child in all later calls.
117 if (!RAI->First) {
118 ++RAI->Cur;
532ac7d7
XL
119 if (*RAI->Err) {
120 LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str());
32a655c1 121 return nullptr;
5bcae85e 122 }
32a655c1
SL
123 } else {
124 RAI->First = false;
125 }
126
127 if (RAI->Cur == RAI->End)
128 return nullptr;
129
32a655c1 130 const Archive::Child &Child = *RAI->Cur.operator->();
32a655c1 131 Archive::Child *Ret = new Archive::Child(Child);
7453a54e 132
32a655c1 133 return Ret;
c1a9b12d
SL
134}
135
32a655c1
SL
136extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
137 delete Child;
c1a9b12d
SL
138}
139
32a655c1
SL
140extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
141 delete RAI;
c1a9b12d
SL
142}
143
32a655c1
SL
144extern "C" const char *
145LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
32a655c1
SL
146 Expected<StringRef> NameOrErr = Child->getName();
147 if (!NameOrErr) {
b7449926 148 // rustc_codegen_llvm currently doesn't use this error string, but it might be
32a655c1
SL
149 // useful in the future, and in the mean time this tells LLVM that the
150 // error was not ignored and that it shouldn't abort the process.
151 LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
152 return nullptr;
153 }
32a655c1
SL
154 StringRef Name = NameOrErr.get();
155 *Size = Name.size();
156 return Name.data();
c1a9b12d
SL
157}
158
32a655c1
SL
159extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
160 size_t *Size) {
161 StringRef Buf;
32a655c1
SL
162 Expected<StringRef> BufOrErr = Child->getBuffer();
163 if (!BufOrErr) {
164 LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
165 return nullptr;
166 }
32a655c1
SL
167 Buf = BufOrErr.get();
168 *Size = Buf.size();
169 return Buf.data();
c1a9b12d
SL
170}
171
5bcae85e
SL
172extern "C" LLVMRustArchiveMemberRef
173LLVMRustArchiveMemberNew(char *Filename, char *Name,
32a655c1
SL
174 LLVMRustArchiveChildRef Child) {
175 RustArchiveMember *Member = new RustArchiveMember;
176 Member->Filename = Filename;
177 Member->Name = Name;
178 if (Child)
179 Member->Child = *Child;
180 return Member;
c1a9b12d
SL
181}
182
32a655c1
SL
183extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
184 delete Member;
c1a9b12d
SL
185}
186
5bcae85e 187extern "C" LLVMRustResult
32a655c1 188LLVMRustWriteArchive(char *Dst, size_t NumMembers,
5bcae85e 189 const LLVMRustArchiveMemberRef *NewMembers,
32a655c1 190 bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
5bcae85e 191
5bcae85e 192 std::vector<NewArchiveMember> Members;
32a655c1 193 auto Kind = fromRust(RustKind);
c1a9b12d 194
32a655c1
SL
195 for (size_t I = 0; I < NumMembers; I++) {
196 auto Member = NewMembers[I];
197 assert(Member->Name);
198 if (Member->Filename) {
32a655c1
SL
199 Expected<NewArchiveMember> MOrErr =
200 NewArchiveMember::getFile(Member->Filename, true);
5bcae85e
SL
201 if (!MOrErr) {
202 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
203 return LLVMRustResult::Failure;
204 }
3b2f2976 205 MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
5bcae85e 206 Members.push_back(std::move(*MOrErr));
c1a9b12d 207 } else {
32a655c1
SL
208 Expected<NewArchiveMember> MOrErr =
209 NewArchiveMember::getOldMember(Member->Child, true);
5bcae85e
SL
210 if (!MOrErr) {
211 LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
212 return LLVMRustResult::Failure;
213 }
214 Members.push_back(std::move(*MOrErr));
c1a9b12d
SL
215 }
216 }
0731742a 217
2c00a5a8 218 auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
2c00a5a8 219 if (!Result)
5bcae85e 220 return LLVMRustResult::Success;
2c00a5a8 221 LLVMRustSetLastError(toString(std::move(Result)).c_str());
2c00a5a8 222
5bcae85e 223 return LLVMRustResult::Failure;
c1a9b12d 224}