]> git.lizzy.rs Git - rust.git/blob - src/rustllvm/ArchiveWrapper.cpp
Auto merge of #43648 - RalfJung:jemalloc-debug, r=alexcrichton
[rust.git] / src / rustllvm / ArchiveWrapper.cpp
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #include "rustllvm.h"
12
13 #include "llvm/Object/Archive.h"
14 #include "llvm/Object/ArchiveWriter.h"
15 #include "llvm/Support/Path.h"
16
17 using namespace llvm;
18 using namespace llvm::object;
19
20 struct RustArchiveMember {
21   const char *Filename;
22   const char *Name;
23   Archive::Child Child;
24
25   RustArchiveMember()
26       : Filename(nullptr), Name(nullptr),
27 #if LLVM_VERSION_GE(3, 8)
28         Child(nullptr, nullptr, nullptr)
29 #else
30         Child(nullptr, nullptr)
31 #endif
32   {
33   }
34   ~RustArchiveMember() {}
35 };
36
37 struct RustArchiveIterator {
38   bool First;
39   Archive::child_iterator Cur;
40   Archive::child_iterator End;
41 #if LLVM_VERSION_GE(3, 9)
42   Error Err;
43
44   RustArchiveIterator() : First(true), Err(Error::success()) {}
45 #else
46   RustArchiveIterator() : First(true) {}
47 #endif
48 };
49
50 enum class LLVMRustArchiveKind {
51   Other,
52   GNU,
53   MIPS64,
54   BSD,
55   COFF,
56 };
57
58 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
59   switch (Kind) {
60   case LLVMRustArchiveKind::GNU:
61     return Archive::K_GNU;
62   case LLVMRustArchiveKind::MIPS64:
63     return Archive::K_MIPS64;
64   case LLVMRustArchiveKind::BSD:
65     return Archive::K_BSD;
66   case LLVMRustArchiveKind::COFF:
67     return Archive::K_COFF;
68   default:
69     llvm_unreachable("Bad ArchiveKind.");
70   }
71 }
72
73 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
74 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
75 typedef Archive::Child *LLVMRustArchiveChildRef;
76 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
77 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
78
79 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
80   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
81       MemoryBuffer::getFile(Path, -1, false);
82   if (!BufOr) {
83     LLVMRustSetLastError(BufOr.getError().message().c_str());
84     return nullptr;
85   }
86
87 #if LLVM_VERSION_LE(3, 8)
88   ErrorOr<std::unique_ptr<Archive>> ArchiveOr =
89 #else
90   Expected<std::unique_ptr<Archive>> ArchiveOr =
91 #endif
92       Archive::create(BufOr.get()->getMemBufferRef());
93
94   if (!ArchiveOr) {
95 #if LLVM_VERSION_LE(3, 8)
96     LLVMRustSetLastError(ArchiveOr.getError().message().c_str());
97 #else
98     LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
99 #endif
100     return nullptr;
101   }
102
103   OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
104       std::move(ArchiveOr.get()), std::move(BufOr.get()));
105
106   return Ret;
107 }
108
109 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
110   delete RustArchive;
111 }
112
113 extern "C" LLVMRustArchiveIteratorRef
114 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
115   Archive *Archive = RustArchive->getBinary();
116   RustArchiveIterator *RAI = new RustArchiveIterator();
117 #if LLVM_VERSION_LE(3, 8)
118   RAI->Cur = Archive->child_begin();
119 #else
120   RAI->Cur = Archive->child_begin(RAI->Err);
121   if (RAI->Err) {
122     LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
123     delete RAI;
124     return nullptr;
125   }
126 #endif
127   RAI->End = Archive->child_end();
128   return RAI;
129 }
130
131 extern "C" LLVMRustArchiveChildConstRef
132 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
133   if (RAI->Cur == RAI->End)
134     return nullptr;
135
136   // Advancing the iterator validates the next child, and this can
137   // uncover an error. LLVM requires that we check all Errors,
138   // so we only advance the iterator if we actually need to fetch
139   // the next child.
140   // This means we must not advance the iterator in the *first* call,
141   // but instead advance it *before* fetching the child in all later calls.
142   if (!RAI->First) {
143     ++RAI->Cur;
144 #if LLVM_VERSION_GE(3, 9)
145     if (RAI->Err) {
146       LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str());
147       return nullptr;
148     }
149 #endif
150   } else {
151     RAI->First = false;
152   }
153
154   if (RAI->Cur == RAI->End)
155     return nullptr;
156
157 #if LLVM_VERSION_EQ(3, 8)
158   const ErrorOr<Archive::Child> *Cur = RAI->Cur.operator->();
159   if (!*Cur) {
160     LLVMRustSetLastError(Cur->getError().message().c_str());
161     return nullptr;
162   }
163   const Archive::Child &Child = Cur->get();
164 #else
165   const Archive::Child &Child = *RAI->Cur.operator->();
166 #endif
167   Archive::Child *Ret = new Archive::Child(Child);
168
169   return Ret;
170 }
171
172 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
173   delete Child;
174 }
175
176 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
177   delete RAI;
178 }
179
180 extern "C" const char *
181 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
182 #if LLVM_VERSION_GE(4, 0)
183   Expected<StringRef> NameOrErr = Child->getName();
184   if (!NameOrErr) {
185     // rustc_llvm currently doesn't use this error string, but it might be
186     // useful in the future, and in the mean time this tells LLVM that the
187     // error was not ignored and that it shouldn't abort the process.
188     LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
189     return nullptr;
190   }
191 #else
192   ErrorOr<StringRef> NameOrErr = Child->getName();
193   if (NameOrErr.getError())
194     return nullptr;
195 #endif
196   StringRef Name = NameOrErr.get();
197   *Size = Name.size();
198   return Name.data();
199 }
200
201 extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
202                                                 size_t *Size) {
203   StringRef Buf;
204 #if LLVM_VERSION_GE(4, 0)
205   Expected<StringRef> BufOrErr = Child->getBuffer();
206   if (!BufOrErr) {
207     LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
208     return nullptr;
209   }
210 #else
211   ErrorOr<StringRef> BufOrErr = Child->getBuffer();
212   if (BufOrErr.getError()) {
213     LLVMRustSetLastError(BufOrErr.getError().message().c_str());
214     return nullptr;
215   }
216 #endif
217   Buf = BufOrErr.get();
218   *Size = Buf.size();
219   return Buf.data();
220 }
221
222 extern "C" LLVMRustArchiveMemberRef
223 LLVMRustArchiveMemberNew(char *Filename, char *Name,
224                          LLVMRustArchiveChildRef Child) {
225   RustArchiveMember *Member = new RustArchiveMember;
226   Member->Filename = Filename;
227   Member->Name = Name;
228   if (Child)
229     Member->Child = *Child;
230   return Member;
231 }
232
233 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
234   delete Member;
235 }
236
237 extern "C" LLVMRustResult
238 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
239                      const LLVMRustArchiveMemberRef *NewMembers,
240                      bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
241
242 #if LLVM_VERSION_LE(3, 8)
243   std::vector<NewArchiveIterator> Members;
244 #else
245   std::vector<NewArchiveMember> Members;
246 #endif
247   auto Kind = fromRust(RustKind);
248
249   for (size_t I = 0; I < NumMembers; I++) {
250     auto Member = NewMembers[I];
251     assert(Member->Name);
252     if (Member->Filename) {
253 #if LLVM_VERSION_GE(3, 9)
254       Expected<NewArchiveMember> MOrErr =
255           NewArchiveMember::getFile(Member->Filename, true);
256       if (!MOrErr) {
257         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
258         return LLVMRustResult::Failure;
259       }
260 #if LLVM_VERSION_GE(5, 0)
261       MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
262 #endif
263       Members.push_back(std::move(*MOrErr));
264 #elif LLVM_VERSION_EQ(3, 8)
265       Members.push_back(NewArchiveIterator(Member->Filename));
266 #else
267       Members.push_back(NewArchiveIterator(Member->Filename, Member->Name));
268 #endif
269     } else {
270 #if LLVM_VERSION_LE(3, 8)
271       Members.push_back(NewArchiveIterator(Member->Child, Member->Name));
272 #else
273       Expected<NewArchiveMember> MOrErr =
274           NewArchiveMember::getOldMember(Member->Child, true);
275       if (!MOrErr) {
276         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
277         return LLVMRustResult::Failure;
278       }
279       Members.push_back(std::move(*MOrErr));
280 #endif
281     }
282   }
283 #if LLVM_VERSION_GE(3, 8)
284   auto Pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
285 #else
286   auto Pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true);
287 #endif
288   if (!Pair.second)
289     return LLVMRustResult::Success;
290   LLVMRustSetLastError(Pair.second.message().c_str());
291   return LLVMRustResult::Failure;
292 }