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/BinaryFormat/Wasm.h"
15 #include "llvm/MC/SubtargetFeature.h"
16 #include "llvm/Object/Binary.h"
17 #include "llvm/Object/Error.h"
18 #include "llvm/Object/ObjectFile.h"
19 #include "llvm/Object/SymbolicFile.h"
20 #include "llvm/Object/Wasm.h"
21 #include "llvm/Support/Endian.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/ErrorHandling.h"
24 #include "llvm/Support/LEB128.h"
25 #include <algorithm>
26 #include <cassert>
27 #include <cstdint>
28 #include <cstring>
29 #include <system_error>
30 
31 #define DEBUG_TYPE "wasm-object"
32 
33 using namespace llvm;
34 using namespace object;
35 
36 Expected<std::unique_ptr<WasmObjectFile>>
37 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
38   Error Err = Error::success();
39   auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err);
40   if (Err)
41     return std::move(Err);
42 
43   return std::move(ObjectFile);
44 }
45 
46 #define VARINT7_MAX ((1<<7)-1)
47 #define VARINT7_MIN (-(1<<7))
48 #define VARUINT7_MAX (1<<7)
49 #define VARUINT1_MAX (1)
50 
51 static uint8_t readUint8(const uint8_t *&Ptr) { return *Ptr++; }
52 
53 static uint32_t readUint32(const uint8_t *&Ptr) {
54   uint32_t Result = support::endian::read32le(Ptr);
55   Ptr += sizeof(Result);
56   return Result;
57 }
58 
59 static int32_t readFloat32(const uint8_t *&Ptr) {
60   int32_t Result = 0;
61   memcpy(&Result, Ptr, sizeof(Result));
62   Ptr += sizeof(Result);
63   return Result;
64 }
65 
66 static int64_t readFloat64(const uint8_t *&Ptr) {
67   int64_t Result = 0;
68   memcpy(&Result, Ptr, sizeof(Result));
69   Ptr += sizeof(Result);
70   return Result;
71 }
72 
73 static uint64_t readULEB128(const uint8_t *&Ptr) {
74   unsigned Count;
75   uint64_t Result = decodeULEB128(Ptr, &Count);
76   Ptr += Count;
77   return Result;
78 }
79 
80 static StringRef readString(const uint8_t *&Ptr) {
81   uint32_t StringLen = readULEB128(Ptr);
82   StringRef Return = StringRef(reinterpret_cast<const char *>(Ptr), StringLen);
83   Ptr += StringLen;
84   return Return;
85 }
86 
87 static int64_t readLEB128(const uint8_t *&Ptr) {
88   unsigned Count;
89   uint64_t Result = decodeSLEB128(Ptr, &Count);
90   Ptr += Count;
91   return Result;
92 }
93 
94 static uint8_t readVaruint1(const uint8_t *&Ptr) {
95   int64_t result = readLEB128(Ptr);
96   assert(result <= VARUINT1_MAX && result >= 0);
97   return result;
98 }
99 
100 static int8_t readVarint7(const uint8_t *&Ptr) {
101   int64_t result = readLEB128(Ptr);
102   assert(result <= VARINT7_MAX && result >= VARINT7_MIN);
103   return result;
104 }
105 
106 static uint8_t readVaruint7(const uint8_t *&Ptr) {
107   uint64_t result = readULEB128(Ptr);
108   assert(result <= VARUINT7_MAX);
109   return result;
110 }
111 
112 static int32_t readVarint32(const uint8_t *&Ptr) {
113   int64_t result = readLEB128(Ptr);
114   assert(result <= INT32_MAX && result >= INT32_MIN);
115   return result;
116 }
117 
118 static uint32_t readVaruint32(const uint8_t *&Ptr) {
119   uint64_t result = readULEB128(Ptr);
120   assert(result <= UINT32_MAX);
121   return result;
122 }
123 
124 static int64_t readVarint64(const uint8_t *&Ptr) {
125   return readLEB128(Ptr);
126 }
127 
128 static uint8_t readOpcode(const uint8_t *&Ptr) {
129   return readUint8(Ptr);
130 }
131 
132 static Error readInitExpr(wasm::WasmInitExpr &Expr, const uint8_t *&Ptr) {
133   Expr.Opcode = readOpcode(Ptr);
134 
135   switch (Expr.Opcode) {
136   case wasm::WASM_OPCODE_I32_CONST:
137     Expr.Value.Int32 = readVarint32(Ptr);
138     break;
139   case wasm::WASM_OPCODE_I64_CONST:
140     Expr.Value.Int64 = readVarint64(Ptr);
141     break;
142   case wasm::WASM_OPCODE_F32_CONST:
143     Expr.Value.Float32 = readFloat32(Ptr);
144     break;
145   case wasm::WASM_OPCODE_F64_CONST:
146     Expr.Value.Float64 = readFloat64(Ptr);
147     break;
148   case wasm::WASM_OPCODE_GET_GLOBAL:
149     Expr.Value.Global = readULEB128(Ptr);
150     break;
151   default:
152     return make_error<GenericBinaryError>("Invalid opcode in init_expr",
153                                           object_error::parse_failed);
154   }
155 
156   uint8_t EndOpcode = readOpcode(Ptr);
157   if (EndOpcode != wasm::WASM_OPCODE_END) {
158     return make_error<GenericBinaryError>("Invalid init_expr",
159                                           object_error::parse_failed);
160   }
161   return Error::success();
162 }
163 
164 static wasm::WasmLimits readLimits(const uint8_t *&Ptr) {
165   wasm::WasmLimits Result;
166   Result.Flags = readVaruint1(Ptr);
167   Result.Initial = readVaruint32(Ptr);
168   if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
169     Result.Maximum = readVaruint32(Ptr);
170   return Result;
171 }
172 
173 static wasm::WasmTable readTable(const uint8_t *&Ptr) {
174   wasm::WasmTable Table;
175   Table.ElemType = readVarint7(Ptr);
176   Table.Limits = readLimits(Ptr);
177   return Table;
178 }
179 
180 static Error readSection(WasmSection &Section, const uint8_t *&Ptr,
181                          const uint8_t *Start) {
182   // TODO(sbc): Avoid reading past EOF in the case of malformed files.
183   Section.Offset = Ptr - Start;
184   Section.Type = readVaruint7(Ptr);
185   uint32_t Size = readVaruint32(Ptr);
186   if (Size == 0)
187     return make_error<StringError>("Zero length section",
188                                    object_error::parse_failed);
189   Section.Content = ArrayRef<uint8_t>(Ptr, Size);
190   Ptr += Size;
191   return Error::success();
192 }
193 
194 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
195     : ObjectFile(Binary::ID_Wasm, Buffer) {
196   ErrorAsOutParameter ErrAsOutParam(&Err);
197   Header.Magic = getData().substr(0, 4);
198   if (Header.Magic != StringRef("\0asm", 4)) {
199     Err = make_error<StringError>("Bad magic number",
200                                   object_error::parse_failed);
201     return;
202   }
203   const uint8_t *Ptr = getPtr(4);
204   Header.Version = readUint32(Ptr);
205   if (Header.Version != wasm::WasmVersion) {
206     Err = make_error<StringError>("Bad version number",
207                                   object_error::parse_failed);
208     return;
209   }
210 
211   const uint8_t *Eof = getPtr(getData().size());
212   WasmSection Sec;
213   while (Ptr < Eof) {
214     if ((Err = readSection(Sec, Ptr, getPtr(0))))
215       return;
216     if ((Err = parseSection(Sec)))
217       return;
218 
219     Sections.push_back(Sec);
220   }
221 }
222 
223 Error WasmObjectFile::parseSection(WasmSection &Sec) {
224   const uint8_t* Start = Sec.Content.data();
225   const uint8_t* End = Start + Sec.Content.size();
226   switch (Sec.Type) {
227   case wasm::WASM_SEC_CUSTOM:
228     return parseCustomSection(Sec, Start, End);
229   case wasm::WASM_SEC_TYPE:
230     return parseTypeSection(Start, End);
231   case wasm::WASM_SEC_IMPORT:
232     return parseImportSection(Start, End);
233   case wasm::WASM_SEC_FUNCTION:
234     return parseFunctionSection(Start, End);
235   case wasm::WASM_SEC_TABLE:
236     return parseTableSection(Start, End);
237   case wasm::WASM_SEC_MEMORY:
238     return parseMemorySection(Start, End);
239   case wasm::WASM_SEC_GLOBAL:
240     return parseGlobalSection(Start, End);
241   case wasm::WASM_SEC_EXPORT:
242     return parseExportSection(Start, End);
243   case wasm::WASM_SEC_START:
244     return parseStartSection(Start, End);
245   case wasm::WASM_SEC_ELEM:
246     return parseElemSection(Start, End);
247   case wasm::WASM_SEC_CODE:
248     return parseCodeSection(Start, End);
249   case wasm::WASM_SEC_DATA:
250     return parseDataSection(Start, End);
251   default:
252     return make_error<GenericBinaryError>("Bad section type",
253                                           object_error::parse_failed);
254   }
255 }
256 
257 Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) {
258   while (Ptr < End) {
259     uint8_t Type = readVarint7(Ptr);
260     uint32_t Size = readVaruint32(Ptr);
261     const uint8_t *SubSectionEnd = Ptr + Size;
262     switch (Type) {
263     case wasm::WASM_NAMES_FUNCTION: {
264       uint32_t Count = readVaruint32(Ptr);
265       while (Count--) {
266         uint32_t Index = readVaruint32(Ptr);
267         StringRef Name = readString(Ptr);
268         if (!Name.empty())
269           Symbols.emplace_back(Name,
270                                WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME,
271                                Sections.size(), Index);
272       }
273       break;
274     }
275     // Ignore local names for now
276     case wasm::WASM_NAMES_LOCAL:
277     default:
278       Ptr += Size;
279       break;
280     }
281     if (Ptr != SubSectionEnd)
282       return make_error<GenericBinaryError>("Name sub-section ended prematurely",
283                                             object_error::parse_failed);
284   }
285 
286   if (Ptr != End)
287     return make_error<GenericBinaryError>("Name section ended prematurely",
288                                           object_error::parse_failed);
289   return Error::success();
290 }
291 
292 Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr,
293                                           const uint8_t *End) {
294   while (Ptr < End) {
295     uint8_t Type = readVarint7(Ptr);
296     uint32_t Size = readVaruint32(Ptr);
297     const uint8_t *SubSectionEnd = Ptr + Size;
298     switch (Type) {
299     case wasm::WASM_SYMBOL_INFO: {
300       uint32_t Count = readVaruint32(Ptr);
301       while (Count--) {
302         StringRef Symbol = readString(Ptr);
303         DEBUG(dbgs() << "reading syminfo: " << Symbol << "\n");
304         uint32_t Flags = readVaruint32(Ptr);
305         auto iter = SymbolMap.find(Symbol);
306         if (iter == SymbolMap.end()) {
307           return make_error<GenericBinaryError>(
308               "Invalid symbol name in linking section",
309               object_error::parse_failed);
310         }
311         uint32_t SymIndex = iter->second;
312         assert(SymIndex < Symbols.size());
313         Symbols[SymIndex].Flags = Flags;
314         DEBUG(dbgs() << "Set symbol flags index:"
315                      << SymIndex << " name:"
316                      << Symbols[SymIndex].Name << " exptected:"
317                      << Symbol << " flags: " << Flags << "\n");
318       }
319       break;
320     }
321     case wasm::WASM_STACK_POINTER:
322     default:
323       Ptr += Size;
324       break;
325     }
326     if (Ptr != SubSectionEnd)
327       return make_error<GenericBinaryError>(
328           "Linking sub-section ended prematurely", object_error::parse_failed);
329   }
330   if (Ptr != End)
331     return make_error<GenericBinaryError>("Linking section ended prematurely",
332                                           object_error::parse_failed);
333   return Error::success();
334 }
335 
336 WasmSection* WasmObjectFile::findCustomSectionByName(StringRef Name) {
337   for (WasmSection& Section : Sections) {
338     if (Section.Type == wasm::WASM_SEC_CUSTOM && Section.Name == Name)
339       return &Section;
340   }
341   return nullptr;
342 }
343 
344 WasmSection* WasmObjectFile::findSectionByType(uint32_t Type) {
345   assert(Type != wasm::WASM_SEC_CUSTOM);
346   for (WasmSection& Section : Sections) {
347     if (Section.Type == Type)
348       return &Section;
349   }
350   return nullptr;
351 }
352 
353 Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr,
354                                         const uint8_t *End) {
355   uint8_t SectionCode = readVarint7(Ptr);
356   WasmSection* Section = nullptr;
357   if (SectionCode == wasm::WASM_SEC_CUSTOM) {
358     StringRef Name = readString(Ptr);
359     Section = findCustomSectionByName(Name);
360   } else {
361     Section = findSectionByType(SectionCode);
362   }
363   if (!Section)
364     return make_error<GenericBinaryError>("Invalid section code",
365                                           object_error::parse_failed);
366   uint32_t RelocCount = readVaruint32(Ptr);
367   while (RelocCount--) {
368     wasm::WasmRelocation Reloc;
369     memset(&Reloc, 0, sizeof(Reloc));
370     Reloc.Type = readVaruint32(Ptr);
371     Reloc.Offset = readVaruint32(Ptr);
372     Reloc.Index = readVaruint32(Ptr);
373     switch (Reloc.Type) {
374     case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
375     case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
376     case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
377     case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
378     case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
379       break;
380     case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
381     case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
382     case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
383       Reloc.Addend = readVarint32(Ptr);
384       break;
385     default:
386       return make_error<GenericBinaryError>("Bad relocation type: " +
387                                                 Twine(Reloc.Type),
388                                             object_error::parse_failed);
389     }
390     Section->Relocations.push_back(Reloc);
391   }
392   if (Ptr != End)
393     return make_error<GenericBinaryError>("Reloc section ended prematurely",
394                                           object_error::parse_failed);
395   return Error::success();
396 }
397 
398 Error WasmObjectFile::parseCustomSection(WasmSection &Sec,
399                                          const uint8_t *Ptr, const uint8_t *End) {
400   Sec.Name = readString(Ptr);
401   if (Sec.Name == "name") {
402     if (Error Err = parseNameSection(Ptr, End))
403       return Err;
404   } else if (Sec.Name == "linking") {
405     if (Error Err = parseLinkingSection(Ptr, End))
406       return Err;
407   } else if (Sec.Name.startswith("reloc.")) {
408     if (Error Err = parseRelocSection(Sec.Name, Ptr, End))
409       return Err;
410   }
411   return Error::success();
412 }
413 
414 Error WasmObjectFile::parseTypeSection(const uint8_t *Ptr, const uint8_t *End) {
415   uint32_t Count = readVaruint32(Ptr);
416   Signatures.reserve(Count);
417   while (Count--) {
418     wasm::WasmSignature Sig;
419     Sig.ReturnType = wasm::WASM_TYPE_NORESULT;
420     int8_t Form = readVarint7(Ptr);
421     if (Form != wasm::WASM_TYPE_FUNC) {
422       return make_error<GenericBinaryError>("Invalid signature type",
423                                             object_error::parse_failed);
424     }
425     uint32_t ParamCount = readVaruint32(Ptr);
426     Sig.ParamTypes.reserve(ParamCount);
427     while (ParamCount--) {
428       uint32_t ParamType = readVarint7(Ptr);
429       Sig.ParamTypes.push_back(ParamType);
430     }
431     uint32_t ReturnCount = readVaruint32(Ptr);
432     if (ReturnCount) {
433       if (ReturnCount != 1) {
434         return make_error<GenericBinaryError>(
435             "Multiple return types not supported", object_error::parse_failed);
436       }
437       Sig.ReturnType = readVarint7(Ptr);
438     }
439     Signatures.push_back(Sig);
440   }
441   if (Ptr != End)
442     return make_error<GenericBinaryError>("Type section ended prematurely",
443                                           object_error::parse_failed);
444   return Error::success();
445 }
446 
447 Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) {
448   uint32_t Count = readVaruint32(Ptr);
449   Imports.reserve(Count);
450   for (uint32_t i = 0; i < Count; i++) {
451     wasm::WasmImport Im;
452     Im.Module = readString(Ptr);
453     Im.Field = readString(Ptr);
454     Im.Kind = readUint8(Ptr);
455     switch (Im.Kind) {
456     case wasm::WASM_EXTERNAL_FUNCTION:
457       Im.SigIndex = readVaruint32(Ptr);
458       SymbolMap.try_emplace(Im.Field, Symbols.size());
459       Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::FUNCTION_IMPORT,
460                            Sections.size(), i);
461       DEBUG(dbgs() << "Adding import: " << Symbols.back()
462                    << " sym index:" << Symbols.size() << "\n");
463       break;
464     case wasm::WASM_EXTERNAL_GLOBAL:
465       Im.Global.Type = readVarint7(Ptr);
466       Im.Global.Mutable = readVaruint1(Ptr);
467       SymbolMap.try_emplace(Im.Field, Symbols.size());
468       Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT,
469                            Sections.size(), i);
470       DEBUG(dbgs() << "Adding import: " << Symbols.back()
471                    << " sym index:" << Symbols.size() << "\n");
472       break;
473     case wasm::WASM_EXTERNAL_MEMORY:
474       Im.Memory = readLimits(Ptr);
475       break;
476     case wasm::WASM_EXTERNAL_TABLE:
477       Im.Table = readTable(Ptr);
478       if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC) {
479         return make_error<GenericBinaryError>("Invalid table element type",
480                                               object_error::parse_failed);
481       }
482       break;
483     default:
484       return make_error<GenericBinaryError>(
485           "Unexpected import kind", object_error::parse_failed);
486     }
487     Imports.push_back(Im);
488   }
489   if (Ptr != End)
490     return make_error<GenericBinaryError>("Import section ended prematurely",
491                                           object_error::parse_failed);
492   return Error::success();
493 }
494 
495 Error WasmObjectFile::parseFunctionSection(const uint8_t *Ptr, const uint8_t *End) {
496   uint32_t Count = readVaruint32(Ptr);
497   FunctionTypes.reserve(Count);
498   while (Count--) {
499     FunctionTypes.push_back(readVaruint32(Ptr));
500   }
501   if (Ptr != End)
502     return make_error<GenericBinaryError>("Function section ended prematurely",
503                                           object_error::parse_failed);
504   return Error::success();
505 }
506 
507 Error WasmObjectFile::parseTableSection(const uint8_t *Ptr, const uint8_t *End) {
508   uint32_t Count = readVaruint32(Ptr);
509   Tables.reserve(Count);
510   while (Count--) {
511     Tables.push_back(readTable(Ptr));
512     if (Tables.back().ElemType != wasm::WASM_TYPE_ANYFUNC) {
513       return make_error<GenericBinaryError>("Invalid table element type",
514                                             object_error::parse_failed);
515     }
516   }
517   if (Ptr != End)
518     return make_error<GenericBinaryError>("Table section ended prematurely",
519                                           object_error::parse_failed);
520   return Error::success();
521 }
522 
523 Error WasmObjectFile::parseMemorySection(const uint8_t *Ptr, const uint8_t *End) {
524   uint32_t Count = readVaruint32(Ptr);
525   Memories.reserve(Count);
526   while (Count--) {
527     Memories.push_back(readLimits(Ptr));
528   }
529   if (Ptr != End)
530     return make_error<GenericBinaryError>("Memory section ended prematurely",
531                                           object_error::parse_failed);
532   return Error::success();
533 }
534 
535 Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) {
536   uint32_t Count = readVaruint32(Ptr);
537   Globals.reserve(Count);
538   while (Count--) {
539     wasm::WasmGlobal Global;
540     Global.Type = readVarint7(Ptr);
541     Global.Mutable = readVaruint1(Ptr);
542     if (Error Err = readInitExpr(Global.InitExpr, Ptr))
543       return Err;
544     Globals.push_back(Global);
545   }
546   if (Ptr != End)
547     return make_error<GenericBinaryError>("Global section ended prematurely",
548                                           object_error::parse_failed);
549   return Error::success();
550 }
551 
552 Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) {
553   uint32_t Count = readVaruint32(Ptr);
554   Exports.reserve(Count);
555   for (uint32_t i = 0; i < Count; i++) {
556     wasm::WasmExport Ex;
557     Ex.Name = readString(Ptr);
558     Ex.Kind = readUint8(Ptr);
559     Ex.Index = readVaruint32(Ptr);
560     switch (Ex.Kind) {
561     case wasm::WASM_EXTERNAL_FUNCTION:
562       SymbolMap.try_emplace(Ex.Name, Symbols.size());
563       Symbols.emplace_back(Ex.Name, WasmSymbol::SymbolType::FUNCTION_EXPORT,
564                            Sections.size(), i);
565       DEBUG(dbgs() << "Adding export: " << Symbols.back()
566                    << " sym index:" << Symbols.size() << "\n");
567       break;
568     case wasm::WASM_EXTERNAL_GLOBAL:
569       SymbolMap.try_emplace(Ex.Name, Symbols.size());
570       Symbols.emplace_back(Ex.Name, WasmSymbol::SymbolType::GLOBAL_EXPORT,
571                            Sections.size(), i);
572       DEBUG(dbgs() << "Adding export: " << Symbols.back()
573                    << " sym index:" << Symbols.size() << "\n");
574       break;
575     case wasm::WASM_EXTERNAL_MEMORY:
576     case wasm::WASM_EXTERNAL_TABLE:
577       break;
578     default:
579       return make_error<GenericBinaryError>(
580           "Unexpected export kind", object_error::parse_failed);
581     }
582     Exports.push_back(Ex);
583   }
584   if (Ptr != End)
585     return make_error<GenericBinaryError>("Export section ended prematurely",
586                                           object_error::parse_failed);
587   return Error::success();
588 }
589 
590 Error WasmObjectFile::parseStartSection(const uint8_t *Ptr, const uint8_t *End) {
591   StartFunction = readVaruint32(Ptr);
592   if (StartFunction >= FunctionTypes.size())
593     return make_error<GenericBinaryError>("Invalid start function",
594                                           object_error::parse_failed);
595   return Error::success();
596 }
597 
598 Error WasmObjectFile::parseCodeSection(const uint8_t *Ptr, const uint8_t *End) {
599   uint32_t FunctionCount = readVaruint32(Ptr);
600   if (FunctionCount != FunctionTypes.size()) {
601     return make_error<GenericBinaryError>("Invalid function count",
602                                           object_error::parse_failed);
603   }
604 
605   CodeSection = ArrayRef<uint8_t>(Ptr, End - Ptr);
606 
607   while (FunctionCount--) {
608     wasm::WasmFunction Function;
609     uint32_t FunctionSize = readVaruint32(Ptr);
610     const uint8_t *FunctionEnd = Ptr + FunctionSize;
611 
612     uint32_t NumLocalDecls = readVaruint32(Ptr);
613     Function.Locals.reserve(NumLocalDecls);
614     while (NumLocalDecls--) {
615       wasm::WasmLocalDecl Decl;
616       Decl.Count = readVaruint32(Ptr);
617       Decl.Type = readVarint7(Ptr);
618       Function.Locals.push_back(Decl);
619     }
620 
621     uint32_t BodySize = FunctionEnd - Ptr;
622     Function.Body = ArrayRef<uint8_t>(Ptr, BodySize);
623     Ptr += BodySize;
624     assert(Ptr == FunctionEnd);
625     Functions.push_back(Function);
626   }
627   if (Ptr != End)
628     return make_error<GenericBinaryError>("Code section ended prematurely",
629                                           object_error::parse_failed);
630   return Error::success();
631 }
632 
633 Error WasmObjectFile::parseElemSection(const uint8_t *Ptr, const uint8_t *End) {
634   uint32_t Count = readVaruint32(Ptr);
635   ElemSegments.reserve(Count);
636   while (Count--) {
637     wasm::WasmElemSegment Segment;
638     Segment.TableIndex = readVaruint32(Ptr);
639     if (Segment.TableIndex != 0) {
640       return make_error<GenericBinaryError>("Invalid TableIndex",
641                                             object_error::parse_failed);
642     }
643     if (Error Err = readInitExpr(Segment.Offset, Ptr))
644       return Err;
645     uint32_t NumElems = readVaruint32(Ptr);
646     while (NumElems--) {
647       Segment.Functions.push_back(readVaruint32(Ptr));
648     }
649     ElemSegments.push_back(Segment);
650   }
651   if (Ptr != End)
652     return make_error<GenericBinaryError>("Elem section ended prematurely",
653                                           object_error::parse_failed);
654   return Error::success();
655 }
656 
657 Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, const uint8_t *End) {
658   uint32_t Count = readVaruint32(Ptr);
659   DataSegments.reserve(Count);
660   while (Count--) {
661     wasm::WasmDataSegment Segment;
662     Segment.Index = readVaruint32(Ptr);
663     if (Error Err = readInitExpr(Segment.Offset, Ptr))
664       return Err;
665     uint32_t Size = readVaruint32(Ptr);
666     Segment.Content = ArrayRef<uint8_t>(Ptr, Size);
667     Ptr += Size;
668     DataSegments.push_back(Segment);
669   }
670   if (Ptr != End)
671     return make_error<GenericBinaryError>("Data section ended prematurely",
672                                           object_error::parse_failed);
673   return Error::success();
674 }
675 
676 const uint8_t *WasmObjectFile::getPtr(size_t Offset) const {
677   return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data());
678 }
679 
680 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
681   return Header;
682 }
683 
684 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.a++; }
685 
686 uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
687   uint32_t Result = SymbolRef::SF_None;
688   const WasmSymbol &Sym = getWasmSymbol(Symb);
689 
690   DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
691   if (Sym.Flags & wasm::WASM_SYMBOL_FLAG_WEAK)
692     Result |= SymbolRef::SF_Weak;
693 
694   switch (Sym.Type) {
695   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
696     Result |= SymbolRef::SF_Undefined | SymbolRef::SF_Executable;
697     break;
698   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
699     Result |= SymbolRef::SF_Global | SymbolRef::SF_Executable;
700     break;
701   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
702     Result |= SymbolRef::SF_Executable;
703     Result |= SymbolRef::SF_FormatSpecific;
704     break;
705   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
706     Result |= SymbolRef::SF_Undefined;
707     break;
708   case WasmSymbol::SymbolType::GLOBAL_EXPORT:
709     Result |= SymbolRef::SF_Global;
710     break;
711   }
712 
713   return Result;
714 }
715 
716 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
717   DataRefImpl Ref;
718   Ref.d.a = 0;
719   return BasicSymbolRef(Ref, this);
720 }
721 
722 basic_symbol_iterator WasmObjectFile::symbol_end() const {
723   DataRefImpl Ref;
724   Ref.d.a = Symbols.size();
725   return BasicSymbolRef(Ref, this);
726 }
727 
728 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
729   return Symbols[Symb.d.a];
730 }
731 
732 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
733   return getWasmSymbol(Symb.getRawDataRefImpl());
734 }
735 
736 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
737   return getWasmSymbol(Symb).Name;
738 }
739 
740 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
741   return getSymbolValue(Symb);
742 }
743 
744 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
745   const WasmSymbol& Sym = getWasmSymbol(Symb);
746   switch (Sym.Type) {
747   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
748   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
749     return 0;
750   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
751   case WasmSymbol::SymbolType::GLOBAL_EXPORT:
752     return Exports[Sym.ElementIndex].Index;
753   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
754     return Sym.ElementIndex;
755   }
756   llvm_unreachable("invalid symbol type");
757 }
758 
759 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
760   llvm_unreachable("not yet implemented");
761   return 0;
762 }
763 
764 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
765   llvm_unreachable("not yet implemented");
766   return 0;
767 }
768 
769 Expected<SymbolRef::Type>
770 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
771   const WasmSymbol &Sym = getWasmSymbol(Symb);
772 
773   switch (Sym.Type) {
774   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
775   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
776   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
777     return SymbolRef::ST_Function;
778   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
779   case WasmSymbol::SymbolType::GLOBAL_EXPORT:
780     return SymbolRef::ST_Data;
781   }
782 
783   llvm_unreachable("Unknown WasmSymbol::SymbolType");
784   return SymbolRef::ST_Other;
785 }
786 
787 Expected<section_iterator>
788 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
789   DataRefImpl Ref;
790   Ref.d.a = getWasmSymbol(Symb).Section;
791   return section_iterator(SectionRef(Ref, this));
792 }
793 
794 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
795 
796 std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
797                                                StringRef &Res) const {
798   const WasmSection &S = Sections[Sec.d.a];
799 #define ECase(X)                                                               \
800   case wasm::WASM_SEC_##X:                                                     \
801     Res = #X;                                                                  \
802     break
803   switch (S.Type) {
804     ECase(TYPE);
805     ECase(IMPORT);
806     ECase(FUNCTION);
807     ECase(TABLE);
808     ECase(MEMORY);
809     ECase(GLOBAL);
810     ECase(EXPORT);
811     ECase(START);
812     ECase(ELEM);
813     ECase(CODE);
814     ECase(DATA);
815   case wasm::WASM_SEC_CUSTOM:
816     Res = S.Name;
817     break;
818   default:
819     return object_error::invalid_section_index;
820   }
821 #undef ECase
822   return std::error_code();
823 }
824 
825 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
826 
827 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
828   return Sec.d.a;
829 }
830 
831 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
832   const WasmSection &S = Sections[Sec.d.a];
833   return S.Content.size();
834 }
835 
836 std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec,
837                                                    StringRef &Res) const {
838   const WasmSection &S = Sections[Sec.d.a];
839   // This will never fail since wasm sections can never be empty (user-sections
840   // must have a name and non-user sections each have a defined structure).
841   Res = StringRef(reinterpret_cast<const char *>(S.Content.data()),
842                   S.Content.size());
843   return std::error_code();
844 }
845 
846 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
847   return 1;
848 }
849 
850 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
851   return false;
852 }
853 
854 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
855   return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
856 }
857 
858 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
859   return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
860 }
861 
862 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
863 
864 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
865 
866 bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; }
867 
868 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
869   DataRefImpl RelocRef;
870   RelocRef.d.a = Ref.d.a;
871   RelocRef.d.b = 0;
872   return relocation_iterator(RelocationRef(RelocRef, this));
873 }
874 
875 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
876   const WasmSection &Sec = getWasmSection(Ref);
877   DataRefImpl RelocRef;
878   RelocRef.d.a = Ref.d.a;
879   RelocRef.d.b = Sec.Relocations.size();
880   return relocation_iterator(RelocationRef(RelocRef, this));
881 }
882 
883 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
884   Rel.d.b++;
885 }
886 
887 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
888   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
889   return Rel.Offset;
890 }
891 
892 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
893   llvm_unreachable("not yet implemented");
894   SymbolRef Ref;
895   return symbol_iterator(Ref);
896 }
897 
898 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
899   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
900   return Rel.Type;
901 }
902 
903 void WasmObjectFile::getRelocationTypeName(
904     DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
905   const wasm::WasmRelocation& Rel = getWasmRelocation(Ref);
906   StringRef Res = "Unknown";
907 
908 #define WASM_RELOC(name, value)  \
909   case wasm::name:              \
910     Res = #name;               \
911     break;
912 
913   switch (Rel.Type) {
914 #include "llvm/BinaryFormat/WasmRelocs/WebAssembly.def"
915   }
916 
917 #undef WASM_RELOC
918 
919   Result.append(Res.begin(), Res.end());
920 }
921 
922 section_iterator WasmObjectFile::section_begin() const {
923   DataRefImpl Ref;
924   Ref.d.a = 0;
925   return section_iterator(SectionRef(Ref, this));
926 }
927 
928 section_iterator WasmObjectFile::section_end() const {
929   DataRefImpl Ref;
930   Ref.d.a = Sections.size();
931   return section_iterator(SectionRef(Ref, this));
932 }
933 
934 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
935 
936 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
937 
938 unsigned WasmObjectFile::getArch() const { return Triple::wasm32; }
939 
940 SubtargetFeatures WasmObjectFile::getFeatures() const {
941   return SubtargetFeatures();
942 }
943 
944 bool WasmObjectFile::isRelocatableObject() const { return false; }
945 
946 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
947   assert(Ref.d.a < Sections.size());
948   return Sections[Ref.d.a];
949 }
950 
951 const WasmSection &
952 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
953   return getWasmSection(Section.getRawDataRefImpl());
954 }
955 
956 const wasm::WasmRelocation &
957 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
958   return getWasmRelocation(Ref.getRawDataRefImpl());
959 }
960 
961 const wasm::WasmRelocation &
962 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
963   assert(Ref.d.a < Sections.size());
964   const WasmSection& Sec = Sections[Ref.d.a];
965   assert(Ref.d.b < Sec.Relocations.size());
966   return Sec.Relocations[Ref.d.b];
967 }
968