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.DataAlignment = 0;
197   LinkingData.DataSize = 0;
198 
199   ErrorAsOutParameter ErrAsOutParam(&Err);
200   Header.Magic = getData().substr(0, 4);
201   if (Header.Magic != StringRef("\0asm", 4)) {
202     Err = make_error<StringError>("Bad magic number",
203                                   object_error::parse_failed);
204     return;
205   }
206 
207   const uint8_t *Eof = getPtr(getData().size());
208   const uint8_t *Ptr = getPtr(4);
209 
210   if (Ptr + 4 > Eof) {
211     Err = make_error<StringError>("Missing version number",
212                                   object_error::parse_failed);
213     return;
214   }
215 
216   Header.Version = readUint32(Ptr);
217   if (Header.Version != wasm::WasmVersion) {
218     Err = make_error<StringError>("Bad version number",
219                                   object_error::parse_failed);
220     return;
221   }
222 
223   WasmSection Sec;
224   while (Ptr < Eof) {
225     if ((Err = readSection(Sec, Ptr, getPtr(0))))
226       return;
227     if ((Err = parseSection(Sec)))
228       return;
229 
230     Sections.push_back(Sec);
231   }
232 }
233 
234 Error WasmObjectFile::parseSection(WasmSection &Sec) {
235   const uint8_t* Start = Sec.Content.data();
236   const uint8_t* End = Start + Sec.Content.size();
237   switch (Sec.Type) {
238   case wasm::WASM_SEC_CUSTOM:
239     return parseCustomSection(Sec, Start, End);
240   case wasm::WASM_SEC_TYPE:
241     return parseTypeSection(Start, End);
242   case wasm::WASM_SEC_IMPORT:
243     return parseImportSection(Start, End);
244   case wasm::WASM_SEC_FUNCTION:
245     return parseFunctionSection(Start, End);
246   case wasm::WASM_SEC_TABLE:
247     return parseTableSection(Start, End);
248   case wasm::WASM_SEC_MEMORY:
249     return parseMemorySection(Start, End);
250   case wasm::WASM_SEC_GLOBAL:
251     return parseGlobalSection(Start, End);
252   case wasm::WASM_SEC_EXPORT:
253     return parseExportSection(Start, End);
254   case wasm::WASM_SEC_START:
255     return parseStartSection(Start, End);
256   case wasm::WASM_SEC_ELEM:
257     return parseElemSection(Start, End);
258   case wasm::WASM_SEC_CODE:
259     return parseCodeSection(Start, End);
260   case wasm::WASM_SEC_DATA:
261     return parseDataSection(Start, End);
262   default:
263     return make_error<GenericBinaryError>("Bad section type",
264                                           object_error::parse_failed);
265   }
266 }
267 
268 Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) {
269   while (Ptr < End) {
270     uint8_t Type = readVarint7(Ptr);
271     uint32_t Size = readVaruint32(Ptr);
272     const uint8_t *SubSectionEnd = Ptr + Size;
273     switch (Type) {
274     case wasm::WASM_NAMES_FUNCTION: {
275       uint32_t Count = readVaruint32(Ptr);
276       while (Count--) {
277         uint32_t Index = readVaruint32(Ptr);
278         StringRef Name = readString(Ptr);
279         if (!Name.empty())
280           Symbols.emplace_back(Name,
281                                WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME,
282                                Sections.size(), Index);
283       }
284       break;
285     }
286     // Ignore local names for now
287     case wasm::WASM_NAMES_LOCAL:
288     default:
289       Ptr += Size;
290       break;
291     }
292     if (Ptr != SubSectionEnd)
293       return make_error<GenericBinaryError>("Name sub-section ended prematurely",
294                                             object_error::parse_failed);
295   }
296 
297   if (Ptr != End)
298     return make_error<GenericBinaryError>("Name section ended prematurely",
299                                           object_error::parse_failed);
300   return Error::success();
301 }
302 
303 void WasmObjectFile::populateSymbolTable() {
304   // Add imports to symbol table
305   size_t ImportIndex = 0;
306   for (const wasm::WasmImport& Import : Imports) {
307     switch (Import.Kind) {
308     case wasm::WASM_EXTERNAL_GLOBAL:
309       assert(Import.Global.Type == wasm::WASM_TYPE_I32);
310       SymbolMap.try_emplace(Import.Field, Symbols.size());
311       Symbols.emplace_back(Import.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT,
312                            ImportSection, ImportIndex);
313       DEBUG(dbgs() << "Adding import: " << Symbols.back()
314                    << " sym index:" << Symbols.size() << "\n");
315       break;
316     case wasm::WASM_EXTERNAL_FUNCTION:
317       SymbolMap.try_emplace(Import.Field, Symbols.size());
318       Symbols.emplace_back(Import.Field,
319                            WasmSymbol::SymbolType::FUNCTION_IMPORT,
320                            ImportSection, ImportIndex);
321       DEBUG(dbgs() << "Adding import: " << Symbols.back()
322                    << " sym index:" << Symbols.size() << "\n");
323       break;
324     default:
325       break;
326     }
327     ImportIndex++;
328   }
329 
330   // Add exports to symbol table
331   size_t ExportIndex = 0;
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       auto Pair = SymbolMap.try_emplace(Export.Name, Symbols.size());
340       if (Pair.second) {
341         Symbols.emplace_back(Export.Name, ExportType,
342                              ExportSection, ExportIndex);
343         DEBUG(dbgs() << "Adding export: " << Symbols.back()
344                      << " sym index:" << Symbols.size() << "\n");
345       } else {
346         uint32_t SymIndex = Pair.first->second;
347         Symbols[SymIndex] =
348             WasmSymbol(Export.Name, ExportType, ExportSection, ExportIndex);
349         DEBUG(dbgs() << "Replacing existing symbol:  " << Symbols[SymIndex]
350                      << " sym index:" << SymIndex << "\n");
351       }
352     }
353     ExportIndex++;
354   }
355 }
356 
357 Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr,
358                                           const uint8_t *End) {
359   HasLinkingSection = true;
360 
361   // Only populate the symbol table with imports and exports if the object
362   // has a linking section (i.e. its a relocatable object file). Otherwise
363   // the global might not represent symbols at all.
364   populateSymbolTable();
365 
366   while (Ptr < End) {
367     uint8_t Type = readVarint7(Ptr);
368     uint32_t Size = readVaruint32(Ptr);
369     const uint8_t *SubSectionEnd = Ptr + Size;
370     switch (Type) {
371     case wasm::WASM_SYMBOL_INFO: {
372       uint32_t Count = readVaruint32(Ptr);
373       while (Count--) {
374         StringRef Symbol = readString(Ptr);
375         DEBUG(dbgs() << "reading syminfo: " << Symbol << "\n");
376         uint32_t Flags = readVaruint32(Ptr);
377         auto iter = SymbolMap.find(Symbol);
378         if (iter == SymbolMap.end()) {
379           return make_error<GenericBinaryError>(
380               "Invalid symbol name in linking section: " + Symbol,
381               object_error::parse_failed);
382         }
383         uint32_t SymIndex = iter->second;
384         assert(SymIndex < Symbols.size());
385         Symbols[SymIndex].Flags = Flags;
386         DEBUG(dbgs() << "Set symbol flags index:"
387                      << SymIndex << " name:"
388                      << Symbols[SymIndex].Name << " exptected:"
389                      << Symbol << " flags: " << Flags << "\n");
390       }
391       break;
392     }
393     case wasm::WASM_DATA_SIZE:
394       LinkingData.DataSize = readVaruint32(Ptr);
395       break;
396     case wasm::WASM_DATA_ALIGNMENT:
397       LinkingData.DataAlignment = readVaruint32(Ptr);
398       break;
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.SectionOffset = Ptr - Start;
737     Ptr += Size;
738     DataSegments.push_back(Segment);
739   }
740   if (Ptr != End)
741     return make_error<GenericBinaryError>("Data section ended prematurely",
742                                           object_error::parse_failed);
743   return Error::success();
744 }
745 
746 const uint8_t *WasmObjectFile::getPtr(size_t Offset) const {
747   return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data());
748 }
749 
750 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
751   return Header;
752 }
753 
754 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.a++; }
755 
756 uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
757   uint32_t Result = SymbolRef::SF_None;
758   const WasmSymbol &Sym = getWasmSymbol(Symb);
759 
760   DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
761   if (Sym.Flags & wasm::WASM_SYMBOL_FLAG_WEAK)
762     Result |= SymbolRef::SF_Weak;
763 
764   switch (Sym.Type) {
765   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
766     Result |= SymbolRef::SF_Undefined | SymbolRef::SF_Executable;
767     break;
768   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
769     Result |= SymbolRef::SF_Global | SymbolRef::SF_Executable;
770     break;
771   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
772     Result |= SymbolRef::SF_Executable;
773     Result |= SymbolRef::SF_FormatSpecific;
774     break;
775   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
776     Result |= SymbolRef::SF_Undefined;
777     break;
778   case WasmSymbol::SymbolType::GLOBAL_EXPORT:
779     Result |= SymbolRef::SF_Global;
780     break;
781   }
782 
783   return Result;
784 }
785 
786 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
787   DataRefImpl Ref;
788   Ref.d.a = 0;
789   return BasicSymbolRef(Ref, this);
790 }
791 
792 basic_symbol_iterator WasmObjectFile::symbol_end() const {
793   DataRefImpl Ref;
794   Ref.d.a = Symbols.size();
795   return BasicSymbolRef(Ref, this);
796 }
797 
798 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
799   return Symbols[Symb.d.a];
800 }
801 
802 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
803   return getWasmSymbol(Symb.getRawDataRefImpl());
804 }
805 
806 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
807   return getWasmSymbol(Symb).Name;
808 }
809 
810 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
811   return getSymbolValue(Symb);
812 }
813 
814 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
815   const WasmSymbol& Sym = getWasmSymbol(Symb);
816   switch (Sym.Type) {
817   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
818   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
819     return 0;
820   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
821     return Exports[Sym.ElementIndex].Index;
822   case WasmSymbol::SymbolType::GLOBAL_EXPORT: {
823     uint32_t GlobalIndex = Exports[Sym.ElementIndex].Index - NumImportedGlobals;
824     assert(GlobalIndex < Globals.size());
825     const wasm::WasmGlobal& Global = Globals[GlobalIndex];
826     // WasmSymbols correspond only to I32_CONST globals
827     assert(Global.InitExpr.Opcode == wasm::WASM_OPCODE_I32_CONST);
828     return Global.InitExpr.Value.Int32;
829   }
830   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
831     return Sym.ElementIndex;
832   }
833   llvm_unreachable("invalid symbol type");
834 }
835 
836 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
837   llvm_unreachable("not yet implemented");
838   return 0;
839 }
840 
841 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
842   llvm_unreachable("not yet implemented");
843   return 0;
844 }
845 
846 Expected<SymbolRef::Type>
847 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
848   const WasmSymbol &Sym = getWasmSymbol(Symb);
849 
850   switch (Sym.Type) {
851   case WasmSymbol::SymbolType::FUNCTION_IMPORT:
852   case WasmSymbol::SymbolType::FUNCTION_EXPORT:
853   case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
854     return SymbolRef::ST_Function;
855   case WasmSymbol::SymbolType::GLOBAL_IMPORT:
856   case WasmSymbol::SymbolType::GLOBAL_EXPORT:
857     return SymbolRef::ST_Data;
858   }
859 
860   llvm_unreachable("Unknown WasmSymbol::SymbolType");
861   return SymbolRef::ST_Other;
862 }
863 
864 Expected<section_iterator>
865 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
866   DataRefImpl Ref;
867   Ref.d.a = getWasmSymbol(Symb).Section;
868   return section_iterator(SectionRef(Ref, this));
869 }
870 
871 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
872 
873 std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
874                                                StringRef &Res) const {
875   const WasmSection &S = Sections[Sec.d.a];
876 #define ECase(X)                                                               \
877   case wasm::WASM_SEC_##X:                                                     \
878     Res = #X;                                                                  \
879     break
880   switch (S.Type) {
881     ECase(TYPE);
882     ECase(IMPORT);
883     ECase(FUNCTION);
884     ECase(TABLE);
885     ECase(MEMORY);
886     ECase(GLOBAL);
887     ECase(EXPORT);
888     ECase(START);
889     ECase(ELEM);
890     ECase(CODE);
891     ECase(DATA);
892   case wasm::WASM_SEC_CUSTOM:
893     Res = S.Name;
894     break;
895   default:
896     return object_error::invalid_section_index;
897   }
898 #undef ECase
899   return std::error_code();
900 }
901 
902 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
903 
904 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
905   return Sec.d.a;
906 }
907 
908 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
909   const WasmSection &S = Sections[Sec.d.a];
910   return S.Content.size();
911 }
912 
913 std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec,
914                                                    StringRef &Res) const {
915   const WasmSection &S = Sections[Sec.d.a];
916   // This will never fail since wasm sections can never be empty (user-sections
917   // must have a name and non-user sections each have a defined structure).
918   Res = StringRef(reinterpret_cast<const char *>(S.Content.data()),
919                   S.Content.size());
920   return std::error_code();
921 }
922 
923 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
924   return 1;
925 }
926 
927 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
928   return false;
929 }
930 
931 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
932   return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
933 }
934 
935 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
936   return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
937 }
938 
939 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
940 
941 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
942 
943 bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; }
944 
945 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
946   DataRefImpl RelocRef;
947   RelocRef.d.a = Ref.d.a;
948   RelocRef.d.b = 0;
949   return relocation_iterator(RelocationRef(RelocRef, this));
950 }
951 
952 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
953   const WasmSection &Sec = getWasmSection(Ref);
954   DataRefImpl RelocRef;
955   RelocRef.d.a = Ref.d.a;
956   RelocRef.d.b = Sec.Relocations.size();
957   return relocation_iterator(RelocationRef(RelocRef, this));
958 }
959 
960 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
961   Rel.d.b++;
962 }
963 
964 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
965   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
966   return Rel.Offset;
967 }
968 
969 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
970   llvm_unreachable("not yet implemented");
971   SymbolRef Ref;
972   return symbol_iterator(Ref);
973 }
974 
975 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
976   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
977   return Rel.Type;
978 }
979 
980 void WasmObjectFile::getRelocationTypeName(
981     DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
982   const wasm::WasmRelocation& Rel = getWasmRelocation(Ref);
983   StringRef Res = "Unknown";
984 
985 #define WASM_RELOC(name, value)  \
986   case wasm::name:              \
987     Res = #name;               \
988     break;
989 
990   switch (Rel.Type) {
991 #include "llvm/BinaryFormat/WasmRelocs/WebAssembly.def"
992   }
993 
994 #undef WASM_RELOC
995 
996   Result.append(Res.begin(), Res.end());
997 }
998 
999 section_iterator WasmObjectFile::section_begin() const {
1000   DataRefImpl Ref;
1001   Ref.d.a = 0;
1002   return section_iterator(SectionRef(Ref, this));
1003 }
1004 
1005 section_iterator WasmObjectFile::section_end() const {
1006   DataRefImpl Ref;
1007   Ref.d.a = Sections.size();
1008   return section_iterator(SectionRef(Ref, this));
1009 }
1010 
1011 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
1012 
1013 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1014 
1015 unsigned WasmObjectFile::getArch() const { return Triple::wasm32; }
1016 
1017 SubtargetFeatures WasmObjectFile::getFeatures() const {
1018   return SubtargetFeatures();
1019 }
1020 
1021 bool WasmObjectFile::isRelocatableObject() const {
1022   return HasLinkingSection;
1023 }
1024 
1025 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1026   assert(Ref.d.a < Sections.size());
1027   return Sections[Ref.d.a];
1028 }
1029 
1030 const WasmSection &
1031 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1032   return getWasmSection(Section.getRawDataRefImpl());
1033 }
1034 
1035 const wasm::WasmRelocation &
1036 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1037   return getWasmRelocation(Ref.getRawDataRefImpl());
1038 }
1039 
1040 const wasm::WasmRelocation &
1041 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1042   assert(Ref.d.a < Sections.size());
1043   const WasmSection& Sec = Sections[Ref.d.a];
1044   assert(Ref.d.b < Sec.Relocations.size());
1045   return Sec.Relocations[Ref.d.b];
1046 }
1047