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