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   LinkingData.DataSize = 0;
197 
198   ErrorAsOutParameter ErrAsOutParam(&Err);
199   Header.Magic = getData().substr(0, 4);
200   if (Header.Magic != StringRef("\0asm", 4)) {
201     Err = make_error<StringError>("Bad magic number",
202                                   object_error::parse_failed);
203     return;
204   }
205 
206   const uint8_t *Eof = getPtr(getData().size());
207   const uint8_t *Ptr = getPtr(4);
208 
209   if (Ptr + 4 > Eof) {
210     Err = make_error<StringError>("Missing version number",
211                                   object_error::parse_failed);
212     return;
213   }
214 
215   Header.Version = readUint32(Ptr);
216   if (Header.Version != wasm::WasmVersion) {
217     Err = make_error<StringError>("Bad version number",
218                                   object_error::parse_failed);
219     return;
220   }
221 
222   WasmSection Sec;
223   while (Ptr < Eof) {
224     if ((Err = readSection(Sec, Ptr, getPtr(0))))
225       return;
226     if ((Err = parseSection(Sec)))
227       return;
228 
229     Sections.push_back(Sec);
230   }
231 }
232 
233 Error WasmObjectFile::parseSection(WasmSection &Sec) {
234   const uint8_t* Start = Sec.Content.data();
235   const uint8_t* End = Start + Sec.Content.size();
236   switch (Sec.Type) {
237   case wasm::WASM_SEC_CUSTOM:
238     return parseCustomSection(Sec, Start, End);
239   case wasm::WASM_SEC_TYPE:
240     return parseTypeSection(Start, End);
241   case wasm::WASM_SEC_IMPORT:
242     return parseImportSection(Start, End);
243   case wasm::WASM_SEC_FUNCTION:
244     return parseFunctionSection(Start, End);
245   case wasm::WASM_SEC_TABLE:
246     return parseTableSection(Start, End);
247   case wasm::WASM_SEC_MEMORY:
248     return parseMemorySection(Start, End);
249   case wasm::WASM_SEC_GLOBAL:
250     return parseGlobalSection(Start, End);
251   case wasm::WASM_SEC_EXPORT:
252     return parseExportSection(Start, End);
253   case wasm::WASM_SEC_START:
254     return parseStartSection(Start, End);
255   case wasm::WASM_SEC_ELEM:
256     return parseElemSection(Start, End);
257   case wasm::WASM_SEC_CODE:
258     return parseCodeSection(Start, End);
259   case wasm::WASM_SEC_DATA:
260     return parseDataSection(Start, End);
261   default:
262     return make_error<GenericBinaryError>("Bad section type",
263                                           object_error::parse_failed);
264   }
265 }
266 
267 Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) {
268   while (Ptr < End) {
269     uint8_t Type = readVarint7(Ptr);
270     uint32_t Size = readVaruint32(Ptr);
271     const uint8_t *SubSectionEnd = Ptr + Size;
272     switch (Type) {
273     case wasm::WASM_NAMES_FUNCTION: {
274       uint32_t Count = readVaruint32(Ptr);
275       while (Count--) {
276         uint32_t Index = readVaruint32(Ptr);
277         StringRef Name = readString(Ptr);
278         if (!Name.empty())
279           Symbols.emplace_back(Name,
280                                WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME,
281                                Sections.size(), Index);
282       }
283       break;
284     }
285     // Ignore local names for now
286     case wasm::WASM_NAMES_LOCAL:
287     default:
288       Ptr += Size;
289       break;
290     }
291     if (Ptr != SubSectionEnd)
292       return make_error<GenericBinaryError>("Name sub-section ended prematurely",
293                                             object_error::parse_failed);
294   }
295 
296   if (Ptr != End)
297     return make_error<GenericBinaryError>("Name section ended prematurely",
298                                           object_error::parse_failed);
299   return Error::success();
300 }
301 
302 void WasmObjectFile::populateSymbolTable() {
303   // Add imports to symbol table
304   size_t ImportIndex = 0;
305   size_t GlobalIndex = 0;
306   size_t FunctionIndex = 0;
307   for (const wasm::WasmImport& Import : Imports) {
308     switch (Import.Kind) {
309     case wasm::WASM_EXTERNAL_GLOBAL:
310       assert(Import.Global.Type == wasm::WASM_TYPE_I32);
311       SymbolMap.try_emplace(Import.Field, Symbols.size());
312       Symbols.emplace_back(Import.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT,
313                            ImportSection, GlobalIndex++, ImportIndex);
314       DEBUG(dbgs() << "Adding import: " << Symbols.back()
315                    << " sym index:" << Symbols.size() << "\n");
316       break;
317     case wasm::WASM_EXTERNAL_FUNCTION:
318       SymbolMap.try_emplace(Import.Field, Symbols.size());
319       Symbols.emplace_back(Import.Field,
320                            WasmSymbol::SymbolType::FUNCTION_IMPORT,
321                            ImportSection, FunctionIndex++, ImportIndex);
322       DEBUG(dbgs() << "Adding import: " << Symbols.back()
323                    << " sym index:" << Symbols.size() << "\n");
324       break;
325     default:
326       break;
327     }
328     ImportIndex++;
329   }
330 
331   // Add exports to symbol table
332   for (const wasm::WasmExport& Export : Exports) {
333     if (Export.Kind == wasm::WASM_EXTERNAL_FUNCTION ||
334         Export.Kind == wasm::WASM_EXTERNAL_GLOBAL) {
335       WasmSymbol::SymbolType ExportType =
336           Export.Kind == wasm::WASM_EXTERNAL_FUNCTION
337               ? WasmSymbol::SymbolType::FUNCTION_EXPORT
338               : WasmSymbol::SymbolType::GLOBAL_EXPORT;
339       SymbolMap.try_emplace(Export.Name, Symbols.size());
340       Symbols.emplace_back(Export.Name, ExportType,
341                            ExportSection, Export.Index);
342       DEBUG(dbgs() << "Adding export: " << Symbols.back()
343                    << " sym index:" << Symbols.size() << "\n");
344     }
345   }
346 }
347 
348 Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr,
349                                           const uint8_t *End) {
350   HasLinkingSection = true;
351 
352   // Only populate the symbol table with imports and exports if the object
353   // has a linking section (i.e. its a relocatable object file). Otherwise
354   // the global might not represent symbols at all.
355   populateSymbolTable();
356 
357   while (Ptr < End) {
358     uint8_t Type = readVarint7(Ptr);
359     uint32_t Size = readVaruint32(Ptr);
360     const uint8_t *SubSectionEnd = Ptr + Size;
361     switch (Type) {
362     case wasm::WASM_SYMBOL_INFO: {
363       uint32_t Count = readVaruint32(Ptr);
364       while (Count--) {
365         StringRef Symbol = readString(Ptr);
366         DEBUG(dbgs() << "reading syminfo: " << Symbol << "\n");
367         uint32_t Flags = readVaruint32(Ptr);
368         auto iter = SymbolMap.find(Symbol);
369         if (iter == SymbolMap.end()) {
370           return make_error<GenericBinaryError>(
371               "Invalid symbol name in linking section: " + Symbol,
372               object_error::parse_failed);
373         }
374         uint32_t SymIndex = iter->second;
375         assert(SymIndex < Symbols.size());
376         Symbols[SymIndex].Flags = Flags;
377         DEBUG(dbgs() << "Set symbol flags index:"
378                      << SymIndex << " name:"
379                      << Symbols[SymIndex].Name << " exptected:"
380                      << Symbol << " flags: " << Flags << "\n");
381       }
382       break;
383     }
384     case wasm::WASM_DATA_SIZE:
385       LinkingData.DataSize = readVaruint32(Ptr);
386       break;
387     case wasm::WASM_SEGMENT_INFO: {
388       uint32_t Count = readVaruint32(Ptr);
389       if (Count > DataSegments.size())
390         return make_error<GenericBinaryError>("Too many segment names",
391                                               object_error::parse_failed);
392       for (uint32_t i = 0; i < Count; i++) {
393         DataSegments[i].Data.Name = readString(Ptr);
394         DataSegments[i].Data.Alignment = readVaruint32(Ptr);
395         DataSegments[i].Data.Flags = readVaruint32(Ptr);
396       }
397       break;
398     }
399     case wasm::WASM_STACK_POINTER:
400     default:
401       Ptr += Size;
402       break;
403     }
404     if (Ptr != SubSectionEnd)
405       return make_error<GenericBinaryError>(
406           "Linking sub-section ended prematurely", object_error::parse_failed);
407   }
408   if (Ptr != End)
409     return make_error<GenericBinaryError>("Linking section ended prematurely",
410                                           object_error::parse_failed);
411   return Error::success();
412 }
413 
414 WasmSection* WasmObjectFile::findCustomSectionByName(StringRef Name) {
415   for (WasmSection& Section : Sections) {
416     if (Section.Type == wasm::WASM_SEC_CUSTOM && Section.Name == Name)
417       return &Section;
418   }
419   return nullptr;
420 }
421 
422 WasmSection* WasmObjectFile::findSectionByType(uint32_t Type) {
423   assert(Type != wasm::WASM_SEC_CUSTOM);
424   for (WasmSection& Section : Sections) {
425     if (Section.Type == Type)
426       return &Section;
427   }
428   return nullptr;
429 }
430 
431 Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr,
432                                         const uint8_t *End) {
433   uint8_t SectionCode = readVarint7(Ptr);
434   WasmSection* Section = nullptr;
435   if (SectionCode == wasm::WASM_SEC_CUSTOM) {
436     StringRef Name = readString(Ptr);
437     Section = findCustomSectionByName(Name);
438   } else {
439     Section = findSectionByType(SectionCode);
440   }
441   if (!Section)
442     return make_error<GenericBinaryError>("Invalid section code",
443                                           object_error::parse_failed);
444   uint32_t RelocCount = readVaruint32(Ptr);
445   while (RelocCount--) {
446     wasm::WasmRelocation Reloc;
447     memset(&Reloc, 0, sizeof(Reloc));
448     Reloc.Type = readVaruint32(Ptr);
449     Reloc.Offset = readVaruint32(Ptr);
450     Reloc.Index = readVaruint32(Ptr);
451     switch (Reloc.Type) {
452     case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
453     case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
454     case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
455     case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
456     case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
457       break;
458     case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
459     case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
460     case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
461       Reloc.Addend = readVarint32(Ptr);
462       break;
463     default:
464       return make_error<GenericBinaryError>("Bad relocation type: " +
465                                                 Twine(Reloc.Type),
466                                             object_error::parse_failed);
467     }
468     Section->Relocations.push_back(Reloc);
469   }
470   if (Ptr != End)
471     return make_error<GenericBinaryError>("Reloc section ended prematurely",
472                                           object_error::parse_failed);
473   return Error::success();
474 }
475 
476 Error WasmObjectFile::parseCustomSection(WasmSection &Sec,
477                                          const uint8_t *Ptr, const uint8_t *End) {
478   Sec.Name = readString(Ptr);
479   if (Sec.Name == "name") {
480     if (Error Err = parseNameSection(Ptr, End))
481       return Err;
482   } else if (Sec.Name == "linking") {
483     if (Error Err = parseLinkingSection(Ptr, End))
484       return Err;
485   } else if (Sec.Name.startswith("reloc.")) {
486     if (Error Err = parseRelocSection(Sec.Name, Ptr, End))
487       return Err;
488   }
489   return Error::success();
490 }
491 
492 Error WasmObjectFile::parseTypeSection(const uint8_t *Ptr, const uint8_t *End) {
493   uint32_t Count = readVaruint32(Ptr);
494   Signatures.reserve(Count);
495   while (Count--) {
496     wasm::WasmSignature Sig;
497     Sig.ReturnType = wasm::WASM_TYPE_NORESULT;
498     int8_t Form = readVarint7(Ptr);
499     if (Form != wasm::WASM_TYPE_FUNC) {
500       return make_error<GenericBinaryError>("Invalid signature type",
501                                             object_error::parse_failed);
502     }
503     uint32_t ParamCount = readVaruint32(Ptr);
504     Sig.ParamTypes.reserve(ParamCount);
505     while (ParamCount--) {
506       uint32_t ParamType = readVarint7(Ptr);
507       Sig.ParamTypes.push_back(ParamType);
508     }
509     uint32_t ReturnCount = readVaruint32(Ptr);
510     if (ReturnCount) {
511       if (ReturnCount != 1) {
512         return make_error<GenericBinaryError>(
513             "Multiple return types not supported", object_error::parse_failed);
514       }
515       Sig.ReturnType = readVarint7(Ptr);
516     }
517     Signatures.push_back(Sig);
518   }
519   if (Ptr != End)
520     return make_error<GenericBinaryError>("Type section ended prematurely",
521                                           object_error::parse_failed);
522   return Error::success();
523 }
524 
525 Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) {
526   ImportSection = Sections.size();
527   uint32_t Count = readVaruint32(Ptr);
528   Imports.reserve(Count);
529   for (uint32_t i = 0; i < Count; i++) {
530     wasm::WasmImport Im;
531     Im.Module = readString(Ptr);
532     Im.Field = readString(Ptr);
533     Im.Kind = readUint8(Ptr);
534     switch (Im.Kind) {
535     case wasm::WASM_EXTERNAL_FUNCTION:
536       NumImportedFunctions++;
537       Im.SigIndex = readVaruint32(Ptr);
538       break;
539     case wasm::WASM_EXTERNAL_GLOBAL:
540       NumImportedGlobals++;
541       Im.Global.Type = readVarint7(Ptr);
542       Im.Global.Mutable = readVaruint1(Ptr);
543       break;
544     case wasm::WASM_EXTERNAL_MEMORY:
545       Im.Memory = readLimits(Ptr);
546       break;
547     case wasm::WASM_EXTERNAL_TABLE:
548       Im.Table = readTable(Ptr);
549       if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC)
550         return make_error<GenericBinaryError>("Invalid table element type",
551                                               object_error::parse_failed);
552       break;
553     default:
554       return make_error<GenericBinaryError>(
555           "Unexpected import kind", object_error::parse_failed);
556     }
557     Imports.push_back(Im);
558   }
559   if (Ptr != End)
560     return make_error<GenericBinaryError>("Import section ended prematurely",
561                                           object_error::parse_failed);
562   return Error::success();
563 }
564 
565 Error WasmObjectFile::parseFunctionSection(const uint8_t *Ptr, const uint8_t *End) {
566   uint32_t Count = readVaruint32(Ptr);
567   FunctionTypes.reserve(Count);
568   while (Count--) {
569     FunctionTypes.push_back(readVaruint32(Ptr));
570   }
571   if (Ptr != End)
572     return make_error<GenericBinaryError>("Function section ended prematurely",
573                                           object_error::parse_failed);
574   return Error::success();
575 }
576 
577 Error WasmObjectFile::parseTableSection(const uint8_t *Ptr, const uint8_t *End) {
578   uint32_t Count = readVaruint32(Ptr);
579   Tables.reserve(Count);
580   while (Count--) {
581     Tables.push_back(readTable(Ptr));
582     if (Tables.back().ElemType != wasm::WASM_TYPE_ANYFUNC) {
583       return make_error<GenericBinaryError>("Invalid table element type",
584                                             object_error::parse_failed);
585     }
586   }
587   if (Ptr != End)
588     return make_error<GenericBinaryError>("Table section ended prematurely",
589                                           object_error::parse_failed);
590   return Error::success();
591 }
592 
593 Error WasmObjectFile::parseMemorySection(const uint8_t *Ptr, const uint8_t *End) {
594   uint32_t Count = readVaruint32(Ptr);
595   Memories.reserve(Count);
596   while (Count--) {
597     Memories.push_back(readLimits(Ptr));
598   }
599   if (Ptr != End)
600     return make_error<GenericBinaryError>("Memory section ended prematurely",
601                                           object_error::parse_failed);
602   return Error::success();
603 }
604 
605 Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) {
606   uint32_t Count = readVaruint32(Ptr);
607   Globals.reserve(Count);
608   while (Count--) {
609     wasm::WasmGlobal Global;
610     Global.Type = readVarint7(Ptr);
611     Global.Mutable = readVaruint1(Ptr);
612     if (Error Err = readInitExpr(Global.InitExpr, Ptr))
613       return Err;
614     Globals.push_back(Global);
615   }
616   if (Ptr != End)
617     return make_error<GenericBinaryError>("Global section ended prematurely",
618                                           object_error::parse_failed);
619   return Error::success();
620 }
621 
622 Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) {
623   ExportSection = Sections.size();
624   uint32_t Count = readVaruint32(Ptr);
625   Exports.reserve(Count);
626   for (uint32_t i = 0; i < Count; i++) {
627     wasm::WasmExport Ex;
628     Ex.Name = readString(Ptr);
629     Ex.Kind = readUint8(Ptr);
630     Ex.Index = readVaruint32(Ptr);
631     switch (Ex.Kind) {
632     case wasm::WASM_EXTERNAL_FUNCTION:
633       if (Ex.Index >= FunctionTypes.size() + NumImportedFunctions)
634         return make_error<GenericBinaryError>("Invalid function export",
635                                               object_error::parse_failed);
636       break;
637     case wasm::WASM_EXTERNAL_GLOBAL: {
638       if (Ex.Index >= Globals.size() + NumImportedGlobals)
639         return make_error<GenericBinaryError>("Invalid global export",
640                                               object_error::parse_failed);
641       break;
642     }
643     case wasm::WASM_EXTERNAL_MEMORY:
644     case wasm::WASM_EXTERNAL_TABLE:
645       break;
646     default:
647       return make_error<GenericBinaryError>(
648           "Unexpected export kind", object_error::parse_failed);
649     }
650     Exports.push_back(Ex);
651   }
652   if (Ptr != End)
653     return make_error<GenericBinaryError>("Export section ended prematurely",
654                                           object_error::parse_failed);
655   return Error::success();
656 }
657 
658 Error WasmObjectFile::parseStartSection(const uint8_t *Ptr, const uint8_t *End) {
659   StartFunction = readVaruint32(Ptr);
660   if (StartFunction >= FunctionTypes.size())
661     return make_error<GenericBinaryError>("Invalid start function",
662                                           object_error::parse_failed);
663   return Error::success();
664 }
665 
666 Error WasmObjectFile::parseCodeSection(const uint8_t *Ptr, const uint8_t *End) {
667   uint32_t FunctionCount = readVaruint32(Ptr);
668   if (FunctionCount != FunctionTypes.size()) {
669     return make_error<GenericBinaryError>("Invalid function count",
670                                           object_error::parse_failed);
671   }
672 
673   CodeSection = ArrayRef<uint8_t>(Ptr, End - Ptr);
674 
675   while (FunctionCount--) {
676     wasm::WasmFunction Function;
677     uint32_t FunctionSize = readVaruint32(Ptr);
678     const uint8_t *FunctionEnd = Ptr + FunctionSize;
679 
680     uint32_t NumLocalDecls = readVaruint32(Ptr);
681     Function.Locals.reserve(NumLocalDecls);
682     while (NumLocalDecls--) {
683       wasm::WasmLocalDecl Decl;
684       Decl.Count = readVaruint32(Ptr);
685       Decl.Type = readVarint7(Ptr);
686       Function.Locals.push_back(Decl);
687     }
688 
689     uint32_t BodySize = FunctionEnd - Ptr;
690     Function.Body = ArrayRef<uint8_t>(Ptr, BodySize);
691     Ptr += BodySize;
692     assert(Ptr == FunctionEnd);
693     Functions.push_back(Function);
694   }
695   if (Ptr != End)
696     return make_error<GenericBinaryError>("Code section ended prematurely",
697                                           object_error::parse_failed);
698   return Error::success();
699 }
700 
701 Error WasmObjectFile::parseElemSection(const uint8_t *Ptr, const uint8_t *End) {
702   uint32_t Count = readVaruint32(Ptr);
703   ElemSegments.reserve(Count);
704   while (Count--) {
705     wasm::WasmElemSegment Segment;
706     Segment.TableIndex = readVaruint32(Ptr);
707     if (Segment.TableIndex != 0) {
708       return make_error<GenericBinaryError>("Invalid TableIndex",
709                                             object_error::parse_failed);
710     }
711     if (Error Err = readInitExpr(Segment.Offset, Ptr))
712       return Err;
713     uint32_t NumElems = readVaruint32(Ptr);
714     while (NumElems--) {
715       Segment.Functions.push_back(readVaruint32(Ptr));
716     }
717     ElemSegments.push_back(Segment);
718   }
719   if (Ptr != End)
720     return make_error<GenericBinaryError>("Elem section ended prematurely",
721                                           object_error::parse_failed);
722   return Error::success();
723 }
724 
725 Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, const uint8_t *End) {
726   const uint8_t *Start = Ptr;
727   uint32_t Count = readVaruint32(Ptr);
728   DataSegments.reserve(Count);
729   while (Count--) {
730     WasmSegment Segment;
731     Segment.Data.MemoryIndex = readVaruint32(Ptr);
732     if (Error Err = readInitExpr(Segment.Data.Offset, Ptr))
733       return Err;
734     uint32_t Size = readVaruint32(Ptr);
735     Segment.Data.Content = ArrayRef<uint8_t>(Ptr, Size);
736     Segment.Data.Alignment = 0;
737     Segment.Data.Flags = 0;
738     Segment.SectionOffset = Ptr - Start;
739     Ptr += Size;
740     DataSegments.push_back(Segment);
741   }
742   if (Ptr != End)
743     return make_error<GenericBinaryError>("Data section ended prematurely",
744                                           object_error::parse_failed);
745   return Error::success();
746 }
747 
748 const uint8_t *WasmObjectFile::getPtr(size_t Offset) const {
749   return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data());
750 }
751 
752 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
753   return Header;
754 }
755 
756 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.a++; }
757 
758 uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
759   uint32_t Result = SymbolRef::SF_None;
760   const WasmSymbol &Sym = getWasmSymbol(Symb);
761 
762   DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
763   if (Sym.isWeak())
764     Result |= SymbolRef::SF_Weak;
765   if (!Sym.isLocal())
766     Result |= SymbolRef::SF_Global;
767 
768   switch (Sym.Type) {
769   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
770     Result |= SymbolRef::SF_Undefined | SymbolRef::SF_Executable;
771     break;
772   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
773     Result |= SymbolRef::SF_Executable;
774     break;
775   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
776     Result |= SymbolRef::SF_Executable;
777     Result |= SymbolRef::SF_FormatSpecific;
778     break;
779   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
780     Result |= SymbolRef::SF_Undefined;
781     break;
782   case WasmSymbol::SymbolType::GLOBAL_EXPORT:
783     break;
784   }
785 
786   return Result;
787 }
788 
789 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
790   DataRefImpl Ref;
791   Ref.d.a = 0;
792   return BasicSymbolRef(Ref, this);
793 }
794 
795 basic_symbol_iterator WasmObjectFile::symbol_end() const {
796   DataRefImpl Ref;
797   Ref.d.a = Symbols.size();
798   return BasicSymbolRef(Ref, this);
799 }
800 
801 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
802   return Symbols[Symb.d.a];
803 }
804 
805 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
806   return getWasmSymbol(Symb.getRawDataRefImpl());
807 }
808 
809 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
810   return getWasmSymbol(Symb).Name;
811 }
812 
813 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
814   return getSymbolValue(Symb);
815 }
816 
817 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol& Sym) const {
818   switch (Sym.Type) {
819   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
820   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
821   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
822   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
823     return Sym.ElementIndex;
824   case WasmSymbol::SymbolType::GLOBAL_EXPORT: {
825     uint32_t GlobalIndex = Sym.ElementIndex - NumImportedGlobals;
826     assert(GlobalIndex < Globals.size());
827     const wasm::WasmGlobal& Global = Globals[GlobalIndex];
828     // WasmSymbols correspond only to I32_CONST globals
829     assert(Global.InitExpr.Opcode == wasm::WASM_OPCODE_I32_CONST);
830     return Global.InitExpr.Value.Int32;
831   }
832   }
833   llvm_unreachable("invalid symbol type");
834 }
835 
836 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
837   return getWasmSymbolValue(getWasmSymbol(Symb));
838 }
839 
840 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
841   llvm_unreachable("not yet implemented");
842   return 0;
843 }
844 
845 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
846   llvm_unreachable("not yet implemented");
847   return 0;
848 }
849 
850 Expected<SymbolRef::Type>
851 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
852   const WasmSymbol &Sym = getWasmSymbol(Symb);
853 
854   switch (Sym.Type) {
855   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
856   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
857   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
858     return SymbolRef::ST_Function;
859   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
860   case WasmSymbol::SymbolType::GLOBAL_EXPORT:
861     return SymbolRef::ST_Data;
862   }
863 
864   llvm_unreachable("Unknown WasmSymbol::SymbolType");
865   return SymbolRef::ST_Other;
866 }
867 
868 Expected<section_iterator>
869 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
870   DataRefImpl Ref;
871   Ref.d.a = getWasmSymbol(Symb).Section;
872   return section_iterator(SectionRef(Ref, this));
873 }
874 
875 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
876 
877 std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
878                                                StringRef &Res) const {
879   const WasmSection &S = Sections[Sec.d.a];
880 #define ECase(X)                                                               \
881   case wasm::WASM_SEC_##X:                                                     \
882     Res = #X;                                                                  \
883     break
884   switch (S.Type) {
885     ECase(TYPE);
886     ECase(IMPORT);
887     ECase(FUNCTION);
888     ECase(TABLE);
889     ECase(MEMORY);
890     ECase(GLOBAL);
891     ECase(EXPORT);
892     ECase(START);
893     ECase(ELEM);
894     ECase(CODE);
895     ECase(DATA);
896   case wasm::WASM_SEC_CUSTOM:
897     Res = S.Name;
898     break;
899   default:
900     return object_error::invalid_section_index;
901   }
902 #undef ECase
903   return std::error_code();
904 }
905 
906 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
907 
908 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
909   return Sec.d.a;
910 }
911 
912 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
913   const WasmSection &S = Sections[Sec.d.a];
914   return S.Content.size();
915 }
916 
917 std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec,
918                                                    StringRef &Res) const {
919   const WasmSection &S = Sections[Sec.d.a];
920   // This will never fail since wasm sections can never be empty (user-sections
921   // must have a name and non-user sections each have a defined structure).
922   Res = StringRef(reinterpret_cast<const char *>(S.Content.data()),
923                   S.Content.size());
924   return std::error_code();
925 }
926 
927 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
928   return 1;
929 }
930 
931 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
932   return false;
933 }
934 
935 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
936   return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
937 }
938 
939 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
940   return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
941 }
942 
943 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
944 
945 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
946 
947 bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; }
948 
949 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
950   DataRefImpl RelocRef;
951   RelocRef.d.a = Ref.d.a;
952   RelocRef.d.b = 0;
953   return relocation_iterator(RelocationRef(RelocRef, this));
954 }
955 
956 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
957   const WasmSection &Sec = getWasmSection(Ref);
958   DataRefImpl RelocRef;
959   RelocRef.d.a = Ref.d.a;
960   RelocRef.d.b = Sec.Relocations.size();
961   return relocation_iterator(RelocationRef(RelocRef, this));
962 }
963 
964 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
965   Rel.d.b++;
966 }
967 
968 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
969   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
970   return Rel.Offset;
971 }
972 
973 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
974   llvm_unreachable("not yet implemented");
975   SymbolRef Ref;
976   return symbol_iterator(Ref);
977 }
978 
979 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
980   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
981   return Rel.Type;
982 }
983 
984 void WasmObjectFile::getRelocationTypeName(
985     DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
986   const wasm::WasmRelocation& Rel = getWasmRelocation(Ref);
987   StringRef Res = "Unknown";
988 
989 #define WASM_RELOC(name, value)  \
990   case wasm::name:              \
991     Res = #name;               \
992     break;
993 
994   switch (Rel.Type) {
995 #include "llvm/BinaryFormat/WasmRelocs/WebAssembly.def"
996   }
997 
998 #undef WASM_RELOC
999 
1000   Result.append(Res.begin(), Res.end());
1001 }
1002 
1003 section_iterator WasmObjectFile::section_begin() const {
1004   DataRefImpl Ref;
1005   Ref.d.a = 0;
1006   return section_iterator(SectionRef(Ref, this));
1007 }
1008 
1009 section_iterator WasmObjectFile::section_end() const {
1010   DataRefImpl Ref;
1011   Ref.d.a = Sections.size();
1012   return section_iterator(SectionRef(Ref, this));
1013 }
1014 
1015 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
1016 
1017 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1018 
1019 unsigned WasmObjectFile::getArch() const { return Triple::wasm32; }
1020 
1021 SubtargetFeatures WasmObjectFile::getFeatures() const {
1022   return SubtargetFeatures();
1023 }
1024 
1025 bool WasmObjectFile::isRelocatableObject() const {
1026   return HasLinkingSection;
1027 }
1028 
1029 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1030   assert(Ref.d.a < Sections.size());
1031   return Sections[Ref.d.a];
1032 }
1033 
1034 const WasmSection &
1035 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1036   return getWasmSection(Section.getRawDataRefImpl());
1037 }
1038 
1039 const wasm::WasmRelocation &
1040 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1041   return getWasmRelocation(Ref.getRawDataRefImpl());
1042 }
1043 
1044 const wasm::WasmRelocation &
1045 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1046   assert(Ref.d.a < Sections.size());
1047   const WasmSection& Sec = Sections[Ref.d.a];
1048   assert(Ref.d.b < Sec.Relocations.size());
1049   return Sec.Relocations[Ref.d.b];
1050 }
1051