1 //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/ADT/Triple.h"
14 #include "llvm/Object/Binary.h"
15 #include "llvm/Object/Error.h"
16 #include "llvm/Object/ObjectFile.h"
17 #include "llvm/Object/SymbolicFile.h"
18 #include "llvm/Object/Wasm.h"
19 #include "llvm/Support/Endian.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/LEB128.h"
23 #include "llvm/Support/Wasm.h"
24 #include <algorithm>
25 #include <cstdint>
26 #include <system_error>
27 
28 using namespace llvm;
29 using namespace object;
30 
31 Expected<std::unique_ptr<WasmObjectFile>>
32 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
33   Error Err = Error::success();
34   auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err);
35   if (Err)
36     return std::move(Err);
37 
38   return std::move(ObjectFile);
39 }
40 
41 static uint32_t readUint32(const uint8_t *&Ptr) {
42   uint32_t Result = support::endian::read32le(Ptr);
43   Ptr += sizeof(Result);
44   return Result;
45 }
46 
47 static uint64_t readULEB128(const uint8_t *&Ptr) {
48   unsigned Count;
49   uint64_t Result = decodeULEB128(Ptr, &Count);
50   Ptr += Count;
51   return Result;
52 }
53 
54 static StringRef readString(const uint8_t *&Ptr) {
55   uint32_t StringLen = readULEB128(Ptr);
56   StringRef Return = StringRef(reinterpret_cast<const char *>(Ptr), StringLen);
57   Ptr += StringLen;
58   return Return;
59 }
60 
61 static Error readSection(wasm::WasmSection &Section, const uint8_t *&Ptr,
62                          const uint8_t *Start) {
63   // TODO(sbc): Avoid reading past EOF in the case of malformed files.
64   Section.Offset = Ptr - Start;
65   Section.Type = readULEB128(Ptr);
66   uint32_t Size = readULEB128(Ptr);
67   if (Size == 0)
68     return make_error<StringError>("Zero length section",
69                                    object_error::parse_failed);
70   Section.Content = ArrayRef<uint8_t>(Ptr, Size);
71   Ptr += Size;
72   return Error::success();
73 }
74 
75 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
76     : ObjectFile(Binary::ID_Wasm, Buffer) {
77   ErrorAsOutParameter ErrAsOutParam(&Err);
78   Header.Magic = getData().substr(0, 4);
79   if (Header.Magic != StringRef("\0asm", 4)) {
80     Err = make_error<StringError>("Bad magic number",
81                                   object_error::parse_failed);
82     return;
83   }
84   const uint8_t *Ptr = getPtr(4);
85   Header.Version = readUint32(Ptr);
86   if (Header.Version != wasm::WasmVersion) {
87     Err = make_error<StringError>("Bad version number",
88                                   object_error::parse_failed);
89     return;
90   }
91 
92   const uint8_t *Eof = getPtr(getData().size());
93   wasm::WasmSection Sec;
94   while (Ptr < Eof) {
95     if ((Err = readSection(Sec, Ptr, getPtr(0))))
96       return;
97     if (Sec.Type == wasm::WASM_SEC_CUSTOM) {
98       if ((Err =
99                parseCustomSection(Sec, Sec.Content.data(), Sec.Content.size())))
100         return;
101     }
102     Sections.push_back(Sec);
103   }
104 }
105 
106 Error WasmObjectFile::parseCustomSection(wasm::WasmSection &Sec,
107                                          const uint8_t *Ptr, size_t Length) {
108   Sec.Name = readString(Ptr);
109   return Error::success();
110 }
111 
112 const uint8_t *WasmObjectFile::getPtr(size_t Offset) const {
113   return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data());
114 }
115 
116 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
117   return Header;
118 }
119 
120 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
121   llvm_unreachable("not yet implemented");
122 }
123 
124 std::error_code WasmObjectFile::printSymbolName(raw_ostream &OS,
125                                                 DataRefImpl Symb) const {
126   llvm_unreachable("not yet implemented");
127   return object_error::invalid_symbol_index;
128 }
129 
130 uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
131   llvm_unreachable("not yet implemented");
132   return 0;
133 }
134 
135 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
136   return BasicSymbolRef(DataRefImpl(), this);
137 }
138 
139 basic_symbol_iterator WasmObjectFile::symbol_end() const {
140   return BasicSymbolRef(DataRefImpl(), this);
141 }
142 
143 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
144   llvm_unreachable("not yet implemented");
145   return errorCodeToError(object_error::invalid_symbol_index);
146 }
147 
148 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
149   llvm_unreachable("not yet implemented");
150   return errorCodeToError(object_error::invalid_symbol_index);
151 }
152 
153 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
154   llvm_unreachable("not yet implemented");
155   return 0;
156 }
157 
158 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
159   llvm_unreachable("not yet implemented");
160   return 0;
161 }
162 
163 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
164   llvm_unreachable("not yet implemented");
165   return 0;
166 }
167 
168 Expected<SymbolRef::Type>
169 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
170   llvm_unreachable("not yet implemented");
171   return errorCodeToError(object_error::invalid_symbol_index);
172 }
173 
174 Expected<section_iterator>
175 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
176   llvm_unreachable("not yet implemented");
177   return errorCodeToError(object_error::invalid_symbol_index);
178 }
179 
180 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
181 
182 std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
183                                                StringRef &Res) const {
184   const wasm::WasmSection &S = Sections[Sec.d.a];
185 #define ECase(X)                                                               \
186   case wasm::WASM_SEC_##X:                                                     \
187     Res = #X;                                                                  \
188     break
189   switch (S.Type) {
190     ECase(TYPE);
191     ECase(IMPORT);
192     ECase(FUNCTION);
193     ECase(TABLE);
194     ECase(MEMORY);
195     ECase(GLOBAL);
196     ECase(EXPORT);
197     ECase(START);
198     ECase(ELEM);
199     ECase(CODE);
200     ECase(DATA);
201   case wasm::WASM_SEC_CUSTOM:
202     Res = S.Name;
203     break;
204   default:
205     return object_error::invalid_section_index;
206   }
207 #undef ECase
208   return std::error_code();
209 }
210 
211 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
212 
213 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
214   const wasm::WasmSection &S = Sections[Sec.d.a];
215   return S.Content.size();
216 }
217 
218 std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec,
219                                                    StringRef &Res) const {
220   const wasm::WasmSection &S = Sections[Sec.d.a];
221   // This will never fail since wasm sections can never be empty (user-sections
222   // must have a name and non-user sections each have a defined structure).
223   Res = StringRef(reinterpret_cast<const char *>(S.Content.data()),
224                   S.Content.size());
225   return std::error_code();
226 }
227 
228 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
229   return 1;
230 }
231 
232 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
233   return false;
234 }
235 
236 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
237   const wasm::WasmSection &S = Sections[Sec.d.a];
238   return S.Type == wasm::WASM_SEC_CODE;
239 }
240 
241 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
242   const wasm::WasmSection &S = Sections[Sec.d.a];
243   return S.Type == wasm::WASM_SEC_DATA;
244 }
245 
246 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
247 
248 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
249 
250 bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; }
251 
252 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Sec) const {
253   llvm_unreachable("not yet implemented");
254   RelocationRef Rel;
255   return relocation_iterator(Rel);
256 }
257 
258 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Sec) const {
259   llvm_unreachable("not yet implemented");
260   RelocationRef Rel;
261   return relocation_iterator(Rel);
262 }
263 
264 section_iterator WasmObjectFile::getRelocatedSection(DataRefImpl Sec) const {
265   llvm_unreachable("not yet implemented");
266   SectionRef Ref;
267   return section_iterator(Ref);
268 }
269 
270 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
271   llvm_unreachable("not yet implemented");
272 }
273 
274 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Rel) const {
275   llvm_unreachable("not yet implemented");
276   return 0;
277 }
278 
279 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
280   llvm_unreachable("not yet implemented");
281   SymbolRef Ref;
282   return symbol_iterator(Ref);
283 }
284 
285 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Rel) const {
286   llvm_unreachable("not yet implemented");
287   return 0;
288 }
289 
290 void WasmObjectFile::getRelocationTypeName(
291     DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
292   llvm_unreachable("not yet implemented");
293 }
294 
295 section_iterator WasmObjectFile::section_begin() const {
296   DataRefImpl Ref;
297   Ref.d.a = 0;
298   return section_iterator(SectionRef(Ref, this));
299 }
300 
301 section_iterator WasmObjectFile::section_end() const {
302   DataRefImpl Ref;
303   Ref.d.a = Sections.size();
304   return section_iterator(SectionRef(Ref, this));
305 }
306 
307 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
308 
309 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
310 
311 unsigned WasmObjectFile::getArch() const { return Triple::wasm32; }
312 
313 SubtargetFeatures WasmObjectFile::getFeatures() const {
314   return SubtargetFeatures();
315 }
316 
317 bool WasmObjectFile::isRelocatableObject() const { return false; }
318 
319 const wasm::WasmSection *
320 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
321   return &Sections[Section.getRawDataRefImpl().d.a];
322 }
323