2280 lines · cpp
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-exception6//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/BinaryFormat/Wasm.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 "llvm/Support/ScopedPrinter.h"26#include "llvm/TargetParser/SubtargetFeature.h"27#include "llvm/TargetParser/Triple.h"28#include <cassert>29#include <cstdint>30#include <cstring>31 32#define DEBUG_TYPE "wasm-object"33 34using namespace llvm;35using namespace object;36 37void WasmSymbol::print(raw_ostream &Out) const {38 Out << "Name=" << Info.Name39 << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"40 << Twine::utohexstr(Info.Flags) << " [";41 switch (getBinding()) {42 case wasm::WASM_SYMBOL_BINDING_GLOBAL: Out << "global"; break;43 case wasm::WASM_SYMBOL_BINDING_LOCAL: Out << "local"; break;44 case wasm::WASM_SYMBOL_BINDING_WEAK: Out << "weak"; break;45 }46 if (isHidden()) {47 Out << ", hidden";48 } else {49 Out << ", default";50 }51 Out << "]";52 if (!isTypeData()) {53 Out << ", ElemIndex=" << Info.ElementIndex;54 } else if (isDefined()) {55 Out << ", Segment=" << Info.DataRef.Segment;56 Out << ", Offset=" << Info.DataRef.Offset;57 Out << ", Size=" << Info.DataRef.Size;58 }59}60 61#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)62LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }63#endif64 65Expected<std::unique_ptr<WasmObjectFile>>66ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {67 Error Err = Error::success();68 auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);69 if (Err)70 return std::move(Err);71 72 return std::move(ObjectFile);73}74 75#define VARINT7_MAX ((1 << 7) - 1)76#define VARINT7_MIN (-(1 << 7))77#define VARUINT7_MAX (1 << 7)78#define VARUINT1_MAX (1)79 80static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {81 if (Ctx.Ptr == Ctx.End)82 report_fatal_error("EOF while reading uint8");83 return *Ctx.Ptr++;84}85 86static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {87 if (Ctx.Ptr + 4 > Ctx.End)88 report_fatal_error("EOF while reading uint32");89 uint32_t Result = support::endian::read32le(Ctx.Ptr);90 Ctx.Ptr += 4;91 return Result;92}93 94static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {95 if (Ctx.Ptr + 4 > Ctx.End)96 report_fatal_error("EOF while reading float64");97 int32_t Result = 0;98 memcpy(&Result, Ctx.Ptr, sizeof(Result));99 Ctx.Ptr += sizeof(Result);100 return Result;101}102 103static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {104 if (Ctx.Ptr + 8 > Ctx.End)105 report_fatal_error("EOF while reading float64");106 int64_t Result = 0;107 memcpy(&Result, Ctx.Ptr, sizeof(Result));108 Ctx.Ptr += sizeof(Result);109 return Result;110}111 112static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {113 unsigned Count;114 const char *Error = nullptr;115 uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);116 if (Error)117 report_fatal_error(Error);118 Ctx.Ptr += Count;119 return Result;120}121 122static StringRef readString(WasmObjectFile::ReadContext &Ctx) {123 uint32_t StringLen = readULEB128(Ctx);124 if (Ctx.Ptr + StringLen > Ctx.End)125 report_fatal_error("EOF while reading string");126 StringRef Return =127 StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);128 Ctx.Ptr += StringLen;129 return Return;130}131 132static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {133 unsigned Count;134 const char *Error = nullptr;135 uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);136 if (Error)137 report_fatal_error(Error);138 Ctx.Ptr += Count;139 return Result;140}141 142static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {143 int64_t Result = readLEB128(Ctx);144 if (Result > VARUINT1_MAX || Result < 0)145 report_fatal_error("LEB is outside Varuint1 range");146 return Result;147}148 149static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {150 int64_t Result = readLEB128(Ctx);151 if (Result > INT32_MAX || Result < INT32_MIN)152 report_fatal_error("LEB is outside Varint32 range");153 return Result;154}155 156static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {157 uint64_t Result = readULEB128(Ctx);158 if (Result > UINT32_MAX)159 report_fatal_error("LEB is outside Varuint32 range");160 return Result;161}162 163static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {164 return readLEB128(Ctx);165}166 167static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {168 return readULEB128(Ctx);169}170 171static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {172 return readUint8(Ctx);173}174 175static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx,176 uint32_t Code) {177 // only directly encoded FUNCREF/EXTERNREF/EXNREF are supported178 // (not ref null func, ref null extern, or ref null exn)179 switch (Code) {180 case wasm::WASM_TYPE_I32:181 case wasm::WASM_TYPE_I64:182 case wasm::WASM_TYPE_F32:183 case wasm::WASM_TYPE_F64:184 case wasm::WASM_TYPE_V128:185 case wasm::WASM_TYPE_FUNCREF:186 case wasm::WASM_TYPE_EXTERNREF:187 case wasm::WASM_TYPE_EXNREF:188 return wasm::ValType(Code);189 }190 if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {191 /* Discard HeapType */ readVarint64(Ctx);192 }193 return wasm::ValType(wasm::ValType::OTHERREF);194}195 196static Error readInitExpr(wasm::WasmInitExpr &Expr,197 WasmObjectFile::ReadContext &Ctx) {198 auto Start = Ctx.Ptr;199 200 Expr.Extended = false;201 Expr.Inst.Opcode = readOpcode(Ctx);202 switch (Expr.Inst.Opcode) {203 case wasm::WASM_OPCODE_I32_CONST:204 Expr.Inst.Value.Int32 = readVarint32(Ctx);205 break;206 case wasm::WASM_OPCODE_I64_CONST:207 Expr.Inst.Value.Int64 = readVarint64(Ctx);208 break;209 case wasm::WASM_OPCODE_F32_CONST:210 Expr.Inst.Value.Float32 = readFloat32(Ctx);211 break;212 case wasm::WASM_OPCODE_F64_CONST:213 Expr.Inst.Value.Float64 = readFloat64(Ctx);214 break;215 case wasm::WASM_OPCODE_GLOBAL_GET:216 Expr.Inst.Value.Global = readULEB128(Ctx);217 break;218 case wasm::WASM_OPCODE_REF_NULL: {219 /* Discard type */ parseValType(Ctx, readVaruint32(Ctx));220 break;221 }222 default:223 Expr.Extended = true;224 }225 226 if (!Expr.Extended) {227 uint8_t EndOpcode = readOpcode(Ctx);228 if (EndOpcode != wasm::WASM_OPCODE_END)229 Expr.Extended = true;230 }231 232 if (Expr.Extended) {233 Ctx.Ptr = Start;234 while (true) {235 uint8_t Opcode = readOpcode(Ctx);236 switch (Opcode) {237 case wasm::WASM_OPCODE_I32_CONST:238 case wasm::WASM_OPCODE_GLOBAL_GET:239 case wasm::WASM_OPCODE_REF_NULL:240 case wasm::WASM_OPCODE_REF_FUNC:241 case wasm::WASM_OPCODE_I64_CONST:242 readULEB128(Ctx);243 break;244 case wasm::WASM_OPCODE_F32_CONST:245 readFloat32(Ctx);246 break;247 case wasm::WASM_OPCODE_F64_CONST:248 readFloat64(Ctx);249 break;250 case wasm::WASM_OPCODE_I32_ADD:251 case wasm::WASM_OPCODE_I32_SUB:252 case wasm::WASM_OPCODE_I32_MUL:253 case wasm::WASM_OPCODE_I64_ADD:254 case wasm::WASM_OPCODE_I64_SUB:255 case wasm::WASM_OPCODE_I64_MUL:256 break;257 case wasm::WASM_OPCODE_GC_PREFIX:258 break;259 // The GC opcodes are in a separate (prefixed space). This flat switch260 // structure works as long as there is no overlap between the GC and261 // general opcodes used in init exprs.262 case wasm::WASM_OPCODE_STRUCT_NEW:263 case wasm::WASM_OPCODE_STRUCT_NEW_DEFAULT:264 case wasm::WASM_OPCODE_ARRAY_NEW:265 case wasm::WASM_OPCODE_ARRAY_NEW_DEFAULT:266 readULEB128(Ctx); // heap type index267 break;268 case wasm::WASM_OPCODE_ARRAY_NEW_FIXED:269 readULEB128(Ctx); // heap type index270 readULEB128(Ctx); // array size271 break;272 case wasm::WASM_OPCODE_REF_I31:273 break;274 case wasm::WASM_OPCODE_END:275 Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);276 return Error::success();277 default:278 return make_error<GenericBinaryError>(279 Twine("invalid opcode in init_expr: ") + Twine(unsigned(Opcode)),280 object_error::parse_failed);281 }282 }283 }284 285 return Error::success();286}287 288static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {289 wasm::WasmLimits Result;290 Result.Flags = readVaruint32(Ctx);291 Result.Minimum = readVaruint64(Ctx);292 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)293 Result.Maximum = readVaruint64(Ctx);294 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_PAGE_SIZE) {295 uint32_t PageSizeLog2 = readVaruint32(Ctx);296 if (PageSizeLog2 >= 32)297 report_fatal_error("log2(wasm page size) too large");298 Result.PageSize = 1 << PageSizeLog2;299 }300 return Result;301}302 303static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {304 wasm::WasmTableType TableType;305 auto ElemType = parseValType(Ctx, readVaruint32(Ctx));306 TableType.ElemType = ElemType;307 TableType.Limits = readLimits(Ctx);308 return TableType;309}310 311static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,312 WasmSectionOrderChecker &Checker) {313 Section.Type = readUint8(Ctx);314 LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");315 // When reading the section's size, store the size of the LEB used to encode316 // it. This allows objcopy/strip to reproduce the binary identically.317 const uint8_t *PreSizePtr = Ctx.Ptr;318 uint32_t Size = readVaruint32(Ctx);319 Section.HeaderSecSizeEncodingLen = Ctx.Ptr - PreSizePtr;320 Section.Offset = Ctx.Ptr - Ctx.Start;321 if (Size == 0)322 return make_error<StringError>("zero length section",323 object_error::parse_failed);324 if (Ctx.Ptr + Size > Ctx.End)325 return make_error<StringError>("section too large",326 object_error::parse_failed);327 if (Section.Type == wasm::WASM_SEC_CUSTOM) {328 WasmObjectFile::ReadContext SectionCtx;329 SectionCtx.Start = Ctx.Ptr;330 SectionCtx.Ptr = Ctx.Ptr;331 SectionCtx.End = Ctx.Ptr + Size;332 333 Section.Name = readString(SectionCtx);334 335 uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;336 Ctx.Ptr += SectionNameSize;337 Size -= SectionNameSize;338 }339 340 if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {341 return make_error<StringError>("out of order section type: " +342 llvm::to_string(Section.Type),343 object_error::parse_failed);344 }345 346 Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);347 Ctx.Ptr += Size;348 return Error::success();349}350 351WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)352 : ObjectFile(Binary::ID_Wasm, Buffer) {353 ErrorAsOutParameter ErrAsOutParam(Err);354 Header.Magic = getData().substr(0, 4);355 if (Header.Magic != StringRef("\0asm", 4)) {356 Err = make_error<StringError>("invalid magic number",357 object_error::parse_failed);358 return;359 }360 361 ReadContext Ctx;362 Ctx.Start = getData().bytes_begin();363 Ctx.Ptr = Ctx.Start + 4;364 Ctx.End = Ctx.Start + getData().size();365 366 if (Ctx.Ptr + 4 > Ctx.End) {367 Err = make_error<StringError>("missing version number",368 object_error::parse_failed);369 return;370 }371 372 Header.Version = readUint32(Ctx);373 if (Header.Version != wasm::WasmVersion) {374 Err = make_error<StringError>("invalid version number: " +375 Twine(Header.Version),376 object_error::parse_failed);377 return;378 }379 380 WasmSectionOrderChecker Checker;381 while (Ctx.Ptr < Ctx.End) {382 WasmSection Sec;383 if ((Err = readSection(Sec, Ctx, Checker)))384 return;385 if ((Err = parseSection(Sec)))386 return;387 388 Sections.push_back(Sec);389 }390}391 392Error WasmObjectFile::parseSection(WasmSection &Sec) {393 ReadContext Ctx;394 Ctx.Start = Sec.Content.data();395 Ctx.End = Ctx.Start + Sec.Content.size();396 Ctx.Ptr = Ctx.Start;397 switch (Sec.Type) {398 case wasm::WASM_SEC_CUSTOM:399 return parseCustomSection(Sec, Ctx);400 case wasm::WASM_SEC_TYPE:401 return parseTypeSection(Ctx);402 case wasm::WASM_SEC_IMPORT:403 return parseImportSection(Ctx);404 case wasm::WASM_SEC_FUNCTION:405 return parseFunctionSection(Ctx);406 case wasm::WASM_SEC_TABLE:407 return parseTableSection(Ctx);408 case wasm::WASM_SEC_MEMORY:409 return parseMemorySection(Ctx);410 case wasm::WASM_SEC_TAG:411 return parseTagSection(Ctx);412 case wasm::WASM_SEC_GLOBAL:413 return parseGlobalSection(Ctx);414 case wasm::WASM_SEC_EXPORT:415 return parseExportSection(Ctx);416 case wasm::WASM_SEC_START:417 return parseStartSection(Ctx);418 case wasm::WASM_SEC_ELEM:419 return parseElemSection(Ctx);420 case wasm::WASM_SEC_CODE:421 return parseCodeSection(Ctx);422 case wasm::WASM_SEC_DATA:423 return parseDataSection(Ctx);424 case wasm::WASM_SEC_DATACOUNT:425 return parseDataCountSection(Ctx);426 default:427 return make_error<GenericBinaryError>(428 "invalid section type: " + Twine(Sec.Type), object_error::parse_failed);429 }430}431 432Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {433 // Legacy "dylink" section support.434 // See parseDylink0Section for the current "dylink.0" section parsing.435 HasDylinkSection = true;436 DylinkInfo.MemorySize = readVaruint32(Ctx);437 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);438 DylinkInfo.TableSize = readVaruint32(Ctx);439 DylinkInfo.TableAlignment = readVaruint32(Ctx);440 uint32_t Count = readVaruint32(Ctx);441 while (Count--) {442 DylinkInfo.Needed.push_back(readString(Ctx));443 }444 445 if (Ctx.Ptr != Ctx.End)446 return make_error<GenericBinaryError>("dylink section ended prematurely",447 object_error::parse_failed);448 return Error::success();449}450 451Error WasmObjectFile::parseDylink0Section(ReadContext &Ctx) {452 // See453 // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md454 HasDylinkSection = true;455 456 const uint8_t *OrigEnd = Ctx.End;457 while (Ctx.Ptr < OrigEnd) {458 Ctx.End = OrigEnd;459 uint8_t Type = readUint8(Ctx);460 uint32_t Size = readVaruint32(Ctx);461 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size462 << "\n");463 Ctx.End = Ctx.Ptr + Size;464 uint32_t Count;465 switch (Type) {466 case wasm::WASM_DYLINK_MEM_INFO:467 DylinkInfo.MemorySize = readVaruint32(Ctx);468 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);469 DylinkInfo.TableSize = readVaruint32(Ctx);470 DylinkInfo.TableAlignment = readVaruint32(Ctx);471 break;472 case wasm::WASM_DYLINK_NEEDED:473 Count = readVaruint32(Ctx);474 while (Count--) {475 DylinkInfo.Needed.push_back(readString(Ctx));476 }477 break;478 case wasm::WASM_DYLINK_EXPORT_INFO: {479 uint32_t Count = readVaruint32(Ctx);480 while (Count--) {481 DylinkInfo.ExportInfo.push_back({readString(Ctx), readVaruint32(Ctx)});482 }483 break;484 }485 case wasm::WASM_DYLINK_IMPORT_INFO: {486 uint32_t Count = readVaruint32(Ctx);487 while (Count--) {488 DylinkInfo.ImportInfo.push_back(489 {readString(Ctx), readString(Ctx), readVaruint32(Ctx)});490 }491 break;492 }493 case wasm::WASM_DYLINK_RUNTIME_PATH: {494 Count = readVaruint32(Ctx);495 while (Count--) {496 DylinkInfo.RuntimePath.push_back(readString(Ctx));497 }498 break;499 }500 default:501 LLVM_DEBUG(dbgs() << "unknown dylink.0 sub-section: " << Type << "\n");502 Ctx.Ptr += Size;503 break;504 }505 if (Ctx.Ptr != Ctx.End) {506 return make_error<GenericBinaryError>(507 "dylink.0 sub-section ended prematurely", object_error::parse_failed);508 }509 }510 511 if (Ctx.Ptr != Ctx.End)512 return make_error<GenericBinaryError>("dylink.0 section ended prematurely",513 object_error::parse_failed);514 return Error::success();515}516 517Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {518 llvm::DenseSet<uint64_t> SeenFunctions;519 llvm::DenseSet<uint64_t> SeenGlobals;520 llvm::DenseSet<uint64_t> SeenSegments;521 522 // If we have linking section (symbol table) or if we are parsing a DSO523 // then we don't use the name section for symbol information.524 bool PopulateSymbolTable = !HasLinkingSection && !HasDylinkSection;525 526 // If we are using the name section for symbol information then it will527 // supersede any symbols created by the export section.528 if (PopulateSymbolTable)529 Symbols.clear();530 531 while (Ctx.Ptr < Ctx.End) {532 uint8_t Type = readUint8(Ctx);533 uint32_t Size = readVaruint32(Ctx);534 const uint8_t *SubSectionEnd = Ctx.Ptr + Size;535 536 switch (Type) {537 case wasm::WASM_NAMES_FUNCTION:538 case wasm::WASM_NAMES_GLOBAL:539 case wasm::WASM_NAMES_DATA_SEGMENT: {540 uint32_t Count = readVaruint32(Ctx);541 while (Count--) {542 uint32_t Index = readVaruint32(Ctx);543 StringRef Name = readString(Ctx);544 wasm::NameType nameType = wasm::NameType::FUNCTION;545 wasm::WasmSymbolInfo Info{Name,546 /*Kind */ wasm::WASM_SYMBOL_TYPE_FUNCTION,547 /* Flags */ 0,548 /* ImportModule */ std::nullopt,549 /* ImportName */ std::nullopt,550 /* ExportName */ std::nullopt,551 {/* ElementIndex */ Index}};552 const wasm::WasmSignature *Signature = nullptr;553 const wasm::WasmGlobalType *GlobalType = nullptr;554 const wasm::WasmTableType *TableType = nullptr;555 if (Type == wasm::WASM_NAMES_FUNCTION) {556 if (!SeenFunctions.insert(Index).second)557 return make_error<GenericBinaryError>(558 "function named more than once", object_error::parse_failed);559 if (!isValidFunctionIndex(Index) || Name.empty())560 return make_error<GenericBinaryError>("invalid function name entry",561 object_error::parse_failed);562 563 if (isDefinedFunctionIndex(Index)) {564 wasm::WasmFunction &F = getDefinedFunction(Index);565 F.DebugName = Name;566 Signature = &Signatures[F.SigIndex];567 if (F.ExportName) {568 Info.ExportName = F.ExportName;569 Info.Flags |= wasm::WASM_SYMBOL_BINDING_GLOBAL;570 } else {571 Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;572 }573 } else {574 Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;575 }576 } else if (Type == wasm::WASM_NAMES_GLOBAL) {577 if (!SeenGlobals.insert(Index).second)578 return make_error<GenericBinaryError>("global named more than once",579 object_error::parse_failed);580 if (!isValidGlobalIndex(Index) || Name.empty())581 return make_error<GenericBinaryError>("invalid global name entry",582 object_error::parse_failed);583 nameType = wasm::NameType::GLOBAL;584 Info.Kind = wasm::WASM_SYMBOL_TYPE_GLOBAL;585 if (isDefinedGlobalIndex(Index)) {586 GlobalType = &getDefinedGlobal(Index).Type;587 } else {588 Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;589 }590 } else {591 if (!SeenSegments.insert(Index).second)592 return make_error<GenericBinaryError>(593 "segment named more than once", object_error::parse_failed);594 if (Index > DataSegments.size())595 return make_error<GenericBinaryError>("invalid data segment name entry",596 object_error::parse_failed);597 nameType = wasm::NameType::DATA_SEGMENT;598 Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;599 Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;600 assert(Index < DataSegments.size());601 Info.DataRef = wasm::WasmDataReference{602 Index, 0, DataSegments[Index].Data.Content.size()};603 }604 DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name});605 if (PopulateSymbolTable)606 Symbols.emplace_back(Info, GlobalType, TableType, Signature);607 }608 break;609 }610 // Ignore local names for now611 case wasm::WASM_NAMES_LOCAL:612 default:613 Ctx.Ptr += Size;614 break;615 }616 if (Ctx.Ptr != SubSectionEnd)617 return make_error<GenericBinaryError>(618 "name sub-section ended prematurely", object_error::parse_failed);619 }620 621 if (Ctx.Ptr != Ctx.End)622 return make_error<GenericBinaryError>("name section ended prematurely",623 object_error::parse_failed);624 return Error::success();625}626 627Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {628 HasLinkingSection = true;629 630 LinkingData.Version = readVaruint32(Ctx);631 if (LinkingData.Version != wasm::WasmMetadataVersion) {632 return make_error<GenericBinaryError>(633 "unexpected metadata version: " + Twine(LinkingData.Version) +634 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",635 object_error::parse_failed);636 }637 638 const uint8_t *OrigEnd = Ctx.End;639 while (Ctx.Ptr < OrigEnd) {640 Ctx.End = OrigEnd;641 uint8_t Type = readUint8(Ctx);642 uint32_t Size = readVaruint32(Ctx);643 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size644 << "\n");645 Ctx.End = Ctx.Ptr + Size;646 switch (Type) {647 case wasm::WASM_SYMBOL_TABLE:648 if (Error Err = parseLinkingSectionSymtab(Ctx))649 return Err;650 break;651 case wasm::WASM_SEGMENT_INFO: {652 uint32_t Count = readVaruint32(Ctx);653 if (Count > DataSegments.size())654 return make_error<GenericBinaryError>("too many segment names",655 object_error::parse_failed);656 for (uint32_t I = 0; I < Count; I++) {657 DataSegments[I].Data.Name = readString(Ctx);658 DataSegments[I].Data.Alignment = readVaruint32(Ctx);659 DataSegments[I].Data.LinkingFlags = readVaruint32(Ctx);660 }661 break;662 }663 case wasm::WASM_INIT_FUNCS: {664 uint32_t Count = readVaruint32(Ctx);665 LinkingData.InitFunctions.reserve(Count);666 for (uint32_t I = 0; I < Count; I++) {667 wasm::WasmInitFunc Init;668 Init.Priority = readVaruint32(Ctx);669 Init.Symbol = readVaruint32(Ctx);670 if (!isValidFunctionSymbol(Init.Symbol))671 return make_error<GenericBinaryError>("invalid function symbol: " +672 Twine(Init.Symbol),673 object_error::parse_failed);674 LinkingData.InitFunctions.emplace_back(Init);675 }676 break;677 }678 case wasm::WASM_COMDAT_INFO:679 if (Error Err = parseLinkingSectionComdat(Ctx))680 return Err;681 break;682 default:683 Ctx.Ptr += Size;684 break;685 }686 if (Ctx.Ptr != Ctx.End)687 return make_error<GenericBinaryError>(688 "linking sub-section ended prematurely", object_error::parse_failed);689 }690 if (Ctx.Ptr != OrigEnd)691 return make_error<GenericBinaryError>("linking section ended prematurely",692 object_error::parse_failed);693 return Error::success();694}695 696Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {697 uint32_t Count = readVaruint32(Ctx);698 // Clear out any symbol information that was derived from the exports699 // section.700 Symbols.clear();701 Symbols.reserve(Count);702 StringSet<> SymbolNames;703 704 std::vector<wasm::WasmImport *> ImportedGlobals;705 std::vector<wasm::WasmImport *> ImportedFunctions;706 std::vector<wasm::WasmImport *> ImportedTags;707 std::vector<wasm::WasmImport *> ImportedTables;708 ImportedGlobals.reserve(Imports.size());709 ImportedFunctions.reserve(Imports.size());710 ImportedTags.reserve(Imports.size());711 ImportedTables.reserve(Imports.size());712 for (auto &I : Imports) {713 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)714 ImportedFunctions.emplace_back(&I);715 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)716 ImportedGlobals.emplace_back(&I);717 else if (I.Kind == wasm::WASM_EXTERNAL_TAG)718 ImportedTags.emplace_back(&I);719 else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)720 ImportedTables.emplace_back(&I);721 }722 723 while (Count--) {724 wasm::WasmSymbolInfo Info;725 const wasm::WasmSignature *Signature = nullptr;726 const wasm::WasmGlobalType *GlobalType = nullptr;727 const wasm::WasmTableType *TableType = nullptr;728 729 Info.Kind = readUint8(Ctx);730 Info.Flags = readVaruint32(Ctx);731 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;732 733 switch (Info.Kind) {734 case wasm::WASM_SYMBOL_TYPE_FUNCTION:735 Info.ElementIndex = readVaruint32(Ctx);736 if (!isValidFunctionIndex(Info.ElementIndex) ||737 IsDefined != isDefinedFunctionIndex(Info.ElementIndex))738 return make_error<GenericBinaryError>("invalid function symbol index",739 object_error::parse_failed);740 if (IsDefined) {741 Info.Name = readString(Ctx);742 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;743 wasm::WasmFunction &Function = Functions[FuncIndex];744 Signature = &Signatures[Function.SigIndex];745 if (Function.SymbolName.empty())746 Function.SymbolName = Info.Name;747 } else {748 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];749 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {750 Info.Name = readString(Ctx);751 Info.ImportName = Import.Field;752 } else {753 Info.Name = Import.Field;754 }755 Signature = &Signatures[Import.SigIndex];756 Info.ImportModule = Import.Module;757 }758 break;759 760 case wasm::WASM_SYMBOL_TYPE_GLOBAL:761 Info.ElementIndex = readVaruint32(Ctx);762 if (!isValidGlobalIndex(Info.ElementIndex) ||763 IsDefined != isDefinedGlobalIndex(Info.ElementIndex))764 return make_error<GenericBinaryError>("invalid global symbol index",765 object_error::parse_failed);766 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==767 wasm::WASM_SYMBOL_BINDING_WEAK)768 return make_error<GenericBinaryError>("undefined weak global symbol",769 object_error::parse_failed);770 if (IsDefined) {771 Info.Name = readString(Ctx);772 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;773 wasm::WasmGlobal &Global = Globals[GlobalIndex];774 GlobalType = &Global.Type;775 if (Global.SymbolName.empty())776 Global.SymbolName = Info.Name;777 } else {778 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];779 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {780 Info.Name = readString(Ctx);781 Info.ImportName = Import.Field;782 } else {783 Info.Name = Import.Field;784 }785 GlobalType = &Import.Global;786 Info.ImportModule = Import.Module;787 }788 break;789 790 case wasm::WASM_SYMBOL_TYPE_TABLE:791 Info.ElementIndex = readVaruint32(Ctx);792 if (!isValidTableNumber(Info.ElementIndex) ||793 IsDefined != isDefinedTableNumber(Info.ElementIndex))794 return make_error<GenericBinaryError>("invalid table symbol index",795 object_error::parse_failed);796 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==797 wasm::WASM_SYMBOL_BINDING_WEAK)798 return make_error<GenericBinaryError>("undefined weak table symbol",799 object_error::parse_failed);800 if (IsDefined) {801 Info.Name = readString(Ctx);802 unsigned TableNumber = Info.ElementIndex - NumImportedTables;803 wasm::WasmTable &Table = Tables[TableNumber];804 TableType = &Table.Type;805 if (Table.SymbolName.empty())806 Table.SymbolName = Info.Name;807 } else {808 wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];809 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {810 Info.Name = readString(Ctx);811 Info.ImportName = Import.Field;812 } else {813 Info.Name = Import.Field;814 }815 TableType = &Import.Table;816 Info.ImportModule = Import.Module;817 }818 break;819 820 case wasm::WASM_SYMBOL_TYPE_DATA:821 Info.Name = readString(Ctx);822 if (IsDefined) {823 auto Index = readVaruint32(Ctx);824 auto Offset = readVaruint64(Ctx);825 auto Size = readVaruint64(Ctx);826 if (!(Info.Flags & wasm::WASM_SYMBOL_ABSOLUTE)) {827 if (static_cast<size_t>(Index) >= DataSegments.size())828 return make_error<GenericBinaryError>(829 "invalid data segment index: " + Twine(Index),830 object_error::parse_failed);831 size_t SegmentSize = DataSegments[Index].Data.Content.size();832 if (Offset > SegmentSize)833 return make_error<GenericBinaryError>(834 "invalid data symbol offset: `" + Info.Name +835 "` (offset: " + Twine(Offset) +836 " segment size: " + Twine(SegmentSize) + ")",837 object_error::parse_failed);838 }839 Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};840 }841 break;842 843 case wasm::WASM_SYMBOL_TYPE_SECTION: {844 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=845 wasm::WASM_SYMBOL_BINDING_LOCAL)846 return make_error<GenericBinaryError>(847 "section symbols must have local binding",848 object_error::parse_failed);849 Info.ElementIndex = readVaruint32(Ctx);850 // Use somewhat unique section name as symbol name.851 StringRef SectionName = Sections[Info.ElementIndex].Name;852 Info.Name = SectionName;853 break;854 }855 856 case wasm::WASM_SYMBOL_TYPE_TAG: {857 Info.ElementIndex = readVaruint32(Ctx);858 if (!isValidTagIndex(Info.ElementIndex) ||859 IsDefined != isDefinedTagIndex(Info.ElementIndex))860 return make_error<GenericBinaryError>("invalid tag symbol index",861 object_error::parse_failed);862 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==863 wasm::WASM_SYMBOL_BINDING_WEAK)864 return make_error<GenericBinaryError>("undefined weak global symbol",865 object_error::parse_failed);866 if (IsDefined) {867 Info.Name = readString(Ctx);868 unsigned TagIndex = Info.ElementIndex - NumImportedTags;869 wasm::WasmTag &Tag = Tags[TagIndex];870 Signature = &Signatures[Tag.SigIndex];871 if (Tag.SymbolName.empty())872 Tag.SymbolName = Info.Name;873 874 } else {875 wasm::WasmImport &Import = *ImportedTags[Info.ElementIndex];876 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {877 Info.Name = readString(Ctx);878 Info.ImportName = Import.Field;879 } else {880 Info.Name = Import.Field;881 }882 Signature = &Signatures[Import.SigIndex];883 Info.ImportModule = Import.Module;884 }885 break;886 }887 888 default:889 return make_error<GenericBinaryError>("invalid symbol type: " +890 Twine(unsigned(Info.Kind)),891 object_error::parse_failed);892 }893 894 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=895 wasm::WASM_SYMBOL_BINDING_LOCAL &&896 !SymbolNames.insert(Info.Name).second)897 return make_error<GenericBinaryError>("duplicate symbol name " +898 Twine(Info.Name),899 object_error::parse_failed);900 Symbols.emplace_back(Info, GlobalType, TableType, Signature);901 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");902 }903 904 return Error::success();905}906 907Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {908 uint32_t ComdatCount = readVaruint32(Ctx);909 StringSet<> ComdatSet;910 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {911 StringRef Name = readString(Ctx);912 if (Name.empty() || !ComdatSet.insert(Name).second)913 return make_error<GenericBinaryError>("bad/duplicate COMDAT name " +914 Twine(Name),915 object_error::parse_failed);916 LinkingData.Comdats.emplace_back(Name);917 uint32_t Flags = readVaruint32(Ctx);918 if (Flags != 0)919 return make_error<GenericBinaryError>("unsupported COMDAT flags",920 object_error::parse_failed);921 922 uint32_t EntryCount = readVaruint32(Ctx);923 while (EntryCount--) {924 unsigned Kind = readVaruint32(Ctx);925 unsigned Index = readVaruint32(Ctx);926 switch (Kind) {927 default:928 return make_error<GenericBinaryError>("invalid COMDAT entry type",929 object_error::parse_failed);930 case wasm::WASM_COMDAT_DATA:931 if (Index >= DataSegments.size())932 return make_error<GenericBinaryError>(933 "COMDAT data index out of range", object_error::parse_failed);934 if (DataSegments[Index].Data.Comdat != UINT32_MAX)935 return make_error<GenericBinaryError>("data segment in two COMDATs",936 object_error::parse_failed);937 DataSegments[Index].Data.Comdat = ComdatIndex;938 break;939 case wasm::WASM_COMDAT_FUNCTION:940 if (!isDefinedFunctionIndex(Index))941 return make_error<GenericBinaryError>(942 "COMDAT function index out of range", object_error::parse_failed);943 if (getDefinedFunction(Index).Comdat != UINT32_MAX)944 return make_error<GenericBinaryError>("function in two COMDATs",945 object_error::parse_failed);946 getDefinedFunction(Index).Comdat = ComdatIndex;947 break;948 case wasm::WASM_COMDAT_SECTION:949 if (Index >= Sections.size())950 return make_error<GenericBinaryError>(951 "COMDAT section index out of range", object_error::parse_failed);952 if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)953 return make_error<GenericBinaryError>(954 "non-custom section in a COMDAT", object_error::parse_failed);955 Sections[Index].Comdat = ComdatIndex;956 break;957 }958 }959 }960 return Error::success();961}962 963Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {964 llvm::SmallSet<StringRef, 3> FieldsSeen;965 uint32_t Fields = readVaruint32(Ctx);966 for (size_t I = 0; I < Fields; ++I) {967 StringRef FieldName = readString(Ctx);968 if (!FieldsSeen.insert(FieldName).second)969 return make_error<GenericBinaryError>(970 "producers section does not have unique fields",971 object_error::parse_failed);972 std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;973 if (FieldName == "language") {974 ProducerVec = &ProducerInfo.Languages;975 } else if (FieldName == "processed-by") {976 ProducerVec = &ProducerInfo.Tools;977 } else if (FieldName == "sdk") {978 ProducerVec = &ProducerInfo.SDKs;979 } else {980 return make_error<GenericBinaryError>(981 "producers section field is not named one of language, processed-by, "982 "or sdk",983 object_error::parse_failed);984 }985 uint32_t ValueCount = readVaruint32(Ctx);986 llvm::SmallSet<StringRef, 8> ProducersSeen;987 for (size_t J = 0; J < ValueCount; ++J) {988 StringRef Name = readString(Ctx);989 StringRef Version = readString(Ctx);990 if (!ProducersSeen.insert(Name).second) {991 return make_error<GenericBinaryError>(992 "producers section contains repeated producer",993 object_error::parse_failed);994 }995 ProducerVec->emplace_back(std::string(Name), std::string(Version));996 }997 }998 if (Ctx.Ptr != Ctx.End)999 return make_error<GenericBinaryError>("producers section ended prematurely",1000 object_error::parse_failed);1001 return Error::success();1002}1003 1004Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {1005 llvm::SmallSet<std::string, 8> FeaturesSeen;1006 uint32_t FeatureCount = readVaruint32(Ctx);1007 for (size_t I = 0; I < FeatureCount; ++I) {1008 wasm::WasmFeatureEntry Feature;1009 Feature.Prefix = readUint8(Ctx);1010 switch (Feature.Prefix) {1011 case wasm::WASM_FEATURE_PREFIX_USED:1012 case wasm::WASM_FEATURE_PREFIX_DISALLOWED:1013 break;1014 default:1015 return make_error<GenericBinaryError>("unknown feature policy prefix",1016 object_error::parse_failed);1017 }1018 Feature.Name = std::string(readString(Ctx));1019 if (!FeaturesSeen.insert(Feature.Name).second)1020 return make_error<GenericBinaryError>(1021 "target features section contains repeated feature \"" +1022 Feature.Name + "\"",1023 object_error::parse_failed);1024 TargetFeatures.push_back(Feature);1025 }1026 if (Ctx.Ptr != Ctx.End)1027 return make_error<GenericBinaryError>(1028 "target features section ended prematurely",1029 object_error::parse_failed);1030 return Error::success();1031}1032 1033Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {1034 uint32_t SectionIndex = readVaruint32(Ctx);1035 if (SectionIndex >= Sections.size())1036 return make_error<GenericBinaryError>("invalid section index",1037 object_error::parse_failed);1038 WasmSection &Section = Sections[SectionIndex];1039 uint32_t RelocCount = readVaruint32(Ctx);1040 uint32_t EndOffset = Section.Content.size();1041 uint32_t PreviousOffset = 0;1042 while (RelocCount--) {1043 wasm::WasmRelocation Reloc = {};1044 uint32_t type = readVaruint32(Ctx);1045 Reloc.Type = type;1046 Reloc.Offset = readVaruint32(Ctx);1047 if (Reloc.Offset < PreviousOffset)1048 return make_error<GenericBinaryError>("relocations not in offset order",1049 object_error::parse_failed);1050 1051 auto badReloc = [&](StringRef msg) {1052 return make_error<GenericBinaryError>(1053 msg + ": " + Twine(Symbols[Reloc.Index].Info.Name),1054 object_error::parse_failed);1055 };1056 1057 PreviousOffset = Reloc.Offset;1058 Reloc.Index = readVaruint32(Ctx);1059 switch (type) {1060 case wasm::R_WASM_FUNCTION_INDEX_LEB:1061 case wasm::R_WASM_FUNCTION_INDEX_I32:1062 case wasm::R_WASM_TABLE_INDEX_SLEB:1063 case wasm::R_WASM_TABLE_INDEX_SLEB64:1064 case wasm::R_WASM_TABLE_INDEX_I32:1065 case wasm::R_WASM_TABLE_INDEX_I64:1066 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:1067 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:1068 if (!isValidFunctionSymbol(Reloc.Index))1069 return badReloc("invalid function relocation");1070 break;1071 case wasm::R_WASM_TABLE_NUMBER_LEB:1072 if (!isValidTableSymbol(Reloc.Index))1073 return badReloc("invalid table relocation");1074 break;1075 case wasm::R_WASM_TYPE_INDEX_LEB:1076 if (Reloc.Index >= Signatures.size())1077 return badReloc("invalid relocation type index");1078 break;1079 case wasm::R_WASM_GLOBAL_INDEX_LEB:1080 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data1081 // symbols to refer to their GOT entries.1082 if (!isValidGlobalSymbol(Reloc.Index) &&1083 !isValidDataSymbol(Reloc.Index) &&1084 !isValidFunctionSymbol(Reloc.Index))1085 return badReloc("invalid global relocation");1086 break;1087 case wasm::R_WASM_GLOBAL_INDEX_I32:1088 if (!isValidGlobalSymbol(Reloc.Index))1089 return badReloc("invalid global relocation");1090 break;1091 case wasm::R_WASM_TAG_INDEX_LEB:1092 if (!isValidTagSymbol(Reloc.Index))1093 return badReloc("invalid tag relocation");1094 break;1095 case wasm::R_WASM_MEMORY_ADDR_LEB:1096 case wasm::R_WASM_MEMORY_ADDR_SLEB:1097 case wasm::R_WASM_MEMORY_ADDR_I32:1098 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:1099 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:1100 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:1101 if (!isValidDataSymbol(Reloc.Index))1102 return badReloc("invalid data relocation");1103 Reloc.Addend = readVarint32(Ctx);1104 break;1105 case wasm::R_WASM_MEMORY_ADDR_LEB64:1106 case wasm::R_WASM_MEMORY_ADDR_SLEB64:1107 case wasm::R_WASM_MEMORY_ADDR_I64:1108 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:1109 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:1110 if (!isValidDataSymbol(Reloc.Index))1111 return badReloc("invalid data relocation");1112 Reloc.Addend = readVarint64(Ctx);1113 break;1114 case wasm::R_WASM_FUNCTION_OFFSET_I32:1115 if (!isValidFunctionSymbol(Reloc.Index))1116 return badReloc("invalid function relocation");1117 Reloc.Addend = readVarint32(Ctx);1118 break;1119 case wasm::R_WASM_FUNCTION_OFFSET_I64:1120 if (!isValidFunctionSymbol(Reloc.Index))1121 return badReloc("invalid function relocation");1122 Reloc.Addend = readVarint64(Ctx);1123 break;1124 case wasm::R_WASM_SECTION_OFFSET_I32:1125 if (!isValidSectionSymbol(Reloc.Index))1126 return badReloc("invalid section relocation");1127 Reloc.Addend = readVarint32(Ctx);1128 break;1129 default:1130 return make_error<GenericBinaryError>("invalid relocation type: " +1131 Twine(type),1132 object_error::parse_failed);1133 }1134 1135 // Relocations must fit inside the section, and must appear in order. They1136 // also shouldn't overlap a function/element boundary, but we don't bother1137 // to check that.1138 uint64_t Size = 5;1139 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||1140 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||1141 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)1142 Size = 10;1143 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||1144 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||1145 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||1146 Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||1147 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||1148 Reloc.Type == wasm::R_WASM_FUNCTION_INDEX_I32 ||1149 Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)1150 Size = 4;1151 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||1152 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||1153 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)1154 Size = 8;1155 if (Reloc.Offset + Size > EndOffset)1156 return make_error<GenericBinaryError>("invalid relocation offset",1157 object_error::parse_failed);1158 1159 Section.Relocations.push_back(Reloc);1160 }1161 if (Ctx.Ptr != Ctx.End)1162 return make_error<GenericBinaryError>("reloc section ended prematurely",1163 object_error::parse_failed);1164 return Error::success();1165}1166 1167Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {1168 if (Sec.Name == "dylink") {1169 if (Error Err = parseDylinkSection(Ctx))1170 return Err;1171 } else if (Sec.Name == "dylink.0") {1172 if (Error Err = parseDylink0Section(Ctx))1173 return Err;1174 } else if (Sec.Name == "name") {1175 if (Error Err = parseNameSection(Ctx))1176 return Err;1177 } else if (Sec.Name == "linking") {1178 if (Error Err = parseLinkingSection(Ctx))1179 return Err;1180 } else if (Sec.Name == "producers") {1181 if (Error Err = parseProducersSection(Ctx))1182 return Err;1183 } else if (Sec.Name == "target_features") {1184 if (Error Err = parseTargetFeaturesSection(Ctx))1185 return Err;1186 } else if (Sec.Name.starts_with("reloc.")) {1187 if (Error Err = parseRelocSection(Sec.Name, Ctx))1188 return Err;1189 }1190 return Error::success();1191}1192 1193Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {1194 auto parseFieldDef = [&]() {1195 uint32_t TypeCode = readVaruint32((Ctx));1196 /* Discard StorageType */ parseValType(Ctx, TypeCode);1197 /* Discard Mutability */ readVaruint32(Ctx);1198 };1199 1200 uint32_t Count = readVaruint32(Ctx);1201 Signatures.reserve(Count);1202 while (Count--) {1203 wasm::WasmSignature Sig;1204 uint8_t Form = readUint8(Ctx);1205 if (Form == wasm::WASM_TYPE_REC) {1206 // Rec groups expand the type index space (beyond what was declared at1207 // the top of the section, and also consume one element in that space.1208 uint32_t RecSize = readVaruint32(Ctx);1209 if (RecSize == 0)1210 return make_error<GenericBinaryError>("Rec group size cannot be 0",1211 object_error::parse_failed);1212 Signatures.reserve(Signatures.size() + RecSize);1213 Count += RecSize;1214 Sig.Kind = wasm::WasmSignature::Placeholder;1215 Signatures.push_back(std::move(Sig));1216 HasUnmodeledTypes = true;1217 continue;1218 }1219 if (Form != wasm::WASM_TYPE_FUNC) {1220 // Currently LLVM only models function types, and not other composite1221 // types. Here we parse the type declarations just enough to skip past1222 // them in the binary.1223 if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {1224 uint32_t Supers = readVaruint32(Ctx);1225 if (Supers > 0) {1226 if (Supers != 1)1227 return make_error<GenericBinaryError>(1228 "Invalid number of supertypes", object_error::parse_failed);1229 /* Discard SuperIndex */ readVaruint32(Ctx);1230 }1231 Form = readVaruint32(Ctx);1232 }1233 if (Form == wasm::WASM_TYPE_STRUCT) {1234 uint32_t FieldCount = readVaruint32(Ctx);1235 while (FieldCount--) {1236 parseFieldDef();1237 }1238 } else if (Form == wasm::WASM_TYPE_ARRAY) {1239 parseFieldDef();1240 } else {1241 return make_error<GenericBinaryError>("bad form",1242 object_error::parse_failed);1243 }1244 Sig.Kind = wasm::WasmSignature::Placeholder;1245 Signatures.push_back(std::move(Sig));1246 HasUnmodeledTypes = true;1247 continue;1248 }1249 1250 uint32_t ParamCount = readVaruint32(Ctx);1251 Sig.Params.reserve(ParamCount);1252 while (ParamCount--) {1253 uint32_t ParamType = readUint8(Ctx);1254 Sig.Params.push_back(parseValType(Ctx, ParamType));1255 }1256 uint32_t ReturnCount = readVaruint32(Ctx);1257 while (ReturnCount--) {1258 uint32_t ReturnType = readUint8(Ctx);1259 Sig.Returns.push_back(parseValType(Ctx, ReturnType));1260 }1261 1262 Signatures.push_back(std::move(Sig));1263 }1264 if (Ctx.Ptr != Ctx.End)1265 return make_error<GenericBinaryError>("type section ended prematurely",1266 object_error::parse_failed);1267 return Error::success();1268}1269 1270Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {1271 uint32_t Count = readVaruint32(Ctx);1272 uint32_t NumTypes = Signatures.size();1273 Imports.reserve(Count);1274 for (uint32_t I = 0; I < Count; I++) {1275 wasm::WasmImport Im;1276 Im.Module = readString(Ctx);1277 Im.Field = readString(Ctx);1278 Im.Kind = readUint8(Ctx);1279 switch (Im.Kind) {1280 case wasm::WASM_EXTERNAL_FUNCTION:1281 NumImportedFunctions++;1282 Im.SigIndex = readVaruint32(Ctx);1283 if (Im.SigIndex >= NumTypes)1284 return make_error<GenericBinaryError>("invalid function type",1285 object_error::parse_failed);1286 break;1287 case wasm::WASM_EXTERNAL_GLOBAL:1288 NumImportedGlobals++;1289 Im.Global.Type = readUint8(Ctx);1290 Im.Global.Mutable = readVaruint1(Ctx);1291 break;1292 case wasm::WASM_EXTERNAL_MEMORY:1293 Im.Memory = readLimits(Ctx);1294 if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)1295 HasMemory64 = true;1296 break;1297 case wasm::WASM_EXTERNAL_TABLE: {1298 Im.Table = readTableType(Ctx);1299 NumImportedTables++;1300 auto ElemType = Im.Table.ElemType;1301 if (ElemType != wasm::ValType::FUNCREF &&1302 ElemType != wasm::ValType::EXTERNREF &&1303 ElemType != wasm::ValType::EXNREF &&1304 ElemType != wasm::ValType::OTHERREF)1305 return make_error<GenericBinaryError>("invalid table element type",1306 object_error::parse_failed);1307 break;1308 }1309 case wasm::WASM_EXTERNAL_TAG:1310 NumImportedTags++;1311 if (readUint8(Ctx) != 0) // Reserved 'attribute' field1312 return make_error<GenericBinaryError>("invalid attribute",1313 object_error::parse_failed);1314 Im.SigIndex = readVaruint32(Ctx);1315 if (Im.SigIndex >= NumTypes)1316 return make_error<GenericBinaryError>("invalid tag type",1317 object_error::parse_failed);1318 break;1319 default:1320 return make_error<GenericBinaryError>("unexpected import kind",1321 object_error::parse_failed);1322 }1323 Imports.push_back(Im);1324 }1325 if (Ctx.Ptr != Ctx.End)1326 return make_error<GenericBinaryError>("import section ended prematurely",1327 object_error::parse_failed);1328 return Error::success();1329}1330 1331Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {1332 uint32_t Count = readVaruint32(Ctx);1333 Functions.reserve(Count);1334 uint32_t NumTypes = Signatures.size();1335 while (Count--) {1336 uint32_t Type = readVaruint32(Ctx);1337 if (Type >= NumTypes)1338 return make_error<GenericBinaryError>("invalid function type",1339 object_error::parse_failed);1340 wasm::WasmFunction F;1341 F.SigIndex = Type;1342 Functions.push_back(F);1343 }1344 if (Ctx.Ptr != Ctx.End)1345 return make_error<GenericBinaryError>("function section ended prematurely",1346 object_error::parse_failed);1347 return Error::success();1348}1349 1350Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {1351 TableSection = Sections.size();1352 uint32_t Count = readVaruint32(Ctx);1353 Tables.reserve(Count);1354 while (Count--) {1355 wasm::WasmTable T;1356 T.Type = readTableType(Ctx);1357 T.Index = NumImportedTables + Tables.size();1358 Tables.push_back(T);1359 auto ElemType = Tables.back().Type.ElemType;1360 if (ElemType != wasm::ValType::FUNCREF &&1361 ElemType != wasm::ValType::EXTERNREF &&1362 ElemType != wasm::ValType::EXNREF &&1363 ElemType != wasm::ValType::OTHERREF) {1364 return make_error<GenericBinaryError>("invalid table element type",1365 object_error::parse_failed);1366 }1367 }1368 if (Ctx.Ptr != Ctx.End)1369 return make_error<GenericBinaryError>("table section ended prematurely",1370 object_error::parse_failed);1371 return Error::success();1372}1373 1374Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {1375 uint32_t Count = readVaruint32(Ctx);1376 Memories.reserve(Count);1377 while (Count--) {1378 auto Limits = readLimits(Ctx);1379 if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)1380 HasMemory64 = true;1381 Memories.push_back(Limits);1382 }1383 if (Ctx.Ptr != Ctx.End)1384 return make_error<GenericBinaryError>("memory section ended prematurely",1385 object_error::parse_failed);1386 return Error::success();1387}1388 1389Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {1390 TagSection = Sections.size();1391 uint32_t Count = readVaruint32(Ctx);1392 Tags.reserve(Count);1393 uint32_t NumTypes = Signatures.size();1394 while (Count--) {1395 if (readUint8(Ctx) != 0) // Reserved 'attribute' field1396 return make_error<GenericBinaryError>("invalid attribute",1397 object_error::parse_failed);1398 uint32_t Type = readVaruint32(Ctx);1399 if (Type >= NumTypes)1400 return make_error<GenericBinaryError>("invalid tag type",1401 object_error::parse_failed);1402 wasm::WasmTag Tag;1403 Tag.Index = NumImportedTags + Tags.size();1404 Tag.SigIndex = Type;1405 Signatures[Type].Kind = wasm::WasmSignature::Tag;1406 Tags.push_back(Tag);1407 }1408 1409 if (Ctx.Ptr != Ctx.End)1410 return make_error<GenericBinaryError>("tag section ended prematurely",1411 object_error::parse_failed);1412 return Error::success();1413}1414 1415Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {1416 GlobalSection = Sections.size();1417 const uint8_t *SectionStart = Ctx.Ptr;1418 uint32_t Count = readVaruint32(Ctx);1419 Globals.reserve(Count);1420 while (Count--) {1421 wasm::WasmGlobal Global;1422 Global.Index = NumImportedGlobals + Globals.size();1423 const uint8_t *GlobalStart = Ctx.Ptr;1424 Global.Offset = static_cast<uint32_t>(GlobalStart - SectionStart);1425 auto GlobalOpcode = readVaruint32(Ctx);1426 Global.Type.Type = (uint8_t)parseValType(Ctx, GlobalOpcode);1427 Global.Type.Mutable = readVaruint1(Ctx);1428 if (Error Err = readInitExpr(Global.InitExpr, Ctx))1429 return Err;1430 Global.Size = static_cast<uint32_t>(Ctx.Ptr - GlobalStart);1431 Globals.push_back(Global);1432 }1433 if (Ctx.Ptr != Ctx.End)1434 return make_error<GenericBinaryError>("global section ended prematurely",1435 object_error::parse_failed);1436 return Error::success();1437}1438 1439Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {1440 uint32_t Count = readVaruint32(Ctx);1441 Exports.reserve(Count);1442 Symbols.reserve(Count);1443 for (uint32_t I = 0; I < Count; I++) {1444 wasm::WasmExport Ex;1445 Ex.Name = readString(Ctx);1446 Ex.Kind = readUint8(Ctx);1447 Ex.Index = readVaruint32(Ctx);1448 const wasm::WasmSignature *Signature = nullptr;1449 const wasm::WasmGlobalType *GlobalType = nullptr;1450 const wasm::WasmTableType *TableType = nullptr;1451 wasm::WasmSymbolInfo Info;1452 Info.Name = Ex.Name;1453 Info.Flags = 0;1454 switch (Ex.Kind) {1455 case wasm::WASM_EXTERNAL_FUNCTION: {1456 if (!isValidFunctionIndex(Ex.Index))1457 return make_error<GenericBinaryError>("invalid function export",1458 object_error::parse_failed);1459 Info.Kind = wasm::WASM_SYMBOL_TYPE_FUNCTION;1460 Info.ElementIndex = Ex.Index;1461 if (isDefinedFunctionIndex(Ex.Index)) {1462 getDefinedFunction(Ex.Index).ExportName = Ex.Name;1463 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;1464 wasm::WasmFunction &Function = Functions[FuncIndex];1465 Signature = &Signatures[Function.SigIndex];1466 }1467 // Else the function is imported. LLVM object files don't use this1468 // pattern and we still treat this as an undefined symbol, but we want to1469 // parse it without crashing.1470 break;1471 }1472 case wasm::WASM_EXTERNAL_GLOBAL: {1473 if (!isValidGlobalIndex(Ex.Index))1474 return make_error<GenericBinaryError>("invalid global export",1475 object_error::parse_failed);1476 Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;1477 uint64_t Offset = 0;1478 if (isDefinedGlobalIndex(Ex.Index)) {1479 auto Global = getDefinedGlobal(Ex.Index);1480 if (!Global.InitExpr.Extended) {1481 auto Inst = Global.InitExpr.Inst;1482 if (Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {1483 Offset = Inst.Value.Int32;1484 } else if (Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {1485 Offset = Inst.Value.Int64;1486 }1487 }1488 }1489 Info.DataRef = wasm::WasmDataReference{0, Offset, 0};1490 break;1491 }1492 case wasm::WASM_EXTERNAL_TAG:1493 if (!isValidTagIndex(Ex.Index))1494 return make_error<GenericBinaryError>("invalid tag export",1495 object_error::parse_failed);1496 Info.Kind = wasm::WASM_SYMBOL_TYPE_TAG;1497 Info.ElementIndex = Ex.Index;1498 break;1499 case wasm::WASM_EXTERNAL_MEMORY:1500 break;1501 case wasm::WASM_EXTERNAL_TABLE:1502 Info.Kind = wasm::WASM_SYMBOL_TYPE_TABLE;1503 Info.ElementIndex = Ex.Index;1504 break;1505 default:1506 return make_error<GenericBinaryError>("unexpected export kind",1507 object_error::parse_failed);1508 }1509 Exports.push_back(Ex);1510 if (Ex.Kind != wasm::WASM_EXTERNAL_MEMORY) {1511 Symbols.emplace_back(Info, GlobalType, TableType, Signature);1512 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");1513 }1514 }1515 if (Ctx.Ptr != Ctx.End)1516 return make_error<GenericBinaryError>("export section ended prematurely",1517 object_error::parse_failed);1518 return Error::success();1519}1520 1521bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {1522 return Index < NumImportedFunctions + Functions.size();1523}1524 1525bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {1526 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);1527}1528 1529bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {1530 return Index < NumImportedGlobals + Globals.size();1531}1532 1533bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {1534 return Index < NumImportedTables + Tables.size();1535}1536 1537bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {1538 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);1539}1540 1541bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {1542 return Index >= NumImportedTables && isValidTableNumber(Index);1543}1544 1545bool WasmObjectFile::isValidTagIndex(uint32_t Index) const {1546 return Index < NumImportedTags + Tags.size();1547}1548 1549bool WasmObjectFile::isDefinedTagIndex(uint32_t Index) const {1550 return Index >= NumImportedTags && isValidTagIndex(Index);1551}1552 1553bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {1554 return Index < Symbols.size() && Symbols[Index].isTypeFunction();1555}1556 1557bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {1558 return Index < Symbols.size() && Symbols[Index].isTypeTable();1559}1560 1561bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {1562 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();1563}1564 1565bool WasmObjectFile::isValidTagSymbol(uint32_t Index) const {1566 return Index < Symbols.size() && Symbols[Index].isTypeTag();1567}1568 1569bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {1570 return Index < Symbols.size() && Symbols[Index].isTypeData();1571}1572 1573bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {1574 return Index < Symbols.size() && Symbols[Index].isTypeSection();1575}1576 1577wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {1578 assert(isDefinedFunctionIndex(Index));1579 return Functions[Index - NumImportedFunctions];1580}1581 1582const wasm::WasmFunction &1583WasmObjectFile::getDefinedFunction(uint32_t Index) const {1584 assert(isDefinedFunctionIndex(Index));1585 return Functions[Index - NumImportedFunctions];1586}1587 1588const wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) const {1589 assert(isDefinedGlobalIndex(Index));1590 return Globals[Index - NumImportedGlobals];1591}1592 1593wasm::WasmTag &WasmObjectFile::getDefinedTag(uint32_t Index) {1594 assert(isDefinedTagIndex(Index));1595 return Tags[Index - NumImportedTags];1596}1597 1598Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {1599 StartFunction = readVaruint32(Ctx);1600 if (!isValidFunctionIndex(StartFunction))1601 return make_error<GenericBinaryError>("invalid start function",1602 object_error::parse_failed);1603 return Error::success();1604}1605 1606Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {1607 CodeSection = Sections.size();1608 uint32_t FunctionCount = readVaruint32(Ctx);1609 if (FunctionCount != Functions.size()) {1610 return make_error<GenericBinaryError>("invalid function count",1611 object_error::parse_failed);1612 }1613 1614 for (uint32_t i = 0; i < FunctionCount; i++) {1615 wasm::WasmFunction& Function = Functions[i];1616 const uint8_t *FunctionStart = Ctx.Ptr;1617 uint32_t Size = readVaruint32(Ctx);1618 const uint8_t *FunctionEnd = Ctx.Ptr + Size;1619 1620 Function.CodeOffset = Ctx.Ptr - FunctionStart;1621 Function.Index = NumImportedFunctions + i;1622 Function.CodeSectionOffset = FunctionStart - Ctx.Start;1623 Function.Size = FunctionEnd - FunctionStart;1624 1625 uint32_t NumLocalDecls = readVaruint32(Ctx);1626 Function.Locals.reserve(NumLocalDecls);1627 while (NumLocalDecls--) {1628 wasm::WasmLocalDecl Decl;1629 Decl.Count = readVaruint32(Ctx);1630 Decl.Type = readUint8(Ctx);1631 Function.Locals.push_back(Decl);1632 }1633 1634 uint32_t BodySize = FunctionEnd - Ctx.Ptr;1635 // Ensure that Function is within Ctx's buffer.1636 if (Ctx.Ptr + BodySize > Ctx.End) {1637 return make_error<GenericBinaryError>("Function extends beyond buffer",1638 object_error::parse_failed);1639 }1640 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);1641 // This will be set later when reading in the linking metadata section.1642 Function.Comdat = UINT32_MAX;1643 Ctx.Ptr += BodySize;1644 assert(Ctx.Ptr == FunctionEnd);1645 }1646 if (Ctx.Ptr != Ctx.End)1647 return make_error<GenericBinaryError>("code section ended prematurely",1648 object_error::parse_failed);1649 return Error::success();1650}1651 1652Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {1653 uint32_t Count = readVaruint32(Ctx);1654 ElemSegments.reserve(Count);1655 while (Count--) {1656 wasm::WasmElemSegment Segment;1657 Segment.Flags = readVaruint32(Ctx);1658 1659 uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |1660 wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |1661 wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;1662 if (Segment.Flags & ~SupportedFlags)1663 return make_error<GenericBinaryError>(1664 "Unsupported flags for element segment", object_error::parse_failed);1665 1666 wasm::ElemSegmentMode Mode;1667 if ((Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) == 0) {1668 Mode = wasm::ElemSegmentMode::Active;1669 } else if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE) {1670 Mode = wasm::ElemSegmentMode::Declarative;1671 } else {1672 Mode = wasm::ElemSegmentMode::Passive;1673 }1674 bool HasTableNumber =1675 Mode == wasm::ElemSegmentMode::Active &&1676 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER);1677 bool HasElemKind =1678 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC) &&1679 !(Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);1680 bool HasElemType =1681 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC) &&1682 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);1683 bool HasInitExprs =1684 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);1685 1686 if (HasTableNumber)1687 Segment.TableNumber = readVaruint32(Ctx);1688 else1689 Segment.TableNumber = 0;1690 1691 if (!isValidTableNumber(Segment.TableNumber))1692 return make_error<GenericBinaryError>("invalid TableNumber",1693 object_error::parse_failed);1694 1695 if (Mode != wasm::ElemSegmentMode::Active) {1696 Segment.Offset.Extended = false;1697 Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;1698 Segment.Offset.Inst.Value.Int32 = 0;1699 } else {1700 if (Error Err = readInitExpr(Segment.Offset, Ctx))1701 return Err;1702 }1703 1704 if (HasElemKind) {1705 auto ElemKind = readVaruint32(Ctx);1706 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {1707 Segment.ElemKind = parseValType(Ctx, ElemKind);1708 if (Segment.ElemKind != wasm::ValType::FUNCREF &&1709 Segment.ElemKind != wasm::ValType::EXTERNREF &&1710 Segment.ElemKind != wasm::ValType::EXNREF &&1711 Segment.ElemKind != wasm::ValType::OTHERREF) {1712 return make_error<GenericBinaryError>("invalid elem type",1713 object_error::parse_failed);1714 }1715 } else {1716 if (ElemKind != 0)1717 return make_error<GenericBinaryError>("invalid elem type",1718 object_error::parse_failed);1719 Segment.ElemKind = wasm::ValType::FUNCREF;1720 }1721 } else if (HasElemType) {1722 auto ElemType = parseValType(Ctx, readVaruint32(Ctx));1723 Segment.ElemKind = ElemType;1724 } else {1725 Segment.ElemKind = wasm::ValType::FUNCREF;1726 }1727 1728 uint32_t NumElems = readVaruint32(Ctx);1729 1730 if (HasInitExprs) {1731 while (NumElems--) {1732 wasm::WasmInitExpr Expr;1733 if (Error Err = readInitExpr(Expr, Ctx))1734 return Err;1735 }1736 } else {1737 while (NumElems--) {1738 Segment.Functions.push_back(readVaruint32(Ctx));1739 }1740 }1741 ElemSegments.push_back(Segment);1742 }1743 if (Ctx.Ptr != Ctx.End)1744 return make_error<GenericBinaryError>("elem section ended prematurely",1745 object_error::parse_failed);1746 return Error::success();1747}1748 1749Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {1750 DataSection = Sections.size();1751 uint32_t Count = readVaruint32(Ctx);1752 if (DataCount && Count != *DataCount)1753 return make_error<GenericBinaryError>(1754 "number of data segments does not match DataCount section");1755 DataSegments.reserve(Count);1756 while (Count--) {1757 WasmSegment Segment;1758 Segment.Data.InitFlags = readVaruint32(Ctx);1759 Segment.Data.MemoryIndex =1760 (Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)1761 ? readVaruint32(Ctx)1762 : 0;1763 if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {1764 if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))1765 return Err;1766 } else {1767 Segment.Data.Offset.Extended = false;1768 Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;1769 Segment.Data.Offset.Inst.Value.Int32 = 0;1770 }1771 uint32_t Size = readVaruint32(Ctx);1772 if (Size > (size_t)(Ctx.End - Ctx.Ptr))1773 return make_error<GenericBinaryError>("invalid segment size",1774 object_error::parse_failed);1775 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);1776 // The rest of these Data fields are set later, when reading in the linking1777 // metadata section.1778 Segment.Data.Alignment = 0;1779 Segment.Data.LinkingFlags = 0;1780 Segment.Data.Comdat = UINT32_MAX;1781 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;1782 Ctx.Ptr += Size;1783 DataSegments.push_back(Segment);1784 }1785 if (Ctx.Ptr != Ctx.End)1786 return make_error<GenericBinaryError>("data section ended prematurely",1787 object_error::parse_failed);1788 return Error::success();1789}1790 1791Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {1792 DataCount = readVaruint32(Ctx);1793 return Error::success();1794}1795 1796const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {1797 return Header;1798}1799 1800void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }1801 1802Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {1803 uint32_t Result = SymbolRef::SF_None;1804 const WasmSymbol &Sym = getWasmSymbol(Symb);1805 1806 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");1807 if (Sym.isBindingWeak())1808 Result |= SymbolRef::SF_Weak;1809 if (!Sym.isBindingLocal())1810 Result |= SymbolRef::SF_Global;1811 if (Sym.isHidden())1812 Result |= SymbolRef::SF_Hidden;1813 if (!Sym.isDefined())1814 Result |= SymbolRef::SF_Undefined;1815 if (Sym.isTypeFunction())1816 Result |= SymbolRef::SF_Executable;1817 return Result;1818}1819 1820basic_symbol_iterator WasmObjectFile::symbol_begin() const {1821 DataRefImpl Ref;1822 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null1823 Ref.d.b = 0; // Symbol index1824 return BasicSymbolRef(Ref, this);1825}1826 1827basic_symbol_iterator WasmObjectFile::symbol_end() const {1828 DataRefImpl Ref;1829 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null1830 Ref.d.b = Symbols.size(); // Symbol index1831 return BasicSymbolRef(Ref, this);1832}1833 1834const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {1835 return Symbols[Symb.d.b];1836}1837 1838const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {1839 return getWasmSymbol(Symb.getRawDataRefImpl());1840}1841 1842Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {1843 return getWasmSymbol(Symb).Info.Name;1844}1845 1846Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {1847 auto &Sym = getWasmSymbol(Symb);1848 if (!Sym.isDefined())1849 return 0;1850 Expected<section_iterator> Sec = getSymbolSection(Symb);1851 if (!Sec)1852 return Sec.takeError();1853 uint32_t SectionAddress = getSectionAddress(Sec.get()->getRawDataRefImpl());1854 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&1855 isDefinedFunctionIndex(Sym.Info.ElementIndex)) {1856 return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset +1857 SectionAddress;1858 }1859 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL &&1860 isDefinedGlobalIndex(Sym.Info.ElementIndex)) {1861 return getDefinedGlobal(Sym.Info.ElementIndex).Offset + SectionAddress;1862 }1863 1864 return getSymbolValue(Symb);1865}1866 1867uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {1868 switch (Sym.Info.Kind) {1869 case wasm::WASM_SYMBOL_TYPE_FUNCTION:1870 case wasm::WASM_SYMBOL_TYPE_GLOBAL:1871 case wasm::WASM_SYMBOL_TYPE_TAG:1872 case wasm::WASM_SYMBOL_TYPE_TABLE:1873 return Sym.Info.ElementIndex;1874 case wasm::WASM_SYMBOL_TYPE_DATA: {1875 // The value of a data symbol is the segment offset, plus the symbol1876 // offset within the segment.1877 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;1878 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;1879 if (Segment.Offset.Extended) {1880 llvm_unreachable("extended init exprs not supported");1881 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {1882 return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;1883 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {1884 return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;1885 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_GLOBAL_GET) {1886 return Sym.Info.DataRef.Offset;1887 } else {1888 llvm_unreachable("unknown init expr opcode");1889 }1890 }1891 case wasm::WASM_SYMBOL_TYPE_SECTION:1892 return 0;1893 }1894 llvm_unreachable("invalid symbol type");1895}1896 1897uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {1898 return getWasmSymbolValue(getWasmSymbol(Symb));1899}1900 1901uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {1902 llvm_unreachable("not yet implemented");1903 return 0;1904}1905 1906uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {1907 llvm_unreachable("not yet implemented");1908 return 0;1909}1910 1911Expected<SymbolRef::Type>1912WasmObjectFile::getSymbolType(DataRefImpl Symb) const {1913 const WasmSymbol &Sym = getWasmSymbol(Symb);1914 1915 switch (Sym.Info.Kind) {1916 case wasm::WASM_SYMBOL_TYPE_FUNCTION:1917 return SymbolRef::ST_Function;1918 case wasm::WASM_SYMBOL_TYPE_GLOBAL:1919 return SymbolRef::ST_Other;1920 case wasm::WASM_SYMBOL_TYPE_DATA:1921 return SymbolRef::ST_Data;1922 case wasm::WASM_SYMBOL_TYPE_SECTION:1923 return SymbolRef::ST_Debug;1924 case wasm::WASM_SYMBOL_TYPE_TAG:1925 return SymbolRef::ST_Other;1926 case wasm::WASM_SYMBOL_TYPE_TABLE:1927 return SymbolRef::ST_Other;1928 }1929 1930 llvm_unreachable("unknown WasmSymbol::SymbolType");1931 return SymbolRef::ST_Other;1932}1933 1934Expected<section_iterator>1935WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {1936 const WasmSymbol &Sym = getWasmSymbol(Symb);1937 if (Sym.isUndefined())1938 return section_end();1939 1940 DataRefImpl Ref;1941 Ref.d.a = getSymbolSectionIdImpl(Sym);1942 return section_iterator(SectionRef(Ref, this));1943}1944 1945uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {1946 const WasmSymbol &Sym = getWasmSymbol(Symb);1947 return getSymbolSectionIdImpl(Sym);1948}1949 1950uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {1951 switch (Sym.Info.Kind) {1952 case wasm::WASM_SYMBOL_TYPE_FUNCTION:1953 return CodeSection;1954 case wasm::WASM_SYMBOL_TYPE_GLOBAL:1955 return GlobalSection;1956 case wasm::WASM_SYMBOL_TYPE_DATA:1957 return DataSection;1958 case wasm::WASM_SYMBOL_TYPE_SECTION:1959 return Sym.Info.ElementIndex;1960 case wasm::WASM_SYMBOL_TYPE_TAG:1961 return TagSection;1962 case wasm::WASM_SYMBOL_TYPE_TABLE:1963 return TableSection;1964 default:1965 llvm_unreachable("unknown WasmSymbol::SymbolType");1966 }1967}1968 1969uint32_t WasmObjectFile::getSymbolSize(SymbolRef Symb) const {1970 const WasmSymbol &Sym = getWasmSymbol(Symb);1971 if (!Sym.isDefined())1972 return 0;1973 if (Sym.isTypeGlobal())1974 return getDefinedGlobal(Sym.Info.ElementIndex).Size;1975 if (Sym.isTypeData())1976 return Sym.Info.DataRef.Size;1977 if (Sym.isTypeFunction())1978 return functions()[Sym.Info.ElementIndex - getNumImportedFunctions()].Size;1979 // Currently symbol size is only tracked for data segments and functions. In1980 // principle we could also track size (e.g. binary size) for tables, globals1981 // and element segments etc too.1982 return 0;1983}1984 1985void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }1986 1987Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {1988 const WasmSection &S = Sections[Sec.d.a];1989 if (S.Type == wasm::WASM_SEC_CUSTOM)1990 return S.Name;1991 if (S.Type > wasm::WASM_SEC_LAST_KNOWN)1992 return createStringError(object_error::invalid_section_index, "");1993 return wasm::sectionTypeToString(S.Type);1994}1995 1996uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const {1997 // For object files, use 0 for section addresses, and section offsets for1998 // symbol addresses. For linked files, use file offsets.1999 // See also getSymbolAddress.2000 return isRelocatableObject() || isSharedObject() ? 02001 : Sections[Sec.d.a].Offset;2002}2003 2004uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {2005 return Sec.d.a;2006}2007 2008uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {2009 const WasmSection &S = Sections[Sec.d.a];2010 return S.Content.size();2011}2012 2013Expected<ArrayRef<uint8_t>>2014WasmObjectFile::getSectionContents(DataRefImpl Sec) const {2015 const WasmSection &S = Sections[Sec.d.a];2016 // This will never fail since wasm sections can never be empty (user-sections2017 // must have a name and non-user sections each have a defined structure).2018 return S.Content;2019}2020 2021uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {2022 return 1;2023}2024 2025bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {2026 return false;2027}2028 2029bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {2030 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;2031}2032 2033bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {2034 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;2035}2036 2037bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }2038 2039bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }2040 2041relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {2042 DataRefImpl RelocRef;2043 RelocRef.d.a = Ref.d.a;2044 RelocRef.d.b = 0;2045 return relocation_iterator(RelocationRef(RelocRef, this));2046}2047 2048relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {2049 const WasmSection &Sec = getWasmSection(Ref);2050 DataRefImpl RelocRef;2051 RelocRef.d.a = Ref.d.a;2052 RelocRef.d.b = Sec.Relocations.size();2053 return relocation_iterator(RelocationRef(RelocRef, this));2054}2055 2056void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }2057 2058uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {2059 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);2060 return Rel.Offset;2061}2062 2063symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {2064 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);2065 if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)2066 return symbol_end();2067 DataRefImpl Sym;2068 Sym.d.a = 1;2069 Sym.d.b = Rel.Index;2070 return symbol_iterator(SymbolRef(Sym, this));2071}2072 2073uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {2074 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);2075 return Rel.Type;2076}2077 2078void WasmObjectFile::getRelocationTypeName(2079 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {2080 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);2081 StringRef Res = "Unknown";2082 2083#define WASM_RELOC(name, value) \2084 case wasm::name: \2085 Res = #name; \2086 break;2087 2088 switch (Rel.Type) {2089#include "llvm/BinaryFormat/WasmRelocs.def"2090 }2091 2092#undef WASM_RELOC2093 2094 Result.append(Res.begin(), Res.end());2095}2096 2097section_iterator WasmObjectFile::section_begin() const {2098 DataRefImpl Ref;2099 Ref.d.a = 0;2100 return section_iterator(SectionRef(Ref, this));2101}2102 2103section_iterator WasmObjectFile::section_end() const {2104 DataRefImpl Ref;2105 Ref.d.a = Sections.size();2106 return section_iterator(SectionRef(Ref, this));2107}2108 2109uint8_t WasmObjectFile::getBytesInAddress() const {2110 return HasMemory64 ? 8 : 4;2111}2112 2113StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }2114 2115Triple::ArchType WasmObjectFile::getArch() const {2116 return HasMemory64 ? Triple::wasm64 : Triple::wasm32;2117}2118 2119Expected<SubtargetFeatures> WasmObjectFile::getFeatures() const {2120 return SubtargetFeatures();2121}2122 2123bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }2124 2125bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }2126 2127const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {2128 assert(Ref.d.a < Sections.size());2129 return Sections[Ref.d.a];2130}2131 2132const WasmSection &2133WasmObjectFile::getWasmSection(const SectionRef &Section) const {2134 return getWasmSection(Section.getRawDataRefImpl());2135}2136 2137const wasm::WasmRelocation &2138WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {2139 return getWasmRelocation(Ref.getRawDataRefImpl());2140}2141 2142const wasm::WasmRelocation &2143WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {2144 assert(Ref.d.a < Sections.size());2145 const WasmSection &Sec = Sections[Ref.d.a];2146 assert(Ref.d.b < Sec.Relocations.size());2147 return Sec.Relocations[Ref.d.b];2148}2149 2150int WasmSectionOrderChecker::getSectionOrder(unsigned ID,2151 StringRef CustomSectionName) {2152 switch (ID) {2153 case wasm::WASM_SEC_CUSTOM:2154 return StringSwitch<unsigned>(CustomSectionName)2155 .Case("dylink", WASM_SEC_ORDER_DYLINK)2156 .Case("dylink.0", WASM_SEC_ORDER_DYLINK)2157 .Case("linking", WASM_SEC_ORDER_LINKING)2158 .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)2159 .Case("name", WASM_SEC_ORDER_NAME)2160 .Case("producers", WASM_SEC_ORDER_PRODUCERS)2161 .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)2162 .Default(WASM_SEC_ORDER_NONE);2163 case wasm::WASM_SEC_TYPE:2164 return WASM_SEC_ORDER_TYPE;2165 case wasm::WASM_SEC_IMPORT:2166 return WASM_SEC_ORDER_IMPORT;2167 case wasm::WASM_SEC_FUNCTION:2168 return WASM_SEC_ORDER_FUNCTION;2169 case wasm::WASM_SEC_TABLE:2170 return WASM_SEC_ORDER_TABLE;2171 case wasm::WASM_SEC_MEMORY:2172 return WASM_SEC_ORDER_MEMORY;2173 case wasm::WASM_SEC_GLOBAL:2174 return WASM_SEC_ORDER_GLOBAL;2175 case wasm::WASM_SEC_EXPORT:2176 return WASM_SEC_ORDER_EXPORT;2177 case wasm::WASM_SEC_START:2178 return WASM_SEC_ORDER_START;2179 case wasm::WASM_SEC_ELEM:2180 return WASM_SEC_ORDER_ELEM;2181 case wasm::WASM_SEC_CODE:2182 return WASM_SEC_ORDER_CODE;2183 case wasm::WASM_SEC_DATA:2184 return WASM_SEC_ORDER_DATA;2185 case wasm::WASM_SEC_DATACOUNT:2186 return WASM_SEC_ORDER_DATACOUNT;2187 case wasm::WASM_SEC_TAG:2188 return WASM_SEC_ORDER_TAG;2189 default:2190 return WASM_SEC_ORDER_NONE;2191 }2192}2193 2194// Represents the edges in a directed graph where any node B reachable from node2195// A is not allowed to appear before A in the section ordering, but may appear2196// afterward.2197int WasmSectionOrderChecker::DisallowedPredecessors2198 [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {2199 // WASM_SEC_ORDER_NONE2200 {},2201 // WASM_SEC_ORDER_TYPE2202 {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},2203 // WASM_SEC_ORDER_IMPORT2204 {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},2205 // WASM_SEC_ORDER_FUNCTION2206 {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},2207 // WASM_SEC_ORDER_TABLE2208 {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},2209 // WASM_SEC_ORDER_MEMORY2210 {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_TAG},2211 // WASM_SEC_ORDER_TAG2212 {WASM_SEC_ORDER_TAG, WASM_SEC_ORDER_GLOBAL},2213 // WASM_SEC_ORDER_GLOBAL2214 {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},2215 // WASM_SEC_ORDER_EXPORT2216 {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},2217 // WASM_SEC_ORDER_START2218 {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},2219 // WASM_SEC_ORDER_ELEM2220 {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},2221 // WASM_SEC_ORDER_DATACOUNT2222 {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},2223 // WASM_SEC_ORDER_CODE2224 {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},2225 // WASM_SEC_ORDER_DATA2226 {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},2227 2228 // Custom Sections2229 // WASM_SEC_ORDER_DYLINK2230 {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},2231 // WASM_SEC_ORDER_LINKING2232 {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},2233 // WASM_SEC_ORDER_RELOC (can be repeated)2234 {},2235 // WASM_SEC_ORDER_NAME2236 {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},2237 // WASM_SEC_ORDER_PRODUCERS2238 {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},2239 // WASM_SEC_ORDER_TARGET_FEATURES2240 {WASM_SEC_ORDER_TARGET_FEATURES}};2241 2242bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,2243 StringRef CustomSectionName) {2244 int Order = getSectionOrder(ID, CustomSectionName);2245 if (Order == WASM_SEC_ORDER_NONE)2246 return true;2247 2248 // Disallowed predecessors we need to check for2249 SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;2250 2251 // Keep track of completed checks to avoid repeating work2252 bool Checked[WASM_NUM_SEC_ORDERS] = {};2253 2254 int Curr = Order;2255 while (true) {2256 // Add new disallowed predecessors to work list2257 for (size_t I = 0;; ++I) {2258 int Next = DisallowedPredecessors[Curr][I];2259 if (Next == WASM_SEC_ORDER_NONE)2260 break;2261 if (Checked[Next])2262 continue;2263 WorkList.push_back(Next);2264 Checked[Next] = true;2265 }2266 2267 if (WorkList.empty())2268 break;2269 2270 // Consider next disallowed predecessor2271 Curr = WorkList.pop_back_val();2272 if (Seen[Curr])2273 return false;2274 }2275 2276 // Have not seen any disallowed predecessors2277 Seen[Order] = true;2278 return true;2279}2280