[[nodiscard]] Result ReadInitExpr(Index index);
[[nodiscard]] Result ReadTable(Type* out_elem_type, Limits* out_elem_limits);
[[nodiscard]] Result ReadMemory(Limits* out_page_limits,
uint32_t* out_page_size);
[[nodiscard]] Result ReadGlobalHeader(Type* out_type, bool* out_mutable);
[[nodiscard]] Result ReadTagType(Index* out_sig_index);
[[nodiscard]] Result ReadAddress(Address* out_value,
Index memory, const char* desc);
[[nodiscard]] Result ReadFunctionBody(Offset end_offset); // ReadInstructions reads until end_offset or the nesting depth reaches zero.
[[nodiscard]] Result ReadInstructions(Offset end_offset, const char* context);
[[nodiscard]] Result ReadNameSection(Offset section_size);
[[nodiscard]] Result ReadRelocSection(Offset section_size);
[[nodiscard]] Result ReadDylinkSection(Offset section_size);
[[nodiscard]] Result ReadGenericCustomSection(std::string_view name,
Offset section_size);
[[nodiscard]] Result ReadDylink0Section(Offset section_size);
[[nodiscard]] Result ReadTargetFeaturesSections(Offset section_size);
[[nodiscard]] Result ReadLinkingSection(Offset section_size);
[[nodiscard]] Result ReadCodeMetadataSection(std::string_view name,
Offset section_size);
[[nodiscard]] Result ReadCustomSection(Index section_index,
Offset section_size);
[[nodiscard]] Result ReadTypeSection(Offset section_size);
[[nodiscard]] Result ReadImportSection(Offset section_size);
[[nodiscard]] Result ReadFunctionSection(Offset section_size);
[[nodiscard]] Result ReadTableSection(Offset section_size);
[[nodiscard]] Result ReadMemorySection(Offset section_size);
[[nodiscard]] Result ReadGlobalSection(Offset section_size);
[[nodiscard]] Result ReadExportSection(Offset section_size);
[[nodiscard]] Result ReadStartSection(Offset section_size);
[[nodiscard]] Result ReadElemSection(Offset section_size);
[[nodiscard]] Result ReadCodeSection(Offset section_size);
[[nodiscard]] Result ReadDataSection(Offset section_size);
[[nodiscard]] Result ReadDataCountSection(Offset section_size);
[[nodiscard]] Result ReadTagSection(Offset section_size);
[[nodiscard]] Result ReadSections(const ReadSectionsOptions& options);
Result ReportUnexpectedOpcode(Opcode opcode, const char* message = nullptr);
size_t read_end_ = 0; // Either the section end or data_size.
BinaryReaderDelegate::State state_;
BinaryReaderLogging logging_delegate_;
BinaryReaderDelegate* delegate_ = nullptr;
TypeVector param_types_;
TypeVector result_types_;
TypeMutVector fields_;
std::vector<Index> target_depths_; const ReadBinaryOptions& options_;
BinarySection last_known_section_ = BinarySection::Invalid; bool did_read_names_section_ = false; bool reading_custom_section_ = false;
Index num_func_imports_ = 0;
Index num_table_imports_ = 0;
Index num_memory_imports_ = 0;
Index num_global_imports_ = 0;
Index num_tag_imports_ = 0;
Index num_function_signatures_ = 0;
Index num_function_bodies_ = 0;
Index num_data_segments_ = 0;
Index data_count_ = kInvalidIndex;
using ReadEndRestoreGuard =
ValueRestoreGuard<size_t, &BinaryReader::read_end_>;
};
if (!handled) { // Not great to just print, but we don't want to eat the error either.
fprintf(stderr, "%07" PRIzx ": %s: %s\n", state_.offset,
GetErrorLevelName(error_level), buffer);
}
}
Result BinaryReader::ReadCount(Index* count, const char* desc) {
CHECK_RESULT(ReadIndex(count, desc));
// This check assumes that each item follows in this section, and takes at // least 1 byte. It's possible that this check passes but reading fails // later. It is still useful to check here, though, because it early-outs // when an erroneous large count is used, before allocating memory for it.
size_t section_remaining = read_end_ - state_.offset;
if (*count > section_remaining) {
PrintError("invalid %s %" PRIindex ", only %" PRIzd " bytes left in section",
desc, *count, section_remaining); return Result::Error;
} return Result::Ok;
}
Result BinaryReader::ReadField(TypeMut* out_value) { // TODO: Reuse for global header too?
Type field_type;
CHECK_RESULT(ReadType(&field_type, "field type"));
ERROR_UNLESS(IsConcreteType(field_type), "expected valid field type (got " PRItypecode ")",
WABT_PRINTF_TYPE_CODE(field_type));
uint8_t mutable_ = 0;
CHECK_RESULT(ReadU8(&mutable_, "field mutability"));
ERROR_UNLESS(mutable_ <= 1, "field mutability must be 0 or 1");
out_value->type = field_type;
out_value->mutable_ = mutable_; return Result::Ok;
}
bool BinaryReader::IsConcreteType(Type type) { switch (type) { case Type::I32: case Type::I64: case Type::F32: case Type::F64: returntrue;
case Type::V128: return options_.features.simd_enabled();
case Type::FuncRef: case Type::ExternRef: return options_.features.reference_types_enabled();
case Type::ExnRef: return options_.features.exceptions_enabled();
case Type::Reference: return options_.features.function_references_enabled();
default: return false;
}
}
bool BinaryReader::IsBlockType(Type type) {
if (IsConcreteType(type) || type == Type::Void) { returntrue;
}
if (!(options_.features.multi_value_enabled() && type.IsIndex())) { return false;
}
returntrue;
}
Index BinaryReader::NumTotalFuncs() { return num_func_imports_ + num_function_signatures_;
}
Result BinaryReader::ReadAddress(Address* out_value,
Index memory, const char* desc) {
if (options_.features.memory64_enabled()) { return ReadU64Leb128(out_value, desc);
} else {
uint32_t val;
Result res = ReadU32Leb128(&val, desc);
*out_value = val; return res;
}
}
Result BinaryReader::ReadFunctionBody(Offset end_offset) {
CHECK_RESULT(ReadInstructions(end_offset, "function body"));
ERROR_UNLESS(state_.offset == end_offset, "function body shorter than given size"); return Result::Ok;
}
case Opcode::Else:
ERROR_IF(nested_blocks.empty() || (nested_blocks.top() != Opcode::If), "else outside if block");
CALLBACK0(OnElseExpr);
CALLBACK0(OnOpcodeBare); break;
case Opcode::SelectT: {
Index num_results;
CHECK_RESULT(ReadCount(&num_results, "num result types"));
result_types_.resize(num_results);
for (Index i = 0; i < num_results; ++i) {
Type result_type;
CHECK_RESULT(ReadType(&result_type, "select result type"));
ERROR_UNLESS(IsConcreteType(result_type), "expected valid select result type (got " PRItypecode ")",
WABT_PRINTF_TYPE_CODE(result_type));
result_types_[i] = result_type;
}
case Opcode::Select:
CALLBACK(OnSelectExpr, 0, nullptr);
CALLBACK0(OnOpcodeBare); break;
case Opcode::Br: {
Index depth;
CHECK_RESULT(ReadIndex(&depth, "br depth"));
CALLBACK(OnBrExpr, depth);
CALLBACK(OnOpcodeIndex, depth); break;
}
case Opcode::BrIf: {
Index depth;
CHECK_RESULT(ReadIndex(&depth, "br_if depth"));
CALLBACK(OnBrIfExpr, depth);
CALLBACK(OnOpcodeIndex, depth); break;
}
case Opcode::BrTable: {
Index num_targets;
CHECK_RESULT(ReadCount(&num_targets, "br_table target count"));
target_depths_.resize(num_targets);
for (Index i = 0; i < num_targets; ++i) {
Index target_depth;
CHECK_RESULT(ReadIndex(&target_depth, "br_table target depth"));
target_depths_[i] = target_depth;
}
Index default_target_depth;
CHECK_RESULT(
ReadIndex(&default_target_depth, "br_table default target depth"));
case Opcode::GlobalGet: {
Index global_index;
CHECK_RESULT(ReadIndex(&global_index, "global.get global index"));
CALLBACK(OnGlobalGetExpr, global_index);
CALLBACK(OnOpcodeIndex, global_index); break;
}
case Opcode::LocalGet: {
Index local_index;
CHECK_RESULT(ReadIndex(&local_index, "local.get local index"));
CALLBACK(OnLocalGetExpr, local_index);
CALLBACK(OnOpcodeIndex, local_index); break;
}
case Opcode::GlobalSet: {
Index global_index;
CHECK_RESULT(ReadIndex(&global_index, "global.set global index"));
CALLBACK(OnGlobalSetExpr, global_index);
CALLBACK(OnOpcodeIndex, global_index); break;
}
case Opcode::LocalSet: {
Index local_index;
CHECK_RESULT(ReadIndex(&local_index, "local.set local index"));
CALLBACK(OnLocalSetExpr, local_index);
CALLBACK(OnOpcodeIndex, local_index); break;
}
case Opcode::Call: {
Index func_index;
CHECK_RESULT(ReadIndex(&func_index, "call function index"));
CALLBACK(OnCallExpr, func_index);
CALLBACK(OnOpcodeIndex, func_index); break;
}
case Opcode::CallIndirect: {
Index sig_index;
CHECK_RESULT(ReadIndex(&sig_index, "call_indirect signature index"));
Index table_index = 0;
if (options_.features.reference_types_enabled()) {
CHECK_RESULT(ReadIndex(&table_index, "call_indirect table index"));
} else {
uint8_t reserved;
CHECK_RESULT(ReadU8(&reserved, "call_indirect reserved"));
ERROR_UNLESS(reserved == 0, "call_indirect reserved value must be 0");
}
CALLBACK(OnCallIndirectExpr, sig_index, table_index);
CALLBACK(OnOpcodeUint32Uint32, sig_index, table_index); break;
}
case Opcode::ReturnCall: {
Index func_index;
CHECK_RESULT(ReadIndex(&func_index, "return_call"));
CALLBACK(OnReturnCallExpr, func_index);
CALLBACK(OnOpcodeIndex, func_index); break;
}
case Opcode::ReturnCallIndirect: {
Index sig_index;
CHECK_RESULT(ReadIndex(&sig_index, "return_call_indirect"));
Index table_index = 0;
if (options_.features.reference_types_enabled()) {
CHECK_RESULT(
ReadIndex(&table_index, "return_call_indirect table index"));
} else {
uint8_t reserved;
CHECK_RESULT(ReadU8(&reserved, "return_call_indirect reserved"));
ERROR_UNLESS(reserved == 0, "return_call_indirect reserved value must be 0");
}
CALLBACK(OnReturnCallIndirectExpr, sig_index, table_index);
CALLBACK(OnOpcodeUint32Uint32, sig_index, table_index); break;
}
case Opcode::LocalTee: {
Index local_index;
CHECK_RESULT(ReadIndex(&local_index, "local.tee local index"));
CALLBACK(OnLocalTeeExpr, local_index);
CALLBACK(OnOpcodeIndex, local_index); break;
}
case Opcode::I32Load8S: case Opcode::I32Load8U: case Opcode::I32Load16S: case Opcode::I32Load16U: case Opcode::I64Load8S: case Opcode::I64Load8U: case Opcode::I64Load16S: case Opcode::I64Load16U: case Opcode::I64Load32S: case Opcode::I64Load32U: case Opcode::I32Load: case Opcode::I64Load: case Opcode::F32Load: case Opcode::F64Load: case Opcode::V128Load: case Opcode::V128Load8X8S: case Opcode::V128Load8X8U: case Opcode::V128Load16X4S: case Opcode::V128Load16X4U: case Opcode::V128Load32X2S: case Opcode::V128Load32X2U: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "load alignment", "load memidx", "load offset"));
CALLBACK(OnLoadExpr, opcode, memidx, alignment_log2, offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
}
case Opcode::I32Store8: case Opcode::I32Store16: case Opcode::I64Store8: case Opcode::I64Store16: case Opcode::I64Store32: case Opcode::I32Store: case Opcode::I64Store: case Opcode::F32Store: case Opcode::F64Store: case Opcode::V128Store: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "store alignment", "store memidx", "store offset"));
CALLBACK(OnStoreExpr, opcode, memidx, alignment_log2, offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
}
case Opcode::MemorySize: {
Index memidx = 0;
if (!options_.features.multi_memory_enabled()) {
uint8_t reserved;
CHECK_RESULT(ReadU8(&reserved, "memory.size reserved"));
ERROR_UNLESS(reserved == 0, "memory.size reserved value must be 0");
} else {
CHECK_RESULT(ReadMemidx(&memidx, "memory.size memidx"));
}
CALLBACK(OnMemorySizeExpr, memidx);
CALLBACK(OnOpcodeUint32, memidx); break;
}
case Opcode::MemoryGrow: {
Index memidx = 0;
if (!options_.features.multi_memory_enabled()) {
uint8_t reserved;
CHECK_RESULT(ReadU8(&reserved, "memory.grow reserved"));
ERROR_UNLESS(reserved == 0, "memory.grow reserved value must be 0");
} else {
CHECK_RESULT(ReadMemidx(&memidx, "memory.grow memidx"));
}
CALLBACK(OnMemoryGrowExpr, memidx);
CALLBACK(OnOpcodeUint32, memidx); break;
}
case Opcode::I32Add: case Opcode::I32Sub: case Opcode::I32Mul: case Opcode::I32DivS: case Opcode::I32DivU: case Opcode::I32RemS: case Opcode::I32RemU: case Opcode::I32And: case Opcode::I32Or: case Opcode::I32Xor: case Opcode::I32Shl: case Opcode::I32ShrU: case Opcode::I32ShrS: case Opcode::I32Rotr: case Opcode::I32Rotl: case Opcode::I64Add: case Opcode::I64Sub: case Opcode::I64Mul: case Opcode::I64DivS: case Opcode::I64DivU: case Opcode::I64RemS: case Opcode::I64RemU: case Opcode::I64And: case Opcode::I64Or: case Opcode::I64Xor: case Opcode::I64Shl: case Opcode::I64ShrU: case Opcode::I64ShrS: case Opcode::I64Rotr: case Opcode::I64Rotl: case Opcode::F32Add: case Opcode::F32Sub: case Opcode::F32Mul: case Opcode::F32Div: case Opcode::F32Min: case Opcode::F32Max: case Opcode::F32Copysign: case Opcode::F64Add: case Opcode::F64Sub: case Opcode::F64Mul: case Opcode::F64Div: case Opcode::F64Min: case Opcode::F64Max: case Opcode::F64Copysign: case Opcode::I8X16Add: case Opcode::I16X8Add: case Opcode::I32X4Add: case Opcode::I64X2Add: case Opcode::I8X16Sub: case Opcode::I16X8Sub: case Opcode::I32X4Sub: case Opcode::I64X2Sub: case Opcode::I16X8Mul: case Opcode::I32X4Mul: case Opcode::I64X2Mul: case Opcode::I8X16AddSatS: case Opcode::I8X16AddSatU: case Opcode::I16X8AddSatS: case Opcode::I16X8AddSatU: case Opcode::I8X16SubSatS: case Opcode::I8X16SubSatU: case Opcode::I16X8SubSatS: case Opcode::I16X8SubSatU: case Opcode::I8X16MinS: case Opcode::I16X8MinS: case Opcode::I32X4MinS: case Opcode::I8X16MinU: case Opcode::I16X8MinU: case Opcode::I32X4MinU: case Opcode::I8X16MaxS: case Opcode::I16X8MaxS: case Opcode::I32X4MaxS: case Opcode::I8X16MaxU: case Opcode::I16X8MaxU: case Opcode::I32X4MaxU: case Opcode::I8X16Shl: case Opcode::I16X8Shl: case Opcode::I32X4Shl: case Opcode::I64X2Shl: case Opcode::I8X16ShrS: case Opcode::I8X16ShrU: case Opcode::I16X8ShrS: case Opcode::I16X8ShrU: case Opcode::I32X4ShrS: case Opcode::I32X4ShrU: case Opcode::I64X2ShrS: case Opcode::I64X2ShrU: case Opcode::V128And: case Opcode::V128Or: case Opcode::V128Xor: case Opcode::F32X4Min: case Opcode::F32X4PMin: case Opcode::F64X2Min: case Opcode::F64X2PMin: case Opcode::F32X4Max: case Opcode::F32X4PMax: case Opcode::F64X2Max: case Opcode::F64X2PMax: case Opcode::F32X4Add: case Opcode::F64X2Add: case Opcode::F32X4Sub: case Opcode::F64X2Sub: case Opcode::F32X4Div: case Opcode::F64X2Div: case Opcode::F32X4Mul: case Opcode::F64X2Mul: case Opcode::I8X16Swizzle: case Opcode::I8X16NarrowI16X8S: case Opcode::I8X16NarrowI16X8U: case Opcode::I16X8NarrowI32X4S: case Opcode::I16X8NarrowI32X4U: case Opcode::V128Andnot: case Opcode::I8X16AvgrU: case Opcode::I16X8AvgrU: case Opcode::I16X8ExtmulLowI8X16S: case Opcode::I16X8ExtmulHighI8X16S: case Opcode::I16X8ExtmulLowI8X16U: case Opcode::I16X8ExtmulHighI8X16U: case Opcode::I32X4ExtmulLowI16X8S: case Opcode::I32X4ExtmulHighI16X8S: case Opcode::I32X4ExtmulLowI16X8U: case Opcode::I32X4ExtmulHighI16X8U: case Opcode::I64X2ExtmulLowI32X4S: case Opcode::I64X2ExtmulHighI32X4S: case Opcode::I64X2ExtmulLowI32X4U: case Opcode::I64X2ExtmulHighI32X4U: case Opcode::I16X8Q15mulrSatS: case Opcode::I32X4DotI16X8S: case Opcode::I8X16RelaxedSwizzle: case Opcode::F32X4RelaxedMin: case Opcode::F32X4RelaxedMax: case Opcode::F64X2RelaxedMin: case Opcode::F64X2RelaxedMax: case Opcode::I16X8RelaxedQ15mulrS: case Opcode::I16X8DotI8X16I7X16S:
CALLBACK(OnBinaryExpr, opcode);
CALLBACK0(OnOpcodeBare); break;
case Opcode::I32Eq: case Opcode::I32Ne: case Opcode::I32LtS: case Opcode::I32LeS: case Opcode::I32LtU: case Opcode::I32LeU: case Opcode::I32GtS: case Opcode::I32GeS: case Opcode::I32GtU: case Opcode::I32GeU: case Opcode::I64Eq: case Opcode::I64Ne: case Opcode::I64LtS: case Opcode::I64LeS: case Opcode::I64LtU: case Opcode::I64LeU: case Opcode::I64GtS: case Opcode::I64GeS: case Opcode::I64GtU: case Opcode::I64GeU: case Opcode::F32Eq: case Opcode::F32Ne: case Opcode::F32Lt: case Opcode::F32Le: case Opcode::F32Gt: case Opcode::F32Ge: case Opcode::F64Eq: case Opcode::F64Ne: case Opcode::F64Lt: case Opcode::F64Le: case Opcode::F64Gt: case Opcode::F64Ge: case Opcode::I8X16Eq: case Opcode::I16X8Eq: case Opcode::I32X4Eq: case Opcode::I64X2Eq: case Opcode::F32X4Eq: case Opcode::F64X2Eq: case Opcode::I8X16Ne: case Opcode::I16X8Ne: case Opcode::I32X4Ne: case Opcode::I64X2Ne: case Opcode::F32X4Ne: case Opcode::F64X2Ne: case Opcode::I8X16LtS: case Opcode::I8X16LtU: case Opcode::I16X8LtS: case Opcode::I16X8LtU: case Opcode::I32X4LtS: case Opcode::I32X4LtU: case Opcode::I64X2LtS: case Opcode::F32X4Lt: case Opcode::F64X2Lt: case Opcode::I8X16LeS: case Opcode::I8X16LeU: case Opcode::I16X8LeS: case Opcode::I16X8LeU: case Opcode::I32X4LeS: case Opcode::I32X4LeU: case Opcode::I64X2LeS: case Opcode::F32X4Le: case Opcode::F64X2Le: case Opcode::I8X16GtS: case Opcode::I8X16GtU: case Opcode::I16X8GtS: case Opcode::I16X8GtU: case Opcode::I32X4GtS: case Opcode::I32X4GtU: case Opcode::I64X2GtS: case Opcode::F32X4Gt: case Opcode::F64X2Gt: case Opcode::I8X16GeS: case Opcode::I8X16GeU: case Opcode::I16X8GeS: case Opcode::I16X8GeU: case Opcode::I32X4GeS: case Opcode::I32X4GeU: case Opcode::I64X2GeS: case Opcode::F32X4Ge: case Opcode::F64X2Ge:
CALLBACK(OnCompareExpr, opcode);
CALLBACK0(OnOpcodeBare); break;
case Opcode::I32Clz: case Opcode::I32Ctz: case Opcode::I32Popcnt: case Opcode::I64Clz: case Opcode::I64Ctz: case Opcode::I64Popcnt: case Opcode::F32Abs: case Opcode::F32Neg: case Opcode::F32Ceil: case Opcode::F32Floor: case Opcode::F32Trunc: case Opcode::F32Nearest: case Opcode::F32Sqrt: case Opcode::F64Abs: case Opcode::F64Neg: case Opcode::F64Ceil: case Opcode::F64Floor: case Opcode::F64Trunc: case Opcode::F64Nearest: case Opcode::F64Sqrt: case Opcode::I8X16Splat: case Opcode::I16X8Splat: case Opcode::I32X4Splat: case Opcode::I64X2Splat: case Opcode::F32X4Splat: case Opcode::F64X2Splat: case Opcode::I8X16Neg: case Opcode::I16X8Neg: case Opcode::I32X4Neg: case Opcode::I64X2Neg: case Opcode::V128Not: case Opcode::V128AnyTrue: case Opcode::I8X16Bitmask: case Opcode::I16X8Bitmask: case Opcode::I32X4Bitmask: case Opcode::I64X2Bitmask: case Opcode::I8X16AllTrue: case Opcode::I16X8AllTrue: case Opcode::I32X4AllTrue: case Opcode::I64X2AllTrue: case Opcode::F32X4Ceil: case Opcode::F64X2Ceil: case Opcode::F32X4Floor: case Opcode::F64X2Floor: case Opcode::F32X4Trunc: case Opcode::F64X2Trunc: case Opcode::F32X4Nearest: case Opcode::F64X2Nearest: case Opcode::F32X4Neg: case Opcode::F64X2Neg: case Opcode::F32X4Abs: case Opcode::F64X2Abs: case Opcode::F32X4Sqrt: case Opcode::F64X2Sqrt: case Opcode::I16X8ExtendLowI8X16S: case Opcode::I16X8ExtendHighI8X16S: case Opcode::I16X8ExtendLowI8X16U: case Opcode::I16X8ExtendHighI8X16U: case Opcode::I32X4ExtendLowI16X8S: case Opcode::I32X4ExtendHighI16X8S: case Opcode::I32X4ExtendLowI16X8U: case Opcode::I32X4ExtendHighI16X8U: case Opcode::I64X2ExtendLowI32X4S: case Opcode::I64X2ExtendHighI32X4S: case Opcode::I64X2ExtendLowI32X4U: case Opcode::I64X2ExtendHighI32X4U: case Opcode::I8X16Abs: case Opcode::I16X8Abs: case Opcode::I32X4Abs: case Opcode::I64X2Abs: case Opcode::I8X16Popcnt: case Opcode::I16X8ExtaddPairwiseI8X16S: case Opcode::I16X8ExtaddPairwiseI8X16U: case Opcode::I32X4ExtaddPairwiseI16X8S: case Opcode::I32X4ExtaddPairwiseI16X8U: case Opcode::I32X4RelaxedTruncF32X4S: case Opcode::I32X4RelaxedTruncF32X4U: case Opcode::I32X4RelaxedTruncF64X2SZero: case Opcode::I32X4RelaxedTruncF64X2UZero:
CALLBACK(OnUnaryExpr, opcode);
CALLBACK0(OnOpcodeBare); break;
case Opcode::V128BitSelect: case Opcode::F32X4RelaxedMadd: case Opcode::F32X4RelaxedNmadd: case Opcode::F64X2RelaxedMadd: case Opcode::F64X2RelaxedNmadd: case Opcode::I8X16RelaxedLaneSelect: case Opcode::I16X8RelaxedLaneSelect: case Opcode::I32X4RelaxedLaneSelect: case Opcode::I64X2RelaxedLaneSelect: case Opcode::I32X4DotI8X16I7X16AddS:
CALLBACK(OnTernaryExpr, opcode);
CALLBACK0(OnOpcodeBare); break;
case Opcode::I8X16ExtractLaneS: case Opcode::I8X16ExtractLaneU: case Opcode::I16X8ExtractLaneS: case Opcode::I16X8ExtractLaneU: case Opcode::I32X4ExtractLane: case Opcode::I64X2ExtractLane: case Opcode::F32X4ExtractLane: case Opcode::F64X2ExtractLane: case Opcode::I8X16ReplaceLane: case Opcode::I16X8ReplaceLane: case Opcode::I32X4ReplaceLane: case Opcode::I64X2ReplaceLane: case Opcode::F32X4ReplaceLane: case Opcode::F64X2ReplaceLane: {
uint8_t lane_val;
CHECK_RESULT(ReadU8(&lane_val, "Lane idx"));
CALLBACK(OnSimdLaneOpExpr, opcode, lane_val);
CALLBACK(OnOpcodeUint64, lane_val); break;
}
case Opcode::V128Load8Splat: case Opcode::V128Load16Splat: case Opcode::V128Load32Splat: case Opcode::V128Load64Splat: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "load alignment", "load memidx", "load offset"));
CALLBACK(OnLoadSplatExpr, opcode, memidx, alignment_log2, offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
} case Opcode::V128Load8Lane: case Opcode::V128Load16Lane: case Opcode::V128Load32Lane: case Opcode::V128Load64Lane: {
Address alignment_log2;
Index memidx;
Address offset;
uint8_t lane_val;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "load alignment", "load memidx", "load offset", &lane_val));
CALLBACK(OnSimdLoadLaneExpr, opcode, memidx, alignment_log2, offset,
lane_val);
CHECK_RESULT(
CallbackMemLocation(&alignment_log2, &memidx, &offset, &lane_val)); break;
} case Opcode::V128Store8Lane: case Opcode::V128Store16Lane: case Opcode::V128Store32Lane: case Opcode::V128Store64Lane: {
Address alignment_log2;
Index memidx;
Address offset;
uint8_t lane_val;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "store alignment", "store memidx", "store offset", &lane_val));
CALLBACK(OnSimdStoreLaneExpr, opcode, memidx, alignment_log2, offset,
lane_val);
CHECK_RESULT(
CallbackMemLocation(&alignment_log2, &memidx, &offset, &lane_val)); break;
} case Opcode::V128Load32Zero: case Opcode::V128Load64Zero: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "load alignment", "load memidx", "load offset"));
CALLBACK(OnLoadZeroExpr, opcode, memidx, alignment_log2, offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
} case Opcode::I32TruncF32S: case Opcode::I32TruncF64S: case Opcode::I32TruncF32U: case Opcode::I32TruncF64U: case Opcode::I32WrapI64: case Opcode::I64TruncF32S: case Opcode::I64TruncF64S: case Opcode::I64TruncF32U: case Opcode::I64TruncF64U: case Opcode::I64ExtendI32S: case Opcode::I64ExtendI32U: case Opcode::F32ConvertI32S: case Opcode::F32ConvertI32U: case Opcode::F32ConvertI64S: case Opcode::F32ConvertI64U: case Opcode::F32DemoteF64: case Opcode::F32ReinterpretI32: case Opcode::F64ConvertI32S: case Opcode::F64ConvertI32U: case Opcode::F64ConvertI64S: case Opcode::F64ConvertI64U: case Opcode::F64PromoteF32: case Opcode::F64ReinterpretI64: case Opcode::I32ReinterpretF32: case Opcode::I64ReinterpretF64: case Opcode::I32Eqz: case Opcode::I64Eqz: case Opcode::F32X4ConvertI32X4S: case Opcode::F32X4ConvertI32X4U: case Opcode::I32X4TruncSatF32X4S: case Opcode::I32X4TruncSatF32X4U: case Opcode::F32X4DemoteF64X2Zero: case Opcode::F64X2PromoteLowF32X4: case Opcode::I32X4TruncSatF64X2SZero: case Opcode::I32X4TruncSatF64X2UZero: case Opcode::F64X2ConvertLowI32X4S: case Opcode::F64X2ConvertLowI32X4U:
CALLBACK(OnConvertExpr, opcode);
CALLBACK0(OnOpcodeBare); break;
case Opcode::Rethrow: {
Index depth;
CHECK_RESULT(ReadIndex(&depth, "catch depth"));
CALLBACK(OnRethrowExpr, depth);
CALLBACK(OnOpcodeIndex, depth); break;
}
case Opcode::Throw: {
Index index;
CHECK_RESULT(ReadIndex(&index, "tag index"));
CALLBACK(OnThrowExpr, index);
CALLBACK(OnOpcodeIndex, index); break;
}
case Opcode::I32Extend8S: case Opcode::I32Extend16S: case Opcode::I64Extend8S: case Opcode::I64Extend16S: case Opcode::I64Extend32S:
CALLBACK(OnUnaryExpr, opcode);
CALLBACK0(OnOpcodeBare); break;
case Opcode::I32TruncSatF32S: case Opcode::I32TruncSatF32U: case Opcode::I32TruncSatF64S: case Opcode::I32TruncSatF64U: case Opcode::I64TruncSatF32S: case Opcode::I64TruncSatF32U: case Opcode::I64TruncSatF64S: case Opcode::I64TruncSatF64U:
CALLBACK(OnConvertExpr, opcode);
CALLBACK0(OnOpcodeBare); break;
case Opcode::MemoryAtomicWait32: case Opcode::MemoryAtomicWait64: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "wait alignment", "wait memidx", "wait offset"));
CALLBACK(OnAtomicWaitExpr, opcode, memidx, alignment_log2, offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
}
case Opcode::AtomicFence: {
uint8_t consistency_model;
CHECK_RESULT(ReadU8(&consistency_model, "consistency model"));
ERROR_UNLESS(consistency_model == 0, "atomic.fence consistency model must be 0");
CALLBACK(OnAtomicFenceExpr, consistency_model);
CALLBACK(OnOpcodeUint32, consistency_model); break;
}
case Opcode::I32AtomicLoad8U: case Opcode::I32AtomicLoad16U: case Opcode::I64AtomicLoad8U: case Opcode::I64AtomicLoad16U: case Opcode::I64AtomicLoad32U: case Opcode::I32AtomicLoad: case Opcode::I64AtomicLoad: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "load alignment", "load memidx", "load offset"));
CALLBACK(OnAtomicLoadExpr, opcode, memidx, alignment_log2, offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
}
case Opcode::I32AtomicStore8: case Opcode::I32AtomicStore16: case Opcode::I64AtomicStore8: case Opcode::I64AtomicStore16: case Opcode::I64AtomicStore32: case Opcode::I32AtomicStore: case Opcode::I64AtomicStore: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "store alignment", "store memidx", "store offset"));
CALLBACK(OnAtomicStoreExpr, opcode, memidx, alignment_log2, offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
}
case Opcode::I32AtomicRmwAdd: case Opcode::I64AtomicRmwAdd: case Opcode::I32AtomicRmw8AddU: case Opcode::I32AtomicRmw16AddU: case Opcode::I64AtomicRmw8AddU: case Opcode::I64AtomicRmw16AddU: case Opcode::I64AtomicRmw32AddU: case Opcode::I32AtomicRmwSub: case Opcode::I64AtomicRmwSub: case Opcode::I32AtomicRmw8SubU: case Opcode::I32AtomicRmw16SubU: case Opcode::I64AtomicRmw8SubU: case Opcode::I64AtomicRmw16SubU: case Opcode::I64AtomicRmw32SubU: case Opcode::I32AtomicRmwAnd: case Opcode::I64AtomicRmwAnd: case Opcode::I32AtomicRmw8AndU: case Opcode::I32AtomicRmw16AndU: case Opcode::I64AtomicRmw8AndU: case Opcode::I64AtomicRmw16AndU: case Opcode::I64AtomicRmw32AndU: case Opcode::I32AtomicRmwOr: case Opcode::I64AtomicRmwOr: case Opcode::I32AtomicRmw8OrU: case Opcode::I32AtomicRmw16OrU: case Opcode::I64AtomicRmw8OrU: case Opcode::I64AtomicRmw16OrU: case Opcode::I64AtomicRmw32OrU: case Opcode::I32AtomicRmwXor: case Opcode::I64AtomicRmwXor: case Opcode::I32AtomicRmw8XorU: case Opcode::I32AtomicRmw16XorU: case Opcode::I64AtomicRmw8XorU: case Opcode::I64AtomicRmw16XorU: case Opcode::I64AtomicRmw32XorU: case Opcode::I32AtomicRmwXchg: case Opcode::I64AtomicRmwXchg: case Opcode::I32AtomicRmw8XchgU: case Opcode::I32AtomicRmw16XchgU: case Opcode::I64AtomicRmw8XchgU: case Opcode::I64AtomicRmw16XchgU: case Opcode::I64AtomicRmw32XchgU: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "memory alignment", "memory memidx", "memory offset"));
CALLBACK(OnAtomicRmwExpr, opcode, memidx, alignment_log2, offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
}
case Opcode::I32AtomicRmwCmpxchg: case Opcode::I64AtomicRmwCmpxchg: case Opcode::I32AtomicRmw8CmpxchgU: case Opcode::I32AtomicRmw16CmpxchgU: case Opcode::I64AtomicRmw8CmpxchgU: case Opcode::I64AtomicRmw16CmpxchgU: case Opcode::I64AtomicRmw32CmpxchgU: {
Address alignment_log2;
Index memidx;
Address offset;
CHECK_RESULT(ReadMemLocation(&alignment_log2, &memidx, &offset, "memory alignment", "memory memidx", "memory offset"));
CALLBACK(OnAtomicRmwCmpxchgExpr, opcode, memidx, alignment_log2,
offset);
CHECK_RESULT(CallbackMemLocation(&alignment_log2, &memidx, &offset)); break;
}
case Opcode::TableInit: {
Index segment;
CHECK_RESULT(ReadIndex(&segment, "elem segment index"));
Index table_index;
CHECK_RESULT(ReadIndex(&table_index, "reserved table index"));
CALLBACK(OnTableInitExpr, segment, table_index);
CALLBACK(OnOpcodeUint32Uint32, segment, table_index); break;
}
case Opcode::MemoryInit: {
Index segment;
ERROR_IF(data_count_ == kInvalidIndex, "memory.init requires data count section");
CHECK_RESULT(ReadIndex(&segment, "elem segment index"));
Index memidx = 0;
if (!options_.features.multi_memory_enabled()) {
uint8_t reserved;
CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
ERROR_UNLESS(reserved == 0, "reserved value must be 0");
} else {
CHECK_RESULT(ReadMemidx(&memidx, "memory.init memidx"));
}
CALLBACK(OnMemoryInitExpr, segment, memidx);
CALLBACK(OnOpcodeUint32Uint32, segment, memidx); break;
}
case Opcode::DataDrop:
ERROR_IF(data_count_ == kInvalidIndex, "data.drop requires data count section");
[[fallthrough]]; case Opcode::ElemDrop: {
Index segment;
CHECK_RESULT(ReadIndex(&segment, "segment index"));
if (opcode == Opcode::DataDrop) {
CALLBACK(OnDataDropExpr, segment);
} else {
CALLBACK(OnElemDropExpr, segment);
}
CALLBACK(OnOpcodeUint32, segment); break;
}
case Opcode::MemoryFill: {
Index memidx = 0;
if (!options_.features.multi_memory_enabled()) {
uint8_t reserved;
CHECK_RESULT(ReadU8(&reserved, "memory.fill reserved"));
ERROR_UNLESS(reserved == 0, "memory.fill reserved value must be 0");
} else {
CHECK_RESULT(ReadMemidx(&memidx, "memory.fill memidx"));
}
CALLBACK(OnMemoryFillExpr, memidx);
CALLBACK(OnOpcodeUint32, memidx); break;
}
case Opcode::MemoryCopy: {
Index destmemidx = 0;
Index srcmemidx = 0;
if (!options_.features.multi_memory_enabled()) {
uint8_t reserved;
CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
ERROR_UNLESS(reserved == 0, "reserved value must be 0");
CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
ERROR_UNLESS(reserved == 0, "reserved value must be 0");
} else {
CHECK_RESULT(ReadMemidx(&destmemidx, "memory.copy destmemindex"));
CHECK_RESULT(ReadMemidx(&srcmemidx, "memory.copy srcmemidx"));
}
CALLBACK(OnMemoryCopyExpr, destmemidx, srcmemidx);
CALLBACK(OnOpcodeUint32Uint32, destmemidx, srcmemidx); break;
}
case Opcode::TableCopy: {
Index table_dst;
Index table_src;
CHECK_RESULT(ReadIndex(&table_dst, "reserved table index"));
CHECK_RESULT(ReadIndex(&table_src, "table src"));
CALLBACK(OnTableCopyExpr, table_dst, table_src);
CALLBACK(OnOpcodeUint32Uint32, table_dst, table_src); break;
}
case Opcode::TableGet: {
Index table;
CHECK_RESULT(ReadIndex(&table, "table index"));
CALLBACK(OnTableGetExpr, table);
CALLBACK(OnOpcodeUint32, table); break;
}
case Opcode::TableSet: {
Index table;
CHECK_RESULT(ReadIndex(&table, "table index"));
CALLBACK(OnTableSetExpr, table);
CALLBACK(OnOpcodeUint32, table); break;
}
case Opcode::TableGrow: {
Index table;
CHECK_RESULT(ReadIndex(&table, "table index"));
CALLBACK(OnTableGrowExpr, table);
CALLBACK(OnOpcodeUint32, table); break;
}
case Opcode::TableSize: {
Index table;
CHECK_RESULT(ReadIndex(&table, "table index"));
CALLBACK(OnTableSizeExpr, table);
CALLBACK(OnOpcodeUint32, table); break;
}
case Opcode::TableFill: {
Index table;
CHECK_RESULT(ReadIndex(&table, "table index"));
CALLBACK(OnTableFillExpr, table);
CALLBACK(OnOpcodeUint32, table); break;
}
case Opcode::RefFunc: {
Index func;
CHECK_RESULT(ReadIndex(&func, "func index"));
CALLBACK(OnRefFuncExpr, func);
CALLBACK(OnOpcodeUint32, func); break;
}
case Opcode::RefNull: {
Type type;
CHECK_RESULT(ReadRefType(&type, "ref.null type"));
CALLBACK(OnRefNullExpr, type);
CALLBACK(OnOpcodeType, type); break;
}
case Opcode::RefIsNull:
CALLBACK(OnRefIsNullExpr);
CALLBACK(OnOpcodeBare); break;
case Opcode::CallRef:
CALLBACK(OnCallRefExpr);
CALLBACK(OnOpcodeBare); break;
PrintError("%s must end with END opcode", context); return Result::Error;
}
Result BinaryReader::ReadNameSection(Offset section_size) {
CALLBACK(BeginNamesSection, section_size);
Index i = 0;
uint32_t previous_subsection_type = 0; while (state_.offset < read_end_) {
uint32_t name_type;
Offset subsection_size;
CHECK_RESULT(ReadU32Leb128(&name_type, "name type"));
if (i != 0) {
ERROR_UNLESS(name_type != previous_subsection_type, "duplicate sub-section");
ERROR_UNLESS(name_type >= previous_subsection_type, "out-of-order sub-section");
}
previous_subsection_type = name_type;
CHECK_RESULT(ReadOffset(&subsection_size, "subsection size"));
size_t subsection_end = state_.offset + subsection_size;
ERROR_UNLESS(subsection_end <= read_end_, "invalid sub-section size: extends past end");
ReadEndRestoreGuard guard(this);
read_end_ = subsection_end;
NameSectionSubsection type = static_cast<NameSectionSubsection>(name_type);
if (type <= NameSectionSubsection::Last) {
CALLBACK(OnNameSubsection, i, type, subsection_size);
}
switch (type) { case NameSectionSubsection::Module:
CALLBACK(OnModuleNameSubsection, i, name_type, subsection_size);
if (subsection_size) {
std::string_view name;
CHECK_RESULT(ReadStr(&name, "module name"));
CALLBACK(OnModuleName, name);
} break; case NameSectionSubsection::Function:
CALLBACK(OnFunctionNameSubsection, i, name_type, subsection_size);
if (subsection_size) {
Index num_names;
CHECK_RESULT(ReadCount(&num_names, "name count"));
CALLBACK(OnFunctionNamesCount, num_names);
Index last_function_index = kInvalidIndex;
for (Index j = 0; j < num_names; ++j) {
Index function_index;
std::string_view function_name;
CHECK_RESULT(ReadIndex(&function_index, "function index"));
ERROR_UNLESS(function_index != last_function_index, "duplicate function name: %u", function_index);
ERROR_UNLESS(last_function_index == kInvalidIndex ||
function_index > last_function_index, "function index out of order: %u", function_index);
last_function_index = function_index;
ERROR_UNLESS(function_index < NumTotalFuncs(), "invalid function index: %" PRIindex, function_index);
CHECK_RESULT(ReadStr(&function_name, "function name"));
CALLBACK(OnFunctionName, function_index, function_name);
}
} break; case NameSectionSubsection::Local:
CALLBACK(OnLocalNameSubsection, i, name_type, subsection_size);
if (subsection_size) {
Index num_funcs;
CHECK_RESULT(ReadCount(&num_funcs, "function count"));
CALLBACK(OnLocalNameFunctionCount, num_funcs);
Index last_function_index = kInvalidIndex;
for (Index j = 0; j < num_funcs; ++j) {
Index function_index;
CHECK_RESULT(ReadIndex(&function_index, "function index"));
ERROR_UNLESS(function_index < NumTotalFuncs(), "invalid function index: %u", function_index);
ERROR_UNLESS(last_function_index == kInvalidIndex ||
function_index > last_function_index, "locals function index out of order: %u",
function_index);
last_function_index = function_index;
Index num_locals;
CHECK_RESULT(ReadCount(&num_locals, "local count"));
CALLBACK(OnLocalNameLocalCount, function_index, num_locals);
Index last_local_index = kInvalidIndex;
for (Index k = 0; k < num_locals; ++k) {
Index local_index;
std::string_view local_name;
CHECK_RESULT(ReadIndex(&local_index, "named index"));
ERROR_UNLESS(local_index != last_local_index, "duplicate local index: %u", local_index);
ERROR_UNLESS(last_local_index == kInvalidIndex ||
local_index > last_local_index, "local index out of order: %u", local_index);
last_local_index = local_index;
CHECK_RESULT(ReadStr(&local_name, "name"));
CALLBACK(OnLocalName, function_index, local_index, local_name);
}
}
} break; case NameSectionSubsection::Label: // TODO(sbc): Implement label names. These are slightly more complicated // since they refer to offsets in the code section / instruction stream.
state_.offset = subsection_end; break; case NameSectionSubsection::Type: case NameSectionSubsection::Table: case NameSectionSubsection::Memory: case NameSectionSubsection::Global: case NameSectionSubsection::ElemSegment: case NameSectionSubsection::DataSegment: case NameSectionSubsection::Tag:
if (subsection_size) {
Index num_names;
CHECK_RESULT(ReadCount(&num_names, "name count"));
CALLBACK(OnNameCount, num_names);
for (Index j = 0; j < num_names; ++j) {
Index index;
std::string_view name;
Result BinaryReader::ReadRelocSection(Offset section_size) {
CALLBACK(BeginRelocSection, section_size);
uint32_t section_index;
CHECK_RESULT(ReadU32Leb128(§ion_index, "section index"));
Index num_relocs;
CHECK_RESULT(ReadCount(&num_relocs, "relocation count"));
CALLBACK(OnRelocCount, num_relocs, section_index);
for (Index i = 0; i < num_relocs; ++i) {
Offset offset;
Index index;
uint32_t reloc_type, addend = 0;
CHECK_RESULT(ReadU32Leb128(&reloc_type, "relocation type"));
CHECK_RESULT(ReadOffset(&offset, "offset"));
CHECK_RESULT(ReadIndex(&index, "index"));
RelocType type = static_cast<RelocType>(reloc_type); switch (type) { case RelocType::MemoryAddressLEB: case RelocType::MemoryAddressLEB64: case RelocType::MemoryAddressSLEB: case RelocType::MemoryAddressSLEB64: case RelocType::MemoryAddressRelSLEB: case RelocType::MemoryAddressRelSLEB64: case RelocType::MemoryAddressI32: case RelocType::MemoryAddressI64: case RelocType::MemoryAddressLocRelI32: case RelocType::FunctionOffsetI32: case RelocType::FunctionOffsetI64: case RelocType::SectionOffsetI32: case RelocType::MemoryAddressTLSSLEB: case RelocType::MemoryAddressTLSSLEB64:
CHECK_RESULT(ReadS32Leb128(&addend, "addend")); break;
case RelocType::FuncIndexLEB: case RelocType::FuncIndexI32: case RelocType::TableIndexSLEB: case RelocType::TableIndexSLEB64: case RelocType::TableIndexI32: case RelocType::TableIndexI64: case RelocType::TypeIndexLEB: case RelocType::GlobalIndexLEB: case RelocType::GlobalIndexI32: case RelocType::TagIndexLEB: case RelocType::TableIndexRelSLEB: case RelocType::TableIndexRelSLEB64: case RelocType::TableNumberLEB: break;
uint32_t count; switch (static_cast<LinkingEntryType>(linking_type)) { case LinkingEntryType::SymbolTable:
CHECK_RESULT(ReadU32Leb128(&count, "sym count"));
CALLBACK(OnSymbolCount, count);
for (Index i = 0; i < count; ++i) {
std::string_view name;
uint32_t flags = 0;
uint32_t kind = 0;
CHECK_RESULT(ReadU32Leb128(&kind, "sym type"));
CHECK_RESULT(ReadU32Leb128(&flags, "sym flags"));
SymbolType sym_type = static_cast<SymbolType>(kind); switch (sym_type) { case SymbolType::Function: case SymbolType::Global: case SymbolType::Tag: case SymbolType::Table: {
uint32_t index = 0;
CHECK_RESULT(ReadU32Leb128(&index, "index"));
if ((flags & WABT_SYMBOL_FLAG_UNDEFINED) == 0 ||
(flags & WABT_SYMBOL_FLAG_EXPLICIT_NAME) != 0)
CHECK_RESULT(ReadStr(&name, "symbol name")); switch (sym_type) { case SymbolType::Function:
CALLBACK(OnFunctionSymbol, i, flags, name, index); break; case SymbolType::Global:
CALLBACK(OnGlobalSymbol, i, flags, name, index); break; case SymbolType::Tag:
CALLBACK(OnTagSymbol, i, flags, name, index); break; case SymbolType::Table:
CALLBACK(OnTableSymbol, i, flags, name, index); break; default:
WABT_UNREACHABLE;
} break;
} case SymbolType::Data: {
uint32_t segment = 0;
uint32_t offset = 0;
uint32_t size = 0;
CHECK_RESULT(ReadStr(&name, "symbol name"));
if ((flags & WABT_SYMBOL_FLAG_UNDEFINED) == 0) {
CHECK_RESULT(ReadU32Leb128(&segment, "segment"));
CHECK_RESULT(ReadU32Leb128(&offset, "offset"));
CHECK_RESULT(ReadU32Leb128(&size, "size"));
}
CALLBACK(OnDataSymbol, i, flags, name, segment, offset, size); break;
} case SymbolType::Section: {
uint32_t index = 0;
CHECK_RESULT(ReadU32Leb128(&index, "index"));
CALLBACK(OnSectionSymbol, i, flags, index); break;
}
}
} break; case LinkingEntryType::SegmentInfo:
CHECK_RESULT(ReadU32Leb128(&count, "info count"));
CALLBACK(OnSegmentInfoCount, count);
for (Index i = 0; i < count; i++) {
std::string_view name;
Address alignment_log2;
uint32_t flags;
CHECK_RESULT(ReadStr(&name, "segment name"));
CHECK_RESULT(ReadAlignment(&alignment_log2, "segment alignment"));
CHECK_RESULT(CheckAlignment(&alignment_log2, "segment alignment"));
CHECK_RESULT(ReadU32Leb128(&flags, "segment flags"));
CALLBACK(OnSegmentInfo, i, name, alignment_log2, flags);
} break; case LinkingEntryType::InitFunctions:
CHECK_RESULT(ReadU32Leb128(&count, "info count"));
CALLBACK(OnInitFunctionCount, count); while (count--) {
uint32_t priority;
uint32_t symbol;
CHECK_RESULT(ReadU32Leb128(&priority, "priority"));
CHECK_RESULT(ReadU32Leb128(&symbol, "symbol index"));
CALLBACK(OnInitFunction, priority, symbol);
} break; case LinkingEntryType::ComdatInfo:
CHECK_RESULT(ReadU32Leb128(&count, "count"));
CALLBACK(OnComdatCount, count); while (count--) {
uint32_t flags;
uint32_t entry_count;
std::string_view name;
CHECK_RESULT(ReadStr(&name, "comdat name"));
CHECK_RESULT(ReadU32Leb128(&flags, "flags"));
CHECK_RESULT(ReadU32Leb128(&entry_count, "entry count"));
CALLBACK(OnComdatBegin, name, flags, entry_count); while (entry_count--) {
uint32_t kind;
uint32_t index;
CHECK_RESULT(ReadU32Leb128(&kind, "kind"));
CHECK_RESULT(ReadU32Leb128(&index, "index"));
ComdatType comdat_type = static_cast<ComdatType>(kind);
CALLBACK(OnComdatEntry, comdat_type, index);
}
} break; default: // Unknown subsection, skip it.
state_.offset = subsection_end; break;
}
ERROR_UNLESS(state_.offset == subsection_end, "unfinished sub-section (expected end: 0x%" PRIzx ")",
subsection_end);
}
CALLBACK0(EndLinkingSection); return Result::Ok;
}
Result BinaryReader::ReadTagType(Index* out_sig_index) {
uint8_t attribute;
CHECK_RESULT(ReadU8(&attribute, "tag attribute"));
ERROR_UNLESS(attribute == 0, "tag attribute must be 0");
CHECK_RESULT(ReadIndex(out_sig_index, "tag signature index")); return Result::Ok;
}
Result BinaryReader::ReadTagSection(Offset section_size) {
CALLBACK(BeginTagSection, section_size);
Index num_tags;
CHECK_RESULT(ReadCount(&num_tags, "tag count"));
CALLBACK(OnTagCount, num_tags);
for (Index i = 0; i < num_tags; ++i) {
Index tag_index = num_tag_imports_ + i;
Index sig_index;
CHECK_RESULT(ReadTagType(&sig_index));
CALLBACK(OnTagType, tag_index, sig_index);
}
CALLBACK(EndTagSection); return Result::Ok;
}
Result BinaryReader::ReadCodeMetadataSection(std::string_view name,
Offset section_size) {
CALLBACK(BeginCodeMetadataSection, name, section_size);
Index num_functions;
CHECK_RESULT(ReadCount(&num_functions, "function count"));
CALLBACK(OnCodeMetadataFuncCount, num_functions);
Index last_function_index = kInvalidIndex;
for (Index i = 0; i < num_functions; ++i) {
Index function_index;
CHECK_RESULT(ReadCount(&function_index, "function index"));
ERROR_UNLESS(function_index >= num_func_imports_, "function import can't have metadata (got %" PRIindex ")",
function_index);
ERROR_UNLESS(function_index < NumTotalFuncs(), "invalid function index: %" PRIindex, function_index);
ERROR_UNLESS(function_index != last_function_index, "duplicate function index: %" PRIindex, function_index);
ERROR_UNLESS(last_function_index == kInvalidIndex ||
function_index > last_function_index, "function index out of order: %" PRIindex, function_index);
last_function_index = function_index;
Index num_metadata;
CHECK_RESULT(ReadCount(&num_metadata, "metadata instances count"));
if (options_.read_debug_names && section_name == WABT_BINARY_SECTION_NAME) {
CHECK_RESULT(ReadNameSection(section_size));
did_read_names_section_ = true;
} else if (section_name == WABT_BINARY_SECTION_DYLINK0) {
CHECK_RESULT(ReadDylink0Section(section_size));
} else if (section_name == WABT_BINARY_SECTION_DYLINK) {
CHECK_RESULT(ReadDylinkSection(section_size));
} else if (section_name.rfind(WABT_BINARY_SECTION_RELOC, 0) == 0) { // Reloc sections always begin with "reloc."
CHECK_RESULT(ReadRelocSection(section_size));
} else if (section_name == WABT_BINARY_SECTION_TARGET_FEATURES) {
CHECK_RESULT(ReadTargetFeaturesSections(section_size));
} else if (section_name == WABT_BINARY_SECTION_LINKING) {
CHECK_RESULT(ReadLinkingSection(section_size));
} else if (options_.features.code_metadata_enabled() &&
section_name.find(WABT_BINARY_SECTION_CODE_METADATA) == 0) {
std::string_view metadata_name = section_name;
metadata_name.remove_prefix(sizeof(WABT_BINARY_SECTION_CODE_METADATA) - 1);
CHECK_RESULT(ReadCodeMetadataSection(metadata_name, section_size));
} else { // Skip. This is a generic custom section, and is handled above.
state_.offset = read_end_;
}
CALLBACK0(EndCustomSection); return Result::Ok;
}
Result BinaryReader::ReadTypeSection(Offset section_size) {
CALLBACK(BeginTypeSection, section_size);
Index num_signatures;
CHECK_RESULT(ReadCount(&num_signatures, "type count"));
CALLBACK(OnTypeCount, num_signatures);
for (Index i = 0; i < num_signatures; ++i) {
Type form;
if (options_.features.gc_enabled()) {
CHECK_RESULT(ReadType(&form, "type form"));
} else {
uint8_t type;
CHECK_RESULT(ReadU8(&type, "type form"));
ERROR_UNLESS(type == 0x60, "unexpected type form (got %#x)", type);
form = Type::Func;
}
switch (form) { case Type::Func: {
Index num_params;
CHECK_RESULT(ReadCount(&num_params, "function param count"));
param_types_.resize(num_params);
for (Index j = 0; j < num_params; ++j) {
Type param_type;
CHECK_RESULT(ReadType(¶m_type, "function param type"));
ERROR_UNLESS(IsConcreteType(param_type), "expected valid param type (got " PRItypecode ")",
WABT_PRINTF_TYPE_CODE(param_type));
param_types_[j] = param_type;
}
Index num_results;
CHECK_RESULT(ReadCount(&num_results, "function result count"));
result_types_.resize(num_results);
for (Index j = 0; j < num_results; ++j) {
Type result_type;
CHECK_RESULT(ReadType(&result_type, "function result type"));
ERROR_UNLESS(IsConcreteType(result_type), "expected valid result type (got " PRItypecode ")",
WABT_PRINTF_TYPE_CODE(result_type));
result_types_[j] = result_type;
}
CALLBACK(OnFuncType, i, num_params, param_types, num_results,
result_types); break;
}
case Type::Struct: {
ERROR_UNLESS(options_.features.gc_enabled(), "invalid type form: struct not allowed");
Index num_fields;
CHECK_RESULT(ReadCount(&num_fields, "field count"));
CALLBACK(OnStructType, i, fields_.size(), fields_.data()); break;
}
case Type::Array: {
ERROR_UNLESS(options_.features.gc_enabled(), "invalid type form: array not allowed");
TypeMut field;
CHECK_RESULT(ReadField(&field));
CALLBACK(OnArrayType, i, field); break;
};
default:
PrintError("unexpected type form (got " PRItypecode ")",
WABT_PRINTF_TYPE_CODE(form)); return Result::Error;
}
}
CALLBACK0(EndTypeSection); return Result::Ok;
}
Result BinaryReader::ReadImportSection(Offset section_size) {
CALLBACK(BeginImportSection, section_size);
Index num_imports;
CHECK_RESULT(ReadCount(&num_imports, "import count"));
CALLBACK(OnImportCount, num_imports);
for (Index i = 0; i < num_imports; ++i) {
std::string_view module_name;
CHECK_RESULT(ReadStr(&module_name, "import module name"));
std::string_view field_name;
CHECK_RESULT(ReadStr(&field_name, "import field name"));
uint8_t kind;
CHECK_RESULT(ReadU8(&kind, "import kind"));
CALLBACK(OnImport, i, static_cast<ExternalKind>(kind), module_name,
field_name); switch (static_cast<ExternalKind>(kind)) { case ExternalKind::Func: {
Index sig_index;
CHECK_RESULT(ReadIndex(&sig_index, "import signature index"));
CALLBACK(OnImportFunc, i, module_name, field_name, num_func_imports_,
sig_index);
num_func_imports_++; break;
}
case ExternalKind::Table: {
Type elem_type;
Limits elem_limits;
CHECK_RESULT(ReadTable(&elem_type, &elem_limits));
CALLBACK(OnImportTable, i, module_name, field_name, num_table_imports_,
elem_type, &elem_limits);
num_table_imports_++; break;
}
case ExternalKind::Memory: {
Limits page_limits;
uint32_t page_size;
CHECK_RESULT(ReadMemory(&page_limits, &page_size));
CALLBACK(OnImportMemory, i, module_name, field_name,
num_memory_imports_, &page_limits, page_size);
num_memory_imports_++; break;
}
case ExternalKind::Global: {
Type type; bool mutable_;
CHECK_RESULT(ReadGlobalHeader(&type, &mutable_));
CALLBACK(OnImportGlobal, i, module_name, field_name,
num_global_imports_, type, mutable_);
num_global_imports_++; break;
}
case ExternalKind::Tag: {
ERROR_UNLESS(options_.features.exceptions_enabled(), "invalid import tag kind: exceptions not allowed");
Index sig_index;
CHECK_RESULT(ReadTagType(&sig_index));
CALLBACK(OnImportTag, i, module_name, field_name, num_tag_imports_,
sig_index);
num_tag_imports_++; break;
}
Index item_index;
CHECK_RESULT(ReadIndex(&item_index, "export item index"));
if (kind == ExternalKind::Tag) {
ERROR_UNLESS(options_.features.exceptions_enabled(), "invalid export tag kind: exceptions not allowed");
}
CALLBACK(OnExport, i, static_cast<ExternalKind>(kind), item_index, name);
}
CALLBACK0(EndExportSection); return Result::Ok;
}
Result BinaryReader::ReadStartSection(Offset section_size) {
CALLBACK(BeginStartSection, section_size);
Index func_index;
CHECK_RESULT(ReadIndex(&func_index, "start function index"));
CALLBACK(OnStartFunction, func_index);
CALLBACK0(EndStartSection); return Result::Ok;
}
Result BinaryReader::ReadElemSection(Offset section_size) {
CALLBACK(BeginElemSection, section_size);
Index num_elem_segments;
CHECK_RESULT(ReadCount(&num_elem_segments, "elem segment count"));
CALLBACK(OnElemSegmentCount, num_elem_segments);
for (Index i = 0; i < num_elem_segments; ++i) {
uint32_t flags;
CHECK_RESULT(ReadU32Leb128(&flags, "elem segment flags"));
ERROR_IF(flags > SegFlagMax, "invalid elem segment flags: %#x", flags);
Index table_index(0);
if ((flags & (SegPassive | SegExplicitIndex)) == SegExplicitIndex) {
CHECK_RESULT(ReadIndex(&table_index, "elem segment table index"));
}
Type elem_type = Type::FuncRef;
CALLBACK(BeginElemSegment, i, table_index, flags);
// For backwards compat we support not declaring the element kind.
if (flags & (SegPassive | SegExplicitIndex)) {
if (flags & SegUseElemExprs) {
CHECK_RESULT(ReadRefType(&elem_type, "table elem type"));
} else {
ExternalKind kind;
CHECK_RESULT(ReadExternalKind(&kind, "export kind"));
ERROR_UNLESS(kind == ExternalKind::Func, "segment elem type must be func (%s)",
elem_type.GetName().c_str());
elem_type = Type::FuncRef;
}
}
CALLBACK(OnElemSegmentElemType, i, elem_type);
Index num_elem_exprs;
CHECK_RESULT(ReadCount(&num_elem_exprs, "elem count"));
CALLBACK(OnElemSegmentElemExprCount, i, num_elem_exprs);
for (Index j = 0; j < num_elem_exprs; ++j) {
CALLBACK(BeginElemExpr, i, j);
if (flags & SegUseElemExprs) {
CHECK_RESULT(ReadInitExpr(j));
} else {
Index func_index;
CHECK_RESULT(ReadIndex(&func_index, "elem expr func index"));
CALLBACK(OnOpcode, Opcode::RefFunc);
CALLBACK(OnRefFuncExpr, func_index);
CALLBACK(OnOpcodeUint32, func_index);
CALLBACK0(OnEndExpr);
}
CALLBACK(EndElemExpr, i, j);
}
CALLBACK(EndElemSegment, i);
}
CALLBACK0(EndElemSection); return Result::Ok;
}
Result BinaryReader::ReadCodeSection(Offset section_size) {
CALLBACK(BeginCodeSection, section_size);
CHECK_RESULT(ReadCount(&num_function_bodies_, "function body count"));
ERROR_UNLESS(num_function_signatures_ == num_function_bodies_, "function signature count != function body count");
CALLBACK(OnFunctionBodyCount, num_function_bodies_);
for (Index i = 0; i < num_function_bodies_; ++i) {
Index func_index = num_func_imports_ + i;
Offset func_offset = state_.offset;
state_.offset = func_offset;
uint32_t body_size;
CHECK_RESULT(ReadU32Leb128(&body_size, "function body size"));
Offset body_start_offset = state_.offset;
Offset end_offset = body_start_offset + body_size;
CALLBACK(BeginFunctionBody, func_index, body_size);
uint64_t total_locals = 0;
Index num_local_decls;
CHECK_RESULT(ReadCount(&num_local_decls, "local declaration count"));
CALLBACK(OnLocalDeclCount, num_local_decls);
for (Index k = 0; k < num_local_decls; ++k) {
Index num_local_types;
CHECK_RESULT(ReadIndex(&num_local_types, "local type count"));
total_locals += num_local_types;
ERROR_UNLESS(total_locals <= UINT32_MAX, "local count must be <= 0x%x",
UINT32_MAX);
Type local_type;
CHECK_RESULT(ReadType(&local_type, "local type"));
ERROR_UNLESS(IsConcreteType(local_type), "expected valid local type");
CALLBACK(OnLocalDecl, k, num_local_types, local_type);
}
CALLBACK(EndLocalDecls);
Result BinaryReader::ReadDataCountSection(Offset section_size) {
CALLBACK(BeginDataCountSection, section_size);
Index data_count;
CHECK_RESULT(ReadIndex(&data_count, "data count"));
CALLBACK(OnDataCount, data_count);
CALLBACK0(EndDataCountSection);
data_count_ = data_count; return Result::Ok;
}
Result BinaryReader::ReadSections(const ReadSectionsOptions& options) {
Result result = Result::Ok;
Index section_index = 0; bool seen_section_code[static_cast<int>(BinarySection::Last) + 1] = {false};
for (; state_.offset < state_.size; ++section_index) {
uint8_t section_code;
Offset section_size;
CHECK_RESULT(ReadU8(§ion_code, "section code"));
CHECK_RESULT(ReadOffset(§ion_size, "section size"));
ReadEndRestoreGuard guard(this);
read_end_ = state_.offset + section_size;
if (section_code >= kBinarySectionCount) {
PrintError("invalid section code: %u", section_code);
if (options.stop_on_first_error) { return Result::Error;
} // If we don't have to stop on first error, continue reading // sections, because although we could not understand the // current section, we can continue and correctly parse // subsequent sections, so we can give back as much information // as we can understand.
result = Result::Error;
state_.offset = read_end_; continue;
}
if (Failed(section_result)) {
if (stop_on_first_error) { return Result::Error;
}
// If we're continuing after failing to read this section, move the // offset to the expected section end. This way we may be able to read // further sections.
state_.offset = read_end_;
}
if (section != BinarySection::Custom) {
last_known_section_ = section;
}
}
CALLBACK(BeginModule, version);
CHECK_RESULT(ReadSections(ReadSectionsOptions{options.stop_on_first_error})); // This is checked in ReadCodeSection, but it must be checked at the end too, // in case the code section was omitted.
ERROR_UNLESS(num_function_signatures_ == num_function_bodies_, "function signature count != function body count"); // This is checked in ReadDataSection, but it must be checked at the end too, // in case the data section was omitted.
ERROR_IF(num_data_segments_ == 0 && data_count_ != kInvalidIndex &&
data_count_ != 0, "Data section missing but DataCount non-zero");
CALLBACK0(EndModule);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.153Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.