summaryrefslogtreecommitdiff
path: root/src/binary-reader.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/binary-reader.cc')
-rw-r--r--src/binary-reader.cc2158
1 files changed, 2158 insertions, 0 deletions
diff --git a/src/binary-reader.cc b/src/binary-reader.cc
new file mode 100644
index 00000000..704886ad
--- /dev/null
+++ b/src/binary-reader.cc
@@ -0,0 +1,2158 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "binary-reader.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "binary.h"
+#include "config.h"
+#include "stream.h"
+#include "vector.h"
+
+#if HAVE_ALLOCA
+#include <alloca.h>
+#endif
+
+#define INDENT_SIZE 2
+
+#define INITIAL_PARAM_TYPES_CAPACITY 128
+#define INITIAL_BR_TABLE_TARGET_CAPACITY 1000
+
+typedef uint32_t Uint32;
+WABT_DEFINE_VECTOR(type, WabtType)
+WABT_DEFINE_VECTOR(uint32, Uint32);
+
+#define CALLBACK_CTX(member, ...) \
+ RAISE_ERROR_UNLESS( \
+ WABT_SUCCEEDED( \
+ ctx->reader->member \
+ ? ctx->reader->member(get_user_context(ctx), __VA_ARGS__) \
+ : WABT_OK), \
+ #member " callback failed")
+
+#define CALLBACK_CTX0(member) \
+ RAISE_ERROR_UNLESS( \
+ WABT_SUCCEEDED(ctx->reader->member \
+ ? ctx->reader->member(get_user_context(ctx)) \
+ : WABT_OK), \
+ #member " callback failed")
+
+#define CALLBACK_SECTION(member, section_size) \
+ CALLBACK_CTX(member, section_size)
+
+#define CALLBACK0(member) \
+ RAISE_ERROR_UNLESS( \
+ WABT_SUCCEEDED(ctx->reader->member \
+ ? ctx->reader->member(ctx->reader->user_data) \
+ : WABT_OK), \
+ #member " callback failed")
+
+#define CALLBACK(member, ...) \
+ RAISE_ERROR_UNLESS( \
+ WABT_SUCCEEDED( \
+ ctx->reader->member \
+ ? ctx->reader->member(__VA_ARGS__, ctx->reader->user_data) \
+ : WABT_OK), \
+ #member " callback failed")
+
+#define FORWARD0(member) \
+ return ctx->reader->member ? ctx->reader->member(ctx->reader->user_data) \
+ : WABT_OK
+
+#define FORWARD_CTX0(member) \
+ if (!ctx->reader->member) \
+ return WABT_OK; \
+ WabtBinaryReaderContext new_ctx = *context; \
+ new_ctx.user_data = ctx->reader->user_data; \
+ return ctx->reader->member(&new_ctx);
+
+#define FORWARD_CTX(member, ...) \
+ if (!ctx->reader->member) \
+ return WABT_OK; \
+ WabtBinaryReaderContext new_ctx = *context; \
+ new_ctx.user_data = ctx->reader->user_data; \
+ return ctx->reader->member(&new_ctx, __VA_ARGS__);
+
+#define FORWARD(member, ...) \
+ return ctx->reader->member \
+ ? ctx->reader->member(__VA_ARGS__, ctx->reader->user_data) \
+ : WABT_OK
+
+#define RAISE_ERROR(...) raise_error(ctx, __VA_ARGS__)
+
+#define RAISE_ERROR_UNLESS(cond, ...) \
+ if (!(cond)) \
+ RAISE_ERROR(__VA_ARGS__);
+
+typedef struct Context {
+ const uint8_t* data;
+ size_t data_size;
+ size_t offset;
+ size_t read_end; /* Either the section end or data_size. */
+ WabtBinaryReaderContext user_ctx;
+ WabtBinaryReader* reader;
+ jmp_buf error_jmp_buf;
+ WabtTypeVector param_types;
+ Uint32Vector target_depths;
+ const WabtReadBinaryOptions* options;
+ WabtBinarySection last_known_section;
+ uint32_t num_signatures;
+ uint32_t num_imports;
+ uint32_t num_func_imports;
+ uint32_t num_table_imports;
+ uint32_t num_memory_imports;
+ uint32_t num_global_imports;
+ uint32_t num_function_signatures;
+ uint32_t num_tables;
+ uint32_t num_memories;
+ uint32_t num_globals;
+ uint32_t num_exports;
+ uint32_t num_function_bodies;
+} Context;
+
+typedef struct LoggingContext {
+ WabtStream* stream;
+ WabtBinaryReader* reader;
+ int indent;
+} LoggingContext;
+
+static WabtBinaryReaderContext* get_user_context(Context* ctx) {
+ ctx->user_ctx.user_data = ctx->reader->user_data;
+ ctx->user_ctx.data = ctx->data;
+ ctx->user_ctx.size = ctx->data_size;
+ ctx->user_ctx.offset = ctx->offset;
+ return &ctx->user_ctx;
+}
+
+static void WABT_PRINTF_FORMAT(2, 3)
+ raise_error(Context* ctx, const char* format, ...) {
+ WABT_SNPRINTF_ALLOCA(buffer, length, format);
+ if (ctx->reader->on_error) {
+ ctx->reader->on_error(get_user_context(ctx), buffer);
+ } else {
+ /* Not great to just print, but we don't want to eat the error either. */
+ fprintf(stderr, "*ERROR*: %s\n", buffer);
+ }
+ longjmp(ctx->error_jmp_buf, 1);
+}
+
+#define IN_SIZE(type) \
+ if (ctx->offset + sizeof(type) > ctx->read_end) { \
+ RAISE_ERROR("unable to read " #type ": %s", desc); \
+ } \
+ memcpy(out_value, ctx->data + ctx->offset, sizeof(type)); \
+ ctx->offset += sizeof(type)
+
+static void in_u8(Context* ctx, uint8_t* out_value, const char* desc) {
+ IN_SIZE(uint8_t);
+}
+
+static void in_u32(Context* ctx, uint32_t* out_value, const char* desc) {
+ IN_SIZE(uint32_t);
+}
+
+static void in_f32(Context* ctx, uint32_t* out_value, const char* desc) {
+ IN_SIZE(float);
+}
+
+static void in_f64(Context* ctx, uint64_t* out_value, const char* desc) {
+ IN_SIZE(double);
+}
+
+#undef IN_SIZE
+
+#define BYTE_AT(type, i, shift) (((type)p[i] & 0x7f) << (shift))
+
+#define LEB128_1(type) (BYTE_AT(type, 0, 0))
+#define LEB128_2(type) (BYTE_AT(type, 1, 7) | LEB128_1(type))
+#define LEB128_3(type) (BYTE_AT(type, 2, 14) | LEB128_2(type))
+#define LEB128_4(type) (BYTE_AT(type, 3, 21) | LEB128_3(type))
+#define LEB128_5(type) (BYTE_AT(type, 4, 28) | LEB128_4(type))
+#define LEB128_6(type) (BYTE_AT(type, 5, 35) | LEB128_5(type))
+#define LEB128_7(type) (BYTE_AT(type, 6, 42) | LEB128_6(type))
+#define LEB128_8(type) (BYTE_AT(type, 7, 49) | LEB128_7(type))
+#define LEB128_9(type) (BYTE_AT(type, 8, 56) | LEB128_8(type))
+#define LEB128_10(type) (BYTE_AT(type, 9, 63) | LEB128_9(type))
+
+#define SHIFT_AMOUNT(type, sign_bit) (sizeof(type) * 8 - 1 - (sign_bit))
+#define SIGN_EXTEND(type, value, sign_bit) \
+ ((type)((value) << SHIFT_AMOUNT(type, sign_bit)) >> \
+ SHIFT_AMOUNT(type, sign_bit))
+
+size_t wabt_read_u32_leb128(const uint8_t* p,
+ const uint8_t* end,
+ uint32_t* out_value) {
+ if (p < end && (p[0] & 0x80) == 0) {
+ *out_value = LEB128_1(uint32_t);
+ return 1;
+ } else if (p + 1 < end && (p[1] & 0x80) == 0) {
+ *out_value = LEB128_2(uint32_t);
+ return 2;
+ } else if (p + 2 < end && (p[2] & 0x80) == 0) {
+ *out_value = LEB128_3(uint32_t);
+ return 3;
+ } else if (p + 3 < end && (p[3] & 0x80) == 0) {
+ *out_value = LEB128_4(uint32_t);
+ return 4;
+ } else if (p + 4 < end && (p[4] & 0x80) == 0) {
+ /* the top bits set represent values > 32 bits */
+ if (p[4] & 0xf0)
+ return 0;
+ *out_value = LEB128_5(uint32_t);
+ return 5;
+ } else {
+ /* past the end */
+ *out_value = 0;
+ return 0;
+ }
+}
+
+static void in_u32_leb128(Context* ctx, uint32_t* out_value, const char* desc) {
+ const uint8_t* p = ctx->data + ctx->offset;
+ const uint8_t* end = ctx->data + ctx->read_end;
+ size_t bytes_read = wabt_read_u32_leb128(p, end, out_value);
+ if (!bytes_read)
+ RAISE_ERROR("unable to read u32 leb128: %s", desc);
+ ctx->offset += bytes_read;
+}
+
+size_t wabt_read_i32_leb128(const uint8_t* p,
+ const uint8_t* end,
+ uint32_t* out_value) {
+ if (p < end && (p[0] & 0x80) == 0) {
+ uint32_t result = LEB128_1(uint32_t);
+ *out_value = SIGN_EXTEND(int32_t, result, 6);
+ return 1;
+ } else if (p + 1 < end && (p[1] & 0x80) == 0) {
+ uint32_t result = LEB128_2(uint32_t);
+ *out_value = SIGN_EXTEND(int32_t, result, 13);
+ return 2;
+ } else if (p + 2 < end && (p[2] & 0x80) == 0) {
+ uint32_t result = LEB128_3(uint32_t);
+ *out_value = SIGN_EXTEND(int32_t, result, 20);
+ return 3;
+ } else if (p + 3 < end && (p[3] & 0x80) == 0) {
+ uint32_t result = LEB128_4(uint32_t);
+ *out_value = SIGN_EXTEND(int32_t, result, 27);
+ return 4;
+ } else if (p + 4 < end && (p[4] & 0x80) == 0) {
+ /* the top bits should be a sign-extension of the sign bit */
+ bool sign_bit_set = (p[4] & 0x8);
+ int top_bits = p[4] & 0xf0;
+ if ((sign_bit_set && top_bits != 0x70) ||
+ (!sign_bit_set && top_bits != 0)) {
+ return 0;
+ }
+ uint32_t result = LEB128_5(uint32_t);
+ *out_value = result;
+ return 5;
+ } else {
+ /* past the end */
+ return 0;
+ }
+}
+
+static void in_i32_leb128(Context* ctx, uint32_t* out_value, const char* desc) {
+ const uint8_t* p = ctx->data + ctx->offset;
+ const uint8_t* end = ctx->data + ctx->read_end;
+ size_t bytes_read = wabt_read_i32_leb128(p, end, out_value);
+ if (!bytes_read)
+ RAISE_ERROR("unable to read i32 leb128: %s", desc);
+ ctx->offset += bytes_read;
+}
+
+static void in_i64_leb128(Context* ctx, uint64_t* out_value, const char* desc) {
+ const uint8_t* p = ctx->data + ctx->offset;
+ const uint8_t* end = ctx->data + ctx->read_end;
+
+ if (p < end && (p[0] & 0x80) == 0) {
+ uint64_t result = LEB128_1(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 6);
+ ctx->offset += 1;
+ } else if (p + 1 < end && (p[1] & 0x80) == 0) {
+ uint64_t result = LEB128_2(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 13);
+ ctx->offset += 2;
+ } else if (p + 2 < end && (p[2] & 0x80) == 0) {
+ uint64_t result = LEB128_3(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 20);
+ ctx->offset += 3;
+ } else if (p + 3 < end && (p[3] & 0x80) == 0) {
+ uint64_t result = LEB128_4(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 27);
+ ctx->offset += 4;
+ } else if (p + 4 < end && (p[4] & 0x80) == 0) {
+ uint64_t result = LEB128_5(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 34);
+ ctx->offset += 5;
+ } else if (p + 5 < end && (p[5] & 0x80) == 0) {
+ uint64_t result = LEB128_6(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 41);
+ ctx->offset += 6;
+ } else if (p + 6 < end && (p[6] & 0x80) == 0) {
+ uint64_t result = LEB128_7(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 48);
+ ctx->offset += 7;
+ } else if (p + 7 < end && (p[7] & 0x80) == 0) {
+ uint64_t result = LEB128_8(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 55);
+ ctx->offset += 8;
+ } else if (p + 8 < end && (p[8] & 0x80) == 0) {
+ uint64_t result = LEB128_9(uint64_t);
+ *out_value = SIGN_EXTEND(int64_t, result, 62);
+ ctx->offset += 9;
+ } else if (p + 9 < end && (p[9] & 0x80) == 0) {
+ /* the top bits should be a sign-extension of the sign bit */
+ bool sign_bit_set = (p[9] & 0x1);
+ int top_bits = p[9] & 0xfe;
+ if ((sign_bit_set && top_bits != 0x7e) ||
+ (!sign_bit_set && top_bits != 0)) {
+ RAISE_ERROR("invalid i64 leb128: %s", desc);
+ }
+ uint64_t result = LEB128_10(uint64_t);
+ *out_value = result;
+ ctx->offset += 10;
+ } else {
+ /* past the end */
+ RAISE_ERROR("unable to read i64 leb128: %s", desc);
+ }
+}
+
+#undef BYTE_AT
+#undef LEB128_1
+#undef LEB128_2
+#undef LEB128_3
+#undef LEB128_4
+#undef LEB128_5
+#undef LEB128_6
+#undef LEB128_7
+#undef LEB128_8
+#undef LEB128_9
+#undef LEB128_10
+#undef SHIFT_AMOUNT
+#undef SIGN_EXTEND
+
+static void in_type(Context* ctx, WabtType* out_value, const char* desc) {
+ uint32_t type = 0;
+ in_i32_leb128(ctx, &type, desc);
+ /* Must be in the vs7 range: [-128, 127). */
+ if ((int32_t)type < -128 || (int32_t)type > 127)
+ RAISE_ERROR("invalid type: %d", type);
+ *out_value = (WabtType)type;
+}
+
+static void in_str(Context* ctx, WabtStringSlice* out_str, const char* desc) {
+ uint32_t str_len = 0;
+ in_u32_leb128(ctx, &str_len, "string length");
+
+ if (ctx->offset + str_len > ctx->read_end)
+ RAISE_ERROR("unable to read string: %s", desc);
+
+ out_str->start = (const char*)ctx->data + ctx->offset;
+ out_str->length = str_len;
+ ctx->offset += str_len;
+}
+
+static void in_bytes(Context* ctx,
+ const void** out_data,
+ uint32_t* out_data_size,
+ const char* desc) {
+ uint32_t data_size = 0;
+ in_u32_leb128(ctx, &data_size, "data size");
+
+ if (ctx->offset + data_size > ctx->read_end)
+ RAISE_ERROR("unable to read data: %s", desc);
+
+ *out_data = (const uint8_t*)ctx->data + ctx->offset;
+ *out_data_size = data_size;
+ ctx->offset += data_size;
+}
+
+static bool is_valid_external_kind(uint8_t kind) {
+ return kind < WABT_NUM_EXTERNAL_KINDS;
+}
+
+static bool is_concrete_type(WabtType type) {
+ switch (type) {
+ case WABT_TYPE_I32:
+ case WABT_TYPE_I64:
+ case WABT_TYPE_F32:
+ case WABT_TYPE_F64:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool is_inline_sig_type(WabtType type) {
+ return is_concrete_type(type) || type == WABT_TYPE_VOID;
+}
+
+static uint32_t num_total_funcs(Context* ctx) {
+ return ctx->num_func_imports + ctx->num_function_signatures;
+}
+
+static uint32_t num_total_tables(Context* ctx) {
+ return ctx->num_table_imports + ctx->num_tables;
+}
+
+static uint32_t num_total_memories(Context* ctx) {
+ return ctx->num_memory_imports + ctx->num_memories;
+}
+
+static uint32_t num_total_globals(Context* ctx) {
+ return ctx->num_global_imports + ctx->num_globals;
+}
+
+static void destroy_context(Context* ctx) {
+ wabt_destroy_type_vector(&ctx->param_types);
+ wabt_destroy_uint32_vector(&ctx->target_depths);
+}
+
+/* Logging */
+
+static void indent(LoggingContext* ctx) {
+ ctx->indent += INDENT_SIZE;
+}
+
+static void dedent(LoggingContext* ctx) {
+ ctx->indent -= INDENT_SIZE;
+ assert(ctx->indent >= 0);
+}
+
+static void write_indent(LoggingContext* ctx) {
+ static char s_indent[] =
+ " "
+ " ";
+ static size_t s_indent_len = sizeof(s_indent) - 1;
+ size_t indent = ctx->indent;
+ while (indent > s_indent_len) {
+ wabt_write_data(ctx->stream, s_indent, s_indent_len, NULL);
+ indent -= s_indent_len;
+ }
+ if (indent > 0) {
+ wabt_write_data(ctx->stream, s_indent, indent, NULL);
+ }
+}
+
+#define LOGF_NOINDENT(...) wabt_writef(ctx->stream, __VA_ARGS__)
+
+#define LOGF(...) \
+ do { \
+ write_indent(ctx); \
+ LOGF_NOINDENT(__VA_ARGS__); \
+ } while (0)
+
+static void logging_on_error(WabtBinaryReaderContext* ctx,
+ const char* message) {
+ LoggingContext* logging_ctx = (LoggingContext*)ctx->user_data;
+ if (logging_ctx->reader->on_error) {
+ WabtBinaryReaderContext new_ctx = *ctx;
+ new_ctx.user_data = logging_ctx->reader->user_data;
+ logging_ctx->reader->on_error(&new_ctx, message);
+ }
+}
+
+static WabtResult logging_begin_custom_section(WabtBinaryReaderContext* context,
+ uint32_t size,
+ WabtStringSlice section_name) {
+ LoggingContext* ctx = (LoggingContext*)context->user_data;
+ LOGF("begin_custom_section: '" PRIstringslice "' size=%d\n",
+ WABT_PRINTF_STRING_SLICE_ARG(section_name), size);
+ indent(ctx);
+ FORWARD_CTX(begin_custom_section, size, section_name);
+}
+
+#define LOGGING_BEGIN(name) \
+ static WabtResult logging_begin_##name(WabtBinaryReaderContext* context, \
+ uint32_t size) { \
+ LoggingContext* ctx = (LoggingContext*)context->user_data; \
+ LOGF("begin_" #name "\n"); \
+ indent(ctx); \
+ FORWARD_CTX(begin_##name, size); \
+ }
+
+#define LOGGING_END(name) \
+ static WabtResult logging_end_##name(WabtBinaryReaderContext* context) { \
+ LoggingContext* ctx = (LoggingContext*)context->user_data; \
+ dedent(ctx); \
+ LOGF("end_" #name "\n"); \
+ FORWARD_CTX0(end_##name); \
+ }
+
+#define LOGGING_UINT32(name) \
+ static WabtResult logging_##name(uint32_t value, void* user_data) { \
+ LoggingContext* ctx = (LoggingContext*)user_data; \
+ LOGF(#name "(%u)\n", value); \
+ FORWARD(name, value); \
+ }
+
+#define LOGGING_UINT32_CTX(name) \
+ static WabtResult logging_##name(WabtBinaryReaderContext* context, \
+ uint32_t value) { \
+ LoggingContext* ctx = (LoggingContext*)context->user_data; \
+ LOGF(#name "(%u)\n", value); \
+ FORWARD_CTX(name, value); \
+ }
+
+#define LOGGING_UINT32_DESC(name, desc) \
+ static WabtResult logging_##name(uint32_t value, void* user_data) { \
+ LoggingContext* ctx = (LoggingContext*)user_data; \
+ LOGF(#name "(" desc ": %u)\n", value); \
+ FORWARD(name, value); \
+ }
+
+#define LOGGING_UINT32_UINT32(name, desc0, desc1) \
+ static WabtResult logging_##name(uint32_t value0, uint32_t value1, \
+ void* user_data) { \
+ LoggingContext* ctx = (LoggingContext*)user_data; \
+ LOGF(#name "(" desc0 ": %u, " desc1 ": %u)\n", value0, value1); \
+ FORWARD(name, value0, value1); \
+ }
+
+#define LOGGING_UINT32_UINT32_CTX(name, desc0, desc1) \
+ static WabtResult logging_##name(WabtBinaryReaderContext* context, \
+ uint32_t value0, uint32_t value1) { \
+ LoggingContext* ctx = (LoggingContext*)context->user_data; \
+ LOGF(#name "(" desc0 ": %u, " desc1 ": %u)\n", value0, value1); \
+ FORWARD_CTX(name, value0, value1); \
+ }
+
+#define LOGGING_OPCODE(name) \
+ static WabtResult logging_##name(WabtOpcode opcode, void* user_data) { \
+ LoggingContext* ctx = (LoggingContext*)user_data; \
+ LOGF(#name "(\"%s\" (%u))\n", wabt_get_opcode_name(opcode), opcode); \
+ FORWARD(name, opcode); \
+ }
+
+#define LOGGING0(name) \
+ static WabtResult logging_##name(void* user_data) { \
+ LoggingContext* ctx = (LoggingContext*)user_data; \
+ LOGF(#name "\n"); \
+ FORWARD0(name); \
+ }
+
+LOGGING_UINT32(begin_module)
+LOGGING0(end_module)
+LOGGING_END(custom_section)
+LOGGING_BEGIN(signature_section)
+LOGGING_UINT32(on_signature_count)
+LOGGING_END(signature_section)
+LOGGING_BEGIN(import_section)
+LOGGING_UINT32(on_import_count)
+LOGGING_END(import_section)
+LOGGING_BEGIN(function_signatures_section)
+LOGGING_UINT32(on_function_signatures_count)
+LOGGING_UINT32_UINT32(on_function_signature, "index", "sig_index")
+LOGGING_END(function_signatures_section)
+LOGGING_BEGIN(table_section)
+LOGGING_UINT32(on_table_count)
+LOGGING_END(table_section)
+LOGGING_BEGIN(memory_section)
+LOGGING_UINT32(on_memory_count)
+LOGGING_END(memory_section)
+LOGGING_BEGIN(global_section)
+LOGGING_UINT32(on_global_count)
+LOGGING_UINT32(begin_global_init_expr)
+LOGGING_UINT32(end_global_init_expr)
+LOGGING_UINT32(end_global)
+LOGGING_END(global_section)
+LOGGING_BEGIN(export_section)
+LOGGING_UINT32(on_export_count)
+LOGGING_END(export_section)
+LOGGING_BEGIN(start_section)
+LOGGING_UINT32(on_start_function)
+LOGGING_END(start_section)
+LOGGING_BEGIN(function_bodies_section)
+LOGGING_UINT32(on_function_bodies_count)
+LOGGING_UINT32_CTX(begin_function_body)
+LOGGING_UINT32(end_function_body)
+LOGGING_UINT32(on_local_decl_count)
+LOGGING_OPCODE(on_binary_expr)
+LOGGING_UINT32_DESC(on_call_expr, "func_index")
+LOGGING_UINT32_DESC(on_call_import_expr, "import_index")
+LOGGING_UINT32_DESC(on_call_indirect_expr, "sig_index")
+LOGGING_OPCODE(on_compare_expr)
+LOGGING_OPCODE(on_convert_expr)
+LOGGING0(on_current_memory_expr)
+LOGGING0(on_drop_expr)
+LOGGING0(on_else_expr)
+LOGGING0(on_end_expr)
+LOGGING_UINT32_DESC(on_get_global_expr, "index")
+LOGGING_UINT32_DESC(on_get_local_expr, "index")
+LOGGING0(on_grow_memory_expr)
+LOGGING0(on_nop_expr)
+LOGGING0(on_return_expr)
+LOGGING0(on_select_expr)
+LOGGING_UINT32_DESC(on_set_global_expr, "index")
+LOGGING_UINT32_DESC(on_set_local_expr, "index")
+LOGGING_UINT32_DESC(on_tee_local_expr, "index")
+LOGGING0(on_unreachable_expr)
+LOGGING_OPCODE(on_unary_expr)
+LOGGING_END(function_bodies_section)
+LOGGING_BEGIN(elem_section)
+LOGGING_UINT32(on_elem_segment_count)
+LOGGING_UINT32_UINT32(begin_elem_segment, "index", "table_index")
+LOGGING_UINT32(begin_elem_segment_init_expr)
+LOGGING_UINT32(end_elem_segment_init_expr)
+LOGGING_UINT32_UINT32_CTX(on_elem_segment_function_index_count,
+ "index",
+ "count")
+LOGGING_UINT32_UINT32(on_elem_segment_function_index, "index", "func_index")
+LOGGING_UINT32(end_elem_segment)
+LOGGING_END(elem_section)
+LOGGING_BEGIN(data_section)
+LOGGING_UINT32(on_data_segment_count)
+LOGGING_UINT32_UINT32(begin_data_segment, "index", "memory_index")
+LOGGING_UINT32(begin_data_segment_init_expr)
+LOGGING_UINT32(end_data_segment_init_expr)
+LOGGING_UINT32(end_data_segment)
+LOGGING_END(data_section)
+LOGGING_BEGIN(names_section)
+LOGGING_UINT32(on_function_names_count)
+LOGGING_UINT32_UINT32(on_local_names_count, "index", "count")
+LOGGING_END(names_section)
+LOGGING_BEGIN(reloc_section)
+LOGGING_END(reloc_section)
+LOGGING_UINT32_UINT32(on_init_expr_get_global_expr, "index", "global_index")
+
+static void sprint_limits(char* dst, size_t size, const WabtLimits* limits) {
+ int result;
+ if (limits->has_max) {
+ result = wabt_snprintf(dst, size, "initial: %" PRIu64 ", max: %" PRIu64,
+ limits->initial, limits->max);
+ } else {
+ result = wabt_snprintf(dst, size, "initial: %" PRIu64, limits->initial);
+ }
+ WABT_USE(result);
+ assert((size_t)result < size);
+}
+
+static void log_types(LoggingContext* ctx,
+ uint32_t type_count,
+ WabtType* types) {
+ uint32_t i;
+ LOGF_NOINDENT("[");
+ for (i = 0; i < type_count; ++i) {
+ LOGF_NOINDENT("%s", wabt_get_type_name(types[i]));
+ if (i != type_count - 1)
+ LOGF_NOINDENT(", ");
+ }
+ LOGF_NOINDENT("]");
+}
+
+static WabtResult logging_on_signature(uint32_t index,
+ uint32_t param_count,
+ WabtType* param_types,
+ uint32_t result_count,
+ WabtType* result_types,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_signature(index: %u, params: ", index);
+ log_types(ctx, param_count, param_types);
+ LOGF_NOINDENT(", results: ");
+ log_types(ctx, result_count, result_types);
+ LOGF_NOINDENT(")\n");
+ FORWARD(on_signature, index, param_count, param_types, result_count,
+ result_types);
+}
+
+static WabtResult logging_on_import(uint32_t index,
+ WabtStringSlice module_name,
+ WabtStringSlice field_name,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_import(index: %u, module: \"" PRIstringslice
+ "\", field: \"" PRIstringslice "\")\n",
+ index, WABT_PRINTF_STRING_SLICE_ARG(module_name),
+ WABT_PRINTF_STRING_SLICE_ARG(field_name));
+ FORWARD(on_import, index, module_name, field_name);
+}
+
+static WabtResult logging_on_import_func(uint32_t import_index,
+ uint32_t func_index,
+ uint32_t sig_index,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_import_func(import_index: %u, func_index: %u, sig_index: %u)\n",
+ import_index, func_index, sig_index);
+ FORWARD(on_import_func, import_index, func_index, sig_index);
+}
+
+
+static WabtResult logging_on_import_table(uint32_t import_index,
+ uint32_t table_index,
+ WabtType elem_type,
+ const WabtLimits* elem_limits,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ char buf[100];
+ sprint_limits(buf, sizeof(buf), elem_limits);
+ LOGF(
+ "on_import_table(import_index: %u, table_index: %u, elem_type: %s, %s)\n",
+ import_index, table_index, wabt_get_type_name(elem_type), buf);
+ FORWARD(on_import_table, import_index, table_index, elem_type, elem_limits);
+}
+
+static WabtResult logging_on_import_memory(uint32_t import_index,
+ uint32_t memory_index,
+ const WabtLimits* page_limits,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ char buf[100];
+ sprint_limits(buf, sizeof(buf), page_limits);
+ LOGF("on_import_memory(import_index: %u, memory_index: %u, %s)\n",
+ import_index, memory_index, buf);
+ FORWARD(on_import_memory, import_index, memory_index, page_limits);
+}
+
+static WabtResult logging_on_import_global(uint32_t import_index,
+ uint32_t global_index,
+ WabtType type,
+ bool mutable_,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF(
+ "on_import_global(import_index: %u, global_index: %u, type: %s, mutable: "
+ "%s)\n",
+ import_index, global_index, wabt_get_type_name(type),
+ mutable_ ? "true" : "false");
+ FORWARD(on_import_global, import_index, global_index, type, mutable_);
+}
+
+static WabtResult logging_on_table(uint32_t index,
+ WabtType elem_type,
+ const WabtLimits* elem_limits,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ char buf[100];
+ sprint_limits(buf, sizeof(buf), elem_limits);
+ LOGF("on_table(index: %u, elem_type: %s, %s)\n", index,
+ wabt_get_type_name(elem_type), buf);
+ FORWARD(on_table, index, elem_type, elem_limits);
+}
+
+static WabtResult logging_on_memory(uint32_t index,
+ const WabtLimits* page_limits,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ char buf[100];
+ sprint_limits(buf, sizeof(buf), page_limits);
+ LOGF("on_memory(index: %u, %s)\n", index, buf);
+ FORWARD(on_memory, index, page_limits);
+}
+
+static WabtResult logging_begin_global(uint32_t index,
+ WabtType type,
+ bool mutable_,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("begin_global(index: %u, type: %s, mutable: %s)\n", index,
+ wabt_get_type_name(type), mutable_ ? "true" : "false");
+ FORWARD(begin_global, index, type, mutable_);
+}
+
+static WabtResult logging_on_export(uint32_t index,
+ WabtExternalKind kind,
+ uint32_t item_index,
+ WabtStringSlice name,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_export(index: %u, kind: %s, item_index: %u, name: \"" PRIstringslice
+ "\")\n",
+ index, wabt_get_kind_name(kind), item_index,
+ WABT_PRINTF_STRING_SLICE_ARG(name));
+ FORWARD(on_export, index, kind, item_index, name);
+}
+
+static WabtResult logging_begin_function_body_pass(uint32_t index,
+ uint32_t pass,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("begin_function_body_pass(index: %u, pass: %u)\n", index, pass);
+ indent(ctx);
+ FORWARD(begin_function_body_pass, index, pass);
+}
+
+static WabtResult logging_on_local_decl(uint32_t decl_index,
+ uint32_t count,
+ WabtType type,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_local_decl(index: %u, count: %u, type: %s)\n", decl_index, count,
+ wabt_get_type_name(type));
+ FORWARD(on_local_decl, decl_index, count, type);
+}
+
+static WabtResult logging_on_block_expr(uint32_t num_types,
+ WabtType* sig_types,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_block_expr(sig: ");
+ log_types(ctx, num_types, sig_types);
+ LOGF_NOINDENT(")\n");
+ FORWARD(on_block_expr, num_types, sig_types);
+}
+
+static WabtResult logging_on_br_expr(uint32_t depth, void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_br_expr(depth: %u)\n", depth);
+ FORWARD(on_br_expr, depth);
+}
+
+static WabtResult logging_on_br_if_expr(uint32_t depth, void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_br_if_expr(depth: %u)\n", depth);
+ FORWARD(on_br_if_expr, depth);
+}
+
+static WabtResult logging_on_br_table_expr(WabtBinaryReaderContext* context,
+ uint32_t num_targets,
+ uint32_t* target_depths,
+ uint32_t default_target_depth) {
+ LoggingContext* ctx = (LoggingContext*)context->user_data;
+ LOGF("on_br_table_expr(num_targets: %u, depths: [", num_targets);
+ uint32_t i;
+ for (i = 0; i < num_targets; ++i) {
+ LOGF_NOINDENT("%u", target_depths[i]);
+ if (i != num_targets - 1)
+ LOGF_NOINDENT(", ");
+ }
+ LOGF_NOINDENT("], default: %u)\n", default_target_depth);
+ FORWARD_CTX(on_br_table_expr, num_targets, target_depths,
+ default_target_depth);
+}
+
+static WabtResult logging_on_f32_const_expr(uint32_t value_bits,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ float value;
+ memcpy(&value, &value_bits, sizeof(value));
+ LOGF("on_f32_const_expr(%g (0x04%x))\n", value, value_bits);
+ FORWARD(on_f32_const_expr, value_bits);
+}
+
+static WabtResult logging_on_f64_const_expr(uint64_t value_bits,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ double value;
+ memcpy(&value, &value_bits, sizeof(value));
+ LOGF("on_f64_const_expr(%g (0x08%" PRIx64 "))\n", value, value_bits);
+ FORWARD(on_f64_const_expr, value_bits);
+}
+
+static WabtResult logging_on_i32_const_expr(uint32_t value, void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_i32_const_expr(%u (0x%x))\n", value, value);
+ FORWARD(on_i32_const_expr, value);
+}
+
+static WabtResult logging_on_i64_const_expr(uint64_t value, void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_i64_const_expr(%" PRIu64 " (0x%" PRIx64 "))\n", value, value);
+ FORWARD(on_i64_const_expr, value);
+}
+
+static WabtResult logging_on_if_expr(uint32_t num_types,
+ WabtType* sig_types,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_if_expr(sig: ");
+ log_types(ctx, num_types, sig_types);
+ LOGF_NOINDENT(")\n");
+ FORWARD(on_if_expr, num_types, sig_types);
+}
+
+static WabtResult logging_on_load_expr(WabtOpcode opcode,
+ uint32_t alignment_log2,
+ uint32_t offset,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_load_expr(opcode: \"%s\" (%u), align log2: %u, offset: %u)\n",
+ wabt_get_opcode_name(opcode), opcode, alignment_log2, offset);
+ FORWARD(on_load_expr, opcode, alignment_log2, offset);
+}
+
+static WabtResult logging_on_loop_expr(uint32_t num_types,
+ WabtType* sig_types,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_loop_expr(sig: ");
+ log_types(ctx, num_types, sig_types);
+ LOGF_NOINDENT(")\n");
+ FORWARD(on_loop_expr, num_types, sig_types);
+}
+
+static WabtResult logging_on_store_expr(WabtOpcode opcode,
+ uint32_t alignment_log2,
+ uint32_t offset,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_store_expr(opcode: \"%s\" (%u), align log2: %u, offset: %u)\n",
+ wabt_get_opcode_name(opcode), opcode, alignment_log2, offset);
+ FORWARD(on_store_expr, opcode, alignment_log2, offset);
+}
+
+static WabtResult logging_end_function_body_pass(uint32_t index,
+ uint32_t pass,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ dedent(ctx);
+ LOGF("end_function_body_pass(index: %u, pass: %u)\n", index, pass);
+ FORWARD(end_function_body_pass, index, pass);
+}
+
+static WabtResult logging_on_data_segment_data(uint32_t index,
+ const void* data,
+ uint32_t size,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_data_segment_data(index:%u, size:%u)\n", index, size);
+ FORWARD(on_data_segment_data, index, data, size);
+}
+
+static WabtResult logging_on_function_name(uint32_t index,
+ WabtStringSlice name,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_function_name(index: %u, name: \"" PRIstringslice "\")\n", index,
+ WABT_PRINTF_STRING_SLICE_ARG(name));
+ FORWARD(on_function_name, index, name);
+}
+
+static WabtResult logging_on_local_name(uint32_t func_index,
+ uint32_t local_index,
+ WabtStringSlice name,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_local_name(func_index: %u, local_index: %u, name: \"" PRIstringslice
+ "\")\n",
+ func_index, local_index, WABT_PRINTF_STRING_SLICE_ARG(name));
+ FORWARD(on_local_name, func_index, local_index, name);
+}
+
+static WabtResult logging_on_init_expr_f32_const_expr(uint32_t index,
+ uint32_t value_bits,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ float value;
+ memcpy(&value, &value_bits, sizeof(value));
+ LOGF("on_init_expr_f32_const_expr(index: %u, value: %g (0x04%x))\n", index,
+ value, value_bits);
+ FORWARD(on_init_expr_f32_const_expr, index, value_bits);
+}
+
+static WabtResult logging_on_init_expr_f64_const_expr(uint32_t index,
+ uint64_t value_bits,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ double value;
+ memcpy(&value, &value_bits, sizeof(value));
+ LOGF("on_init_expr_f64_const_expr(index: %u value: %g (0x08%" PRIx64 "))\n",
+ index, value, value_bits);
+ FORWARD(on_init_expr_f64_const_expr, index, value_bits);
+}
+
+static WabtResult logging_on_init_expr_i32_const_expr(uint32_t index,
+ uint32_t value,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_init_expr_i32_const_expr(index: %u, value: %u)\n", index, value);
+ FORWARD(on_init_expr_i32_const_expr, index, value);
+}
+
+static WabtResult logging_on_init_expr_i64_const_expr(uint32_t index,
+ uint64_t value,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_init_expr_i64_const_expr(index: %u, value: %" PRIu64 ")\n", index,
+ value);
+ FORWARD(on_init_expr_i64_const_expr, index, value);
+}
+
+static WabtResult logging_on_reloc_count(uint32_t count,
+ WabtBinarySection section_code,
+ WabtStringSlice section_name,
+ void* user_data) {
+ LoggingContext* ctx = (LoggingContext*)user_data;
+ LOGF("on_reloc_count(count: %d, section: %s, section_name: " PRIstringslice
+ ")\n",
+ count, wabt_get_section_name(section_code),
+ WABT_PRINTF_STRING_SLICE_ARG(section_name));
+ FORWARD(on_reloc_count, count, section_code, section_name);
+}
+
+static void read_init_expr(Context* ctx, uint32_t index) {
+ uint8_t opcode;
+ in_u8(ctx, &opcode, "opcode");
+ switch (opcode) {
+ case WABT_OPCODE_I32_CONST: {
+ uint32_t value = 0;
+ in_i32_leb128(ctx, &value, "init_expr i32.const value");
+ CALLBACK(on_init_expr_i32_const_expr, index, value);
+ break;
+ }
+
+ case WABT_OPCODE_I64_CONST: {
+ uint64_t value = 0;
+ in_i64_leb128(ctx, &value, "init_expr i64.const value");
+ CALLBACK(on_init_expr_i64_const_expr, index, value);
+ break;
+ }
+
+ case WABT_OPCODE_F32_CONST: {
+ uint32_t value_bits = 0;
+ in_f32(ctx, &value_bits, "init_expr f32.const value");
+ CALLBACK(on_init_expr_f32_const_expr, index, value_bits);
+ break;
+ }
+
+ case WABT_OPCODE_F64_CONST: {
+ uint64_t value_bits = 0;
+ in_f64(ctx, &value_bits, "init_expr f64.const value");
+ CALLBACK(on_init_expr_f64_const_expr, index, value_bits);
+ break;
+ }
+
+ case WABT_OPCODE_GET_GLOBAL: {
+ uint32_t global_index;
+ in_u32_leb128(ctx, &global_index, "init_expr get_global index");
+ CALLBACK(on_init_expr_get_global_expr, index, global_index);
+ break;
+ }
+
+ case WABT_OPCODE_END:
+ return;
+
+ default:
+ RAISE_ERROR("unexpected opcode in initializer expression: %d (0x%x)",
+ opcode, opcode);
+ break;
+ }
+
+ in_u8(ctx, &opcode, "opcode");
+ RAISE_ERROR_UNLESS(opcode == WABT_OPCODE_END,
+ "expected END opcode after initializer expression");
+}
+
+static void read_table(Context* ctx,
+ WabtType* out_elem_type,
+ WabtLimits* out_elem_limits) {
+ in_type(ctx, out_elem_type, "table elem type");
+ RAISE_ERROR_UNLESS(*out_elem_type == WABT_TYPE_ANYFUNC,
+ "table elem type must by anyfunc");
+
+ uint32_t flags;
+ uint32_t initial;
+ uint32_t max = 0;
+ in_u32_leb128(ctx, &flags, "table flags");
+ in_u32_leb128(ctx, &initial, "table initial elem count");
+ bool has_max = flags & WABT_BINARY_LIMITS_HAS_MAX_FLAG;
+ if (has_max) {
+ in_u32_leb128(ctx, &max, "table max elem count");
+ RAISE_ERROR_UNLESS(initial <= max,
+ "table initial elem count must be <= max elem count");
+ }
+
+ out_elem_limits->has_max = has_max;
+ out_elem_limits->initial = initial;
+ out_elem_limits->max = max;
+}
+
+static void read_memory(Context* ctx, WabtLimits* out_page_limits) {
+ uint32_t flags;
+ uint32_t initial;
+ uint32_t max = 0;
+ in_u32_leb128(ctx, &flags, "memory flags");
+ in_u32_leb128(ctx, &initial, "memory initial page count");
+ bool has_max = flags & WABT_BINARY_LIMITS_HAS_MAX_FLAG;
+ RAISE_ERROR_UNLESS(initial <= WABT_MAX_PAGES, "invalid memory initial size");
+ if (has_max) {
+ in_u32_leb128(ctx, &max, "memory max page count");
+ RAISE_ERROR_UNLESS(max <= WABT_MAX_PAGES, "invalid memory max size");
+ RAISE_ERROR_UNLESS(initial <= max,
+ "memory initial size must be <= max size");
+ }
+
+ out_page_limits->has_max = has_max;
+ out_page_limits->initial = initial;
+ out_page_limits->max = max;
+}
+
+static void read_global_header(Context* ctx,
+ WabtType* out_type,
+ bool* out_mutable) {
+ WabtType global_type;
+ uint8_t mutable_;
+ in_type(ctx, &global_type, "global type");
+ RAISE_ERROR_UNLESS(is_concrete_type(global_type),
+ "expected valid global type");
+
+ in_u8(ctx, &mutable_, "global mutability");
+ RAISE_ERROR_UNLESS(mutable_ <= 1, "global mutability must be 0 or 1");
+
+ *out_type = global_type;
+ *out_mutable = mutable_;
+}
+
+static void read_function_body(Context* ctx, uint32_t end_offset) {
+ bool seen_end_opcode = false;
+ while (ctx->offset < end_offset) {
+ uint8_t opcode_u8;
+ in_u8(ctx, &opcode_u8, "opcode");
+ WabtOpcode opcode = (WabtOpcode)opcode_u8;
+ CALLBACK_CTX(on_opcode, opcode);
+ switch (opcode) {
+ case WABT_OPCODE_UNREACHABLE:
+ CALLBACK0(on_unreachable_expr);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_BLOCK: {
+ WabtType sig_type;
+ in_type(ctx, &sig_type, "block signature type");
+ RAISE_ERROR_UNLESS(is_inline_sig_type(sig_type),
+ "expected valid block signature type");
+ uint32_t num_types = sig_type == WABT_TYPE_VOID ? 0 : 1;
+ CALLBACK(on_block_expr, num_types, &sig_type);
+ CALLBACK_CTX(on_opcode_block_sig, num_types, &sig_type);
+ break;
+ }
+
+ case WABT_OPCODE_LOOP: {
+ WabtType sig_type;
+ in_type(ctx, &sig_type, "loop signature type");
+ RAISE_ERROR_UNLESS(is_inline_sig_type(sig_type),
+ "expected valid block signature type");
+ uint32_t num_types = sig_type == WABT_TYPE_VOID ? 0 : 1;
+ CALLBACK(on_loop_expr, num_types, &sig_type);
+ CALLBACK_CTX(on_opcode_block_sig, num_types, &sig_type);
+ break;
+ }
+
+ case WABT_OPCODE_IF: {
+ WabtType sig_type;
+ in_type(ctx, &sig_type, "if signature type");
+ RAISE_ERROR_UNLESS(is_inline_sig_type(sig_type),
+ "expected valid block signature type");
+ uint32_t num_types = sig_type == WABT_TYPE_VOID ? 0 : 1;
+ CALLBACK(on_if_expr, num_types, &sig_type);
+ CALLBACK_CTX(on_opcode_block_sig, num_types, &sig_type);
+ break;
+ }
+
+ case WABT_OPCODE_ELSE:
+ CALLBACK0(on_else_expr);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_SELECT:
+ CALLBACK0(on_select_expr);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_BR: {
+ uint32_t depth;
+ in_u32_leb128(ctx, &depth, "br depth");
+ CALLBACK(on_br_expr, depth);
+ CALLBACK_CTX(on_opcode_uint32, depth);
+ break;
+ }
+
+ case WABT_OPCODE_BR_IF: {
+ uint32_t depth;
+ in_u32_leb128(ctx, &depth, "br_if depth");
+ CALLBACK(on_br_if_expr, depth);
+ CALLBACK_CTX(on_opcode_uint32, depth);
+ break;
+ }
+
+ case WABT_OPCODE_BR_TABLE: {
+ uint32_t num_targets;
+ in_u32_leb128(ctx, &num_targets, "br_table target count");
+ if (num_targets > ctx->target_depths.capacity) {
+ wabt_reserve_uint32s(&ctx->target_depths, num_targets);
+ ctx->target_depths.size = num_targets;
+ }
+
+ uint32_t i;
+ for (i = 0; i < num_targets; ++i) {
+ uint32_t target_depth;
+ in_u32_leb128(ctx, &target_depth, "br_table target depth");
+ ctx->target_depths.data[i] = target_depth;
+ }
+
+ uint32_t default_target_depth;
+ in_u32_leb128(ctx, &default_target_depth,
+ "br_table default target depth");
+
+ CALLBACK_CTX(on_br_table_expr, num_targets, ctx->target_depths.data,
+ default_target_depth);
+ break;
+ }
+
+ case WABT_OPCODE_RETURN:
+ CALLBACK0(on_return_expr);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_NOP:
+ CALLBACK0(on_nop_expr);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_DROP:
+ CALLBACK0(on_drop_expr);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_END:
+ if (ctx->offset == end_offset)
+ seen_end_opcode = true;
+ else
+ CALLBACK0(on_end_expr);
+ break;
+
+ case WABT_OPCODE_I32_CONST: {
+ uint32_t value = 0;
+ in_i32_leb128(ctx, &value, "i32.const value");
+ CALLBACK(on_i32_const_expr, value);
+ CALLBACK_CTX(on_opcode_uint32, value);
+ break;
+ }
+
+ case WABT_OPCODE_I64_CONST: {
+ uint64_t value = 0;
+ in_i64_leb128(ctx, &value, "i64.const value");
+ CALLBACK(on_i64_const_expr, value);
+ CALLBACK_CTX(on_opcode_uint64, value);
+ break;
+ }
+
+ case WABT_OPCODE_F32_CONST: {
+ uint32_t value_bits = 0;
+ in_f32(ctx, &value_bits, "f32.const value");
+ CALLBACK(on_f32_const_expr, value_bits);
+ CALLBACK_CTX(on_opcode_f32, value_bits);
+ break;
+ }
+
+ case WABT_OPCODE_F64_CONST: {
+ uint64_t value_bits = 0;
+ in_f64(ctx, &value_bits, "f64.const value");
+ CALLBACK(on_f64_const_expr, value_bits);
+ CALLBACK_CTX(on_opcode_f64, value_bits);
+ break;
+ }
+
+ case WABT_OPCODE_GET_GLOBAL: {
+ uint32_t global_index;
+ in_u32_leb128(ctx, &global_index, "get_global global index");
+ CALLBACK(on_get_global_expr, global_index);
+ CALLBACK_CTX(on_opcode_uint32, global_index);
+ break;
+ }
+
+ case WABT_OPCODE_GET_LOCAL: {
+ uint32_t local_index;
+ in_u32_leb128(ctx, &local_index, "get_local local index");
+ CALLBACK(on_get_local_expr, local_index);
+ CALLBACK_CTX(on_opcode_uint32, local_index);
+ break;
+ }
+
+ case WABT_OPCODE_SET_GLOBAL: {
+ uint32_t global_index;
+ in_u32_leb128(ctx, &global_index, "set_global global index");
+ CALLBACK(on_set_global_expr, global_index);
+ CALLBACK_CTX(on_opcode_uint32, global_index);
+ break;
+ }
+
+ case WABT_OPCODE_SET_LOCAL: {
+ uint32_t local_index;
+ in_u32_leb128(ctx, &local_index, "set_local local index");
+ CALLBACK(on_set_local_expr, local_index);
+ CALLBACK_CTX(on_opcode_uint32, local_index);
+ break;
+ }
+
+ case WABT_OPCODE_CALL: {
+ uint32_t func_index;
+ in_u32_leb128(ctx, &func_index, "call function index");
+ RAISE_ERROR_UNLESS(func_index < num_total_funcs(ctx),
+ "invalid call function index");
+ CALLBACK(on_call_expr, func_index);
+ CALLBACK_CTX(on_opcode_uint32, func_index);
+ break;
+ }
+
+ case WABT_OPCODE_CALL_INDIRECT: {
+ uint32_t sig_index;
+ in_u32_leb128(ctx, &sig_index, "call_indirect signature index");
+ RAISE_ERROR_UNLESS(sig_index < ctx->num_signatures,
+ "invalid call_indirect signature index");
+ uint32_t reserved;
+ in_u32_leb128(ctx, &reserved, "call_indirect reserved");
+ RAISE_ERROR_UNLESS(reserved == 0,
+ "call_indirect reserved value must be 0");
+ CALLBACK(on_call_indirect_expr, sig_index);
+ CALLBACK_CTX(on_opcode_uint32_uint32, sig_index, reserved);
+ break;
+ }
+
+ case WABT_OPCODE_TEE_LOCAL: {
+ uint32_t local_index;
+ in_u32_leb128(ctx, &local_index, "tee_local local index");
+ CALLBACK(on_tee_local_expr, local_index);
+ CALLBACK_CTX(on_opcode_uint32, local_index);
+ break;
+ }
+
+ case WABT_OPCODE_I32_LOAD8_S:
+ case WABT_OPCODE_I32_LOAD8_U:
+ case WABT_OPCODE_I32_LOAD16_S:
+ case WABT_OPCODE_I32_LOAD16_U:
+ case WABT_OPCODE_I64_LOAD8_S:
+ case WABT_OPCODE_I64_LOAD8_U:
+ case WABT_OPCODE_I64_LOAD16_S:
+ case WABT_OPCODE_I64_LOAD16_U:
+ case WABT_OPCODE_I64_LOAD32_S:
+ case WABT_OPCODE_I64_LOAD32_U:
+ case WABT_OPCODE_I32_LOAD:
+ case WABT_OPCODE_I64_LOAD:
+ case WABT_OPCODE_F32_LOAD:
+ case WABT_OPCODE_F64_LOAD: {
+ uint32_t alignment_log2;
+ in_u32_leb128(ctx, &alignment_log2, "load alignment");
+ uint32_t offset;
+ in_u32_leb128(ctx, &offset, "load offset");
+
+ CALLBACK(on_load_expr, opcode, alignment_log2, offset);
+ CALLBACK_CTX(on_opcode_uint32_uint32, alignment_log2, offset);
+ break;
+ }
+
+ case WABT_OPCODE_I32_STORE8:
+ case WABT_OPCODE_I32_STORE16:
+ case WABT_OPCODE_I64_STORE8:
+ case WABT_OPCODE_I64_STORE16:
+ case WABT_OPCODE_I64_STORE32:
+ case WABT_OPCODE_I32_STORE:
+ case WABT_OPCODE_I64_STORE:
+ case WABT_OPCODE_F32_STORE:
+ case WABT_OPCODE_F64_STORE: {
+ uint32_t alignment_log2;
+ in_u32_leb128(ctx, &alignment_log2, "store alignment");
+ uint32_t offset;
+ in_u32_leb128(ctx, &offset, "store offset");
+
+ CALLBACK(on_store_expr, opcode, alignment_log2, offset);
+ CALLBACK_CTX(on_opcode_uint32_uint32, alignment_log2, offset);
+ break;
+ }
+
+ case WABT_OPCODE_CURRENT_MEMORY: {
+ uint32_t reserved;
+ in_u32_leb128(ctx, &reserved, "current_memory reserved");
+ RAISE_ERROR_UNLESS(reserved == 0,
+ "current_memory reserved value must be 0");
+ CALLBACK0(on_current_memory_expr);
+ CALLBACK_CTX(on_opcode_uint32, reserved);
+ break;
+ }
+
+ case WABT_OPCODE_GROW_MEMORY: {
+ uint32_t reserved;
+ in_u32_leb128(ctx, &reserved, "grow_memory reserved");
+ RAISE_ERROR_UNLESS(reserved == 0,
+ "grow_memory reserved value must be 0");
+ CALLBACK0(on_grow_memory_expr);
+ CALLBACK_CTX(on_opcode_uint32, reserved);
+ break;
+ }
+
+ case WABT_OPCODE_I32_ADD:
+ case WABT_OPCODE_I32_SUB:
+ case WABT_OPCODE_I32_MUL:
+ case WABT_OPCODE_I32_DIV_S:
+ case WABT_OPCODE_I32_DIV_U:
+ case WABT_OPCODE_I32_REM_S:
+ case WABT_OPCODE_I32_REM_U:
+ case WABT_OPCODE_I32_AND:
+ case WABT_OPCODE_I32_OR:
+ case WABT_OPCODE_I32_XOR:
+ case WABT_OPCODE_I32_SHL:
+ case WABT_OPCODE_I32_SHR_U:
+ case WABT_OPCODE_I32_SHR_S:
+ case WABT_OPCODE_I32_ROTR:
+ case WABT_OPCODE_I32_ROTL:
+ case WABT_OPCODE_I64_ADD:
+ case WABT_OPCODE_I64_SUB:
+ case WABT_OPCODE_I64_MUL:
+ case WABT_OPCODE_I64_DIV_S:
+ case WABT_OPCODE_I64_DIV_U:
+ case WABT_OPCODE_I64_REM_S:
+ case WABT_OPCODE_I64_REM_U:
+ case WABT_OPCODE_I64_AND:
+ case WABT_OPCODE_I64_OR:
+ case WABT_OPCODE_I64_XOR:
+ case WABT_OPCODE_I64_SHL:
+ case WABT_OPCODE_I64_SHR_U:
+ case WABT_OPCODE_I64_SHR_S:
+ case WABT_OPCODE_I64_ROTR:
+ case WABT_OPCODE_I64_ROTL:
+ case WABT_OPCODE_F32_ADD:
+ case WABT_OPCODE_F32_SUB:
+ case WABT_OPCODE_F32_MUL:
+ case WABT_OPCODE_F32_DIV:
+ case WABT_OPCODE_F32_MIN:
+ case WABT_OPCODE_F32_MAX:
+ case WABT_OPCODE_F32_COPYSIGN:
+ case WABT_OPCODE_F64_ADD:
+ case WABT_OPCODE_F64_SUB:
+ case WABT_OPCODE_F64_MUL:
+ case WABT_OPCODE_F64_DIV:
+ case WABT_OPCODE_F64_MIN:
+ case WABT_OPCODE_F64_MAX:
+ case WABT_OPCODE_F64_COPYSIGN:
+ CALLBACK(on_binary_expr, opcode);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_I32_EQ:
+ case WABT_OPCODE_I32_NE:
+ case WABT_OPCODE_I32_LT_S:
+ case WABT_OPCODE_I32_LE_S:
+ case WABT_OPCODE_I32_LT_U:
+ case WABT_OPCODE_I32_LE_U:
+ case WABT_OPCODE_I32_GT_S:
+ case WABT_OPCODE_I32_GE_S:
+ case WABT_OPCODE_I32_GT_U:
+ case WABT_OPCODE_I32_GE_U:
+ case WABT_OPCODE_I64_EQ:
+ case WABT_OPCODE_I64_NE:
+ case WABT_OPCODE_I64_LT_S:
+ case WABT_OPCODE_I64_LE_S:
+ case WABT_OPCODE_I64_LT_U:
+ case WABT_OPCODE_I64_LE_U:
+ case WABT_OPCODE_I64_GT_S:
+ case WABT_OPCODE_I64_GE_S:
+ case WABT_OPCODE_I64_GT_U:
+ case WABT_OPCODE_I64_GE_U:
+ case WABT_OPCODE_F32_EQ:
+ case WABT_OPCODE_F32_NE:
+ case WABT_OPCODE_F32_LT:
+ case WABT_OPCODE_F32_LE:
+ case WABT_OPCODE_F32_GT:
+ case WABT_OPCODE_F32_GE:
+ case WABT_OPCODE_F64_EQ:
+ case WABT_OPCODE_F64_NE:
+ case WABT_OPCODE_F64_LT:
+ case WABT_OPCODE_F64_LE:
+ case WABT_OPCODE_F64_GT:
+ case WABT_OPCODE_F64_GE:
+ CALLBACK(on_compare_expr, opcode);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_I32_CLZ:
+ case WABT_OPCODE_I32_CTZ:
+ case WABT_OPCODE_I32_POPCNT:
+ case WABT_OPCODE_I64_CLZ:
+ case WABT_OPCODE_I64_CTZ:
+ case WABT_OPCODE_I64_POPCNT:
+ case WABT_OPCODE_F32_ABS:
+ case WABT_OPCODE_F32_NEG:
+ case WABT_OPCODE_F32_CEIL:
+ case WABT_OPCODE_F32_FLOOR:
+ case WABT_OPCODE_F32_TRUNC:
+ case WABT_OPCODE_F32_NEAREST:
+ case WABT_OPCODE_F32_SQRT:
+ case WABT_OPCODE_F64_ABS:
+ case WABT_OPCODE_F64_NEG:
+ case WABT_OPCODE_F64_CEIL:
+ case WABT_OPCODE_F64_FLOOR:
+ case WABT_OPCODE_F64_TRUNC:
+ case WABT_OPCODE_F64_NEAREST:
+ case WABT_OPCODE_F64_SQRT:
+ CALLBACK(on_unary_expr, opcode);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ case WABT_OPCODE_I32_TRUNC_S_F32:
+ case WABT_OPCODE_I32_TRUNC_S_F64:
+ case WABT_OPCODE_I32_TRUNC_U_F32:
+ case WABT_OPCODE_I32_TRUNC_U_F64:
+ case WABT_OPCODE_I32_WRAP_I64:
+ case WABT_OPCODE_I64_TRUNC_S_F32:
+ case WABT_OPCODE_I64_TRUNC_S_F64:
+ case WABT_OPCODE_I64_TRUNC_U_F32:
+ case WABT_OPCODE_I64_TRUNC_U_F64:
+ case WABT_OPCODE_I64_EXTEND_S_I32:
+ case WABT_OPCODE_I64_EXTEND_U_I32:
+ case WABT_OPCODE_F32_CONVERT_S_I32:
+ case WABT_OPCODE_F32_CONVERT_U_I32:
+ case WABT_OPCODE_F32_CONVERT_S_I64:
+ case WABT_OPCODE_F32_CONVERT_U_I64:
+ case WABT_OPCODE_F32_DEMOTE_F64:
+ case WABT_OPCODE_F32_REINTERPRET_I32:
+ case WABT_OPCODE_F64_CONVERT_S_I32:
+ case WABT_OPCODE_F64_CONVERT_U_I32:
+ case WABT_OPCODE_F64_CONVERT_S_I64:
+ case WABT_OPCODE_F64_CONVERT_U_I64:
+ case WABT_OPCODE_F64_PROMOTE_F32:
+ case WABT_OPCODE_F64_REINTERPRET_I64:
+ case WABT_OPCODE_I32_REINTERPRET_F32:
+ case WABT_OPCODE_I64_REINTERPRET_F64:
+ case WABT_OPCODE_I32_EQZ:
+ case WABT_OPCODE_I64_EQZ:
+ CALLBACK(on_convert_expr, opcode);
+ CALLBACK_CTX0(on_opcode_bare);
+ break;
+
+ default:
+ RAISE_ERROR("unexpected opcode: %d (0x%x)", opcode, opcode);
+ }
+ }
+ RAISE_ERROR_UNLESS(ctx->offset == end_offset,
+ "function body longer than given size");
+ RAISE_ERROR_UNLESS(seen_end_opcode, "function body must end with END opcode");
+}
+
+static void read_custom_section(Context* ctx, uint32_t section_size) {
+ WabtStringSlice section_name;
+ in_str(ctx, &section_name, "section name");
+ CALLBACK_CTX(begin_custom_section, section_size, section_name);
+
+ bool name_section_ok = ctx->last_known_section >= WABT_BINARY_SECTION_IMPORT;
+ if (ctx->options->read_debug_names && name_section_ok &&
+ strncmp(section_name.start, WABT_BINARY_SECTION_NAME,
+ section_name.length) == 0) {
+ CALLBACK_SECTION(begin_names_section, section_size);
+ uint32_t i, num_functions;
+ in_u32_leb128(ctx, &num_functions, "function name count");
+ CALLBACK(on_function_names_count, num_functions);
+ for (i = 0; i < num_functions; ++i) {
+ WabtStringSlice function_name;
+ in_str(ctx, &function_name, "function name");
+ CALLBACK(on_function_name, i, function_name);
+
+ uint32_t num_locals;
+ in_u32_leb128(ctx, &num_locals, "local name count");
+ CALLBACK(on_local_names_count, i, num_locals);
+ uint32_t j;
+ for (j = 0; j < num_locals; ++j) {
+ WabtStringSlice local_name;
+ in_str(ctx, &local_name, "local name");
+ CALLBACK(on_local_name, i, j, local_name);
+ }
+ }
+ CALLBACK_CTX0(end_names_section);
+ } else if (strncmp(section_name.start, WABT_BINARY_SECTION_RELOC,
+ strlen(WABT_BINARY_SECTION_RELOC)) == 0) {
+ CALLBACK_SECTION(begin_reloc_section, section_size);
+ uint32_t i, num_relocs, section;
+ in_u32_leb128(ctx, &section, "section");
+ WABT_ZERO_MEMORY(section_name);
+ if (section == WABT_BINARY_SECTION_CUSTOM)
+ in_str(ctx, &section_name, "section name");
+ in_u32_leb128(ctx, &num_relocs, "relocation count");
+ CALLBACK(on_reloc_count, num_relocs, (WabtBinarySection)section,
+ section_name);
+ for (i = 0; i < num_relocs; ++i) {
+ uint32_t reloc_type, offset;
+ in_u32_leb128(ctx, &reloc_type, "relocation type");
+ in_u32_leb128(ctx, &offset, "offset");
+ CALLBACK(on_reloc, (WabtRelocType)reloc_type, offset);
+ }
+ CALLBACK_CTX0(end_reloc_section);
+ } else {
+ /* This is an unknown custom section, skip it. */
+ ctx->offset = ctx->read_end;
+ }
+ CALLBACK_CTX0(end_custom_section);
+}
+
+static void read_type_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_signature_section, section_size);
+ uint32_t i;
+ in_u32_leb128(ctx, &ctx->num_signatures, "type count");
+ CALLBACK(on_signature_count, ctx->num_signatures);
+
+ for (i = 0; i < ctx->num_signatures; ++i) {
+ WabtType form;
+ in_type(ctx, &form, "type form");
+ RAISE_ERROR_UNLESS(form == WABT_TYPE_FUNC, "unexpected type form");
+
+ uint32_t num_params;
+ in_u32_leb128(ctx, &num_params, "function param count");
+
+ if (num_params > ctx->param_types.capacity)
+ wabt_reserve_types(&ctx->param_types, num_params);
+
+ uint32_t j;
+ for (j = 0; j < num_params; ++j) {
+ WabtType param_type;
+ in_type(ctx, &param_type, "function param type");
+ RAISE_ERROR_UNLESS(is_concrete_type(param_type),
+ "expected valid param type");
+ ctx->param_types.data[j] = param_type;
+ }
+
+ uint32_t num_results;
+ in_u32_leb128(ctx, &num_results, "function result count");
+ RAISE_ERROR_UNLESS(num_results <= 1, "result count must be 0 or 1");
+
+ WabtType result_type = WABT_TYPE_VOID;
+ if (num_results) {
+ in_type(ctx, &result_type, "function result type");
+ RAISE_ERROR_UNLESS(is_concrete_type(result_type),
+ "expected valid result type");
+ }
+
+ CALLBACK(on_signature, i, num_params, ctx->param_types.data, num_results,
+ &result_type);
+ }
+ CALLBACK_CTX0(end_signature_section);
+}
+
+static void read_import_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_import_section, section_size);
+ uint32_t i;
+ in_u32_leb128(ctx, &ctx->num_imports, "import count");
+ CALLBACK(on_import_count, ctx->num_imports);
+ for (i = 0; i < ctx->num_imports; ++i) {
+ WabtStringSlice module_name;
+ in_str(ctx, &module_name, "import module name");
+ WabtStringSlice field_name;
+ in_str(ctx, &field_name, "import field name");
+ CALLBACK(on_import, i, module_name, field_name);
+
+ uint32_t kind;
+ in_u32_leb128(ctx, &kind, "import kind");
+ switch (kind) {
+ case WABT_EXTERNAL_KIND_FUNC: {
+ uint32_t sig_index;
+ in_u32_leb128(ctx, &sig_index, "import signature index");
+ RAISE_ERROR_UNLESS(sig_index < ctx->num_signatures,
+ "invalid import signature index");
+ CALLBACK(on_import_func, i, ctx->num_func_imports, sig_index);
+ ctx->num_func_imports++;
+ break;
+ }
+
+ case WABT_EXTERNAL_KIND_TABLE: {
+ WabtType elem_type;
+ WabtLimits elem_limits;
+ read_table(ctx, &elem_type, &elem_limits);
+ CALLBACK(on_import_table, i, ctx->num_table_imports, elem_type,
+ &elem_limits);
+ ctx->num_table_imports++;
+ break;
+ }
+
+ case WABT_EXTERNAL_KIND_MEMORY: {
+ WabtLimits page_limits;
+ read_memory(ctx, &page_limits);
+ CALLBACK(on_import_memory, i, ctx->num_memory_imports, &page_limits);
+ ctx->num_memory_imports++;
+ break;
+ }
+
+ case WABT_EXTERNAL_KIND_GLOBAL: {
+ WabtType type;
+ bool mutable_;
+ read_global_header(ctx, &type, &mutable_);
+ CALLBACK(on_import_global, i, ctx->num_global_imports, type, mutable_);
+ ctx->num_global_imports++;
+ break;
+ }
+
+ default:
+ RAISE_ERROR("invalid import kind: %d", kind);
+ }
+ }
+ CALLBACK_CTX0(end_import_section);
+}
+
+static void read_function_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_function_signatures_section, section_size);
+ uint32_t i;
+ in_u32_leb128(ctx, &ctx->num_function_signatures, "function signature count");
+ CALLBACK(on_function_signatures_count, ctx->num_function_signatures);
+ for (i = 0; i < ctx->num_function_signatures; ++i) {
+ uint32_t func_index = ctx->num_func_imports + i;
+ uint32_t sig_index;
+ in_u32_leb128(ctx, &sig_index, "function signature index");
+ RAISE_ERROR_UNLESS(sig_index < ctx->num_signatures,
+ "invalid function signature index: %d", sig_index);
+ CALLBACK(on_function_signature, func_index, sig_index);
+ }
+ CALLBACK_CTX0(end_function_signatures_section);
+}
+
+static void read_table_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_table_section, section_size);
+ uint32_t i;
+ in_u32_leb128(ctx, &ctx->num_tables, "table count");
+ RAISE_ERROR_UNLESS(ctx->num_tables <= 1, "table count (%d) must be 0 or 1",
+ ctx->num_tables);
+ CALLBACK(on_table_count, ctx->num_tables);
+ for (i = 0; i < ctx->num_tables; ++i) {
+ uint32_t table_index = ctx->num_table_imports + i;
+ WabtType elem_type;
+ WabtLimits elem_limits;
+ read_table(ctx, &elem_type, &elem_limits);
+ CALLBACK(on_table, table_index, elem_type, &elem_limits);
+ }
+ CALLBACK_CTX0(end_table_section);
+}
+
+static void read_memory_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_memory_section, section_size);
+ uint32_t i;
+ in_u32_leb128(ctx, &ctx->num_memories, "memory count");
+ RAISE_ERROR_UNLESS(ctx->num_memories <= 1, "memory count must be 0 or 1");
+ CALLBACK(on_memory_count, ctx->num_memories);
+ for (i = 0; i < ctx->num_memories; ++i) {
+ uint32_t memory_index = ctx->num_memory_imports + i;
+ WabtLimits page_limits;
+ read_memory(ctx, &page_limits);
+ CALLBACK(on_memory, memory_index, &page_limits);
+ }
+ CALLBACK_CTX0(end_memory_section);
+}
+
+static void read_global_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_global_section, section_size);
+ uint32_t i;
+ in_u32_leb128(ctx, &ctx->num_globals, "global count");
+ CALLBACK(on_global_count, ctx->num_globals);
+ for (i = 0; i < ctx->num_globals; ++i) {
+ uint32_t global_index = ctx->num_global_imports + i;
+ WabtType global_type;
+ bool mutable_;
+ read_global_header(ctx, &global_type, &mutable_);
+ CALLBACK(begin_global, global_index, global_type, mutable_);
+ CALLBACK(begin_global_init_expr, global_index);
+ read_init_expr(ctx, global_index);
+ CALLBACK(end_global_init_expr, global_index);
+ CALLBACK(end_global, global_index);
+ }
+ CALLBACK_CTX0(end_global_section);
+}
+
+static void read_export_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_export_section, section_size);
+ uint32_t i;
+ in_u32_leb128(ctx, &ctx->num_exports, "export count");
+ CALLBACK(on_export_count, ctx->num_exports);
+ for (i = 0; i < ctx->num_exports; ++i) {
+ WabtStringSlice name;
+ in_str(ctx, &name, "export item name");
+
+ uint8_t external_kind;
+ in_u8(ctx, &external_kind, "export external kind");
+ RAISE_ERROR_UNLESS(is_valid_external_kind(external_kind),
+ "invalid export external kind");
+
+ uint32_t item_index;
+ in_u32_leb128(ctx, &item_index, "export item index");
+ switch (external_kind) {
+ case WABT_EXTERNAL_KIND_FUNC:
+ RAISE_ERROR_UNLESS(item_index < num_total_funcs(ctx),
+ "invalid export func index: %d", item_index);
+ break;
+ case WABT_EXTERNAL_KIND_TABLE:
+ RAISE_ERROR_UNLESS(item_index < num_total_tables(ctx),
+ "invalid export table index");
+ break;
+ case WABT_EXTERNAL_KIND_MEMORY:
+ RAISE_ERROR_UNLESS(item_index < num_total_memories(ctx),
+ "invalid export memory index");
+ break;
+ case WABT_EXTERNAL_KIND_GLOBAL:
+ RAISE_ERROR_UNLESS(item_index < num_total_globals(ctx),
+ "invalid export global index");
+ break;
+ case WABT_NUM_EXTERNAL_KINDS:
+ assert(0);
+ break;
+ }
+
+ CALLBACK(on_export, i, (WabtExternalKind)external_kind, item_index, name);
+ }
+ CALLBACK_CTX0(end_export_section);
+}
+
+static void read_start_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_start_section, section_size);
+ uint32_t func_index;
+ in_u32_leb128(ctx, &func_index, "start function index");
+ RAISE_ERROR_UNLESS(func_index < num_total_funcs(ctx),
+ "invalid start function index");
+ CALLBACK(on_start_function, func_index);
+ CALLBACK_CTX0(end_start_section);
+}
+
+static void read_elem_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_elem_section, section_size);
+ uint32_t i, num_elem_segments;
+ in_u32_leb128(ctx, &num_elem_segments, "elem segment count");
+ CALLBACK(on_elem_segment_count, num_elem_segments);
+ RAISE_ERROR_UNLESS(num_elem_segments == 0 || num_total_tables(ctx) > 0,
+ "elem section without table section");
+ for (i = 0; i < num_elem_segments; ++i) {
+ uint32_t table_index;
+ in_u32_leb128(ctx, &table_index, "elem segment table index");
+ CALLBACK(begin_elem_segment, i, table_index);
+ CALLBACK(begin_elem_segment_init_expr, i);
+ read_init_expr(ctx, i);
+ CALLBACK(end_elem_segment_init_expr, i);
+
+ uint32_t j, num_function_indexes;
+ in_u32_leb128(ctx, &num_function_indexes,
+ "elem segment function index count");
+ CALLBACK_CTX(on_elem_segment_function_index_count, i, num_function_indexes);
+ for (j = 0; j < num_function_indexes; ++j) {
+ uint32_t func_index;
+ in_u32_leb128(ctx, &func_index, "elem segment function index");
+ CALLBACK(on_elem_segment_function_index, i, func_index);
+ }
+ CALLBACK(end_elem_segment, i);
+ }
+ CALLBACK_CTX0(end_elem_section);
+}
+
+static void read_code_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_function_bodies_section, section_size);
+ uint32_t i;
+ in_u32_leb128(ctx, &ctx->num_function_bodies, "function body count");
+ RAISE_ERROR_UNLESS(ctx->num_function_signatures == ctx->num_function_bodies,
+ "function signature count != function body count");
+ CALLBACK(on_function_bodies_count, ctx->num_function_bodies);
+ for (i = 0; i < ctx->num_function_bodies; ++i) {
+ uint32_t func_index = ctx->num_func_imports + i;
+ uint32_t func_offset = ctx->offset;
+ ctx->offset = func_offset;
+ CALLBACK_CTX(begin_function_body, func_index);
+ uint32_t body_size;
+ in_u32_leb128(ctx, &body_size, "function body size");
+ uint32_t body_start_offset = ctx->offset;
+ uint32_t end_offset = body_start_offset + body_size;
+
+ uint32_t num_local_decls;
+ in_u32_leb128(ctx, &num_local_decls, "local declaration count");
+ CALLBACK(on_local_decl_count, num_local_decls);
+ uint32_t k;
+ for (k = 0; k < num_local_decls; ++k) {
+ uint32_t num_local_types;
+ in_u32_leb128(ctx, &num_local_types, "local type count");
+ WabtType local_type;
+ in_type(ctx, &local_type, "local type");
+ RAISE_ERROR_UNLESS(is_concrete_type(local_type),
+ "expected valid local type");
+ CALLBACK(on_local_decl, k, num_local_types, local_type);
+ }
+
+ read_function_body(ctx, end_offset);
+
+ CALLBACK(end_function_body, func_index);
+ }
+ CALLBACK_CTX0(end_function_bodies_section);
+}
+
+static void read_data_section(Context* ctx, uint32_t section_size) {
+ CALLBACK_SECTION(begin_data_section, section_size);
+ uint32_t i, num_data_segments;
+ in_u32_leb128(ctx, &num_data_segments, "data segment count");
+ CALLBACK(on_data_segment_count, num_data_segments);
+ RAISE_ERROR_UNLESS(num_data_segments == 0 || num_total_memories(ctx) > 0,
+ "data section without memory section");
+ for (i = 0; i < num_data_segments; ++i) {
+ uint32_t memory_index;
+ in_u32_leb128(ctx, &memory_index, "data segment memory index");
+ CALLBACK(begin_data_segment, i, memory_index);
+ CALLBACK(begin_data_segment_init_expr, i);
+ read_init_expr(ctx, i);
+ CALLBACK(end_data_segment_init_expr, i);
+
+ uint32_t data_size;
+ const void* data;
+ in_bytes(ctx, &data, &data_size, "data segment data");
+ CALLBACK(on_data_segment_data, i, data, data_size);
+ CALLBACK(end_data_segment, i);
+ }
+ CALLBACK_CTX0(end_data_section);
+}
+
+static void read_sections(Context* ctx) {
+ while (ctx->offset < ctx->data_size) {
+ uint32_t section_code;
+ uint32_t section_size;
+ /* Temporarily reset read_end to the full data size so the next section
+ * can be read. */
+ ctx->read_end = ctx->data_size;
+ in_u32_leb128(ctx, &section_code, "section code");
+ in_u32_leb128(ctx, &section_size, "section size");
+ ctx->read_end = ctx->offset + section_size;
+ if (section_code >= WABT_NUM_BINARY_SECTIONS) {
+ RAISE_ERROR("invalid section code: %u; max is %u", section_code,
+ WABT_NUM_BINARY_SECTIONS - 1);
+ }
+
+ WabtBinarySection section = (WabtBinarySection)section_code;
+
+ if (ctx->read_end > ctx->data_size)
+ RAISE_ERROR("invalid section size: extends past end");
+
+ if (ctx->last_known_section != WABT_NUM_BINARY_SECTIONS &&
+ section != WABT_BINARY_SECTION_CUSTOM &&
+ section_code <= ctx->last_known_section) {
+ RAISE_ERROR("section %s out of order", wabt_get_section_name(section));
+ }
+
+ CALLBACK_CTX(begin_section, section, section_size);
+
+#define V(NAME, name, code) \
+ case WABT_BINARY_SECTION_##NAME: \
+ read_##name##_section(ctx, section_size); \
+ break;
+
+ switch (section) {
+ WABT_FOREACH_BINARY_SECTION(V)
+
+ default:
+ assert(0);
+ break;
+ }
+
+#undef V
+
+ if (ctx->offset != ctx->read_end) {
+ RAISE_ERROR("unfinished section (expected end: 0x%" PRIzx ")",
+ ctx->read_end);
+ }
+
+ if (section != WABT_BINARY_SECTION_CUSTOM)
+ ctx->last_known_section = section;
+ }
+}
+
+WabtResult wabt_read_binary(const void* data,
+ size_t size,
+ WabtBinaryReader* reader,
+ uint32_t num_function_passes,
+ const WabtReadBinaryOptions* options) {
+ LoggingContext logging_context;
+ WABT_ZERO_MEMORY(logging_context);
+ logging_context.reader = reader;
+ logging_context.stream = options->log_stream;
+
+ WabtBinaryReader logging_reader;
+ WABT_ZERO_MEMORY(logging_reader);
+ logging_reader.user_data = &logging_context;
+
+ logging_reader.on_error = logging_on_error;
+ logging_reader.begin_module = logging_begin_module;
+ logging_reader.end_module = logging_end_module;
+
+ logging_reader.begin_custom_section = logging_begin_custom_section;
+ logging_reader.end_custom_section = logging_end_custom_section;
+
+ logging_reader.begin_signature_section = logging_begin_signature_section;
+ logging_reader.on_signature_count = logging_on_signature_count;
+ logging_reader.on_signature = logging_on_signature;
+ logging_reader.end_signature_section = logging_end_signature_section;
+
+ logging_reader.begin_import_section = logging_begin_import_section;
+ logging_reader.on_import_count = logging_on_import_count;
+ logging_reader.on_import = logging_on_import;
+ logging_reader.on_import_func = logging_on_import_func;
+ logging_reader.on_import_table = logging_on_import_table;
+ logging_reader.on_import_memory = logging_on_import_memory;
+ logging_reader.on_import_global = logging_on_import_global;
+ logging_reader.end_import_section = logging_end_import_section;
+
+ logging_reader.begin_function_signatures_section =
+ logging_begin_function_signatures_section;
+ logging_reader.on_function_signatures_count =
+ logging_on_function_signatures_count;
+ logging_reader.on_function_signature = logging_on_function_signature;
+ logging_reader.end_function_signatures_section =
+ logging_end_function_signatures_section;
+
+ logging_reader.begin_table_section = logging_begin_table_section;
+ logging_reader.on_table_count = logging_on_table_count;
+ logging_reader.on_table = logging_on_table;
+ logging_reader.end_table_section = logging_end_table_section;
+
+ logging_reader.begin_memory_section = logging_begin_memory_section;
+ logging_reader.on_memory_count = logging_on_memory_count;
+ logging_reader.on_memory = logging_on_memory;
+ logging_reader.end_memory_section = logging_end_memory_section;
+
+ logging_reader.begin_global_section = logging_begin_global_section;
+ logging_reader.on_global_count = logging_on_global_count;
+ logging_reader.begin_global = logging_begin_global;
+ logging_reader.begin_global_init_expr = logging_begin_global_init_expr;
+ logging_reader.end_global_init_expr = logging_end_global_init_expr;
+ logging_reader.end_global = logging_end_global;
+ logging_reader.end_global_section = logging_end_global_section;
+
+ logging_reader.begin_export_section = logging_begin_export_section;
+ logging_reader.on_export_count = logging_on_export_count;
+ logging_reader.on_export = logging_on_export;
+ logging_reader.end_export_section = logging_end_export_section;
+
+ logging_reader.begin_start_section = logging_begin_start_section;
+ logging_reader.on_start_function = logging_on_start_function;
+ logging_reader.end_start_section = logging_end_start_section;
+
+ logging_reader.begin_function_bodies_section =
+ logging_begin_function_bodies_section;
+ logging_reader.on_function_bodies_count = logging_on_function_bodies_count;
+ logging_reader.begin_function_body_pass = logging_begin_function_body_pass;
+ logging_reader.begin_function_body = logging_begin_function_body;
+ logging_reader.on_local_decl_count = logging_on_local_decl_count;
+ logging_reader.on_local_decl = logging_on_local_decl;
+ logging_reader.on_binary_expr = logging_on_binary_expr;
+ logging_reader.on_block_expr = logging_on_block_expr;
+ logging_reader.on_br_expr = logging_on_br_expr;
+ logging_reader.on_br_if_expr = logging_on_br_if_expr;
+ logging_reader.on_br_table_expr = logging_on_br_table_expr;
+ logging_reader.on_call_expr = logging_on_call_expr;
+ logging_reader.on_call_import_expr = logging_on_call_import_expr;
+ logging_reader.on_call_indirect_expr = logging_on_call_indirect_expr;
+ logging_reader.on_compare_expr = logging_on_compare_expr;
+ logging_reader.on_convert_expr = logging_on_convert_expr;
+ logging_reader.on_drop_expr = logging_on_drop_expr;
+ logging_reader.on_else_expr = logging_on_else_expr;
+ logging_reader.on_end_expr = logging_on_end_expr;
+ logging_reader.on_f32_const_expr = logging_on_f32_const_expr;
+ logging_reader.on_f64_const_expr = logging_on_f64_const_expr;
+ logging_reader.on_get_global_expr = logging_on_get_global_expr;
+ logging_reader.on_get_local_expr = logging_on_get_local_expr;
+ logging_reader.on_grow_memory_expr = logging_on_grow_memory_expr;
+ logging_reader.on_i32_const_expr = logging_on_i32_const_expr;
+ logging_reader.on_i64_const_expr = logging_on_i64_const_expr;
+ logging_reader.on_if_expr = logging_on_if_expr;
+ logging_reader.on_load_expr = logging_on_load_expr;
+ logging_reader.on_loop_expr = logging_on_loop_expr;
+ logging_reader.on_current_memory_expr = logging_on_current_memory_expr;
+ logging_reader.on_nop_expr = logging_on_nop_expr;
+ logging_reader.on_return_expr = logging_on_return_expr;
+ logging_reader.on_select_expr = logging_on_select_expr;
+ logging_reader.on_set_global_expr = logging_on_set_global_expr;
+ logging_reader.on_set_local_expr = logging_on_set_local_expr;
+ logging_reader.on_store_expr = logging_on_store_expr;
+ logging_reader.on_tee_local_expr = logging_on_tee_local_expr;
+ logging_reader.on_unary_expr = logging_on_unary_expr;
+ logging_reader.on_unreachable_expr = logging_on_unreachable_expr;
+ logging_reader.end_function_body = logging_end_function_body;
+ logging_reader.end_function_body_pass = logging_end_function_body_pass;
+ logging_reader.end_function_bodies_section =
+ logging_end_function_bodies_section;
+
+ logging_reader.begin_elem_section = logging_begin_elem_section;
+ logging_reader.on_elem_segment_count = logging_on_elem_segment_count;
+ logging_reader.begin_elem_segment = logging_begin_elem_segment;
+ logging_reader.begin_elem_segment_init_expr =
+ logging_begin_elem_segment_init_expr;
+ logging_reader.end_elem_segment_init_expr =
+ logging_end_elem_segment_init_expr;
+ logging_reader.on_elem_segment_function_index_count =
+ logging_on_elem_segment_function_index_count;
+ logging_reader.on_elem_segment_function_index =
+ logging_on_elem_segment_function_index;
+ logging_reader.end_elem_segment = logging_end_elem_segment;
+ logging_reader.end_elem_section = logging_end_elem_section;
+
+ logging_reader.begin_data_section = logging_begin_data_section;
+ logging_reader.on_data_segment_count = logging_on_data_segment_count;
+ logging_reader.begin_data_segment = logging_begin_data_segment;
+ logging_reader.begin_data_segment_init_expr =
+ logging_begin_data_segment_init_expr;
+ logging_reader.end_data_segment_init_expr =
+ logging_end_data_segment_init_expr;
+ logging_reader.on_data_segment_data = logging_on_data_segment_data;
+ logging_reader.end_data_segment = logging_end_data_segment;
+ logging_reader.end_data_section = logging_end_data_section;
+
+ logging_reader.begin_names_section = logging_begin_names_section;
+ logging_reader.on_function_names_count = logging_on_function_names_count;
+ logging_reader.on_function_name = logging_on_function_name;
+ logging_reader.on_local_names_count = logging_on_local_names_count;
+ logging_reader.on_local_name = logging_on_local_name;
+ logging_reader.end_names_section = logging_end_names_section;
+
+ logging_reader.begin_reloc_section = logging_begin_reloc_section;
+ logging_reader.on_reloc_count = logging_on_reloc_count;
+ logging_reader.end_reloc_section = logging_end_reloc_section;
+
+ logging_reader.on_init_expr_f32_const_expr =
+ logging_on_init_expr_f32_const_expr;
+ logging_reader.on_init_expr_f64_const_expr =
+ logging_on_init_expr_f64_const_expr;
+ logging_reader.on_init_expr_get_global_expr =
+ logging_on_init_expr_get_global_expr;
+ logging_reader.on_init_expr_i32_const_expr =
+ logging_on_init_expr_i32_const_expr;
+ logging_reader.on_init_expr_i64_const_expr =
+ logging_on_init_expr_i64_const_expr;
+
+ Context context;
+ WABT_ZERO_MEMORY(context);
+ /* all the macros assume a Context* named ctx */
+ Context* ctx = &context;
+ ctx->data = (const uint8_t*)data;
+ ctx->data_size = ctx->read_end = size;
+ ctx->reader = options->log_stream ? &logging_reader : reader;
+ ctx->options = options;
+ ctx->last_known_section = WABT_NUM_BINARY_SECTIONS;
+
+ if (setjmp(ctx->error_jmp_buf) == 1) {
+ destroy_context(ctx);
+ return WABT_ERROR;
+ }
+
+ wabt_reserve_types(&ctx->param_types, INITIAL_PARAM_TYPES_CAPACITY);
+ wabt_reserve_uint32s(&ctx->target_depths, INITIAL_BR_TABLE_TARGET_CAPACITY);
+
+ uint32_t magic;
+ in_u32(ctx, &magic, "magic");
+ RAISE_ERROR_UNLESS(magic == WABT_BINARY_MAGIC, "bad magic value");
+ uint32_t version;
+ in_u32(ctx, &version, "version");
+ RAISE_ERROR_UNLESS(version == WABT_BINARY_VERSION,
+ "bad wasm file version: %#x (expected %#x)", version,
+ WABT_BINARY_VERSION);
+
+ CALLBACK(begin_module, version);
+ read_sections(ctx);
+ CALLBACK0(end_module);
+ destroy_context(ctx);
+ return WABT_OK;
+}