summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt18
-rw-r--r--Makefile2
-rw-r--r--src/wasm-binary-reader.c923
-rw-r--r--src/wasm-binary-reader.h175
-rw-r--r--src/wasm-binary-writer.c20
-rw-r--r--src/wasm-binary.h34
-rw-r--r--src/wasm-objdump.c609
-rw-r--r--src/wasm-parser-lexer-shared.h1
8 files changed, 1755 insertions, 27 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 74ca15f6..153498fb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,7 +69,6 @@ find_package(FLEX)
find_package(BISON 3.0)
if (RUN_FLEX_BISON AND FLEX_FOUND AND BISON_FOUND)
set(BISON_PARSER_C ${SEXPR_WASM_BINARY_DIR}/wasm-bison-parser.c)
- set(BISON_PARSER_H )
BISON_TARGET(WASM_BISON_PARSER
${SEXPR_WASM_SOURCE_DIR}/src/wasm-bison-parser.y
${BISON_PARSER_C}
@@ -115,6 +114,15 @@ set(SEXPR_WASM_SRCS
add_executable(sexpr-wasm ${SEXPR_WASM_SRCS})
add_dependencies(everything sexpr-wasm)
+# wasm-objdump
+set(WASM_OBJDUMP_SRCS
+ src/wasm-binary-reader.c
+ src/wasm-objdump.c
+)
+
+add_executable(wasm-objdump ${WASM_OBJDUMP_SRCS})
+add_dependencies(everything wasm-objdump)
+
# hexfloat-test
option(BUILD_TESTS "Build GTest-based tests" ON)
find_package(Threads)
@@ -148,7 +156,7 @@ find_package(PythonInterp 2.7 REQUIRED)
set(RUN_TESTS_PY ${SEXPR_WASM_SOURCE_DIR}/test/run-tests.py)
add_custom_target(run-tests
COMMAND ${PYTHON_EXECUTABLE} ${RUN_TESTS_PY} -e $<TARGET_FILE:sexpr-wasm>
- DEPENDS sexpr-wasm
+ DEPENDS sexpr-wasm wasm-objdump
WORKING_DIRECTORY ${SEXPR_WASM_SOURCE_DIR}
)
@@ -171,12 +179,14 @@ if (COMPILER_IS_CLANG)
endif ()
add_custom_target(all-${SANITIZER_NAME}
- DEPENDS sexpr-wasm-${SANITIZER_NAME} hexfloat_test-${SANITIZER_NAME})
+ DEPENDS sexpr-wasm-${SANITIZER_NAME}
+ hexfloat_test-${SANITIZER_NAME}
+ wasm-objdump-${SANITIZER_NAME})
add_custom_target(run-tests-${SANITIZER_NAME}
COMMAND ${PYTHON_EXECUTABLE} ${RUN_TESTS_PY}
-e $<TARGET_FILE:sexpr-wasm-${SANITIZER_NAME}>
- DEPENDS sexpr-wasm-${SANITIZER_NAME}
+ DEPENDS sexpr-wasm-${SANITIZER_NAME} wasm-objdump-${SANITIZER_NAME}
WORKING_DIRECTORY ${SEXPR_WASM_SOURCE_DIR}
)
endmacro ()
diff --git a/Makefile b/Makefile
index b66644b1..be31bf9e 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ DEFAULT_BUILD_TYPE = DEBUG
COMPILERS := GCC GCC_I686 CLANG
BUILD_TYPES := DEBUG RELEASE
SANITIZERS := NO ASAN MSAN LSAN
-EXECUTABLES := sexpr-wasm hexfloat_test
+EXECUTABLES := sexpr-wasm wasm-objdump hexfloat_test
GCC_DEBUG_DIR := out/gcc/Debug
GCC_DEBUG_NO_FLEX_BISON_DIR := out/gcc/Debug-no-flex-bison
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, &section_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, &section_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, &param_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;
+}
diff --git a/src/wasm-binary-reader.h b/src/wasm-binary-reader.h
new file mode 100644
index 00000000..dd74e0fe
--- /dev/null
+++ b/src/wasm-binary-reader.h
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+#ifndef WASM_BINARY_READER_H_
+#define WASM_BINARY_READER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "wasm-binary.h"
+#include "wasm-common.h"
+
+typedef struct WasmBinaryReader {
+ void* user_data;
+
+ void (*on_error)(const char* message, void* user_data);
+
+ /* module */
+ void (*begin_module)(void* user_data);
+ void (*end_module)(void* user_data);
+
+ /* memory section */
+ void (*begin_memory_section)(void* user_data);
+ void (*on_memory_initial_size_pages)(uint32_t pages, void* user_data);
+ void (*on_memory_max_size_pages)(uint32_t pages, void* user_data);
+ void (*on_memory_exported)(int exported, void* user_data);
+ void (*end_memory_section)(void* user_data);
+
+ /* data segment section */
+ void (*begin_data_segment_section)(void* user_data);
+ void (*on_data_segment_count)(uint32_t count, void* user_data);
+ void (*on_data_segment)(uint32_t index,
+ uint32_t address,
+ const void* data,
+ uint32_t size,
+ void* user_data);
+ void (*end_data_segment_section)(void* user_data);
+
+ /* signatures section */
+ void (*begin_signature_section)(void* user_data);
+ void (*on_signature_count)(uint32_t count, void* user_data);
+ void (*on_signature)(uint32_t index,
+ WasmType result_type,
+ uint32_t param_count,
+ WasmType* param_types,
+ void* user_data);
+ void (*end_signature_section)(void* user_data);
+
+ /* imports section */
+ void (*begin_import_section)(void* user_data);
+ void (*on_import_count)(uint32_t count, void* user_data);
+ void (*on_import)(uint32_t index,
+ uint32_t sig_index,
+ WasmStringSlice module_name,
+ WasmStringSlice function_name,
+ void* user_data);
+ void (*end_import_section)(void* user_data);
+
+ /* function signatures section */
+ void (*begin_function_signatures_section)(void* user_data);
+ void (*on_function_signatures_count)(uint32_t count, void* user_data);
+ void (*on_function_signature)(uint32_t index,
+ uint32_t sig_index,
+ void* user_data);
+ void (*end_function_signatures_section)(void* user_data);
+
+ /* function bodies section */
+ void (*begin_function_bodies_section)(void* user_data);
+ void (*on_function_bodies_count)(uint32_t count, void* user_data);
+ void (*begin_function_body)(uint32_t index, void* user_data);
+ void (*on_local_decl_count)(uint32_t count, void* user_data);
+ void (*on_local_decl)(uint32_t decl_index,
+ uint32_t count,
+ WasmType type,
+ void* user_data);
+
+ /* function expressions; called between begin_function_body and
+ end_function_body */
+ void (*on_binary_expr)(WasmOpcode opcode, void* user_data);
+ void (*on_block_expr)(uint32_t count, void* user_data);
+ void (*on_br_expr)(uint32_t depth, void* user_data);
+ void (*on_br_if_expr)(uint32_t depth, void* user_data);
+ void (*on_br_table_expr)(uint32_t num_targets,
+ uint32_t* target_depths,
+ uint32_t default_target_depth,
+ void* user_data);
+ void (*on_call_expr)(uint32_t func_index, void* user_data);
+ void (*on_call_import_expr)(uint32_t import_index, void* user_data);
+ void (*on_call_indirect_expr)(uint32_t sig_index, void* user_data);
+ void (*on_compare_expr)(WasmOpcode opcode, void* user_data);
+ void (*on_i32_const_expr)(uint32_t value, void* user_data);
+ void (*on_i64_const_expr)(uint64_t value, void* user_data);
+ void (*on_f32_const_expr)(uint32_t value_bits, void* user_data);
+ void (*on_f64_const_expr)(uint64_t value_bits, void* user_data);
+ void (*on_convert_expr)(WasmOpcode opcode, void* user_data);
+ void (*on_get_local_expr)(uint32_t local_index, void* user_data);
+ void (*on_grow_memory_expr)(void* user_data);
+ void (*on_if_expr)(void* user_data);
+ void (*on_if_else_expr)(void* user_data);
+ void (*on_load_expr)(WasmOpcode opcode,
+ uint32_t alignment_log2,
+ uint32_t offset,
+ void* user_data);
+ void (*on_loop_expr)(uint32_t count, void* user_data);
+ void (*on_memory_size_expr)(void* user_data);
+ void (*on_nop_expr)(void* user_data);
+ void (*on_return_expr)(void* user_data);
+ void (*on_select_expr)(void* user_data);
+ void (*on_set_local_expr)(uint32_t local_index, void* user_data);
+ void (*on_store_expr)(WasmOpcode opcode,
+ uint32_t alignment_log2,
+ uint32_t offset,
+ void* user_data);
+ void (*on_unary_expr)(WasmOpcode opcode, void* user_data);
+ void (*on_unreachable_expr)(void* user_data);
+ void (*end_function_body)(uint32_t index, void* user_data);
+ void (*end_function_bodies_section)(void* user_data);
+
+ /* function table section */
+ void (*begin_function_table_section)(void* user_data);
+ void (*on_function_table_count)(uint32_t count, void* user_data);
+ void (*on_function_table_entry)(uint32_t index,
+ uint32_t func_index,
+ void* user_data);
+ void (*end_function_table_section)(void* user_data);
+
+ /* start section */
+ void (*begin_start_section)(void* user_data);
+ void (*on_start_function)(uint32_t func_index, void* user_data);
+ void (*end_start_section)(void* user_data);
+
+ /* exports section */
+ void (*begin_export_section)(void* user_data);
+ void (*on_export_count)(uint32_t count, void* user_data);
+ void (*on_export)(uint32_t index,
+ uint32_t func_index,
+ WasmStringSlice name,
+ void* user_data);
+ void (*end_export_section)(void* user_data);
+
+ /* names section */
+ void (*begin_names_section)(void* user_data);
+ void (*on_function_names_count)(uint32_t count, void* user_data);
+ void (*on_function_name)(uint32_t index,
+ WasmStringSlice name,
+ void* user_data);
+ void (*on_local_names_count)(uint32_t index, uint32_t count, void* user_data);
+ void (*on_local_name)(uint32_t func_index,
+ uint32_t local_index,
+ WasmStringSlice name,
+ void* user_data);
+ void (*end_names_section)(void* user_data);
+
+} WasmBinaryReader;
+
+WASM_EXTERN_C_BEGIN
+WasmResult wasm_read_binary(const void* data,
+ size_t size,
+ WasmBinaryReader* reader);
+WASM_EXTERN_C_END
+
+#endif /* WASM_BINARY_READER_H_ */
diff --git a/src/wasm-binary-writer.c b/src/wasm-binary-writer.c
index ea34d214..01ce8e63 100644
--- a/src/wasm-binary-writer.c
+++ b/src/wasm-binary-writer.c
@@ -915,7 +915,7 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
WASM_ZERO_MEMORY(sigs);
get_func_signatures(ctx, module, &sigs);
if (sigs.size) {
- begin_section(ctx, WASM_BINARY_SECTION_SIGNATURES, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_SIGNATURES, leb_size_guess);
out_u32_leb128(ws, sigs.size, "num signatures");
for (i = 0; i < sigs.size; ++i) {
WasmFuncSignature* sig = &sigs.data[i];
@@ -930,7 +930,7 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
}
if (module->imports.size) {
- begin_section(ctx, WASM_BINARY_SECTION_IMPORTS, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_IMPORT_TABLE, leb_size_guess);
out_u32_leb128(ws, module->imports.size, "num imports");
for (i = 0; i < module->imports.size; ++i) {
@@ -946,7 +946,7 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
}
if (module->funcs.size) {
- begin_section(ctx, WASM_BINARY_SECTION_FUNCTION_SIGNATURES, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_FUNCTION_SIGNATURES, leb_size_guess);
out_u32_leb128(ws, module->funcs.size, "num functions");
for (i = 0; i < module->funcs.size; ++i) {
@@ -958,7 +958,7 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
}
if (module->table && module->table->size) {
- begin_section(ctx, WASM_BINARY_SECTION_FUNCTION_TABLE, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_FUNCTION_TABLE, leb_size_guess);
out_u32_leb128(ws, module->table->size, "num function table entries");
for (i = 0; i < module->table->size; ++i) {
int index = wasm_get_func_index_by_var(module, &module->table->data[i]);
@@ -970,7 +970,7 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
if (module->memory) {
int export_memory = module->export_memory != NULL;
- begin_section(ctx, WASM_BINARY_SECTION_MEMORY, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_MEMORY, leb_size_guess);
out_u32_leb128(ws, module->memory->initial_pages, "min mem pages");
out_u32_leb128(ws, module->memory->max_pages, "max mem pages");
out_u8(ws, export_memory, "export mem");
@@ -978,7 +978,7 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
}
if (module->exports.size) {
- begin_section(ctx, WASM_BINARY_SECTION_EXPORTS, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_EXPORT_TABLE, leb_size_guess);
out_u32_leb128(ws, module->exports.size, "num exports");
for (i = 0; i < module->exports.size; ++i) {
@@ -994,13 +994,13 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
int start_func_index = wasm_get_func_index_by_var(module, &module->start);
if (start_func_index != -1) {
- begin_section(ctx, WASM_BINARY_SECTION_START, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_START_FUNCTION, leb_size_guess);
out_u32_leb128(ws, start_func_index, "start func index");
end_section(ctx);
}
if (module->funcs.size) {
- begin_section(ctx, WASM_BINARY_SECTION_FUNCTION_BODIES, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_FUNCTION_BODIES, leb_size_guess);
out_u32_leb128(ws, module->funcs.size, "num functions");
for (i = 0; i < module->funcs.size; ++i) {
@@ -1019,7 +1019,7 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
}
if (module->memory && module->memory->segments.size) {
- begin_section(ctx, WASM_BINARY_SECTION_DATA_SEGMENTS, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_DATA_SEGMENTS, leb_size_guess);
out_u32_leb128(ws, module->memory->segments.size, "num data segments");
for (i = 0; i < module->memory->segments.size; ++i) {
WasmSegment* segment = &module->memory->segments.data[i];
@@ -1034,7 +1034,7 @@ static void write_module(WasmWriteContext* ctx, WasmModule* module) {
if (ctx->options->write_debug_names) {
char desc[100];
- begin_section(ctx, WASM_BINARY_SECTION_NAMES, leb_size_guess);
+ begin_section(ctx, WASM_SECTION_NAME_NAMES, leb_size_guess);
out_u32_leb128(ws, module->funcs.size, "num functions");
for (i = 0; i < module->funcs.size; ++i) {
WasmFunc* func = module->funcs.data[i];
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 75ded56b..75525d9f 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -17,20 +17,30 @@
#ifndef WASM_BINARY_H_
#define WASM_BINARY_H_
-#include <stdint.h>
-
#define WASM_BINARY_MAGIC 0x6d736100
#define WASM_BINARY_VERSION 0x0a
-#define WASM_BINARY_SECTION_DATA_SEGMENTS "data_segments"
-#define WASM_BINARY_SECTION_EXPORTS "export_table"
-#define WASM_BINARY_SECTION_FUNCTION_BODIES "function_bodies"
-#define WASM_BINARY_SECTION_FUNCTION_SIGNATURES "function_signatures"
-#define WASM_BINARY_SECTION_FUNCTION_TABLE "function_table"
-#define WASM_BINARY_SECTION_IMPORTS "import_table"
-#define WASM_BINARY_SECTION_MEMORY "memory"
-#define WASM_BINARY_SECTION_NAMES "names"
-#define WASM_BINARY_SECTION_SIGNATURES "signatures"
-#define WASM_BINARY_SECTION_START "start_function"
+#define WASM_SECTION_NAME_SIGNATURES "signatures"
+#define WASM_SECTION_NAME_IMPORT_TABLE "import_table"
+#define WASM_SECTION_NAME_FUNCTION_SIGNATURES "function_signatures"
+#define WASM_SECTION_NAME_FUNCTION_TABLE "function_table"
+#define WASM_SECTION_NAME_MEMORY "memory"
+#define WASM_SECTION_NAME_EXPORT_TABLE "export_table"
+#define WASM_SECTION_NAME_START_FUNCTION "start_function"
+#define WASM_SECTION_NAME_FUNCTION_BODIES "function_bodies"
+#define WASM_SECTION_NAME_DATA_SEGMENTS "data_segments"
+#define WASM_SECTION_NAME_NAMES "names"
+
+#define WASM_FOREACH_SECTION(V) \
+ V(SIGNATURES) \
+ V(IMPORT_TABLE) \
+ V(FUNCTION_SIGNATURES) \
+ V(FUNCTION_TABLE) \
+ V(MEMORY) \
+ V(EXPORT_TABLE) \
+ V(START_FUNCTION) \
+ V(FUNCTION_BODIES) \
+ V(DATA_SEGMENTS) \
+ V(NAMES)
#endif /* WASM_BINARY_H_ */
diff --git a/src/wasm-objdump.c b/src/wasm-objdump.c
new file mode 100644
index 00000000..a4d5f4dd
--- /dev/null
+++ b/src/wasm-objdump.c
@@ -0,0 +1,609 @@
+/*
+ * 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 <assert.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "wasm-binary-reader.h"
+
+enum {
+ FLAG_VERBOSE,
+ FLAG_HELP,
+ NUM_FLAGS
+};
+
+static int s_verbose;
+static const char* s_infile;
+
+static struct option s_long_options[] = {
+ {"verbose", no_argument, NULL, 'v'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0},
+};
+WASM_STATIC_ASSERT(NUM_FLAGS + 1 == WASM_ARRAY_SIZE(s_long_options));
+
+typedef struct OptionHelp {
+ int flag;
+ const char* metavar;
+ const char* help;
+} OptionHelp;
+
+static OptionHelp s_option_help[] = {
+ {FLAG_VERBOSE, NULL, "use multiple times for more info"},
+ {NUM_FLAGS, NULL},
+};
+
+static void usage(const char* prog) {
+ printf("usage: %s [option] filename\n", prog);
+ printf("options:\n");
+ struct option* opt = &s_long_options[0];
+ int i = 0;
+ for (; opt->name; ++i, ++opt) {
+ OptionHelp* help = NULL;
+
+ int n = 0;
+ while (s_option_help[n].help) {
+ if (i == s_option_help[n].flag) {
+ help = &s_option_help[n];
+ break;
+ }
+ n++;
+ }
+
+ if (opt->val) {
+ printf(" -%c, ", opt->val);
+ } else {
+ printf(" ");
+ }
+
+ if (help && help->metavar) {
+ char buf[100];
+ snprintf(buf, 100, "%s=%s", opt->name, help->metavar);
+ printf("--%-30s", buf);
+ } else {
+ printf("--%-30s", opt->name);
+ }
+
+ if (help) {
+ printf("%s", help->help);
+ }
+
+ printf("\n");
+ }
+ exit(0);
+}
+
+static void parse_options(int argc, char** argv) {
+ int c;
+ int option_index = 0;
+
+ while (1) {
+ c = getopt_long(argc, argv, "vh", s_long_options, &option_index);
+ if (c == -1) {
+ break;
+ }
+
+ redo_switch:
+ switch (c) {
+ case 0:
+ c = s_long_options[option_index].val;
+ if (c) {
+ goto redo_switch;
+ }
+
+ switch (option_index) {
+ case FLAG_VERBOSE:
+ case FLAG_HELP:
+ /* Handled above by goto */
+ assert(0);
+ break;
+ }
+ break;
+
+ case 'v':
+ s_verbose++;
+ break;
+
+ case 'h':
+ usage(argv[0]);
+
+ case '?':
+ break;
+
+ default:
+ WASM_FATAL("getopt_long returned '%c' (%d)\n", c, c);
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ s_infile = argv[optind];
+ } else {
+ WASM_FATAL("No filename given.\n");
+ usage(argv[0]);
+ }
+}
+
+#if 0
+#define LOG(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define LOG(...) (void)0
+#endif
+
+void on_error(const char* message, void* user_data) {
+ LOG("error: %s\n", message);
+}
+
+static void begin_module(void* user_data) {
+ LOG("begin_module\n");
+}
+
+static void end_module(void* user_data) {
+ LOG("end_module\n");
+}
+
+static void begin_memory_section(void* user_data) {
+ LOG("begin_memory_section\n");
+}
+
+static void on_memory_initial_size_pages(uint32_t pages, void* user_data) {
+ LOG("on_memory_initial_size(%u)\n", pages);
+}
+
+static void on_memory_max_size_pages(uint32_t pages, void* user_data) {
+ LOG("on_memory_max_size(%u)\n", pages);
+}
+
+static void on_memory_exported(int exported, void* user_data) {
+ LOG("on_memory_exported(%d)\n", exported);
+}
+
+static void end_memory_section(void* user_data) {
+ LOG("end_memory_section\n");
+}
+
+static void begin_data_segment_section(void* user_data) {
+ LOG("begin_data_segment_section\n");
+}
+
+static void on_data_segment_count(uint32_t count, void* user_data) {
+ LOG("on_data_segment_count(%u)\n", count);
+}
+
+static void on_data_segment(uint32_t index,
+ uint32_t address,
+ const void* data,
+ uint32_t size,
+ void* user_data) {
+ LOG("on_data_segment(%u, addr:%u, size:%u)\n", index, address, size);
+}
+
+static void end_data_segment_section(void* user_data) {
+ LOG("end_data_segment_section\n");
+}
+
+static void begin_signature_section(void* user_data) {
+ LOG("begin_signature_section\n");
+}
+
+static void on_signature_count(uint32_t count, void* user_data) {
+ LOG("on_signature_count(%u)\n", count);
+}
+
+static void on_signature(uint32_t index,
+ WasmType result_type,
+ uint32_t param_count,
+ WasmType* param_types,
+ void* user_data) {
+ LOG("on_signature(%u, %d, %d)\n", index, result_type, param_count);
+}
+
+static void end_signature_section(void* user_data) {
+ LOG("end_signature_section\n");
+}
+
+static void begin_import_section(void* user_data) {
+ LOG("begin_import_section\n");
+}
+
+static void on_import_count(uint32_t count, void* user_data) {
+ LOG("on_import_count(%u)\n", count);
+}
+
+static void on_import(uint32_t index,
+ uint32_t sig_index,
+ WasmStringSlice module_name,
+ WasmStringSlice function_name,
+ void* user_data) {
+ LOG("on_import(%u, %u, %.*s, %.*s)\n", index, sig_index,
+ (int)module_name.length, module_name.start, (int)function_name.length,
+ function_name.start);
+}
+
+static void end_import_section(void* user_data) {
+ LOG("end_import_section\n");
+}
+
+static void begin_function_signatures_section(void* user_data) {
+ LOG("begin_function_signatures_section\n");
+}
+
+static void on_function_signatures_count(uint32_t count, void* user_data) {
+ LOG("on_function_signatures_count(%u)\n", count);
+}
+
+static void on_function_signature(uint32_t index,
+ uint32_t sig_index,
+ void* user_data) {
+ LOG("on_function_signature(%u, %u)\n", index, sig_index);
+}
+
+static void end_function_signatures_section(void* user_data) {
+ LOG("end_function_signatures_section\n");
+}
+
+static void begin_function_bodies_section(void* user_data) {
+ LOG("begin_function_bodies_section\n");
+}
+
+static void end_function_bodies_section(void* user_data) {
+ LOG("end_function_bodies_section\n");
+}
+
+static void on_function_bodies_count(uint32_t count, void* user_data) {
+ LOG("on_function_bodies_count(%u)\n", count);
+}
+
+static void begin_function_body(uint32_t index, void* user_data) {
+ LOG("begin_function_body(%u)\n", index);
+}
+
+static void end_function_body(uint32_t index, void* user_data) {
+ LOG("end_function_body(%u)\n", index);
+}
+
+static void on_local_decl_count(uint32_t count, void* user_data) {
+ LOG("on_local_decl_count(%u)\n", count);
+}
+
+static void on_local_decl(uint32_t decl_index,
+ uint32_t count,
+ WasmType type,
+ void* user_data) {
+ LOG("on_local_decl(%u, %u, %u)\n", decl_index, count, type);
+}
+
+static void on_binary_expr(WasmOpcode opcode, void* user_data) {
+ LOG("on_binary_expr(%u)\n", opcode);
+}
+
+static void on_block_expr(uint32_t count, void* user_data) {
+ LOG("on_block_expr(%u)\n", count);
+}
+
+static void on_br_expr(uint32_t depth, void* user_data) {
+ LOG("on_br_expr(%u)\n", depth);
+}
+
+static void on_br_if_expr(uint32_t depth, void* user_data) {
+ LOG("on_br_if_expr(%u)\n", depth);
+}
+
+static void on_call_expr(uint32_t func_index, void* user_data) {
+ LOG("on_call_expr(%u)\n", func_index);
+}
+
+static void on_call_import_expr(uint32_t import_index, void* user_data) {
+ LOG("on_call_import_expr(%u)\n", import_index);
+}
+
+static void on_call_indirect_expr(uint32_t sig_index, void* user_data) {
+ LOG("on_call_indirect_expr(%u)\n", sig_index);
+}
+
+static void on_compare_expr(WasmOpcode opcode, void* user_data) {
+ LOG("on_compare_expr(%u)\n", opcode);
+}
+
+static void on_i32_const_expr(uint32_t value, void* user_data) {
+ LOG("on_i32_const_expr(%u)\n", value);
+}
+
+static void on_i64_const_expr(uint64_t value, void* user_data) {
+ LOG("on_i64_const_expr(%" PRIu64 ")\n", value);
+}
+
+static void on_f32_const_expr(uint32_t value_bits, void* user_data) {
+ LOG("on_f32_const_expr(%u)\n", value_bits);
+}
+
+static void on_f64_const_expr(uint64_t value_bits, void* user_data) {
+ LOG("on_f64_const_expr(%" PRId64 ")\n", value_bits);
+}
+
+static void on_convert_expr(WasmOpcode opcode, void* user_data) {
+ LOG("on_convert_expr(%u)\n", opcode);
+}
+
+static void on_get_local_expr(uint32_t local_index, void* user_data) {
+ LOG("on_get_local_expr(%u)\n", local_index);
+}
+
+static void on_grow_memory_expr(void* user_data) {
+ LOG("on_grow_memory_expr\n");
+}
+
+static void on_if_expr(void* user_data) {
+ LOG("on_if_expr\n");
+}
+
+static void on_if_else_expr(void* user_data) {
+ LOG("on_if_else_expr\n");
+}
+
+static void on_load_expr(WasmOpcode opcode,
+ uint32_t alignment_log2,
+ uint32_t offset,
+ void* user_data) {
+ LOG("on_load_expr(%u, alignment_log2:%u, offset:%u)\n", opcode,
+ alignment_log2, offset);
+}
+
+static void on_loop_expr(uint32_t count, void* user_data) {
+ LOG("on_loop_expr(%u)\n", count);
+}
+
+static void on_memory_size_expr(void* user_data) {
+ LOG("on_memory_size_expr\n");
+}
+
+static void on_nop_expr(void* user_data) {
+ LOG("on_nop_expr\n");
+}
+
+static void on_return_expr(void* user_data) {
+ LOG("on_return_expr\n");
+}
+
+static void on_select_expr(void* user_data) {
+ LOG("on_select_expr\n");
+}
+
+static void on_set_local_expr(uint32_t local_index, void* user_data) {
+ LOG("on_set_local_expr(%u)\n", local_index);
+}
+
+static void on_store_expr(WasmOpcode opcode,
+ uint32_t alignment_log2,
+ uint32_t offset,
+ void* user_data) {
+ LOG("on_store_expr(%u, alignment_log2:%d, offset:%u)\n", opcode,
+ alignment_log2, offset);
+}
+
+static void on_br_table_expr(uint32_t num_targets,
+ uint32_t* target_depths,
+ uint32_t default_target_depth,
+ void* user_data) {
+ LOG("on_br_table_expr(%u, %u)\n", num_targets, default_target_depth);
+}
+
+static void on_unary_expr(WasmOpcode opcode, void* user_data) {
+ LOG("on_unary_expr(%u)\n", opcode);
+}
+
+static void on_unreachable_expr(void* user_data) {
+ LOG("on_unreachable_expr\n");
+}
+
+static void begin_function_table_section(void* user_data) {
+ LOG("begin_function_table_section\n");
+}
+
+static void on_function_table_count(uint32_t count, void* user_data) {
+ LOG("on_function_table_count(%u)\n", count);
+}
+
+static void on_function_table_entry(uint32_t index,
+ uint32_t func_index,
+ void* user_data) {
+ LOG("on_function_table_entry(%u, %u)\n", index, func_index);
+}
+
+static void end_function_table_section(void* user_data) {
+ LOG("end_function_table_section\n");
+}
+
+static void begin_start_section(void* user_data) {
+ LOG("begin_start_section\n");
+}
+
+static void on_start_function(uint32_t func_index, void* user_data) {
+ LOG("on_start_function(%u)\n", func_index);
+}
+
+static void end_start_section(void* user_data) {
+ LOG("end_start_section\n");
+}
+
+static void begin_export_section(void* user_data) {
+ LOG("begin_export_section\n");
+}
+
+static void on_export_count(uint32_t count, void* user_data) {
+ LOG("on_export_count(%u)\n", count);
+}
+
+static void on_export(uint32_t index,
+ uint32_t func_index,
+ WasmStringSlice name,
+ void* user_data) {
+ LOG("on_export(%u, %u, %.*s)\n", index, func_index, (int)name.length,
+ name.start);
+}
+
+static void end_export_section(void* user_data) {
+ LOG("end_export_section\n");
+}
+
+void begin_names_section(void* user_data) {
+ LOG("begin_export_section\n");
+}
+
+void on_function_names_count(uint32_t count, void* user_data) {
+ LOG("on_function_names_count(%u)\n", count);
+}
+
+void on_function_name(uint32_t index,
+ WasmStringSlice name,
+ void* user_data) {
+ LOG("on_function_names_count(%.*s)\n", (int)name.length, name.start);
+}
+
+void on_local_names_count(uint32_t index, uint32_t count, void* user_data) {
+ LOG("on_local_names_count(%u, %u)\n", index, count);
+}
+
+void on_local_name(uint32_t func_index,
+ uint32_t local_index,
+ WasmStringSlice name,
+ void* user_data) {
+ LOG("on_local_name(%u, %u, %.*s)\n", func_index, local_index,
+ (int)name.length, name.start);
+}
+
+void end_names_section(void* user_data) {
+ LOG("end_export_section\n");
+}
+
+static WasmBinaryReader s_binary_reader = {
+ .user_data = NULL,
+ .on_error = &on_error,
+ .begin_module = &begin_module,
+ .end_module = &end_module,
+
+ .begin_memory_section = &begin_memory_section,
+ .on_memory_initial_size_pages = &on_memory_initial_size_pages,
+ .on_memory_max_size_pages = &on_memory_max_size_pages,
+ .on_memory_exported = &on_memory_exported,
+ .end_memory_section = &end_memory_section,
+
+ .begin_data_segment_section = &begin_data_segment_section,
+ .on_data_segment_count = &on_data_segment_count,
+ .on_data_segment = &on_data_segment,
+ .end_data_segment_section = &end_data_segment_section,
+
+ .begin_signature_section = &begin_signature_section,
+ .on_signature_count = &on_signature_count,
+ .on_signature = &on_signature,
+ .end_signature_section = &end_signature_section,
+
+ .begin_import_section = &begin_import_section,
+ .on_import_count = &on_import_count,
+ .on_import = &on_import,
+ .end_import_section = &end_import_section,
+
+ .begin_function_signatures_section = &begin_function_signatures_section,
+ .on_function_signatures_count = &on_function_signatures_count,
+ .on_function_signature = &on_function_signature,
+ .end_function_signatures_section = &end_function_signatures_section,
+
+ .begin_function_bodies_section = &begin_function_bodies_section,
+ .on_function_bodies_count = &on_function_bodies_count,
+ .begin_function_body = &begin_function_body,
+ .on_local_decl_count = &on_local_decl_count,
+ .on_local_decl = &on_local_decl,
+ .on_binary_expr = &on_binary_expr,
+ .on_block_expr = &on_block_expr,
+ .on_br_expr = &on_br_expr,
+ .on_br_if_expr = &on_br_if_expr,
+ .on_br_table_expr = &on_br_table_expr,
+ .on_call_expr = &on_call_expr,
+ .on_call_import_expr = &on_call_import_expr,
+ .on_call_indirect_expr = &on_call_indirect_expr,
+ .on_compare_expr = &on_compare_expr,
+ .on_i32_const_expr = &on_i32_const_expr,
+ .on_i64_const_expr = &on_i64_const_expr,
+ .on_f32_const_expr = &on_f32_const_expr,
+ .on_f64_const_expr = &on_f64_const_expr,
+ .on_convert_expr = &on_convert_expr,
+ .on_get_local_expr = &on_get_local_expr,
+ .on_grow_memory_expr = &on_grow_memory_expr,
+ .on_if_expr = &on_if_expr,
+ .on_if_else_expr = &on_if_else_expr,
+ .on_load_expr = &on_load_expr,
+ .on_loop_expr = &on_loop_expr,
+ .on_memory_size_expr = &on_memory_size_expr,
+ .on_nop_expr = &on_nop_expr,
+ .on_return_expr = &on_return_expr,
+ .on_select_expr = &on_select_expr,
+ .on_set_local_expr = &on_set_local_expr,
+ .on_store_expr = &on_store_expr,
+ .on_unary_expr = &on_unary_expr,
+ .on_unreachable_expr = &on_unreachable_expr,
+ .end_function_body = &end_function_body,
+ .end_function_bodies_section = &end_function_bodies_section,
+
+ .begin_function_table_section = &begin_function_table_section,
+ .on_function_table_count = &on_function_table_count,
+ .on_function_table_entry = &on_function_table_entry,
+ .end_function_table_section = &end_function_table_section,
+
+ .begin_start_section = &begin_start_section,
+ .on_start_function = &on_start_function,
+ .end_start_section = &end_start_section,
+
+ .begin_export_section = &begin_export_section,
+ .on_export_count = &on_export_count,
+ .on_export = &on_export,
+ .end_export_section = &end_export_section,
+
+ .begin_names_section = &begin_names_section,
+ .on_function_names_count = &on_function_names_count,
+ .on_function_name = &on_function_name,
+ .on_local_names_count = &on_local_names_count,
+ .on_local_name = &on_local_name,
+ .end_names_section = &end_names_section,
+};
+
+int main(int argc, char** argv) {
+ parse_options(argc, argv);
+
+ int fd = open(s_infile, O_RDONLY);
+ if (fd == -1)
+ WASM_FATAL("Unable to open file %s.\n", s_infile);
+
+ struct stat statbuf;
+ if (fstat(fd, &statbuf) == -1)
+ WASM_FATAL("Unable to stat file %s.\n", s_infile);
+
+ size_t length = statbuf.st_size;
+ void* addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (addr == MAP_FAILED)
+ WASM_FATAL("Unable to mmap file %s.\n", s_infile);
+
+ WasmResult result = wasm_read_binary(addr, length, &s_binary_reader);
+ if (result == WASM_ERROR)
+ return 1;
+ return 0;
+}
diff --git a/src/wasm-parser-lexer-shared.h b/src/wasm-parser-lexer-shared.h
index 3159480c..e61c002a 100644
--- a/src/wasm-parser-lexer-shared.h
+++ b/src/wasm-parser-lexer-shared.h
@@ -19,6 +19,7 @@
#include <stdarg.h>
#include <stdio.h>
+#include <stdarg.h>
#include "wasm-ast.h"
#include "wasm-common.h"