1 //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ADT/ArrayRef.h"
10 #include "llvm/ADT/DenseSet.h"
11 #include "llvm/ADT/SmallSet.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/ADT/StringSet.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/BinaryFormat/Wasm.h"
17 #include "llvm/MC/SubtargetFeature.h"
18 #include "llvm/Object/Binary.h"
19 #include "llvm/Object/Error.h"
20 #include "llvm/Object/ObjectFile.h"
21 #include "llvm/Object/SymbolicFile.h"
22 #include "llvm/Object/Wasm.h"
23 #include "llvm/Support/Endian.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/ErrorHandling.h"
26 #include "llvm/Support/LEB128.h"
27 #include "llvm/Support/ScopedPrinter.h"
28 #include <algorithm>
29 #include <cassert>
30 #include <cstdint>
31 #include <cstring>
32 
33 #define DEBUG_TYPE "wasm-object"
34 
35 using namespace llvm;
36 using namespace object;
37 
print(raw_ostream & Out) const38 void WasmSymbol::print(raw_ostream &Out) const {
39   Out << "Name=" << Info.Name
40       << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"
41       << Twine::utohexstr(Info.Flags);
42   if (!isTypeData()) {
43     Out << ", ElemIndex=" << Info.ElementIndex;
44   } else if (isDefined()) {
45     Out << ", Segment=" << Info.DataRef.Segment;
46     Out << ", Offset=" << Info.DataRef.Offset;
47     Out << ", Size=" << Info.DataRef.Size;
48   }
49 }
50 
51 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const52 LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
53 #endif
54 
55 Expected<std::unique_ptr<WasmObjectFile>>
createWasmObjectFile(MemoryBufferRef Buffer)56 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
57   Error Err = Error::success();
58   auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
59   if (Err)
60     return std::move(Err);
61 
62   return std::move(ObjectFile);
63 }
64 
65 #define VARINT7_MAX ((1 << 7) - 1)
66 #define VARINT7_MIN (-(1 << 7))
67 #define VARUINT7_MAX (1 << 7)
68 #define VARUINT1_MAX (1)
69 
readUint8(WasmObjectFile::ReadContext & Ctx)70 static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
71   if (Ctx.Ptr == Ctx.End)
72     report_fatal_error("EOF while reading uint8");
73   return *Ctx.Ptr++;
74 }
75 
readUint32(WasmObjectFile::ReadContext & Ctx)76 static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
77   if (Ctx.Ptr + 4 > Ctx.End)
78     report_fatal_error("EOF while reading uint32");
79   uint32_t Result = support::endian::read32le(Ctx.Ptr);
80   Ctx.Ptr += 4;
81   return Result;
82 }
83 
readFloat32(WasmObjectFile::ReadContext & Ctx)84 static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
85   if (Ctx.Ptr + 4 > Ctx.End)
86     report_fatal_error("EOF while reading float64");
87   int32_t Result = 0;
88   memcpy(&Result, Ctx.Ptr, sizeof(Result));
89   Ctx.Ptr += sizeof(Result);
90   return Result;
91 }
92 
readFloat64(WasmObjectFile::ReadContext & Ctx)93 static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
94   if (Ctx.Ptr + 8 > Ctx.End)
95     report_fatal_error("EOF while reading float64");
96   int64_t Result = 0;
97   memcpy(&Result, Ctx.Ptr, sizeof(Result));
98   Ctx.Ptr += sizeof(Result);
99   return Result;
100 }
101 
readULEB128(WasmObjectFile::ReadContext & Ctx)102 static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
103   unsigned Count;
104   const char *Error = nullptr;
105   uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
106   if (Error)
107     report_fatal_error(Error);
108   Ctx.Ptr += Count;
109   return Result;
110 }
111 
readString(WasmObjectFile::ReadContext & Ctx)112 static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
113   uint32_t StringLen = readULEB128(Ctx);
114   if (Ctx.Ptr + StringLen > Ctx.End)
115     report_fatal_error("EOF while reading string");
116   StringRef Return =
117       StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
118   Ctx.Ptr += StringLen;
119   return Return;
120 }
121 
readLEB128(WasmObjectFile::ReadContext & Ctx)122 static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
123   unsigned Count;
124   const char *Error = nullptr;
125   uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
126   if (Error)
127     report_fatal_error(Error);
128   Ctx.Ptr += Count;
129   return Result;
130 }
131 
readVaruint1(WasmObjectFile::ReadContext & Ctx)132 static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
133   int64_t Result = readLEB128(Ctx);
134   if (Result > VARUINT1_MAX || Result < 0)
135     report_fatal_error("LEB is outside Varuint1 range");
136   return Result;
137 }
138 
readVarint32(WasmObjectFile::ReadContext & Ctx)139 static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
140   int64_t Result = readLEB128(Ctx);
141   if (Result > INT32_MAX || Result < INT32_MIN)
142     report_fatal_error("LEB is outside Varint32 range");
143   return Result;
144 }
145 
readVaruint32(WasmObjectFile::ReadContext & Ctx)146 static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
147   uint64_t Result = readULEB128(Ctx);
148   if (Result > UINT32_MAX)
149     report_fatal_error("LEB is outside Varuint32 range");
150   return Result;
151 }
152 
readVarint64(WasmObjectFile::ReadContext & Ctx)153 static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
154   return readLEB128(Ctx);
155 }
156 
readVaruint64(WasmObjectFile::ReadContext & Ctx)157 static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
158   return readULEB128(Ctx);
159 }
160 
readOpcode(WasmObjectFile::ReadContext & Ctx)161 static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
162   return readUint8(Ctx);
163 }
164 
readInitExpr(wasm::WasmInitExpr & Expr,WasmObjectFile::ReadContext & Ctx)165 static Error readInitExpr(wasm::WasmInitExpr &Expr,
166                           WasmObjectFile::ReadContext &Ctx) {
167   auto Start = Ctx.Ptr;
168 
169   Expr.Extended = false;
170   Expr.Inst.Opcode = readOpcode(Ctx);
171   switch (Expr.Inst.Opcode) {
172   case wasm::WASM_OPCODE_I32_CONST:
173     Expr.Inst.Value.Int32 = readVarint32(Ctx);
174     break;
175   case wasm::WASM_OPCODE_I64_CONST:
176     Expr.Inst.Value.Int64 = readVarint64(Ctx);
177     break;
178   case wasm::WASM_OPCODE_F32_CONST:
179     Expr.Inst.Value.Float32 = readFloat32(Ctx);
180     break;
181   case wasm::WASM_OPCODE_F64_CONST:
182     Expr.Inst.Value.Float64 = readFloat64(Ctx);
183     break;
184   case wasm::WASM_OPCODE_GLOBAL_GET:
185     Expr.Inst.Value.Global = readULEB128(Ctx);
186     break;
187   case wasm::WASM_OPCODE_REF_NULL: {
188     wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
189     if (Ty != wasm::ValType::EXTERNREF) {
190       return make_error<GenericBinaryError>("invalid type for ref.null",
191                                             object_error::parse_failed);
192     }
193     break;
194   }
195   default:
196     Expr.Extended = true;
197   }
198 
199   if (!Expr.Extended) {
200     uint8_t EndOpcode = readOpcode(Ctx);
201     if (EndOpcode != wasm::WASM_OPCODE_END)
202       Expr.Extended = true;
203   }
204 
205   if (Expr.Extended) {
206     Ctx.Ptr = Start;
207     while (true) {
208       uint8_t Opcode = readOpcode(Ctx);
209       switch (Opcode) {
210       case wasm::WASM_OPCODE_I32_CONST:
211       case wasm::WASM_OPCODE_GLOBAL_GET:
212       case wasm::WASM_OPCODE_REF_NULL:
213       case wasm::WASM_OPCODE_I64_CONST:
214       case wasm::WASM_OPCODE_F32_CONST:
215       case wasm::WASM_OPCODE_F64_CONST:
216         readULEB128(Ctx);
217         break;
218       case wasm::WASM_OPCODE_I32_ADD:
219       case wasm::WASM_OPCODE_I32_SUB:
220       case wasm::WASM_OPCODE_I32_MUL:
221       case wasm::WASM_OPCODE_I64_ADD:
222       case wasm::WASM_OPCODE_I64_SUB:
223       case wasm::WASM_OPCODE_I64_MUL:
224         break;
225       case wasm::WASM_OPCODE_END:
226         Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);
227         return Error::success();
228       default:
229         return make_error<GenericBinaryError>(
230             Twine("invalid opcode in init_expr: ") + Twine(unsigned(Opcode)),
231             object_error::parse_failed);
232       }
233     }
234   }
235 
236   return Error::success();
237 }
238 
readLimits(WasmObjectFile::ReadContext & Ctx)239 static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
240   wasm::WasmLimits Result;
241   Result.Flags = readVaruint32(Ctx);
242   Result.Minimum = readVaruint64(Ctx);
243   if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
244     Result.Maximum = readVaruint64(Ctx);
245   return Result;
246 }
247 
readTableType(WasmObjectFile::ReadContext & Ctx)248 static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
249   wasm::WasmTableType TableType;
250   TableType.ElemType = readUint8(Ctx);
251   TableType.Limits = readLimits(Ctx);
252   return TableType;
253 }
254 
readSection(WasmSection & Section,WasmObjectFile::ReadContext & Ctx,WasmSectionOrderChecker & Checker)255 static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
256                          WasmSectionOrderChecker &Checker) {
257   Section.Offset = Ctx.Ptr - Ctx.Start;
258   Section.Type = readUint8(Ctx);
259   LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
260   uint32_t Size = readVaruint32(Ctx);
261   if (Size == 0)
262     return make_error<StringError>("zero length section",
263                                    object_error::parse_failed);
264   if (Ctx.Ptr + Size > Ctx.End)
265     return make_error<StringError>("section too large",
266                                    object_error::parse_failed);
267   if (Section.Type == wasm::WASM_SEC_CUSTOM) {
268     WasmObjectFile::ReadContext SectionCtx;
269     SectionCtx.Start = Ctx.Ptr;
270     SectionCtx.Ptr = Ctx.Ptr;
271     SectionCtx.End = Ctx.Ptr + Size;
272 
273     Section.Name = readString(SectionCtx);
274 
275     uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
276     Ctx.Ptr += SectionNameSize;
277     Size -= SectionNameSize;
278   }
279 
280   if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
281     return make_error<StringError>("out of order section type: " +
282                                        llvm::to_string(Section.Type),
283                                    object_error::parse_failed);
284   }
285 
286   Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
287   Ctx.Ptr += Size;
288   return Error::success();
289 }
290 
WasmObjectFile(MemoryBufferRef Buffer,Error & Err)291 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
292     : ObjectFile(Binary::ID_Wasm, Buffer) {
293   ErrorAsOutParameter ErrAsOutParam(&Err);
294   Header.Magic = getData().substr(0, 4);
295   if (Header.Magic != StringRef("\0asm", 4)) {
296     Err = make_error<StringError>("invalid magic number",
297                                   object_error::parse_failed);
298     return;
299   }
300 
301   ReadContext Ctx;
302   Ctx.Start = getData().bytes_begin();
303   Ctx.Ptr = Ctx.Start + 4;
304   Ctx.End = Ctx.Start + getData().size();
305 
306   if (Ctx.Ptr + 4 > Ctx.End) {
307     Err = make_error<StringError>("missing version number",
308                                   object_error::parse_failed);
309     return;
310   }
311 
312   Header.Version = readUint32(Ctx);
313   if (Header.Version != wasm::WasmVersion) {
314     Err = make_error<StringError>("invalid version number: " +
315                                       Twine(Header.Version),
316                                   object_error::parse_failed);
317     return;
318   }
319 
320   WasmSectionOrderChecker Checker;
321   while (Ctx.Ptr < Ctx.End) {
322     WasmSection Sec;
323     if ((Err = readSection(Sec, Ctx, Checker)))
324       return;
325     if ((Err = parseSection(Sec)))
326       return;
327 
328     Sections.push_back(Sec);
329   }
330 }
331 
parseSection(WasmSection & Sec)332 Error WasmObjectFile::parseSection(WasmSection &Sec) {
333   ReadContext Ctx;
334   Ctx.Start = Sec.Content.data();
335   Ctx.End = Ctx.Start + Sec.Content.size();
336   Ctx.Ptr = Ctx.Start;
337   switch (Sec.Type) {
338   case wasm::WASM_SEC_CUSTOM:
339     return parseCustomSection(Sec, Ctx);
340   case wasm::WASM_SEC_TYPE:
341     return parseTypeSection(Ctx);
342   case wasm::WASM_SEC_IMPORT:
343     return parseImportSection(Ctx);
344   case wasm::WASM_SEC_FUNCTION:
345     return parseFunctionSection(Ctx);
346   case wasm::WASM_SEC_TABLE:
347     return parseTableSection(Ctx);
348   case wasm::WASM_SEC_MEMORY:
349     return parseMemorySection(Ctx);
350   case wasm::WASM_SEC_TAG:
351     return parseTagSection(Ctx);
352   case wasm::WASM_SEC_GLOBAL:
353     return parseGlobalSection(Ctx);
354   case wasm::WASM_SEC_EXPORT:
355     return parseExportSection(Ctx);
356   case wasm::WASM_SEC_START:
357     return parseStartSection(Ctx);
358   case wasm::WASM_SEC_ELEM:
359     return parseElemSection(Ctx);
360   case wasm::WASM_SEC_CODE:
361     return parseCodeSection(Ctx);
362   case wasm::WASM_SEC_DATA:
363     return parseDataSection(Ctx);
364   case wasm::WASM_SEC_DATACOUNT:
365     return parseDataCountSection(Ctx);
366   default:
367     return make_error<GenericBinaryError>(
368         "invalid section type: " + Twine(Sec.Type), object_error::parse_failed);
369   }
370 }
371 
parseDylinkSection(ReadContext & Ctx)372 Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
373   // Legacy "dylink" section support.
374   // See parseDylink0Section for the current "dylink.0" section parsing.
375   HasDylinkSection = true;
376   DylinkInfo.MemorySize = readVaruint32(Ctx);
377   DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
378   DylinkInfo.TableSize = readVaruint32(Ctx);
379   DylinkInfo.TableAlignment = readVaruint32(Ctx);
380   uint32_t Count = readVaruint32(Ctx);
381   while (Count--) {
382     DylinkInfo.Needed.push_back(readString(Ctx));
383   }
384 
385   if (Ctx.Ptr != Ctx.End)
386     return make_error<GenericBinaryError>("dylink section ended prematurely",
387                                           object_error::parse_failed);
388   return Error::success();
389 }
390 
parseDylink0Section(ReadContext & Ctx)391 Error WasmObjectFile::parseDylink0Section(ReadContext &Ctx) {
392   // See
393   // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
394   HasDylinkSection = true;
395 
396   const uint8_t *OrigEnd = Ctx.End;
397   while (Ctx.Ptr < OrigEnd) {
398     Ctx.End = OrigEnd;
399     uint8_t Type = readUint8(Ctx);
400     uint32_t Size = readVaruint32(Ctx);
401     LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
402                       << "\n");
403     Ctx.End = Ctx.Ptr + Size;
404     uint32_t Count;
405     switch (Type) {
406     case wasm::WASM_DYLINK_MEM_INFO:
407       DylinkInfo.MemorySize = readVaruint32(Ctx);
408       DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
409       DylinkInfo.TableSize = readVaruint32(Ctx);
410       DylinkInfo.TableAlignment = readVaruint32(Ctx);
411       break;
412     case wasm::WASM_DYLINK_NEEDED:
413       Count = readVaruint32(Ctx);
414       while (Count--) {
415         DylinkInfo.Needed.push_back(readString(Ctx));
416       }
417       break;
418     case wasm::WASM_DYLINK_EXPORT_INFO: {
419       uint32_t Count = readVaruint32(Ctx);
420       while (Count--) {
421         DylinkInfo.ExportInfo.push_back({readString(Ctx), readVaruint32(Ctx)});
422       }
423       break;
424     }
425     case wasm::WASM_DYLINK_IMPORT_INFO: {
426       uint32_t Count = readVaruint32(Ctx);
427       while (Count--) {
428         DylinkInfo.ImportInfo.push_back(
429             {readString(Ctx), readString(Ctx), readVaruint32(Ctx)});
430       }
431       break;
432     }
433     default:
434       LLVM_DEBUG(dbgs() << "unknown dylink.0 sub-section: " << Type << "\n");
435       Ctx.Ptr += Size;
436       break;
437     }
438     if (Ctx.Ptr != Ctx.End) {
439       return make_error<GenericBinaryError>(
440           "dylink.0 sub-section ended prematurely", object_error::parse_failed);
441     }
442   }
443 
444   if (Ctx.Ptr != Ctx.End)
445     return make_error<GenericBinaryError>("dylink.0 section ended prematurely",
446                                           object_error::parse_failed);
447   return Error::success();
448 }
449 
parseNameSection(ReadContext & Ctx)450 Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
451   llvm::DenseSet<uint64_t> SeenFunctions;
452   llvm::DenseSet<uint64_t> SeenGlobals;
453   llvm::DenseSet<uint64_t> SeenSegments;
454 
455   while (Ctx.Ptr < Ctx.End) {
456     uint8_t Type = readUint8(Ctx);
457     uint32_t Size = readVaruint32(Ctx);
458     const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
459     switch (Type) {
460     case wasm::WASM_NAMES_FUNCTION:
461     case wasm::WASM_NAMES_GLOBAL:
462     case wasm::WASM_NAMES_DATA_SEGMENT: {
463       uint32_t Count = readVaruint32(Ctx);
464       while (Count--) {
465         uint32_t Index = readVaruint32(Ctx);
466         StringRef Name = readString(Ctx);
467         wasm::NameType nameType = wasm::NameType::FUNCTION;
468         if (Type == wasm::WASM_NAMES_FUNCTION) {
469           if (!SeenFunctions.insert(Index).second)
470             return make_error<GenericBinaryError>(
471                 "function named more than once", object_error::parse_failed);
472           if (!isValidFunctionIndex(Index) || Name.empty())
473             return make_error<GenericBinaryError>("invalid function name entry",
474                                                   object_error::parse_failed);
475 
476           if (isDefinedFunctionIndex(Index))
477             getDefinedFunction(Index).DebugName = Name;
478         } else if (Type == wasm::WASM_NAMES_GLOBAL) {
479           nameType = wasm::NameType::GLOBAL;
480           if (!SeenGlobals.insert(Index).second)
481             return make_error<GenericBinaryError>("global named more than once",
482                                                   object_error::parse_failed);
483           if (!isValidGlobalIndex(Index) || Name.empty())
484             return make_error<GenericBinaryError>("invalid global name entry",
485                                                   object_error::parse_failed);
486         } else {
487           nameType = wasm::NameType::DATA_SEGMENT;
488           if (!SeenSegments.insert(Index).second)
489             return make_error<GenericBinaryError>(
490                 "segment named more than once", object_error::parse_failed);
491           if (Index > DataSegments.size())
492             return make_error<GenericBinaryError>("invalid data segment name entry",
493                                                   object_error::parse_failed);
494         }
495         DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name});
496       }
497       break;
498     }
499     // Ignore local names for now
500     case wasm::WASM_NAMES_LOCAL:
501     default:
502       Ctx.Ptr += Size;
503       break;
504     }
505     if (Ctx.Ptr != SubSectionEnd)
506       return make_error<GenericBinaryError>(
507           "name sub-section ended prematurely", object_error::parse_failed);
508   }
509 
510   if (Ctx.Ptr != Ctx.End)
511     return make_error<GenericBinaryError>("name section ended prematurely",
512                                           object_error::parse_failed);
513   return Error::success();
514 }
515 
parseLinkingSection(ReadContext & Ctx)516 Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
517   HasLinkingSection = true;
518 
519   LinkingData.Version = readVaruint32(Ctx);
520   if (LinkingData.Version != wasm::WasmMetadataVersion) {
521     return make_error<GenericBinaryError>(
522         "unexpected metadata version: " + Twine(LinkingData.Version) +
523             " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
524         object_error::parse_failed);
525   }
526 
527   const uint8_t *OrigEnd = Ctx.End;
528   while (Ctx.Ptr < OrigEnd) {
529     Ctx.End = OrigEnd;
530     uint8_t Type = readUint8(Ctx);
531     uint32_t Size = readVaruint32(Ctx);
532     LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
533                       << "\n");
534     Ctx.End = Ctx.Ptr + Size;
535     switch (Type) {
536     case wasm::WASM_SYMBOL_TABLE:
537       if (Error Err = parseLinkingSectionSymtab(Ctx))
538         return Err;
539       break;
540     case wasm::WASM_SEGMENT_INFO: {
541       uint32_t Count = readVaruint32(Ctx);
542       if (Count > DataSegments.size())
543         return make_error<GenericBinaryError>("too many segment names",
544                                               object_error::parse_failed);
545       for (uint32_t I = 0; I < Count; I++) {
546         DataSegments[I].Data.Name = readString(Ctx);
547         DataSegments[I].Data.Alignment = readVaruint32(Ctx);
548         DataSegments[I].Data.LinkingFlags = readVaruint32(Ctx);
549       }
550       break;
551     }
552     case wasm::WASM_INIT_FUNCS: {
553       uint32_t Count = readVaruint32(Ctx);
554       LinkingData.InitFunctions.reserve(Count);
555       for (uint32_t I = 0; I < Count; I++) {
556         wasm::WasmInitFunc Init;
557         Init.Priority = readVaruint32(Ctx);
558         Init.Symbol = readVaruint32(Ctx);
559         if (!isValidFunctionSymbol(Init.Symbol))
560           return make_error<GenericBinaryError>("invalid function symbol: " +
561                                                     Twine(Init.Symbol),
562                                                 object_error::parse_failed);
563         LinkingData.InitFunctions.emplace_back(Init);
564       }
565       break;
566     }
567     case wasm::WASM_COMDAT_INFO:
568       if (Error Err = parseLinkingSectionComdat(Ctx))
569         return Err;
570       break;
571     default:
572       Ctx.Ptr += Size;
573       break;
574     }
575     if (Ctx.Ptr != Ctx.End)
576       return make_error<GenericBinaryError>(
577           "linking sub-section ended prematurely", object_error::parse_failed);
578   }
579   if (Ctx.Ptr != OrigEnd)
580     return make_error<GenericBinaryError>("linking section ended prematurely",
581                                           object_error::parse_failed);
582   return Error::success();
583 }
584 
parseLinkingSectionSymtab(ReadContext & Ctx)585 Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
586   uint32_t Count = readVaruint32(Ctx);
587   LinkingData.SymbolTable.reserve(Count);
588   Symbols.reserve(Count);
589   StringSet<> SymbolNames;
590 
591   std::vector<wasm::WasmImport *> ImportedGlobals;
592   std::vector<wasm::WasmImport *> ImportedFunctions;
593   std::vector<wasm::WasmImport *> ImportedTags;
594   std::vector<wasm::WasmImport *> ImportedTables;
595   ImportedGlobals.reserve(Imports.size());
596   ImportedFunctions.reserve(Imports.size());
597   ImportedTags.reserve(Imports.size());
598   ImportedTables.reserve(Imports.size());
599   for (auto &I : Imports) {
600     if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
601       ImportedFunctions.emplace_back(&I);
602     else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
603       ImportedGlobals.emplace_back(&I);
604     else if (I.Kind == wasm::WASM_EXTERNAL_TAG)
605       ImportedTags.emplace_back(&I);
606     else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
607       ImportedTables.emplace_back(&I);
608   }
609 
610   while (Count--) {
611     wasm::WasmSymbolInfo Info;
612     const wasm::WasmSignature *Signature = nullptr;
613     const wasm::WasmGlobalType *GlobalType = nullptr;
614     const wasm::WasmTableType *TableType = nullptr;
615 
616     Info.Kind = readUint8(Ctx);
617     Info.Flags = readVaruint32(Ctx);
618     bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
619 
620     switch (Info.Kind) {
621     case wasm::WASM_SYMBOL_TYPE_FUNCTION:
622       Info.ElementIndex = readVaruint32(Ctx);
623       if (!isValidFunctionIndex(Info.ElementIndex) ||
624           IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
625         return make_error<GenericBinaryError>("invalid function symbol index",
626                                               object_error::parse_failed);
627       if (IsDefined) {
628         Info.Name = readString(Ctx);
629         unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
630         wasm::WasmFunction &Function = Functions[FuncIndex];
631         Signature = &Signatures[Function.SigIndex];
632         if (Function.SymbolName.empty())
633           Function.SymbolName = Info.Name;
634       } else {
635         wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
636         if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
637           Info.Name = readString(Ctx);
638           Info.ImportName = Import.Field;
639         } else {
640           Info.Name = Import.Field;
641         }
642         Signature = &Signatures[Import.SigIndex];
643         Info.ImportModule = Import.Module;
644       }
645       break;
646 
647     case wasm::WASM_SYMBOL_TYPE_GLOBAL:
648       Info.ElementIndex = readVaruint32(Ctx);
649       if (!isValidGlobalIndex(Info.ElementIndex) ||
650           IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
651         return make_error<GenericBinaryError>("invalid global symbol index",
652                                               object_error::parse_failed);
653       if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
654                             wasm::WASM_SYMBOL_BINDING_WEAK)
655         return make_error<GenericBinaryError>("undefined weak global symbol",
656                                               object_error::parse_failed);
657       if (IsDefined) {
658         Info.Name = readString(Ctx);
659         unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
660         wasm::WasmGlobal &Global = Globals[GlobalIndex];
661         GlobalType = &Global.Type;
662         if (Global.SymbolName.empty())
663           Global.SymbolName = Info.Name;
664       } else {
665         wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
666         if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
667           Info.Name = readString(Ctx);
668           Info.ImportName = Import.Field;
669         } else {
670           Info.Name = Import.Field;
671         }
672         GlobalType = &Import.Global;
673         Info.ImportModule = Import.Module;
674       }
675       break;
676 
677     case wasm::WASM_SYMBOL_TYPE_TABLE:
678       Info.ElementIndex = readVaruint32(Ctx);
679       if (!isValidTableNumber(Info.ElementIndex) ||
680           IsDefined != isDefinedTableNumber(Info.ElementIndex))
681         return make_error<GenericBinaryError>("invalid table symbol index",
682                                               object_error::parse_failed);
683       if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
684                             wasm::WASM_SYMBOL_BINDING_WEAK)
685         return make_error<GenericBinaryError>("undefined weak table symbol",
686                                               object_error::parse_failed);
687       if (IsDefined) {
688         Info.Name = readString(Ctx);
689         unsigned TableNumber = Info.ElementIndex - NumImportedTables;
690         wasm::WasmTable &Table = Tables[TableNumber];
691         TableType = &Table.Type;
692         if (Table.SymbolName.empty())
693           Table.SymbolName = Info.Name;
694       } else {
695         wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];
696         if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
697           Info.Name = readString(Ctx);
698           Info.ImportName = Import.Field;
699         } else {
700           Info.Name = Import.Field;
701         }
702         TableType = &Import.Table;
703         Info.ImportModule = Import.Module;
704       }
705       break;
706 
707     case wasm::WASM_SYMBOL_TYPE_DATA:
708       Info.Name = readString(Ctx);
709       if (IsDefined) {
710         auto Index = readVaruint32(Ctx);
711         if (Index >= DataSegments.size())
712           return make_error<GenericBinaryError>("invalid data symbol index",
713                                                 object_error::parse_failed);
714         auto Offset = readVaruint64(Ctx);
715         auto Size = readVaruint64(Ctx);
716         size_t SegmentSize = DataSegments[Index].Data.Content.size();
717         if (Offset > SegmentSize)
718           return make_error<GenericBinaryError>(
719               "invalid data symbol offset: `" + Info.Name + "` (offset: " +
720                   Twine(Offset) + " segment size: " + Twine(SegmentSize) + ")",
721               object_error::parse_failed);
722         Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
723       }
724       break;
725 
726     case wasm::WASM_SYMBOL_TYPE_SECTION: {
727       if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
728           wasm::WASM_SYMBOL_BINDING_LOCAL)
729         return make_error<GenericBinaryError>(
730             "section symbols must have local binding",
731             object_error::parse_failed);
732       Info.ElementIndex = readVaruint32(Ctx);
733       // Use somewhat unique section name as symbol name.
734       StringRef SectionName = Sections[Info.ElementIndex].Name;
735       Info.Name = SectionName;
736       break;
737     }
738 
739     case wasm::WASM_SYMBOL_TYPE_TAG: {
740       Info.ElementIndex = readVaruint32(Ctx);
741       if (!isValidTagIndex(Info.ElementIndex) ||
742           IsDefined != isDefinedTagIndex(Info.ElementIndex))
743         return make_error<GenericBinaryError>("invalid tag symbol index",
744                                               object_error::parse_failed);
745       if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
746                             wasm::WASM_SYMBOL_BINDING_WEAK)
747         return make_error<GenericBinaryError>("undefined weak global symbol",
748                                               object_error::parse_failed);
749       if (IsDefined) {
750         Info.Name = readString(Ctx);
751         unsigned TagIndex = Info.ElementIndex - NumImportedTags;
752         wasm::WasmTag &Tag = Tags[TagIndex];
753         Signature = &Signatures[Tag.SigIndex];
754         if (Tag.SymbolName.empty())
755           Tag.SymbolName = Info.Name;
756 
757       } else {
758         wasm::WasmImport &Import = *ImportedTags[Info.ElementIndex];
759         if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
760           Info.Name = readString(Ctx);
761           Info.ImportName = Import.Field;
762         } else {
763           Info.Name = Import.Field;
764         }
765         Signature = &Signatures[Import.SigIndex];
766         Info.ImportModule = Import.Module;
767       }
768       break;
769     }
770 
771     default:
772       return make_error<GenericBinaryError>("invalid symbol type: " +
773                                                 Twine(unsigned(Info.Kind)),
774                                             object_error::parse_failed);
775     }
776 
777     if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
778             wasm::WASM_SYMBOL_BINDING_LOCAL &&
779         !SymbolNames.insert(Info.Name).second)
780       return make_error<GenericBinaryError>("duplicate symbol name " +
781                                                 Twine(Info.Name),
782                                             object_error::parse_failed);
783     LinkingData.SymbolTable.emplace_back(Info);
784     Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, TableType,
785                          Signature);
786     LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
787   }
788 
789   return Error::success();
790 }
791 
parseLinkingSectionComdat(ReadContext & Ctx)792 Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
793   uint32_t ComdatCount = readVaruint32(Ctx);
794   StringSet<> ComdatSet;
795   for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
796     StringRef Name = readString(Ctx);
797     if (Name.empty() || !ComdatSet.insert(Name).second)
798       return make_error<GenericBinaryError>("bad/duplicate COMDAT name " +
799                                                 Twine(Name),
800                                             object_error::parse_failed);
801     LinkingData.Comdats.emplace_back(Name);
802     uint32_t Flags = readVaruint32(Ctx);
803     if (Flags != 0)
804       return make_error<GenericBinaryError>("unsupported COMDAT flags",
805                                             object_error::parse_failed);
806 
807     uint32_t EntryCount = readVaruint32(Ctx);
808     while (EntryCount--) {
809       unsigned Kind = readVaruint32(Ctx);
810       unsigned Index = readVaruint32(Ctx);
811       switch (Kind) {
812       default:
813         return make_error<GenericBinaryError>("invalid COMDAT entry type",
814                                               object_error::parse_failed);
815       case wasm::WASM_COMDAT_DATA:
816         if (Index >= DataSegments.size())
817           return make_error<GenericBinaryError>(
818               "COMDAT data index out of range", object_error::parse_failed);
819         if (DataSegments[Index].Data.Comdat != UINT32_MAX)
820           return make_error<GenericBinaryError>("data segment in two COMDATs",
821                                                 object_error::parse_failed);
822         DataSegments[Index].Data.Comdat = ComdatIndex;
823         break;
824       case wasm::WASM_COMDAT_FUNCTION:
825         if (!isDefinedFunctionIndex(Index))
826           return make_error<GenericBinaryError>(
827               "COMDAT function index out of range", object_error::parse_failed);
828         if (getDefinedFunction(Index).Comdat != UINT32_MAX)
829           return make_error<GenericBinaryError>("function in two COMDATs",
830                                                 object_error::parse_failed);
831         getDefinedFunction(Index).Comdat = ComdatIndex;
832         break;
833       case wasm::WASM_COMDAT_SECTION:
834         if (Index >= Sections.size())
835           return make_error<GenericBinaryError>(
836               "COMDAT section index out of range", object_error::parse_failed);
837         if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)
838           return make_error<GenericBinaryError>(
839               "non-custom section in a COMDAT", object_error::parse_failed);
840         Sections[Index].Comdat = ComdatIndex;
841         break;
842       }
843     }
844   }
845   return Error::success();
846 }
847 
parseProducersSection(ReadContext & Ctx)848 Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
849   llvm::SmallSet<StringRef, 3> FieldsSeen;
850   uint32_t Fields = readVaruint32(Ctx);
851   for (size_t I = 0; I < Fields; ++I) {
852     StringRef FieldName = readString(Ctx);
853     if (!FieldsSeen.insert(FieldName).second)
854       return make_error<GenericBinaryError>(
855           "producers section does not have unique fields",
856           object_error::parse_failed);
857     std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
858     if (FieldName == "language") {
859       ProducerVec = &ProducerInfo.Languages;
860     } else if (FieldName == "processed-by") {
861       ProducerVec = &ProducerInfo.Tools;
862     } else if (FieldName == "sdk") {
863       ProducerVec = &ProducerInfo.SDKs;
864     } else {
865       return make_error<GenericBinaryError>(
866           "producers section field is not named one of language, processed-by, "
867           "or sdk",
868           object_error::parse_failed);
869     }
870     uint32_t ValueCount = readVaruint32(Ctx);
871     llvm::SmallSet<StringRef, 8> ProducersSeen;
872     for (size_t J = 0; J < ValueCount; ++J) {
873       StringRef Name = readString(Ctx);
874       StringRef Version = readString(Ctx);
875       if (!ProducersSeen.insert(Name).second) {
876         return make_error<GenericBinaryError>(
877             "producers section contains repeated producer",
878             object_error::parse_failed);
879       }
880       ProducerVec->emplace_back(std::string(Name), std::string(Version));
881     }
882   }
883   if (Ctx.Ptr != Ctx.End)
884     return make_error<GenericBinaryError>("producers section ended prematurely",
885                                           object_error::parse_failed);
886   return Error::success();
887 }
888 
parseTargetFeaturesSection(ReadContext & Ctx)889 Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
890   llvm::SmallSet<std::string, 8> FeaturesSeen;
891   uint32_t FeatureCount = readVaruint32(Ctx);
892   for (size_t I = 0; I < FeatureCount; ++I) {
893     wasm::WasmFeatureEntry Feature;
894     Feature.Prefix = readUint8(Ctx);
895     switch (Feature.Prefix) {
896     case wasm::WASM_FEATURE_PREFIX_USED:
897     case wasm::WASM_FEATURE_PREFIX_REQUIRED:
898     case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
899       break;
900     default:
901       return make_error<GenericBinaryError>("unknown feature policy prefix",
902                                             object_error::parse_failed);
903     }
904     Feature.Name = std::string(readString(Ctx));
905     if (!FeaturesSeen.insert(Feature.Name).second)
906       return make_error<GenericBinaryError>(
907           "target features section contains repeated feature \"" +
908               Feature.Name + "\"",
909           object_error::parse_failed);
910     TargetFeatures.push_back(Feature);
911   }
912   if (Ctx.Ptr != Ctx.End)
913     return make_error<GenericBinaryError>(
914         "target features section ended prematurely",
915         object_error::parse_failed);
916   return Error::success();
917 }
918 
parseRelocSection(StringRef Name,ReadContext & Ctx)919 Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
920   uint32_t SectionIndex = readVaruint32(Ctx);
921   if (SectionIndex >= Sections.size())
922     return make_error<GenericBinaryError>("invalid section index",
923                                           object_error::parse_failed);
924   WasmSection &Section = Sections[SectionIndex];
925   uint32_t RelocCount = readVaruint32(Ctx);
926   uint32_t EndOffset = Section.Content.size();
927   uint32_t PreviousOffset = 0;
928   while (RelocCount--) {
929     wasm::WasmRelocation Reloc = {};
930     uint32_t type = readVaruint32(Ctx);
931     Reloc.Type = type;
932     Reloc.Offset = readVaruint32(Ctx);
933     if (Reloc.Offset < PreviousOffset)
934       return make_error<GenericBinaryError>("relocations not in offset order",
935                                             object_error::parse_failed);
936     PreviousOffset = Reloc.Offset;
937     Reloc.Index = readVaruint32(Ctx);
938     switch (type) {
939     case wasm::R_WASM_FUNCTION_INDEX_LEB:
940     case wasm::R_WASM_TABLE_INDEX_SLEB:
941     case wasm::R_WASM_TABLE_INDEX_SLEB64:
942     case wasm::R_WASM_TABLE_INDEX_I32:
943     case wasm::R_WASM_TABLE_INDEX_I64:
944     case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
945     case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
946       if (!isValidFunctionSymbol(Reloc.Index))
947         return make_error<GenericBinaryError>(
948             "invalid relocation function index", object_error::parse_failed);
949       break;
950     case wasm::R_WASM_TABLE_NUMBER_LEB:
951       if (!isValidTableSymbol(Reloc.Index))
952         return make_error<GenericBinaryError>("invalid relocation table index",
953                                               object_error::parse_failed);
954       break;
955     case wasm::R_WASM_TYPE_INDEX_LEB:
956       if (Reloc.Index >= Signatures.size())
957         return make_error<GenericBinaryError>("invalid relocation type index",
958                                               object_error::parse_failed);
959       break;
960     case wasm::R_WASM_GLOBAL_INDEX_LEB:
961       // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
962       // symbols to refer to their GOT entries.
963       if (!isValidGlobalSymbol(Reloc.Index) &&
964           !isValidDataSymbol(Reloc.Index) &&
965           !isValidFunctionSymbol(Reloc.Index))
966         return make_error<GenericBinaryError>("invalid relocation global index",
967                                               object_error::parse_failed);
968       break;
969     case wasm::R_WASM_GLOBAL_INDEX_I32:
970       if (!isValidGlobalSymbol(Reloc.Index))
971         return make_error<GenericBinaryError>("invalid relocation global index",
972                                               object_error::parse_failed);
973       break;
974     case wasm::R_WASM_TAG_INDEX_LEB:
975       if (!isValidTagSymbol(Reloc.Index))
976         return make_error<GenericBinaryError>("invalid relocation tag index",
977                                               object_error::parse_failed);
978       break;
979     case wasm::R_WASM_MEMORY_ADDR_LEB:
980     case wasm::R_WASM_MEMORY_ADDR_SLEB:
981     case wasm::R_WASM_MEMORY_ADDR_I32:
982     case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
983     case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
984     case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
985       if (!isValidDataSymbol(Reloc.Index))
986         return make_error<GenericBinaryError>("invalid relocation data index",
987                                               object_error::parse_failed);
988       Reloc.Addend = readVarint32(Ctx);
989       break;
990     case wasm::R_WASM_MEMORY_ADDR_LEB64:
991     case wasm::R_WASM_MEMORY_ADDR_SLEB64:
992     case wasm::R_WASM_MEMORY_ADDR_I64:
993     case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
994     case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
995       if (!isValidDataSymbol(Reloc.Index))
996         return make_error<GenericBinaryError>("invalid relocation data index",
997                                               object_error::parse_failed);
998       Reloc.Addend = readVarint64(Ctx);
999       break;
1000     case wasm::R_WASM_FUNCTION_OFFSET_I32:
1001       if (!isValidFunctionSymbol(Reloc.Index))
1002         return make_error<GenericBinaryError>(
1003             "invalid relocation function index", object_error::parse_failed);
1004       Reloc.Addend = readVarint32(Ctx);
1005       break;
1006     case wasm::R_WASM_FUNCTION_OFFSET_I64:
1007       if (!isValidFunctionSymbol(Reloc.Index))
1008         return make_error<GenericBinaryError>(
1009             "invalid relocation function index", object_error::parse_failed);
1010       Reloc.Addend = readVarint64(Ctx);
1011       break;
1012     case wasm::R_WASM_SECTION_OFFSET_I32:
1013       if (!isValidSectionSymbol(Reloc.Index))
1014         return make_error<GenericBinaryError>(
1015             "invalid relocation section index", object_error::parse_failed);
1016       Reloc.Addend = readVarint32(Ctx);
1017       break;
1018     default:
1019       return make_error<GenericBinaryError>("invalid relocation type: " +
1020                                                 Twine(type),
1021                                             object_error::parse_failed);
1022     }
1023 
1024     // Relocations must fit inside the section, and must appear in order.  They
1025     // also shouldn't overlap a function/element boundary, but we don't bother
1026     // to check that.
1027     uint64_t Size = 5;
1028     if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
1029         Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
1030         Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
1031       Size = 10;
1032     if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
1033         Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
1034         Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
1035         Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
1036         Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
1037         Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
1038       Size = 4;
1039     if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
1040         Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
1041         Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)
1042       Size = 8;
1043     if (Reloc.Offset + Size > EndOffset)
1044       return make_error<GenericBinaryError>("invalid relocation offset",
1045                                             object_error::parse_failed);
1046 
1047     Section.Relocations.push_back(Reloc);
1048   }
1049   if (Ctx.Ptr != Ctx.End)
1050     return make_error<GenericBinaryError>("reloc section ended prematurely",
1051                                           object_error::parse_failed);
1052   return Error::success();
1053 }
1054 
parseCustomSection(WasmSection & Sec,ReadContext & Ctx)1055 Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
1056   if (Sec.Name == "dylink") {
1057     if (Error Err = parseDylinkSection(Ctx))
1058       return Err;
1059   } else if (Sec.Name == "dylink.0") {
1060     if (Error Err = parseDylink0Section(Ctx))
1061       return Err;
1062   } else if (Sec.Name == "name") {
1063     if (Error Err = parseNameSection(Ctx))
1064       return Err;
1065   } else if (Sec.Name == "linking") {
1066     if (Error Err = parseLinkingSection(Ctx))
1067       return Err;
1068   } else if (Sec.Name == "producers") {
1069     if (Error Err = parseProducersSection(Ctx))
1070       return Err;
1071   } else if (Sec.Name == "target_features") {
1072     if (Error Err = parseTargetFeaturesSection(Ctx))
1073       return Err;
1074   } else if (Sec.Name.startswith("reloc.")) {
1075     if (Error Err = parseRelocSection(Sec.Name, Ctx))
1076       return Err;
1077   }
1078   return Error::success();
1079 }
1080 
parseTypeSection(ReadContext & Ctx)1081 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
1082   uint32_t Count = readVaruint32(Ctx);
1083   Signatures.reserve(Count);
1084   while (Count--) {
1085     wasm::WasmSignature Sig;
1086     uint8_t Form = readUint8(Ctx);
1087     if (Form != wasm::WASM_TYPE_FUNC) {
1088       return make_error<GenericBinaryError>("invalid signature type",
1089                                             object_error::parse_failed);
1090     }
1091     uint32_t ParamCount = readVaruint32(Ctx);
1092     Sig.Params.reserve(ParamCount);
1093     while (ParamCount--) {
1094       uint32_t ParamType = readUint8(Ctx);
1095       Sig.Params.push_back(wasm::ValType(ParamType));
1096     }
1097     uint32_t ReturnCount = readVaruint32(Ctx);
1098     while (ReturnCount--) {
1099       uint32_t ReturnType = readUint8(Ctx);
1100       Sig.Returns.push_back(wasm::ValType(ReturnType));
1101     }
1102     Signatures.push_back(std::move(Sig));
1103   }
1104   if (Ctx.Ptr != Ctx.End)
1105     return make_error<GenericBinaryError>("type section ended prematurely",
1106                                           object_error::parse_failed);
1107   return Error::success();
1108 }
1109 
parseImportSection(ReadContext & Ctx)1110 Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
1111   uint32_t Count = readVaruint32(Ctx);
1112   uint32_t NumTypes = Signatures.size();
1113   Imports.reserve(Count);
1114   for (uint32_t I = 0; I < Count; I++) {
1115     wasm::WasmImport Im;
1116     Im.Module = readString(Ctx);
1117     Im.Field = readString(Ctx);
1118     Im.Kind = readUint8(Ctx);
1119     switch (Im.Kind) {
1120     case wasm::WASM_EXTERNAL_FUNCTION:
1121       NumImportedFunctions++;
1122       Im.SigIndex = readVaruint32(Ctx);
1123       if (Im.SigIndex >= NumTypes)
1124         return make_error<GenericBinaryError>("invalid function type",
1125                                               object_error::parse_failed);
1126       break;
1127     case wasm::WASM_EXTERNAL_GLOBAL:
1128       NumImportedGlobals++;
1129       Im.Global.Type = readUint8(Ctx);
1130       Im.Global.Mutable = readVaruint1(Ctx);
1131       break;
1132     case wasm::WASM_EXTERNAL_MEMORY:
1133       Im.Memory = readLimits(Ctx);
1134       if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1135         HasMemory64 = true;
1136       break;
1137     case wasm::WASM_EXTERNAL_TABLE: {
1138       Im.Table = readTableType(Ctx);
1139       NumImportedTables++;
1140       auto ElemType = Im.Table.ElemType;
1141       if (ElemType != wasm::WASM_TYPE_FUNCREF &&
1142           ElemType != wasm::WASM_TYPE_EXTERNREF)
1143         return make_error<GenericBinaryError>("invalid table element type",
1144                                               object_error::parse_failed);
1145       break;
1146     }
1147     case wasm::WASM_EXTERNAL_TAG:
1148       NumImportedTags++;
1149       if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1150         return make_error<GenericBinaryError>("invalid attribute",
1151                                               object_error::parse_failed);
1152       Im.SigIndex = readVaruint32(Ctx);
1153       if (Im.SigIndex >= NumTypes)
1154         return make_error<GenericBinaryError>("invalid tag type",
1155                                               object_error::parse_failed);
1156       break;
1157     default:
1158       return make_error<GenericBinaryError>("unexpected import kind",
1159                                             object_error::parse_failed);
1160     }
1161     Imports.push_back(Im);
1162   }
1163   if (Ctx.Ptr != Ctx.End)
1164     return make_error<GenericBinaryError>("import section ended prematurely",
1165                                           object_error::parse_failed);
1166   return Error::success();
1167 }
1168 
parseFunctionSection(ReadContext & Ctx)1169 Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
1170   uint32_t Count = readVaruint32(Ctx);
1171   Functions.reserve(Count);
1172   uint32_t NumTypes = Signatures.size();
1173   while (Count--) {
1174     uint32_t Type = readVaruint32(Ctx);
1175     if (Type >= NumTypes)
1176       return make_error<GenericBinaryError>("invalid function type",
1177                                             object_error::parse_failed);
1178     wasm::WasmFunction F;
1179     F.SigIndex = Type;
1180     Functions.push_back(F);
1181   }
1182   if (Ctx.Ptr != Ctx.End)
1183     return make_error<GenericBinaryError>("function section ended prematurely",
1184                                           object_error::parse_failed);
1185   return Error::success();
1186 }
1187 
parseTableSection(ReadContext & Ctx)1188 Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1189   TableSection = Sections.size();
1190   uint32_t Count = readVaruint32(Ctx);
1191   Tables.reserve(Count);
1192   while (Count--) {
1193     wasm::WasmTable T;
1194     T.Type = readTableType(Ctx);
1195     T.Index = NumImportedTables + Tables.size();
1196     Tables.push_back(T);
1197     auto ElemType = Tables.back().Type.ElemType;
1198     if (ElemType != wasm::WASM_TYPE_FUNCREF &&
1199         ElemType != wasm::WASM_TYPE_EXTERNREF) {
1200       return make_error<GenericBinaryError>("invalid table element type",
1201                                             object_error::parse_failed);
1202     }
1203   }
1204   if (Ctx.Ptr != Ctx.End)
1205     return make_error<GenericBinaryError>("table section ended prematurely",
1206                                           object_error::parse_failed);
1207   return Error::success();
1208 }
1209 
parseMemorySection(ReadContext & Ctx)1210 Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1211   uint32_t Count = readVaruint32(Ctx);
1212   Memories.reserve(Count);
1213   while (Count--) {
1214     auto Limits = readLimits(Ctx);
1215     if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1216       HasMemory64 = true;
1217     Memories.push_back(Limits);
1218   }
1219   if (Ctx.Ptr != Ctx.End)
1220     return make_error<GenericBinaryError>("memory section ended prematurely",
1221                                           object_error::parse_failed);
1222   return Error::success();
1223 }
1224 
parseTagSection(ReadContext & Ctx)1225 Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
1226   TagSection = Sections.size();
1227   uint32_t Count = readVaruint32(Ctx);
1228   Tags.reserve(Count);
1229   uint32_t NumTypes = Signatures.size();
1230   while (Count--) {
1231     if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1232       return make_error<GenericBinaryError>("invalid attribute",
1233                                             object_error::parse_failed);
1234     uint32_t Type = readVaruint32(Ctx);
1235     if (Type >= NumTypes)
1236       return make_error<GenericBinaryError>("invalid tag type",
1237                                             object_error::parse_failed);
1238     wasm::WasmTag Tag;
1239     Tag.Index = NumImportedTags + Tags.size();
1240     Tag.SigIndex = Type;
1241     Tags.push_back(Tag);
1242   }
1243 
1244   if (Ctx.Ptr != Ctx.End)
1245     return make_error<GenericBinaryError>("tag section ended prematurely",
1246                                           object_error::parse_failed);
1247   return Error::success();
1248 }
1249 
parseGlobalSection(ReadContext & Ctx)1250 Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1251   GlobalSection = Sections.size();
1252   uint32_t Count = readVaruint32(Ctx);
1253   Globals.reserve(Count);
1254   while (Count--) {
1255     wasm::WasmGlobal Global;
1256     Global.Index = NumImportedGlobals + Globals.size();
1257     Global.Type.Type = readUint8(Ctx);
1258     Global.Type.Mutable = readVaruint1(Ctx);
1259     if (Error Err = readInitExpr(Global.InitExpr, Ctx))
1260       return Err;
1261     Globals.push_back(Global);
1262   }
1263   if (Ctx.Ptr != Ctx.End)
1264     return make_error<GenericBinaryError>("global section ended prematurely",
1265                                           object_error::parse_failed);
1266   return Error::success();
1267 }
1268 
parseExportSection(ReadContext & Ctx)1269 Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1270   uint32_t Count = readVaruint32(Ctx);
1271   Exports.reserve(Count);
1272   for (uint32_t I = 0; I < Count; I++) {
1273     wasm::WasmExport Ex;
1274     Ex.Name = readString(Ctx);
1275     Ex.Kind = readUint8(Ctx);
1276     Ex.Index = readVaruint32(Ctx);
1277     switch (Ex.Kind) {
1278     case wasm::WASM_EXTERNAL_FUNCTION:
1279 
1280       if (!isDefinedFunctionIndex(Ex.Index))
1281         return make_error<GenericBinaryError>("invalid function export",
1282                                               object_error::parse_failed);
1283       getDefinedFunction(Ex.Index).ExportName = Ex.Name;
1284       break;
1285     case wasm::WASM_EXTERNAL_GLOBAL:
1286       if (!isValidGlobalIndex(Ex.Index))
1287         return make_error<GenericBinaryError>("invalid global export",
1288                                               object_error::parse_failed);
1289       break;
1290     case wasm::WASM_EXTERNAL_TAG:
1291       if (!isValidTagIndex(Ex.Index))
1292         return make_error<GenericBinaryError>("invalid tag export",
1293                                               object_error::parse_failed);
1294       break;
1295     case wasm::WASM_EXTERNAL_MEMORY:
1296     case wasm::WASM_EXTERNAL_TABLE:
1297       break;
1298     default:
1299       return make_error<GenericBinaryError>("unexpected export kind",
1300                                             object_error::parse_failed);
1301     }
1302     Exports.push_back(Ex);
1303   }
1304   if (Ctx.Ptr != Ctx.End)
1305     return make_error<GenericBinaryError>("export section ended prematurely",
1306                                           object_error::parse_failed);
1307   return Error::success();
1308 }
1309 
isValidFunctionIndex(uint32_t Index) const1310 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1311   return Index < NumImportedFunctions + Functions.size();
1312 }
1313 
isDefinedFunctionIndex(uint32_t Index) const1314 bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1315   return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1316 }
1317 
isValidGlobalIndex(uint32_t Index) const1318 bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1319   return Index < NumImportedGlobals + Globals.size();
1320 }
1321 
isValidTableNumber(uint32_t Index) const1322 bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
1323   return Index < NumImportedTables + Tables.size();
1324 }
1325 
isDefinedGlobalIndex(uint32_t Index) const1326 bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1327   return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1328 }
1329 
isDefinedTableNumber(uint32_t Index) const1330 bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
1331   return Index >= NumImportedTables && isValidTableNumber(Index);
1332 }
1333 
isValidTagIndex(uint32_t Index) const1334 bool WasmObjectFile::isValidTagIndex(uint32_t Index) const {
1335   return Index < NumImportedTags + Tags.size();
1336 }
1337 
isDefinedTagIndex(uint32_t Index) const1338 bool WasmObjectFile::isDefinedTagIndex(uint32_t Index) const {
1339   return Index >= NumImportedTags && isValidTagIndex(Index);
1340 }
1341 
isValidFunctionSymbol(uint32_t Index) const1342 bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1343   return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1344 }
1345 
isValidTableSymbol(uint32_t Index) const1346 bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
1347   return Index < Symbols.size() && Symbols[Index].isTypeTable();
1348 }
1349 
isValidGlobalSymbol(uint32_t Index) const1350 bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1351   return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1352 }
1353 
isValidTagSymbol(uint32_t Index) const1354 bool WasmObjectFile::isValidTagSymbol(uint32_t Index) const {
1355   return Index < Symbols.size() && Symbols[Index].isTypeTag();
1356 }
1357 
isValidDataSymbol(uint32_t Index) const1358 bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1359   return Index < Symbols.size() && Symbols[Index].isTypeData();
1360 }
1361 
isValidSectionSymbol(uint32_t Index) const1362 bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1363   return Index < Symbols.size() && Symbols[Index].isTypeSection();
1364 }
1365 
getDefinedFunction(uint32_t Index)1366 wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1367   assert(isDefinedFunctionIndex(Index));
1368   return Functions[Index - NumImportedFunctions];
1369 }
1370 
1371 const wasm::WasmFunction &
getDefinedFunction(uint32_t Index) const1372 WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1373   assert(isDefinedFunctionIndex(Index));
1374   return Functions[Index - NumImportedFunctions];
1375 }
1376 
getDefinedGlobal(uint32_t Index)1377 wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
1378   assert(isDefinedGlobalIndex(Index));
1379   return Globals[Index - NumImportedGlobals];
1380 }
1381 
getDefinedTag(uint32_t Index)1382 wasm::WasmTag &WasmObjectFile::getDefinedTag(uint32_t Index) {
1383   assert(isDefinedTagIndex(Index));
1384   return Tags[Index - NumImportedTags];
1385 }
1386 
parseStartSection(ReadContext & Ctx)1387 Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1388   StartFunction = readVaruint32(Ctx);
1389   if (!isValidFunctionIndex(StartFunction))
1390     return make_error<GenericBinaryError>("invalid start function",
1391                                           object_error::parse_failed);
1392   return Error::success();
1393 }
1394 
parseCodeSection(ReadContext & Ctx)1395 Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1396   CodeSection = Sections.size();
1397   uint32_t FunctionCount = readVaruint32(Ctx);
1398   if (FunctionCount != Functions.size()) {
1399     return make_error<GenericBinaryError>("invalid function count",
1400                                           object_error::parse_failed);
1401   }
1402 
1403   for (uint32_t i = 0; i < FunctionCount; i++) {
1404     wasm::WasmFunction& Function = Functions[i];
1405     const uint8_t *FunctionStart = Ctx.Ptr;
1406     uint32_t Size = readVaruint32(Ctx);
1407     const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1408 
1409     Function.CodeOffset = Ctx.Ptr - FunctionStart;
1410     Function.Index = NumImportedFunctions + i;
1411     Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1412     Function.Size = FunctionEnd - FunctionStart;
1413 
1414     uint32_t NumLocalDecls = readVaruint32(Ctx);
1415     Function.Locals.reserve(NumLocalDecls);
1416     while (NumLocalDecls--) {
1417       wasm::WasmLocalDecl Decl;
1418       Decl.Count = readVaruint32(Ctx);
1419       Decl.Type = readUint8(Ctx);
1420       Function.Locals.push_back(Decl);
1421     }
1422 
1423     uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1424     Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1425     // This will be set later when reading in the linking metadata section.
1426     Function.Comdat = UINT32_MAX;
1427     Ctx.Ptr += BodySize;
1428     assert(Ctx.Ptr == FunctionEnd);
1429   }
1430   if (Ctx.Ptr != Ctx.End)
1431     return make_error<GenericBinaryError>("code section ended prematurely",
1432                                           object_error::parse_failed);
1433   return Error::success();
1434 }
1435 
parseElemSection(ReadContext & Ctx)1436 Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1437   uint32_t Count = readVaruint32(Ctx);
1438   ElemSegments.reserve(Count);
1439   while (Count--) {
1440     wasm::WasmElemSegment Segment;
1441     Segment.Flags = readVaruint32(Ctx);
1442 
1443     uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
1444                               wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
1445                               wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
1446     if (Segment.Flags & ~SupportedFlags)
1447       return make_error<GenericBinaryError>(
1448           "Unsupported flags for element segment", object_error::parse_failed);
1449 
1450     if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
1451       Segment.TableNumber = readVaruint32(Ctx);
1452     else
1453       Segment.TableNumber = 0;
1454     if (!isValidTableNumber(Segment.TableNumber))
1455       return make_error<GenericBinaryError>("invalid TableNumber",
1456                                             object_error::parse_failed);
1457 
1458     if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
1459       Segment.Offset.Extended = false;
1460       Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1461       Segment.Offset.Inst.Value.Int32 = 0;
1462     } else {
1463       if (Error Err = readInitExpr(Segment.Offset, Ctx))
1464         return Err;
1465     }
1466 
1467     if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
1468       Segment.ElemKind = readUint8(Ctx);
1469       if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
1470         if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
1471             Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF)) {
1472           return make_error<GenericBinaryError>("invalid reference type",
1473                                                 object_error::parse_failed);
1474         }
1475       } else {
1476         if (Segment.ElemKind != 0)
1477           return make_error<GenericBinaryError>("invalid elemtype",
1478                                                 object_error::parse_failed);
1479         Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
1480       }
1481     } else {
1482       Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
1483     }
1484 
1485     if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS)
1486       return make_error<GenericBinaryError>(
1487           "elem segment init expressions not yet implemented",
1488           object_error::parse_failed);
1489 
1490     uint32_t NumElems = readVaruint32(Ctx);
1491     while (NumElems--) {
1492       Segment.Functions.push_back(readVaruint32(Ctx));
1493     }
1494     ElemSegments.push_back(Segment);
1495   }
1496   if (Ctx.Ptr != Ctx.End)
1497     return make_error<GenericBinaryError>("elem section ended prematurely",
1498                                           object_error::parse_failed);
1499   return Error::success();
1500 }
1501 
parseDataSection(ReadContext & Ctx)1502 Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1503   DataSection = Sections.size();
1504   uint32_t Count = readVaruint32(Ctx);
1505   if (DataCount && Count != *DataCount)
1506     return make_error<GenericBinaryError>(
1507         "number of data segments does not match DataCount section");
1508   DataSegments.reserve(Count);
1509   while (Count--) {
1510     WasmSegment Segment;
1511     Segment.Data.InitFlags = readVaruint32(Ctx);
1512     Segment.Data.MemoryIndex =
1513         (Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1514             ? readVaruint32(Ctx)
1515             : 0;
1516     if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1517       if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
1518         return Err;
1519     } else {
1520       Segment.Data.Offset.Extended = false;
1521       Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1522       Segment.Data.Offset.Inst.Value.Int32 = 0;
1523     }
1524     uint32_t Size = readVaruint32(Ctx);
1525     if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1526       return make_error<GenericBinaryError>("invalid segment size",
1527                                             object_error::parse_failed);
1528     Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1529     // The rest of these Data fields are set later, when reading in the linking
1530     // metadata section.
1531     Segment.Data.Alignment = 0;
1532     Segment.Data.LinkingFlags = 0;
1533     Segment.Data.Comdat = UINT32_MAX;
1534     Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1535     Ctx.Ptr += Size;
1536     DataSegments.push_back(Segment);
1537   }
1538   if (Ctx.Ptr != Ctx.End)
1539     return make_error<GenericBinaryError>("data section ended prematurely",
1540                                           object_error::parse_failed);
1541   return Error::success();
1542 }
1543 
parseDataCountSection(ReadContext & Ctx)1544 Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1545   DataCount = readVaruint32(Ctx);
1546   return Error::success();
1547 }
1548 
getHeader() const1549 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1550   return Header;
1551 }
1552 
moveSymbolNext(DataRefImpl & Symb) const1553 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1554 
getSymbolFlags(DataRefImpl Symb) const1555 Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1556   uint32_t Result = SymbolRef::SF_None;
1557   const WasmSymbol &Sym = getWasmSymbol(Symb);
1558 
1559   LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1560   if (Sym.isBindingWeak())
1561     Result |= SymbolRef::SF_Weak;
1562   if (!Sym.isBindingLocal())
1563     Result |= SymbolRef::SF_Global;
1564   if (Sym.isHidden())
1565     Result |= SymbolRef::SF_Hidden;
1566   if (!Sym.isDefined())
1567     Result |= SymbolRef::SF_Undefined;
1568   if (Sym.isTypeFunction())
1569     Result |= SymbolRef::SF_Executable;
1570   return Result;
1571 }
1572 
symbol_begin() const1573 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1574   DataRefImpl Ref;
1575   Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1576   Ref.d.b = 0; // Symbol index
1577   return BasicSymbolRef(Ref, this);
1578 }
1579 
symbol_end() const1580 basic_symbol_iterator WasmObjectFile::symbol_end() const {
1581   DataRefImpl Ref;
1582   Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1583   Ref.d.b = Symbols.size(); // Symbol index
1584   return BasicSymbolRef(Ref, this);
1585 }
1586 
getWasmSymbol(const DataRefImpl & Symb) const1587 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1588   return Symbols[Symb.d.b];
1589 }
1590 
getWasmSymbol(const SymbolRef & Symb) const1591 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1592   return getWasmSymbol(Symb.getRawDataRefImpl());
1593 }
1594 
getSymbolName(DataRefImpl Symb) const1595 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1596   return getWasmSymbol(Symb).Info.Name;
1597 }
1598 
getSymbolAddress(DataRefImpl Symb) const1599 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1600   auto &Sym = getWasmSymbol(Symb);
1601   if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1602       isDefinedFunctionIndex(Sym.Info.ElementIndex))
1603     return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
1604   else
1605     return getSymbolValue(Symb);
1606 }
1607 
getWasmSymbolValue(const WasmSymbol & Sym) const1608 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1609   switch (Sym.Info.Kind) {
1610   case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1611   case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1612   case wasm::WASM_SYMBOL_TYPE_TAG:
1613   case wasm::WASM_SYMBOL_TYPE_TABLE:
1614     return Sym.Info.ElementIndex;
1615   case wasm::WASM_SYMBOL_TYPE_DATA: {
1616     // The value of a data symbol is the segment offset, plus the symbol
1617     // offset within the segment.
1618     uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1619     const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1620     if (Segment.Offset.Extended) {
1621       llvm_unreachable("extended init exprs not supported");
1622     } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1623       return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;
1624     } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1625       return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;
1626     } else {
1627       llvm_unreachable("unknown init expr opcode");
1628     }
1629   }
1630   case wasm::WASM_SYMBOL_TYPE_SECTION:
1631     return 0;
1632   }
1633   llvm_unreachable("invalid symbol type");
1634 }
1635 
getSymbolValueImpl(DataRefImpl Symb) const1636 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1637   return getWasmSymbolValue(getWasmSymbol(Symb));
1638 }
1639 
getSymbolAlignment(DataRefImpl Symb) const1640 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1641   llvm_unreachable("not yet implemented");
1642   return 0;
1643 }
1644 
getCommonSymbolSizeImpl(DataRefImpl Symb) const1645 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1646   llvm_unreachable("not yet implemented");
1647   return 0;
1648 }
1649 
1650 Expected<SymbolRef::Type>
getSymbolType(DataRefImpl Symb) const1651 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1652   const WasmSymbol &Sym = getWasmSymbol(Symb);
1653 
1654   switch (Sym.Info.Kind) {
1655   case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1656     return SymbolRef::ST_Function;
1657   case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1658     return SymbolRef::ST_Other;
1659   case wasm::WASM_SYMBOL_TYPE_DATA:
1660     return SymbolRef::ST_Data;
1661   case wasm::WASM_SYMBOL_TYPE_SECTION:
1662     return SymbolRef::ST_Debug;
1663   case wasm::WASM_SYMBOL_TYPE_TAG:
1664     return SymbolRef::ST_Other;
1665   case wasm::WASM_SYMBOL_TYPE_TABLE:
1666     return SymbolRef::ST_Other;
1667   }
1668 
1669   llvm_unreachable("unknown WasmSymbol::SymbolType");
1670   return SymbolRef::ST_Other;
1671 }
1672 
1673 Expected<section_iterator>
getSymbolSection(DataRefImpl Symb) const1674 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1675   const WasmSymbol &Sym = getWasmSymbol(Symb);
1676   if (Sym.isUndefined())
1677     return section_end();
1678 
1679   DataRefImpl Ref;
1680   Ref.d.a = getSymbolSectionIdImpl(Sym);
1681   return section_iterator(SectionRef(Ref, this));
1682 }
1683 
getSymbolSectionId(SymbolRef Symb) const1684 uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
1685   const WasmSymbol &Sym = getWasmSymbol(Symb);
1686   return getSymbolSectionIdImpl(Sym);
1687 }
1688 
getSymbolSectionIdImpl(const WasmSymbol & Sym) const1689 uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
1690   switch (Sym.Info.Kind) {
1691   case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1692     return CodeSection;
1693   case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1694     return GlobalSection;
1695   case wasm::WASM_SYMBOL_TYPE_DATA:
1696     return DataSection;
1697   case wasm::WASM_SYMBOL_TYPE_SECTION:
1698     return Sym.Info.ElementIndex;
1699   case wasm::WASM_SYMBOL_TYPE_TAG:
1700     return TagSection;
1701   case wasm::WASM_SYMBOL_TYPE_TABLE:
1702     return TableSection;
1703   default:
1704     llvm_unreachable("unknown WasmSymbol::SymbolType");
1705   }
1706 }
1707 
moveSectionNext(DataRefImpl & Sec) const1708 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1709 
getSectionName(DataRefImpl Sec) const1710 Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
1711   const WasmSection &S = Sections[Sec.d.a];
1712   if (S.Type == wasm::WASM_SEC_CUSTOM)
1713     return S.Name;
1714   if (S.Type > wasm::WASM_SEC_LAST_KNOWN)
1715     return createStringError(object_error::invalid_section_index, "");
1716   return wasm::sectionTypeToString(S.Type);
1717 }
1718 
getSectionAddress(DataRefImpl Sec) const1719 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
1720 
getSectionIndex(DataRefImpl Sec) const1721 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1722   return Sec.d.a;
1723 }
1724 
getSectionSize(DataRefImpl Sec) const1725 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1726   const WasmSection &S = Sections[Sec.d.a];
1727   return S.Content.size();
1728 }
1729 
1730 Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Sec) const1731 WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
1732   const WasmSection &S = Sections[Sec.d.a];
1733   // This will never fail since wasm sections can never be empty (user-sections
1734   // must have a name and non-user sections each have a defined structure).
1735   return S.Content;
1736 }
1737 
getSectionAlignment(DataRefImpl Sec) const1738 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1739   return 1;
1740 }
1741 
isSectionCompressed(DataRefImpl Sec) const1742 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1743   return false;
1744 }
1745 
isSectionText(DataRefImpl Sec) const1746 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
1747   return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
1748 }
1749 
isSectionData(DataRefImpl Sec) const1750 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
1751   return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
1752 }
1753 
isSectionBSS(DataRefImpl Sec) const1754 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
1755 
isSectionVirtual(DataRefImpl Sec) const1756 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
1757 
section_rel_begin(DataRefImpl Ref) const1758 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
1759   DataRefImpl RelocRef;
1760   RelocRef.d.a = Ref.d.a;
1761   RelocRef.d.b = 0;
1762   return relocation_iterator(RelocationRef(RelocRef, this));
1763 }
1764 
section_rel_end(DataRefImpl Ref) const1765 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
1766   const WasmSection &Sec = getWasmSection(Ref);
1767   DataRefImpl RelocRef;
1768   RelocRef.d.a = Ref.d.a;
1769   RelocRef.d.b = Sec.Relocations.size();
1770   return relocation_iterator(RelocationRef(RelocRef, this));
1771 }
1772 
moveRelocationNext(DataRefImpl & Rel) const1773 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
1774 
getRelocationOffset(DataRefImpl Ref) const1775 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
1776   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1777   return Rel.Offset;
1778 }
1779 
getRelocationSymbol(DataRefImpl Ref) const1780 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
1781   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1782   if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
1783     return symbol_end();
1784   DataRefImpl Sym;
1785   Sym.d.a = 1;
1786   Sym.d.b = Rel.Index;
1787   return symbol_iterator(SymbolRef(Sym, this));
1788 }
1789 
getRelocationType(DataRefImpl Ref) const1790 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1791   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1792   return Rel.Type;
1793 }
1794 
getRelocationTypeName(DataRefImpl Ref,SmallVectorImpl<char> & Result) const1795 void WasmObjectFile::getRelocationTypeName(
1796     DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1797   const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1798   StringRef Res = "Unknown";
1799 
1800 #define WASM_RELOC(name, value)                                                \
1801   case wasm::name:                                                             \
1802     Res = #name;                                                               \
1803     break;
1804 
1805   switch (Rel.Type) {
1806 #include "llvm/BinaryFormat/WasmRelocs.def"
1807   }
1808 
1809 #undef WASM_RELOC
1810 
1811   Result.append(Res.begin(), Res.end());
1812 }
1813 
section_begin() const1814 section_iterator WasmObjectFile::section_begin() const {
1815   DataRefImpl Ref;
1816   Ref.d.a = 0;
1817   return section_iterator(SectionRef(Ref, this));
1818 }
1819 
section_end() const1820 section_iterator WasmObjectFile::section_end() const {
1821   DataRefImpl Ref;
1822   Ref.d.a = Sections.size();
1823   return section_iterator(SectionRef(Ref, this));
1824 }
1825 
getBytesInAddress() const1826 uint8_t WasmObjectFile::getBytesInAddress() const {
1827   return HasMemory64 ? 8 : 4;
1828 }
1829 
getFileFormatName() const1830 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1831 
getArch() const1832 Triple::ArchType WasmObjectFile::getArch() const {
1833   return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
1834 }
1835 
getFeatures() const1836 Expected<SubtargetFeatures> WasmObjectFile::getFeatures() const {
1837   return SubtargetFeatures();
1838 }
1839 
isRelocatableObject() const1840 bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
1841 
isSharedObject() const1842 bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
1843 
getWasmSection(DataRefImpl Ref) const1844 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1845   assert(Ref.d.a < Sections.size());
1846   return Sections[Ref.d.a];
1847 }
1848 
1849 const WasmSection &
getWasmSection(const SectionRef & Section) const1850 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1851   return getWasmSection(Section.getRawDataRefImpl());
1852 }
1853 
1854 const wasm::WasmRelocation &
getWasmRelocation(const RelocationRef & Ref) const1855 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1856   return getWasmRelocation(Ref.getRawDataRefImpl());
1857 }
1858 
1859 const wasm::WasmRelocation &
getWasmRelocation(DataRefImpl Ref) const1860 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1861   assert(Ref.d.a < Sections.size());
1862   const WasmSection &Sec = Sections[Ref.d.a];
1863   assert(Ref.d.b < Sec.Relocations.size());
1864   return Sec.Relocations[Ref.d.b];
1865 }
1866 
getSectionOrder(unsigned ID,StringRef CustomSectionName)1867 int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
1868                                              StringRef CustomSectionName) {
1869   switch (ID) {
1870   case wasm::WASM_SEC_CUSTOM:
1871     return StringSwitch<unsigned>(CustomSectionName)
1872         .Case("dylink", WASM_SEC_ORDER_DYLINK)
1873         .Case("dylink.0", WASM_SEC_ORDER_DYLINK)
1874         .Case("linking", WASM_SEC_ORDER_LINKING)
1875         .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
1876         .Case("name", WASM_SEC_ORDER_NAME)
1877         .Case("producers", WASM_SEC_ORDER_PRODUCERS)
1878         .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
1879         .Default(WASM_SEC_ORDER_NONE);
1880   case wasm::WASM_SEC_TYPE:
1881     return WASM_SEC_ORDER_TYPE;
1882   case wasm::WASM_SEC_IMPORT:
1883     return WASM_SEC_ORDER_IMPORT;
1884   case wasm::WASM_SEC_FUNCTION:
1885     return WASM_SEC_ORDER_FUNCTION;
1886   case wasm::WASM_SEC_TABLE:
1887     return WASM_SEC_ORDER_TABLE;
1888   case wasm::WASM_SEC_MEMORY:
1889     return WASM_SEC_ORDER_MEMORY;
1890   case wasm::WASM_SEC_GLOBAL:
1891     return WASM_SEC_ORDER_GLOBAL;
1892   case wasm::WASM_SEC_EXPORT:
1893     return WASM_SEC_ORDER_EXPORT;
1894   case wasm::WASM_SEC_START:
1895     return WASM_SEC_ORDER_START;
1896   case wasm::WASM_SEC_ELEM:
1897     return WASM_SEC_ORDER_ELEM;
1898   case wasm::WASM_SEC_CODE:
1899     return WASM_SEC_ORDER_CODE;
1900   case wasm::WASM_SEC_DATA:
1901     return WASM_SEC_ORDER_DATA;
1902   case wasm::WASM_SEC_DATACOUNT:
1903     return WASM_SEC_ORDER_DATACOUNT;
1904   case wasm::WASM_SEC_TAG:
1905     return WASM_SEC_ORDER_TAG;
1906   default:
1907     return WASM_SEC_ORDER_NONE;
1908   }
1909 }
1910 
1911 // Represents the edges in a directed graph where any node B reachable from node
1912 // A is not allowed to appear before A in the section ordering, but may appear
1913 // afterward.
1914 int WasmSectionOrderChecker::DisallowedPredecessors
1915     [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
1916         // WASM_SEC_ORDER_NONE
1917         {},
1918         // WASM_SEC_ORDER_TYPE
1919         {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
1920         // WASM_SEC_ORDER_IMPORT
1921         {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
1922         // WASM_SEC_ORDER_FUNCTION
1923         {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
1924         // WASM_SEC_ORDER_TABLE
1925         {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
1926         // WASM_SEC_ORDER_MEMORY
1927         {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_TAG},
1928         // WASM_SEC_ORDER_TAG
1929         {WASM_SEC_ORDER_TAG, WASM_SEC_ORDER_GLOBAL},
1930         // WASM_SEC_ORDER_GLOBAL
1931         {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
1932         // WASM_SEC_ORDER_EXPORT
1933         {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
1934         // WASM_SEC_ORDER_START
1935         {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
1936         // WASM_SEC_ORDER_ELEM
1937         {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
1938         // WASM_SEC_ORDER_DATACOUNT
1939         {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
1940         // WASM_SEC_ORDER_CODE
1941         {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
1942         // WASM_SEC_ORDER_DATA
1943         {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
1944 
1945         // Custom Sections
1946         // WASM_SEC_ORDER_DYLINK
1947         {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
1948         // WASM_SEC_ORDER_LINKING
1949         {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
1950         // WASM_SEC_ORDER_RELOC (can be repeated)
1951         {},
1952         // WASM_SEC_ORDER_NAME
1953         {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
1954         // WASM_SEC_ORDER_PRODUCERS
1955         {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
1956         // WASM_SEC_ORDER_TARGET_FEATURES
1957         {WASM_SEC_ORDER_TARGET_FEATURES}};
1958 
isValidSectionOrder(unsigned ID,StringRef CustomSectionName)1959 bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
1960                                                   StringRef CustomSectionName) {
1961   int Order = getSectionOrder(ID, CustomSectionName);
1962   if (Order == WASM_SEC_ORDER_NONE)
1963     return true;
1964 
1965   // Disallowed predecessors we need to check for
1966   SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
1967 
1968   // Keep track of completed checks to avoid repeating work
1969   bool Checked[WASM_NUM_SEC_ORDERS] = {};
1970 
1971   int Curr = Order;
1972   while (true) {
1973     // Add new disallowed predecessors to work list
1974     for (size_t I = 0;; ++I) {
1975       int Next = DisallowedPredecessors[Curr][I];
1976       if (Next == WASM_SEC_ORDER_NONE)
1977         break;
1978       if (Checked[Next])
1979         continue;
1980       WorkList.push_back(Next);
1981       Checked[Next] = true;
1982     }
1983 
1984     if (WorkList.empty())
1985       break;
1986 
1987     // Consider next disallowed predecessor
1988     Curr = WorkList.pop_back_val();
1989     if (Seen[Curr])
1990       return false;
1991   }
1992 
1993   // Have not seen any disallowed predecessors
1994   Seen[Order] = true;
1995   return true;
1996 }
1997