• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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