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