diff options
author | Ben Smith <binji@chromium.org> | 2016-02-24 15:35:05 -0800 |
---|---|---|
committer | Ben Smith <binji@chromium.org> | 2016-03-21 15:31:16 -0700 |
commit | c57b3fbe4278d55749d6fa1273ee979956ae1123 (patch) | |
tree | 7bea5ced5be7b7e2334a1f50597e1f5859dc5c9e /src/wasm-binary-reader.c | |
parent | 5954eeb27b2ee7d3e12329a4cbe37ec8fb89b5a6 (diff) | |
download | wabt-c57b3fbe4278d55749d6fa1273ee979956ae1123.tar.gz wabt-c57b3fbe4278d55749d6fa1273ee979956ae1123.tar.bz2 wabt-c57b3fbe4278d55749d6fa1273ee979956ae1123.zip |
rebase of a bunch of early work on binary reading
* basic reading works
* update to latest binary format
* read names section
* use setjmp/longjmp for error handling
Diffstat (limited to 'src/wasm-binary-reader.c')
-rw-r--r-- | src/wasm-binary-reader.c | 923 |
1 files changed, 923 insertions, 0 deletions
diff --git a/src/wasm-binary-reader.c b/src/wasm-binary-reader.c new file mode 100644 index 00000000..839cba3b --- /dev/null +++ b/src/wasm-binary-reader.c @@ -0,0 +1,923 @@ +/* + * 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 "wasm-binary-reader.h" + +#include <alloca.h> +#include <assert.h> +#include <setjmp.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "wasm-allocator.h" +#include "wasm-binary.h" +#include "wasm-vector.h" + +#define CALLBACK0(ctx, member) \ + ((ctx)->reader->member ? (ctx)->reader->member((ctx)->reader->user_data) \ + : (void)0) + +#define CALLBACK(ctx, member, ...) \ + ((ctx)->reader->member \ + ? (ctx)->reader->member(__VA_ARGS__, (ctx)->reader->user_data) \ + : (void)0) + +#define RAISE_ERROR(ctx, ...) \ + ((ctx)->reader->on_error ? raise_error((ctx), __VA_ARGS__) : (void)0) + +#define RAISE_ERROR_UNLESS(ctx, cond, ...) \ + if (!cond) \ + RAISE_ERROR((ctx), __VA_ARGS__); + +enum { +#define V(name) WASM_SECTION_INDEX_##name, + WASM_FOREACH_SECTION(V) +#undef V + WASM_NUM_SECTIONS +}; + +typedef struct WasmReadContext { + const uint8_t* data; + size_t size; + size_t offset; + WasmBinaryReader* reader; + jmp_buf error_jmp_buf; +} WasmReadContext; + +static void raise_error(WasmReadContext* ctx, const char* format, ...) { + assert(ctx->reader->on_error); + + va_list args; + va_list args_copy; + va_start(args, format); + va_copy(args_copy, args); + /* + 1 to account for the \0 that will be added automatically by + wasm_vsnprintf */ + int len = wasm_vsnprintf(NULL, 0, format, args) + 1; + va_end(args); + + char* buffer = alloca(len); + wasm_vsnprintf(buffer, len, format, args_copy); + va_end(args_copy); + + ctx->reader->on_error(buffer, ctx->reader->user_data); + longjmp(ctx->error_jmp_buf, 1); +} + +#define IN_SIZE(type) \ + if (ctx->offset + sizeof(type) > ctx->size) { \ + RAISE_ERROR(ctx, "unable to read " #type ": %s", desc); \ + } \ + memcpy(out_value, ctx->data + ctx->offset, sizeof(type)); \ + ctx->offset += sizeof(type) + +static void in_u8(WasmReadContext* ctx, uint8_t* out_value, const char* desc) { + IN_SIZE(uint8_t); +} + +static void in_u32(WasmReadContext* ctx, + uint32_t* out_value, + const char* desc) { + IN_SIZE(uint32_t); +} + +static void in_f32(WasmReadContext* ctx, + uint32_t* out_value, + const char* desc) { + IN_SIZE(float); +} + +static void in_f64(WasmReadContext* 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) | BYTE_AT(type, 0, 0)) +#define LEB128_3(type) \ + (BYTE_AT(type, 2, 14) | BYTE_AT(type, 1, 7) | BYTE_AT(type, 0, 0)) +#define LEB128_4(type) \ + (BYTE_AT(type, 3, 21) | BYTE_AT(type, 2, 14) | BYTE_AT(type, 1, 7) | \ + BYTE_AT(type, 0, 0)) +#define LEB128_5(type) \ + (BYTE_AT(type, 4, 28) | BYTE_AT(type, 3, 21) | BYTE_AT(type, 2, 14) | \ + BYTE_AT(type, 1, 7) | BYTE_AT(type, 0, 0)) +#define LEB128_6(type) \ + (BYTE_AT(type, 5, 35) | BYTE_AT(type, 4, 28) | BYTE_AT(type, 3, 21) | \ + BYTE_AT(type, 2, 14) | BYTE_AT(type, 1, 7) | BYTE_AT(type, 0, 0)) +#define LEB128_7(type) \ + (BYTE_AT(type, 6, 42) | BYTE_AT(type, 5, 35) | BYTE_AT(type, 4, 28) | \ + BYTE_AT(type, 3, 21) | BYTE_AT(type, 2, 14) | BYTE_AT(type, 1, 7) | \ + BYTE_AT(type, 0, 0)) +#define LEB128_8(type) \ + (BYTE_AT(type, 7, 49) | BYTE_AT(type, 6, 42) | BYTE_AT(type, 5, 35) | \ + BYTE_AT(type, 4, 28) | BYTE_AT(type, 3, 21) | BYTE_AT(type, 2, 14) | \ + BYTE_AT(type, 1, 7) | BYTE_AT(type, 0, 0)) +#define LEB128_9(type) \ + (BYTE_AT(type, 8, 56) | BYTE_AT(type, 7, 49) | BYTE_AT(type, 6, 42) | \ + BYTE_AT(type, 5, 35) | BYTE_AT(type, 4, 28) | BYTE_AT(type, 3, 21) | \ + BYTE_AT(type, 2, 14) | BYTE_AT(type, 1, 7) | BYTE_AT(type, 0, 0)) +#define LEB128_10(type) \ + (BYTE_AT(type, 9, 63) | BYTE_AT(type, 8, 56) | BYTE_AT(type, 7, 49) | \ + BYTE_AT(type, 6, 42) | BYTE_AT(type, 5, 35) | BYTE_AT(type, 4, 28) | \ + BYTE_AT(type, 3, 21) | BYTE_AT(type, 2, 14) | BYTE_AT(type, 1, 7) | \ + BYTE_AT(type, 0, 0)) + +#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)) + +static void in_u32_leb128(WasmReadContext* ctx, + uint32_t* out_value, + const char* desc) { + const uint8_t* p = ctx->data + ctx->offset; + const uint8_t* end = ctx->data + ctx->size; + + if (p < end && (p[0] & 0x80) == 0) { + *out_value = LEB128_1(uint32_t); + ctx->offset += 1; + } else if (p + 1 < end && (p[1] & 0x80) == 0) { + *out_value = LEB128_2(uint32_t); + ctx->offset += 2; + } else if (p + 2 < end && (p[2] & 0x80) == 0) { + *out_value = LEB128_3(uint32_t); + ctx->offset += 3; + } else if (p + 3 < end && (p[3] & 0x80) == 0) { + *out_value = LEB128_4(uint32_t); + ctx->offset += 4; + } else if (p + 4 < end && (p[4] & 0x80) == 0) { + /* the top bits set represent values > 32 bits */ + if (p[4] & 0xf0) + RAISE_ERROR(ctx, "invalid u32 leb128: %s", desc); + *out_value = LEB128_5(uint32_t); + ctx->offset += 5; + } else { + /* past the end */ + RAISE_ERROR(ctx, "unable to read u32 leb128: %s", desc); + } +} + +static void in_i32_leb128(WasmReadContext* ctx, + uint32_t* out_value, + const char* desc) { + const uint8_t* p = ctx->data + ctx->offset; + const uint8_t* end = ctx->data + ctx->size; + + if (p < end && (p[0] & 0x80) == 0) { + uint32_t result = LEB128_1(uint32_t); + *out_value = SIGN_EXTEND(int32_t, result, 6); + ctx->offset += 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); + ctx->offset += 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); + ctx->offset += 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); + ctx->offset += 4; + } else if (p + 4 < end && (p[4] & 0x80) == 0) { + /* the top bits should be a sign-extension of the sign bit */ + int 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)) { + RAISE_ERROR(ctx, "invalid i32 leb128: %s", desc); + } + uint32_t result = LEB128_5(uint32_t); + *out_value = result; + ctx->offset += 5; + } else { + /* past the end */ + RAISE_ERROR(ctx, "unable to read i32 leb128: %s", desc); + } +} + +static void in_i64_leb128(WasmReadContext* ctx, + uint64_t* out_value, + const char* desc) { + const uint8_t* p = ctx->data + ctx->offset; + const uint8_t* end = ctx->data + ctx->size; + + 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 */ + int 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(ctx, "invalid i64 leb128: %s", desc); + } + uint64_t result = LEB128_10(uint64_t); + *out_value = result; + ctx->offset += 10; + } else { + /* past the end */ + RAISE_ERROR(ctx, "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_str(WasmReadContext* ctx, + WasmStringSlice* out_str, + const char* desc) { + uint32_t str_len; + in_u32_leb128(ctx, &str_len, "string length"); + + if (ctx->offset + str_len > ctx->size) + RAISE_ERROR(ctx, "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(WasmReadContext* ctx, + const void** out_data, + uint32_t* out_data_size, + const char* desc) { + uint32_t data_size; + in_u32_leb128(ctx, &data_size, "data size"); + + if (ctx->offset + data_size > ctx->size) + RAISE_ERROR(ctx, "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 int is_valid_type(uint8_t type) { + return type < WASM_NUM_TYPES; +} + +static int is_bool(uint8_t value) { + return value < 2; +} + +static int skip_until_section(WasmReadContext* ctx, int section_index) { + uint32_t section_start_offset = ctx->offset; + uint32_t section_size; + if (ctx->offset == ctx->size) { + /* ok, no more sections */ + return 0; + } + + in_u32_leb128(ctx, §ion_size, "section size"); + + uint32_t after_size_offset = ctx->offset; + if (after_size_offset + section_size > ctx->size) + RAISE_ERROR(ctx, "invalid section size: extends past end"); + + WasmStringSlice section_name; + in_str(ctx, §ion_name, "section name"); + + int index = -1; +#define V(name) \ + else if (strncmp(section_name.start, WASM_SECTION_NAME_##name, \ + section_name.length) == 0) { \ + index = WASM_SECTION_INDEX_##name; \ + } + if (0) {} + WASM_FOREACH_SECTION(V) +#undef V + + if (index == -1) { + /* ok, unknown section, skip it. */ + ctx->offset = after_size_offset + section_size; + return 0; + } else if (index < section_index) { + RAISE_ERROR(ctx, "section %.*s out of order", section_name.length, + section_name.start); + } else if (index > section_index) { + /* ok, future section. Reset the offset. */ + /* TODO(binji): slightly inefficient to re-read the section later. But + there aren't many so it probably doesn't matter */ + ctx->offset = section_start_offset; + return 0; + } + + assert(index == section_index); + return 1; +} + +WasmResult wasm_read_binary(const void* data, + size_t size, + WasmBinaryReader* reader) { + WasmReadContext ctx = {.data = data, .size = size, .reader = reader}; + if (setjmp(ctx.error_jmp_buf) == 1) + return WASM_ERROR; + + CALLBACK0(&ctx, begin_module); + + uint32_t magic; + in_u32(&ctx, &magic, "magic"); + RAISE_ERROR_UNLESS(&ctx, magic == WASM_BINARY_MAGIC, "magic value mismatch"); + uint32_t version; + in_u32(&ctx, &version, "version"); + RAISE_ERROR_UNLESS(&ctx, version == WASM_BINARY_VERSION, "version mismatch"); + + /* signatures */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_SIGNATURES)) { + CALLBACK0(&ctx, begin_signature_section); + uint32_t i, num_signatures; + in_u32_leb128(&ctx, &num_signatures, "signature count"); + CALLBACK(&ctx, on_signature_count, num_signatures); + + for (i = 0; i < num_signatures; ++i) { + uint32_t num_params; + in_u32_leb128(&ctx, &num_params, "signature param count"); + + uint8_t result_type; + in_u8(&ctx, &result_type, "signature result type"); + RAISE_ERROR_UNLESS(&ctx, is_valid_type(result_type), + "expected valid result type"); + int j; + WasmType param_types[num_params]; + for (j = 0; j < num_params; ++j) { + uint8_t param_type; + in_u8(&ctx, ¶m_type, "signature param type"); + RAISE_ERROR_UNLESS(&ctx, is_valid_type(param_type), + "expected valid param type"); + param_types[j] = param_type; + } + + CALLBACK(&ctx, on_signature, i, (WasmType)result_type, num_params, + param_types); + } + CALLBACK0(&ctx, end_signature_section); + } + + /* import_table */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_IMPORT_TABLE)) { + CALLBACK0(&ctx, begin_import_section); + uint32_t i, num_imports; + in_u32_leb128(&ctx, &num_imports, "import count"); + CALLBACK(&ctx, on_import_count, num_imports); + for (i = 0; i < num_imports; ++i) { + uint32_t sig_index; + in_u32_leb128(&ctx, &sig_index, "import signature index"); + + WasmStringSlice module_name; + in_str(&ctx, &module_name, "import module name"); + + WasmStringSlice function_name; + in_str(&ctx, &function_name, "import function name"); + + CALLBACK(&ctx, on_import, i, sig_index, module_name, function_name); + } + CALLBACK0(&ctx, end_import_section); + } + + /* function_signatures */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_FUNCTION_SIGNATURES)) { + CALLBACK0(&ctx, begin_function_signatures_section); + uint32_t i, num_functions; + in_u32_leb128(&ctx, &num_functions, "function signature count"); + CALLBACK(&ctx, on_function_signatures_count, num_functions); + for (i = 0; i < num_functions; ++i) { + uint32_t sig_index; + in_u32_leb128(&ctx, &sig_index, "function signature index"); + CALLBACK(&ctx, on_function_signature, i, sig_index); + } + CALLBACK0(&ctx, end_function_signatures_section); + } + + /* function_table */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_FUNCTION_TABLE)) { + CALLBACK0(&ctx, begin_function_table_section); + uint32_t i, num_entries; + in_u32_leb128(&ctx, &num_entries, "function table entry count"); + CALLBACK(&ctx, on_function_table_count, num_entries); + for (i = 0; i < num_entries; ++i) { + uint32_t func_index; + in_u32_leb128(&ctx, &func_index, "function table function index"); + CALLBACK(&ctx, on_function_table_entry, i, func_index); + } + CALLBACK0(&ctx, end_function_table_section); + } + + /* memory */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_MEMORY)) { + CALLBACK0(&ctx, begin_memory_section); + uint32_t initial_size_pages; + in_u32_leb128(&ctx, &initial_size_pages, "memory initial size"); + CALLBACK(&ctx, on_memory_initial_size_pages, initial_size_pages); + + uint32_t max_size_pages; + in_u32_leb128(&ctx, &max_size_pages, "memory max size"); + CALLBACK(&ctx, on_memory_max_size_pages, max_size_pages); + + uint8_t mem_exported; + in_u8(&ctx, &mem_exported, "memory export"); + RAISE_ERROR_UNLESS(&ctx, is_bool(mem_exported), + "expected valid mem export flag"); + CALLBACK(&ctx, on_memory_exported, mem_exported); + CALLBACK0(&ctx, end_memory_section); + } + + /* export_table */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_EXPORT_TABLE)) { + CALLBACK0(&ctx, begin_export_section); + uint32_t i, num_exports; + in_u32_leb128(&ctx, &num_exports, "export count"); + CALLBACK(&ctx, on_export_count, num_exports); + for (i = 0; i < num_exports; ++i) { + uint32_t func_index; + in_u32_leb128(&ctx, &func_index, "export function index"); + + WasmStringSlice name; + in_str(&ctx, &name, "export function name"); + + CALLBACK(&ctx, on_export, i, func_index, name); + } + CALLBACK0(&ctx, end_export_section); + } + + /* start_function */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_START_FUNCTION)) { + CALLBACK0(&ctx, begin_start_section); + uint32_t func_index; + in_u32_leb128(&ctx, &func_index, "start function index"); + CALLBACK(&ctx, on_start_function, func_index); + CALLBACK0(&ctx, end_start_section); + } + + /* function_bodies */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_FUNCTION_BODIES)) { + CALLBACK0(&ctx, begin_function_bodies_section); + uint32_t i, num_functions; + in_u32_leb128(&ctx, &num_functions, "function body count"); + CALLBACK(&ctx, on_function_bodies_count, num_functions); + for (i = 0; i < num_functions; ++i) { + CALLBACK(&ctx, begin_function_body, i); + 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(&ctx, on_local_decl_count, num_local_decls); + uint32_t j; + for (j = 0; j < num_local_decls; ++j) { + uint32_t num_local_types; + in_u32_leb128(&ctx, &num_local_types, "local type count"); + uint8_t local_type; + in_u8(&ctx, &local_type, "local type"); + RAISE_ERROR_UNLESS(&ctx, is_valid_type(local_type), + "expected valid local type"); + CALLBACK(&ctx, on_local_decl, j, num_local_types, local_type); + } + + while (ctx.offset < end_offset) { + uint8_t opcode; + in_u8(&ctx, &opcode, "opcode"); + switch (opcode) { + case WASM_OPCODE_NOP: + CALLBACK0(&ctx, on_nop_expr); + break; + + case WASM_OPCODE_BLOCK: { + uint32_t num_exprs; + in_u32_leb128(&ctx, &num_exprs, "block expression count"); + CALLBACK(&ctx, on_block_expr, num_exprs); + break; + } + + case WASM_OPCODE_LOOP: { + uint32_t num_exprs; + in_u32_leb128(&ctx, &num_exprs, "loop expression count"); + CALLBACK(&ctx, on_loop_expr, num_exprs); + break; + } + + case WASM_OPCODE_IF: + CALLBACK0(&ctx, on_if_expr); + break; + + case WASM_OPCODE_IF_ELSE: + CALLBACK0(&ctx, on_if_else_expr); + break; + + case WASM_OPCODE_SELECT: + CALLBACK0(&ctx, on_select_expr); + break; + + case WASM_OPCODE_BR: { + uint32_t depth; + in_u32_leb128(&ctx, &depth, "br depth"); + CALLBACK(&ctx, on_br_expr, depth); + break; + } + + case WASM_OPCODE_BR_IF: { + uint32_t depth; + in_u32_leb128(&ctx, &depth, "br_if depth"); + CALLBACK(&ctx, on_br_if_expr, depth); + break; + } + + case WASM_OPCODE_BR_TABLE: { + uint32_t num_targets; + in_u32_leb128(&ctx, &num_targets, "br_table target count"); + uint32_t target_depths[num_targets]; + + int i; + for (i = 0; i < num_targets; ++i) { + uint32_t target_depth; + in_u32(&ctx, &target_depth, "br_table target depth"); + target_depths[i] = target_depth; + } + + uint32_t default_target_depth; + in_u32(&ctx, &default_target_depth, + "br_table default target depth"); + + CALLBACK(&ctx, on_br_table_expr, num_targets, target_depths, + default_target_depth); + break; + } + + case WASM_OPCODE_RETURN: + CALLBACK0(&ctx, on_return_expr); + break; + + case WASM_OPCODE_UNREACHABLE: + CALLBACK0(&ctx, on_unreachable_expr); + break; + + case WASM_OPCODE_I32_CONST: { + uint32_t value; + in_i32_leb128(&ctx, &value, "i32.const value"); + CALLBACK(&ctx, on_i32_const_expr, value); + break; + } + + case WASM_OPCODE_I64_CONST: { + uint64_t value; + in_i64_leb128(&ctx, &value, "i64.const value"); + CALLBACK(&ctx, on_i64_const_expr, value); + break; + } + + case WASM_OPCODE_F32_CONST: { + uint32_t value_bits; + in_f32(&ctx, &value_bits, "f32.const value"); + CALLBACK(&ctx, on_f32_const_expr, value_bits); + break; + } + + case WASM_OPCODE_F64_CONST: { + uint64_t value_bits; + in_f64(&ctx, &value_bits, "f64.const value"); + CALLBACK(&ctx, on_f64_const_expr, value_bits); + break; + } + + case WASM_OPCODE_GET_LOCAL: { + uint32_t local_index; + in_u32_leb128(&ctx, &local_index, "get_local local index"); + CALLBACK(&ctx, on_get_local_expr, local_index); + break; + } + + case WASM_OPCODE_SET_LOCAL: { + uint32_t local_index; + in_u32_leb128(&ctx, &local_index, "set_local local index"); + CALLBACK(&ctx, on_set_local_expr, local_index); + break; + } + + case WASM_OPCODE_CALL_FUNCTION: { + uint32_t func_index; + in_u32_leb128(&ctx, &func_index, "call_function function index"); + CALLBACK(&ctx, on_call_expr, func_index); + break; + } + + case WASM_OPCODE_CALL_INDIRECT: { + uint32_t sig_index; + in_u32_leb128(&ctx, &sig_index, "call_indirect signature index"); + CALLBACK(&ctx, on_call_indirect_expr, sig_index); + break; + } + + case WASM_OPCODE_CALL_IMPORT: { + uint32_t import_index; + in_u32_leb128(&ctx, &import_index, "call_import import index"); + CALLBACK(&ctx, on_call_import_expr, import_index); + break; + } + + case WASM_OPCODE_I32_LOAD8_S: + case WASM_OPCODE_I32_LOAD8_U: + case WASM_OPCODE_I32_LOAD16_S: + case WASM_OPCODE_I32_LOAD16_U: + case WASM_OPCODE_I64_LOAD8_S: + case WASM_OPCODE_I64_LOAD8_U: + case WASM_OPCODE_I64_LOAD16_S: + case WASM_OPCODE_I64_LOAD16_U: + case WASM_OPCODE_I64_LOAD32_S: + case WASM_OPCODE_I64_LOAD32_U: + case WASM_OPCODE_I32_LOAD: + case WASM_OPCODE_I64_LOAD: + case WASM_OPCODE_F32_LOAD: + case WASM_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(&ctx, on_load_expr, opcode, alignment_log2, offset); + break; + } + + case WASM_OPCODE_I32_STORE8: + case WASM_OPCODE_I32_STORE16: + case WASM_OPCODE_I64_STORE8: + case WASM_OPCODE_I64_STORE16: + case WASM_OPCODE_I64_STORE32: + case WASM_OPCODE_I32_STORE: + case WASM_OPCODE_I64_STORE: + case WASM_OPCODE_F32_STORE: + case WASM_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(&ctx, on_store_expr, opcode, alignment_log2, offset); + break; + } + + case WASM_OPCODE_MEMORY_SIZE: + CALLBACK0(&ctx, on_memory_size_expr); + break; + + case WASM_OPCODE_GROW_MEMORY: + CALLBACK0(&ctx, on_grow_memory_expr); + break; + + case WASM_OPCODE_I32_ADD: + case WASM_OPCODE_I32_SUB: + case WASM_OPCODE_I32_MUL: + case WASM_OPCODE_I32_DIV_S: + case WASM_OPCODE_I32_DIV_U: + case WASM_OPCODE_I32_REM_S: + case WASM_OPCODE_I32_REM_U: + case WASM_OPCODE_I32_AND: + case WASM_OPCODE_I32_OR: + case WASM_OPCODE_I32_XOR: + case WASM_OPCODE_I32_SHL: + case WASM_OPCODE_I32_SHR_U: + case WASM_OPCODE_I32_SHR_S: + case WASM_OPCODE_I32_ROTR: + case WASM_OPCODE_I32_ROTL: + case WASM_OPCODE_I64_ADD: + case WASM_OPCODE_I64_SUB: + case WASM_OPCODE_I64_MUL: + case WASM_OPCODE_I64_DIV_S: + case WASM_OPCODE_I64_DIV_U: + case WASM_OPCODE_I64_REM_S: + case WASM_OPCODE_I64_REM_U: + case WASM_OPCODE_I64_AND: + case WASM_OPCODE_I64_OR: + case WASM_OPCODE_I64_XOR: + case WASM_OPCODE_I64_SHL: + case WASM_OPCODE_I64_SHR_U: + case WASM_OPCODE_I64_SHR_S: + case WASM_OPCODE_I64_ROTR: + case WASM_OPCODE_I64_ROTL: + case WASM_OPCODE_F32_ADD: + case WASM_OPCODE_F32_SUB: + case WASM_OPCODE_F32_MUL: + case WASM_OPCODE_F32_DIV: + case WASM_OPCODE_F32_MIN: + case WASM_OPCODE_F32_MAX: + case WASM_OPCODE_F32_COPYSIGN: + case WASM_OPCODE_F64_ADD: + case WASM_OPCODE_F64_SUB: + case WASM_OPCODE_F64_MUL: + case WASM_OPCODE_F64_DIV: + case WASM_OPCODE_F64_MIN: + case WASM_OPCODE_F64_MAX: + case WASM_OPCODE_F64_COPYSIGN: + CALLBACK(&ctx, on_binary_expr, opcode); + break; + + case WASM_OPCODE_I32_EQ: + case WASM_OPCODE_I32_NE: + case WASM_OPCODE_I32_LT_S: + case WASM_OPCODE_I32_LE_S: + case WASM_OPCODE_I32_LT_U: + case WASM_OPCODE_I32_LE_U: + case WASM_OPCODE_I32_GT_S: + case WASM_OPCODE_I32_GE_S: + case WASM_OPCODE_I32_GT_U: + case WASM_OPCODE_I32_GE_U: + case WASM_OPCODE_I64_EQ: + case WASM_OPCODE_I64_NE: + case WASM_OPCODE_I64_LT_S: + case WASM_OPCODE_I64_LE_S: + case WASM_OPCODE_I64_LT_U: + case WASM_OPCODE_I64_LE_U: + case WASM_OPCODE_I64_GT_S: + case WASM_OPCODE_I64_GE_S: + case WASM_OPCODE_I64_GT_U: + case WASM_OPCODE_I64_GE_U: + case WASM_OPCODE_F32_EQ: + case WASM_OPCODE_F32_NE: + case WASM_OPCODE_F32_LT: + case WASM_OPCODE_F32_LE: + case WASM_OPCODE_F32_GT: + case WASM_OPCODE_F32_GE: + case WASM_OPCODE_F64_EQ: + case WASM_OPCODE_F64_NE: + case WASM_OPCODE_F64_LT: + case WASM_OPCODE_F64_LE: + case WASM_OPCODE_F64_GT: + case WASM_OPCODE_F64_GE: + CALLBACK(&ctx, on_compare_expr, opcode); + break; + + case WASM_OPCODE_I32_CLZ: + case WASM_OPCODE_I32_CTZ: + case WASM_OPCODE_I32_POPCNT: + case WASM_OPCODE_I32_EQZ: + case WASM_OPCODE_I64_CLZ: + case WASM_OPCODE_I64_CTZ: + case WASM_OPCODE_I64_POPCNT: + case WASM_OPCODE_F32_ABS: + case WASM_OPCODE_F32_NEG: + case WASM_OPCODE_F32_CEIL: + case WASM_OPCODE_F32_FLOOR: + case WASM_OPCODE_F32_TRUNC: + case WASM_OPCODE_F32_NEAREST: + case WASM_OPCODE_F32_SQRT: + case WASM_OPCODE_F64_ABS: + case WASM_OPCODE_F64_NEG: + case WASM_OPCODE_F64_CEIL: + case WASM_OPCODE_F64_FLOOR: + case WASM_OPCODE_F64_TRUNC: + case WASM_OPCODE_F64_NEAREST: + case WASM_OPCODE_F64_SQRT: + CALLBACK(&ctx, on_unary_expr, opcode); + break; + + case WASM_OPCODE_I32_TRUNC_S_F32: + case WASM_OPCODE_I32_TRUNC_S_F64: + case WASM_OPCODE_I32_TRUNC_U_F32: + case WASM_OPCODE_I32_TRUNC_U_F64: + case WASM_OPCODE_I32_WRAP_I64: + case WASM_OPCODE_I64_TRUNC_S_F32: + case WASM_OPCODE_I64_TRUNC_S_F64: + case WASM_OPCODE_I64_TRUNC_U_F32: + case WASM_OPCODE_I64_TRUNC_U_F64: + case WASM_OPCODE_I64_EXTEND_S_I32: + case WASM_OPCODE_I64_EXTEND_U_I32: + case WASM_OPCODE_F32_CONVERT_S_I32: + case WASM_OPCODE_F32_CONVERT_U_I32: + case WASM_OPCODE_F32_CONVERT_S_I64: + case WASM_OPCODE_F32_CONVERT_U_I64: + case WASM_OPCODE_F32_DEMOTE_F64: + case WASM_OPCODE_F32_REINTERPRET_I32: + case WASM_OPCODE_F64_CONVERT_S_I32: + case WASM_OPCODE_F64_CONVERT_U_I32: + case WASM_OPCODE_F64_CONVERT_S_I64: + case WASM_OPCODE_F64_CONVERT_U_I64: + case WASM_OPCODE_F64_PROMOTE_F32: + case WASM_OPCODE_F64_REINTERPRET_I64: + case WASM_OPCODE_I32_REINTERPRET_F32: + case WASM_OPCODE_I64_REINTERPRET_F64: + CALLBACK(&ctx, on_convert_expr, opcode); + break; + + default: + RAISE_ERROR(&ctx, "unexpected opcode: %d (0x%x)", opcode, opcode); + } + } + RAISE_ERROR_UNLESS(&ctx, ctx.offset == end_offset, + "function body longer than given size"); + CALLBACK(&ctx, end_function_body, i); + } + CALLBACK0(&ctx, end_function_bodies_section); + } + + /* data_segments */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_DATA_SEGMENTS)) { + CALLBACK0(&ctx, begin_data_segment_section); + uint32_t i, num_data_segments; + in_u32_leb128(&ctx, &num_data_segments, "data segment count"); + CALLBACK(&ctx, on_data_segment_count, num_data_segments); + for (i = 0; i < num_data_segments; ++i) { + uint32_t address; + in_u32_leb128(&ctx, &address, "data segment address"); + + uint32_t data_size; + const void* data; + in_bytes(&ctx, &data, &data_size, "data segment data"); + + CALLBACK(&ctx, on_data_segment, i, address, data, data_size); + } + CALLBACK0(&ctx, end_data_segment_section); + } + + /* names */ + if (skip_until_section(&ctx, WASM_SECTION_INDEX_NAMES)) { + CALLBACK0(&ctx, begin_names_section); + uint32_t i, num_functions; + in_u32_leb128(&ctx, &num_functions, "function name count"); + CALLBACK(&ctx, on_function_names_count, num_functions); + for (i = 0; i < num_functions; ++i) { + WasmStringSlice function_name; + in_str(&ctx, &function_name, "function name"); + CALLBACK(&ctx, on_function_name, i, function_name); + + uint32_t num_locals; + in_u32_leb128(&ctx, &num_locals, "local name count"); + CALLBACK(&ctx, on_local_names_count, i, num_locals); + uint32_t j; + for (j = 0; j < num_locals; ++j) { + WasmStringSlice local_name; + in_str(&ctx, &local_name, "local name"); + CALLBACK(&ctx, on_local_name, i, j, local_name); + } + } + CALLBACK0(&ctx, end_names_section); + } + + CALLBACK0(&ctx, end_module); + return WASM_OK; +} |