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