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