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