diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-binary-reader-ast.c | 13 | ||||
-rw-r--r-- | src/wasm-binary-reader-interpreter.c | 18 | ||||
-rw-r--r-- | src/wasm-binary-reader-objdump.c | 434 | ||||
-rw-r--r-- | src/wasm-binary-reader-objdump.h | 43 | ||||
-rw-r--r-- | src/wasm-binary-reader.c | 135 | ||||
-rw-r--r-- | src/wasm-binary-reader.h | 45 | ||||
-rw-r--r-- | src/wasm-common.c | 7 | ||||
-rw-r--r-- | src/wasm-common.h | 7 | ||||
-rw-r--r-- | src/wasmdump.c | 137 |
9 files changed, 752 insertions, 87 deletions
diff --git a/src/wasm-binary-reader-ast.c b/src/wasm-binary-reader-ast.c index 796f42eb..33b19d7e 100644 --- a/src/wasm-binary-reader-ast.c +++ b/src/wasm-binary-reader-ast.c @@ -128,7 +128,8 @@ static WasmResult append_expr(Context* ctx, WasmExpr* expr) { static void handle_error(Context* ctx, uint32_t offset, const char* message) { if (ctx->error_handler->on_error) { - ctx->error_handler->on_error(offset, message, ctx->error_handler->user_data); + ctx->error_handler->on_error(offset, message, + ctx->error_handler->user_data); } } @@ -535,11 +536,11 @@ static WasmResult on_br_if_expr(uint32_t depth, void* user_data) { return append_expr(ctx, expr); } -static WasmResult on_br_table_expr(uint32_t num_targets, +static WasmResult on_br_table_expr(WasmBinaryReaderContext* context, + uint32_t num_targets, uint32_t* target_depths, - uint32_t default_target_depth, - void* user_data) { - Context* ctx = user_data; + uint32_t default_target_depth) { + Context* ctx = context->user_data; WasmExpr* expr = wasm_new_br_table_expr(ctx->allocator); wasm_reserve_vars(ctx->allocator, &expr->br_table.targets, num_targets); expr->br_table.targets.size = num_targets; @@ -574,7 +575,7 @@ static WasmResult on_call_indirect_expr(uint32_t sig_index, void* user_data) { static WasmResult on_compare_expr(WasmOpcode opcode, void* user_data) { Context* ctx = user_data; - WasmExpr *expr = wasm_new_compare_expr(ctx->allocator); + WasmExpr* expr = wasm_new_compare_expr(ctx->allocator); expr->compare.opcode = opcode; return append_expr(ctx, expr); } diff --git a/src/wasm-binary-reader-interpreter.c b/src/wasm-binary-reader-interpreter.c index bc18030c..3155d98f 100644 --- a/src/wasm-binary-reader-interpreter.c +++ b/src/wasm-binary-reader-interpreter.c @@ -320,8 +320,7 @@ static WasmResult emit_func_offset(Context* ctx, return WASM_OK; } -static void on_error(WasmBinaryReaderContext* ctx, - const char* message) { +static void on_error(WasmBinaryReaderContext* ctx, const char* message) { handle_error(ctx->offset, message, ctx->user_data); } @@ -510,8 +509,7 @@ static WasmResult on_init_expr_get_global_expr(uint32_t index, void* user_data) { Context* ctx = user_data; assert(global_index < ctx->module->globals.size); - WasmInterpreterGlobal* ref_global = - &ctx->module->globals.data[global_index]; + WasmInterpreterGlobal* ref_global = &ctx->module->globals.data[global_index]; ctx->init_expr_value = ref_global->typed_value; return WASM_OK; } @@ -719,8 +717,8 @@ static WasmResult check_n_types(Context* ctx, for (i = 0; i < expected->size; ++i) { WasmType actual = ctx->type_stack.data[ctx->type_stack.size - expected->size + i]; - CHECK_RESULT(check_type(ctx, expected->data[expected->size - i - 1], - actual, desc)); + CHECK_RESULT( + check_type(ctx, expected->data[expected->size - i - 1], actual, desc)); } return WASM_OK; } @@ -1049,11 +1047,11 @@ static WasmResult on_br_if_expr(uint32_t depth, void* user_data) { return WASM_OK; } -static WasmResult on_br_table_expr(uint32_t num_targets, +static WasmResult on_br_table_expr(WasmBinaryReaderContext* context, + uint32_t num_targets, uint32_t* target_depths, - uint32_t default_target_depth, - void* user_data) { - Context* ctx = user_data; + uint32_t default_target_depth) { + Context* ctx = context->user_data; CHECK_RESULT(pop_and_check_1_type(ctx, WASM_TYPE_I32, "br_table")); CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR_TABLE)); CHECK_RESULT(emit_i32(ctx, num_targets)); diff --git a/src/wasm-binary-reader-objdump.c b/src/wasm-binary-reader-objdump.c new file mode 100644 index 00000000..c940b227 --- /dev/null +++ b/src/wasm-binary-reader-objdump.c @@ -0,0 +1,434 @@ +/* + * 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-objdump.h" + +#include <assert.h> +#include <string.h> +#include <stdio.h> + +#include "wasm-binary-reader.h" + +typedef struct Context { + const WasmObjdumpOptions* options; + WasmStream* out_stream; + const uint8_t* data; + size_t size; + WasmOpcode current_opcode; + size_t current_opcode_offset; + size_t last_opcode_end; + int indent_level; +} Context; + +static void WASM_PRINTF_FORMAT(2, 3) + print_details(Context* ctx, const char* fmt, ...) { + if (!ctx->options->verbose) + return; + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +#define SEGSTART(segname, name) \ + static WasmResult begin_##segname##_section(WasmBinaryReaderContext* ctx, \ + uint32_t size) { \ + return begin_section(ctx->user_data, name, ctx->offset, size); \ + } + +static WasmResult begin_section(Context* ctx, + const char* name, + size_t offset, + size_t size) { + if (ctx->options->headers) { + printf("%-12s start=%#010" PRIzx " end=%#010" PRIzx " (size=%#010" PRIzx + ")\n", + name, offset, offset + size, size); + } + if (ctx->options->raw) { + printf("\n"); + wasm_write_memory_dump(ctx->out_stream, ctx->data + offset, size, offset, + WASM_PRINT_CHARS, NULL); + } + return WASM_OK; +} + +SEGSTART(signature, "TYPE") +SEGSTART(import, "IMPORT") +SEGSTART(function_signatures, "FUNCTION") +SEGSTART(table, "TABLE") +SEGSTART(memory, "MEMORY") +SEGSTART(global, "GLOBAL") +SEGSTART(export, "EXPORT") +SEGSTART(start, "START") +SEGSTART(function_bodies, "CODE") +SEGSTART(elem, "ELEM") +SEGSTART(data, "DATA") +SEGSTART(names, "NAMES") + +static WasmResult on_count(uint32_t count, void* user_data) { + Context* ctx = user_data; + print_details(ctx, " - count: %d\n", count); + return WASM_OK; +} + +static WasmResult on_opcode(WasmBinaryReaderContext* ctx, WasmOpcode opcode) { + Context* context = ctx->user_data; + + if (context->options->debug) { + const char* opcode_name = wasm_get_opcode_name(opcode); + printf("on_opcode: %#" PRIzx ": %s\n", ctx->offset, opcode_name); + } + + if (context->last_opcode_end) { + if (ctx->offset != context->last_opcode_end + 1) { + uint8_t missing_opcode = ctx->data[context->last_opcode_end]; + const char* opcode_name = wasm_get_opcode_name(missing_opcode); + fprintf(stderr, "warning: %#" PRIzx " missing opcode callback at %#" PRIzx + " (%#02x=%s)\n", + ctx->offset, context->last_opcode_end + 1, + ctx->data[context->last_opcode_end], opcode_name); + return WASM_ERROR; + } + } + + context->current_opcode_offset = ctx->offset; + context->current_opcode = opcode; + return WASM_OK; +} + +#define IMMEDIATE_OCTET_COUNT 9 + +static void log_opcode(Context* ctx, + const uint8_t* data, + size_t data_size, + const char* fmt, + ...) { + size_t offset = ctx->current_opcode_offset; + + // Print binary data + printf(" %06zx: %02x", offset - 1, ctx->current_opcode); + size_t i; + for (i = 0; i < data_size && i < IMMEDIATE_OCTET_COUNT; i++, offset++) { + printf(" %02x", data[offset]); + } + for (i = data_size + 1; i < IMMEDIATE_OCTET_COUNT; i++) { + printf(" "); + } + printf(" | "); + + // Print disassemble + int j; + int indent_level = ctx->indent_level; + if (ctx->current_opcode == WASM_OPCODE_ELSE) + indent_level--; + for (j = 0; j < indent_level; j++) { + printf(" "); + } + + const char* opcode_name = wasm_get_opcode_name(ctx->current_opcode); + printf("%s", opcode_name); + if (fmt) { + printf(" "); + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + } + + printf("\n"); + + ctx->last_opcode_end = ctx->current_opcode_offset + data_size; +} + +static WasmResult on_opcode_bare(WasmBinaryReaderContext* ctx) { + Context* context = ctx->user_data; + log_opcode(context, ctx->data, 0, NULL); + return WASM_OK; +} + +static WasmResult on_opcode_uint32(WasmBinaryReaderContext* ctx, + uint32_t value) { + Context* context = ctx->user_data; + size_t immediate_len = ctx->offset - context->current_opcode_offset; + log_opcode(context, ctx->data, immediate_len, "%#x", value); + return WASM_OK; +} + +static WasmResult on_opcode_uint32_uint32(WasmBinaryReaderContext* ctx, + uint32_t value, + uint32_t value2) { + Context* context = ctx->user_data; + size_t immediate_len = ctx->offset - context->current_opcode_offset; + log_opcode(context, ctx->data, immediate_len, "%lu %lu", value, value2); + return WASM_OK; +} + +static WasmResult on_opcode_uint64(WasmBinaryReaderContext* ctx, + uint64_t value) { + Context* context = ctx->user_data; + size_t immediate_len = ctx->offset - context->current_opcode_offset; + log_opcode(context, ctx->data, immediate_len, "%d", value); + return WASM_OK; +} + +WasmResult on_br_table_expr(WasmBinaryReaderContext* ctx, + uint32_t num_targets, + uint32_t* target_depths, + uint32_t default_target_depth) { + Context* context = ctx->user_data; + size_t immediate_len = ctx->offset - context->current_opcode_offset; + /* TODO(sbc): Print targets */ + log_opcode(context, ctx->data, immediate_len, NULL); + return WASM_OK; +} + +static WasmResult on_end_expr(void* user_data) { + Context* context = user_data; + context->indent_level--; + assert(context->indent_level >= 0); + log_opcode(context, NULL, 0, NULL); + return WASM_OK; +} + +static const char* wasm_type_name(WasmType type) { + switch (type) { + case WASM_TYPE_I32: + return "i32"; + + case WASM_TYPE_I64: + return "i64"; + + case WASM_TYPE_F32: + return "f32"; + + case WASM_TYPE_F64: + return "f64"; + + default: + assert(0); + return "INVALID TYPE"; + } +} + +static WasmResult on_opcode_block_sig(WasmBinaryReaderContext* ctx, + uint32_t num_types, + WasmType* sig_types) { + Context* context = ctx->user_data; + if (num_types) + log_opcode(context, ctx->data, 1, "%s", wasm_type_name(*sig_types)); + else + log_opcode(context, ctx->data, 1, NULL); + context->indent_level++; + return WASM_OK; +} + +static WasmResult on_signature(uint32_t index, + uint32_t param_count, + WasmType* param_types, + uint32_t result_count, + WasmType* result_types, + void* user_data) { + Context* ctx = user_data; + + if (!ctx->options->verbose) + return WASM_OK; + printf(" - [%d] (", index); + uint32_t i; + for (i = 0; i < param_count; i++) { + if (i != 0) { + printf(", "); + } + printf("%s", wasm_type_name(param_types[i])); + } + printf(") -> "); + if (result_count) + printf("%s", wasm_type_name(result_types[0])); + else + printf("nil"); + printf("\n"); + return WASM_OK; +} + +static WasmResult on_function_signature(uint32_t index, + uint32_t sig_index, + void* user_data) { + print_details(user_data, " - [%d] sig=%d\n", index, sig_index); + return WASM_OK; +} + +static WasmResult begin_function_body(uint32_t index, void* user_data) { + Context* ctx = user_data; + if (ctx->options->verbose || ctx->options->disassemble) + printf("func %d\n", index); + ctx->last_opcode_end = 0; + return WASM_OK; +} + +static WasmResult on_import_func(uint32_t index, + uint32_t sig_index, + void* user_data) { + print_details(user_data, "- func sig=%d\n", sig_index); + return WASM_OK; +} + +static WasmResult on_import_table(uint32_t index, + uint32_t elem_type, + const WasmLimits* elem_limits, + void* user_data) { + /* TODO(sbc): print more useful information about the table here */ + print_details(user_data, "- table elem_type=%d\n", elem_type); + return WASM_OK; +} + +static WasmResult on_import_memory(uint32_t index, + const WasmLimits* page_limits, + void* user_data) { + print_details(user_data, "- memory\n"); + return WASM_OK; +} + +static WasmResult on_import_global(uint32_t index, + WasmType type, + WasmBool mutable_, + void* user_data) { + print_details(user_data, "- global\n"); + return WASM_OK; +} + +static WasmResult on_memory(uint32_t index, + const WasmLimits* page_limits, + void* user_data) { + print_details(user_data, "- memory %d\n", index); + return WASM_OK; +} + +static WasmResult on_table(uint32_t index, + uint32_t elem_type, + const WasmLimits* elem_limits, + void* user_data) { + print_details(user_data, "- table %d\n", index); + return WASM_OK; +} + +static WasmResult on_export(uint32_t index, + WasmExternalKind kind, + uint32_t item_index, + WasmStringSlice name, + void* user_data) { + print_details(user_data, " - [%d] %s ", item_index, wasm_get_kind_name(kind)); + print_details(user_data, PRIstringslice, WASM_PRINTF_STRING_SLICE_ARG(name)); + print_details(user_data, "\n"); + return WASM_OK; +} + +static void on_error(WasmBinaryReaderContext* ctx, const char* message) { + wasm_default_binary_error_callback(ctx->offset, message, ctx->user_data); +} + +static WasmBinaryReader s_binary_reader = { + .user_data = NULL, + .on_error = on_error, + + // Signature sections + .begin_signature_section = begin_signature_section, + .on_signature_count = on_count, + .on_signature = on_signature, + + // Import section + .begin_import_section = begin_import_section, + .on_import_count = on_count, + .on_import_func = on_import_func, + .on_import_table = on_import_table, + .on_import_memory = on_import_memory, + .on_import_global = on_import_global, + + // Function sigs section + .begin_function_signatures_section = begin_function_signatures_section, + .on_function_signatures_count = on_count, + .on_function_signature = on_function_signature, + + // Table section + .begin_table_section = begin_table_section, + .on_table_count = on_count, + .on_table = on_table, + + // Memory section + .begin_memory_section = begin_memory_section, + .on_memory_count = on_count, + .on_memory = on_memory, + + // Globl seciont + .begin_global_section = begin_global_section, + .on_global_count = on_count, + + // Export section + .begin_export_section = begin_export_section, + .on_export_count = on_count, + .on_export = on_export, + + // Start section + .begin_start_section = begin_start_section, + + // Body section + .begin_function_bodies_section = begin_function_bodies_section, + .on_function_bodies_count = on_count, + .begin_function_body = begin_function_body, + + // Elems section + .begin_elem_section = begin_elem_section, + .on_elem_segment_count = on_count, + + // Data section + .begin_data_section = begin_data_section, + .on_data_segment_count = on_count, + + // Names section + .begin_names_section = begin_names_section, + .on_function_names_count = on_count, +}; + +WasmResult wasm_read_binary_objdump(struct WasmAllocator* allocator, + const uint8_t* data, + size_t size, + const WasmObjdumpOptions* options) { + WasmBinaryReader reader; + WASM_ZERO_MEMORY(reader); + reader = s_binary_reader; + Context context; + WASM_ZERO_MEMORY(context); + context.data = data; + context.size = size; + context.options = options; + context.out_stream = wasm_init_stdout_stream(); + + if (options->disassemble) { + reader.on_opcode = on_opcode; + reader.on_opcode_bare = on_opcode_bare; + reader.on_opcode_uint32 = on_opcode_uint32; + reader.on_opcode_uint32_uint32 = on_opcode_uint32_uint32; + reader.on_opcode_uint64 = on_opcode_uint64; + reader.on_opcode_block_sig = on_opcode_block_sig; + reader.on_end_expr = on_end_expr; + reader.on_br_table_expr = on_br_table_expr; + } + + reader.user_data = &context; + WasmReadBinaryOptions read_options = WASM_READ_BINARY_OPTIONS_DEFAULT; + read_options.read_debug_names = WASM_TRUE; + + return wasm_read_binary(allocator, data, size, &reader, 1, &read_options); +} diff --git a/src/wasm-binary-reader-objdump.h b/src/wasm-binary-reader-objdump.h new file mode 100644 index 00000000..c0318f14 --- /dev/null +++ b/src/wasm-binary-reader-objdump.h @@ -0,0 +1,43 @@ +/* + * 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_OBJDUMP_H_ +#define WASM_BINARY_READER_OBJDUMP_H_ + +#include "wasm-common.h" +#include "wasm-stream.h" + +struct WasmAllocator; +struct WasmModule; +struct WasmReadBinaryOptions; + +typedef struct WasmObjdumpOptions { + WasmBool headers; + WasmBool verbose; + WasmBool raw; + WasmBool disassemble; + WasmBool debug; +} WasmObjdumpOptions; + +WASM_EXTERN_C_BEGIN +WasmResult wasm_read_binary_objdump(struct WasmAllocator* allocator, + const uint8_t* data, + size_t size, + const WasmObjdumpOptions* options); + +WASM_EXTERN_C_END + +#endif /* WASM_BINARY_READER_OBJDUMP_H_ */ diff --git a/src/wasm-binary-reader.c b/src/wasm-binary-reader.c index b9d40262..378f5927 100644 --- a/src/wasm-binary-reader.c +++ b/src/wasm-binary-reader.c @@ -43,19 +43,19 @@ typedef uint32_t Uint32; WASM_DEFINE_VECTOR(type, WasmType) WASM_DEFINE_VECTOR(uint32, Uint32); -#define CALLBACK_CTX(member, ...) \ - RAISE_ERROR_UNLESS( \ - WASM_SUCCEEDED( \ - ctx->reader->member \ - ? ctx->reader->member(get_user_context(ctx), __VA_ARGS__)\ - : WASM_OK), \ +#define CALLBACK_CTX(member, ...) \ + RAISE_ERROR_UNLESS( \ + WASM_SUCCEEDED( \ + ctx->reader->member \ + ? ctx->reader->member(get_user_context(ctx), __VA_ARGS__) \ + : WASM_OK), \ #member " callback failed") -#define CALLBACK_CTX0(member) \ - RAISE_ERROR_UNLESS( \ - WASM_SUCCEEDED(ctx->reader->member \ - ? ctx->reader->member(get_user_context(ctx)) \ - : WASM_OK), \ +#define CALLBACK_CTX0(member) \ + RAISE_ERROR_UNLESS( \ + WASM_SUCCEEDED(ctx->reader->member \ + ? ctx->reader->member(get_user_context(ctx)) \ + : WASM_OK), \ #member " callback failed") #define CALLBACK_SECTION(member) CALLBACK_CTX(member, section_size) @@ -79,16 +79,18 @@ WASM_DEFINE_VECTOR(uint32, Uint32); return ctx->reader->member ? ctx->reader->member(ctx->reader->user_data) \ : WASM_OK -#define FORWARD_CTX0(member) \ - if (!ctx->reader->member) return WASM_OK; \ - WasmBinaryReaderContext new_ctx = *reader_context;\ - new_ctx.user_data = ctx->reader->user_data; \ +#define FORWARD_CTX0(member) \ + if (!ctx->reader->member) \ + return WASM_OK; \ + WasmBinaryReaderContext 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 WASM_OK; \ - WasmBinaryReaderContext new_ctx = *reader_context;\ - new_ctx.user_data = ctx->reader->user_data; \ +#define FORWARD_CTX(member, ...) \ + if (!ctx->reader->member) \ + return WASM_OK; \ + WasmBinaryReaderContext new_ctx = *context; \ + new_ctx.user_data = ctx->reader->user_data; \ return ctx->reader->member(&new_ctx, __VA_ARGS__); #define FORWARD(member, ...) \ @@ -110,11 +112,6 @@ WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(s_type_names) == WASM_NUM_TYPES); static const char* s_section_name[] = {WASM_FOREACH_BINARY_SECTION(V)}; #undef V -static const char* s_external_kind_name[] = {"func", "table", "memory", - "global"}; -WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(s_external_kind_name) == - WASM_NUM_EXTERNAL_KINDS); - typedef struct Context { const uint8_t* data; size_t size; @@ -400,8 +397,7 @@ static uint32_t num_total_globals(Context* ctx) { static WasmBool handle_unknown_section(Context* ctx, WasmStringSlice* section_name, uint32_t section_size) { - if (ctx->options->read_debug_names && - ctx->name_section_ok && + if (ctx->options->read_debug_names && ctx->name_section_ok && strncmp(section_name->start, WASM_BINARY_SECTION_NAME, section_name->length) == 0) { CALLBACK_SECTION(begin_names_section); @@ -482,7 +478,6 @@ static void destroy_context(WasmAllocator* allocator, Context* ctx) { wasm_destroy_uint32_vector(allocator, &ctx->target_depths); } - /* Logging */ static void indent(LoggingContext* ctx) { @@ -526,20 +521,21 @@ static void logging_on_error(WasmBinaryReaderContext* ctx, } } -#define LOGGING_BEGIN(name) \ - static WasmResult logging_begin_##name(WasmBinaryReaderContext* reader_context, uint32_t size) { \ - LoggingContext* ctx = reader_context->user_data; \ - LOGF("begin_" #name "\n"); \ - indent(ctx); \ - FORWARD_CTX(begin_##name, size); \ +#define LOGGING_BEGIN(name) \ + static WasmResult logging_begin_##name(WasmBinaryReaderContext* context, \ + uint32_t size) { \ + LoggingContext* ctx = context->user_data; \ + LOGF("begin_" #name "\n"); \ + indent(ctx); \ + FORWARD_CTX(begin_##name, size); \ } -#define LOGGING_END(name) \ - static WasmResult logging_end_##name(WasmBinaryReaderContext* reader_context) { \ - LoggingContext* ctx = reader_context->user_data; \ - dedent(ctx); \ - LOGF("end_" #name "\n"); \ - FORWARD_CTX0(end_##name); \ +#define LOGGING_END(name) \ + static WasmResult logging_end_##name(WasmBinaryReaderContext* context) { \ + LoggingContext* ctx = context->user_data; \ + dedent(ctx); \ + LOGF("end_" #name "\n"); \ + FORWARD_CTX0(end_##name); \ } #define LOGGING_UINT32(name) \ @@ -782,7 +778,7 @@ static WasmResult logging_on_export(uint32_t index, LoggingContext* ctx = user_data; LOGF("on_export(index: %u, kind: %s, item_index: %u, name: \"" PRIstringslice "\")\n", - index, s_external_kind_name[kind], item_index, + index, wasm_get_kind_name(kind), item_index, WASM_PRINTF_STRING_SLICE_ARG(name)); FORWARD(on_export, index, kind, item_index, name); } @@ -828,11 +824,11 @@ static WasmResult logging_on_br_if_expr(uint32_t depth, void* user_data) { FORWARD(on_br_if_expr, depth); } -static WasmResult logging_on_br_table_expr(uint32_t num_targets, +static WasmResult logging_on_br_table_expr(WasmBinaryReaderContext* context, + uint32_t num_targets, uint32_t* target_depths, - uint32_t default_target_depth, - void* user_data) { - LoggingContext* ctx = user_data; + uint32_t default_target_depth) { + LoggingContext* ctx = context->user_data; LOGF("on_br_table_expr(num_targets: %u, depths: [", num_targets); uint32_t i; for (i = 0; i < num_targets; ++i) { @@ -841,7 +837,8 @@ static WasmResult logging_on_br_table_expr(uint32_t num_targets, LOGF_NOINDENT(", "); } LOGF_NOINDENT("], default: %u)\n", default_target_depth); - FORWARD(on_br_table_expr, num_targets, target_depths, default_target_depth); + FORWARD_CTX(on_br_table_expr, num_targets, target_depths, + default_target_depth); } static WasmResult logging_on_f32_const_expr(uint32_t value_bits, @@ -1245,6 +1242,7 @@ static void read_function_body(Context* ctx, switch (opcode) { case WASM_OPCODE_UNREACHABLE: CALLBACK0(on_unreachable_expr); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_BLOCK: { @@ -1254,6 +1252,7 @@ static void read_function_body(Context* ctx, "expected valid block signature type"); uint32_t num_types = sig_type == WASM_TYPE_VOID ? 0 : 1; CALLBACK(on_block_expr, num_types, &sig_type); + CALLBACK_CTX(on_opcode_block_sig, num_types, &sig_type); break; } @@ -1264,6 +1263,7 @@ static void read_function_body(Context* ctx, "expected valid block signature type"); uint32_t num_types = sig_type == WASM_TYPE_VOID ? 0 : 1; CALLBACK(on_loop_expr, num_types, &sig_type); + CALLBACK_CTX(on_opcode_block_sig, num_types, &sig_type); break; } @@ -1274,21 +1274,25 @@ static void read_function_body(Context* ctx, "expected valid block signature type"); uint32_t num_types = sig_type == WASM_TYPE_VOID ? 0 : 1; CALLBACK(on_if_expr, num_types, &sig_type); + CALLBACK_CTX(on_opcode_block_sig, num_types, &sig_type); break; } case WASM_OPCODE_ELSE: CALLBACK0(on_else_expr); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_SELECT: CALLBACK0(on_select_expr); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_BR: { uint32_t depth; in_u32_leb128(ctx, &depth, "br depth"); CALLBACK(on_br_expr, depth); + CALLBACK_CTX(on_opcode_uint32, depth); break; } @@ -1296,6 +1300,7 @@ static void read_function_body(Context* ctx, uint32_t depth; in_u32_leb128(ctx, &depth, "br_if depth"); CALLBACK(on_br_if_expr, depth); + CALLBACK_CTX(on_opcode_uint32, depth); break; } @@ -1303,8 +1308,7 @@ static void read_function_body(Context* ctx, uint32_t num_targets; in_u32_leb128(ctx, &num_targets, "br_table target count"); if (num_targets > ctx->target_depths.capacity) { - wasm_reserve_uint32s(allocator, &ctx->target_depths, - num_targets); + wasm_reserve_uint32s(allocator, &ctx->target_depths, num_targets); ctx->target_depths.size = num_targets; } @@ -1319,21 +1323,24 @@ static void read_function_body(Context* ctx, in_u32_leb128(ctx, &default_target_depth, "br_table default target depth"); - CALLBACK(on_br_table_expr, num_targets, ctx->target_depths.data, - default_target_depth); + CALLBACK_CTX(on_br_table_expr, num_targets, ctx->target_depths.data, + default_target_depth); break; } case WASM_OPCODE_RETURN: CALLBACK0(on_return_expr); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_NOP: CALLBACK0(on_nop_expr); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_DROP: CALLBACK0(on_drop_expr); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_END: @@ -1347,6 +1354,7 @@ static void read_function_body(Context* ctx, 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; } @@ -1354,6 +1362,7 @@ static void read_function_body(Context* ctx, 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; } @@ -1361,6 +1370,7 @@ static void read_function_body(Context* ctx, uint32_t value_bits = 0; in_f32(ctx, &value_bits, "f32.const value"); CALLBACK(on_f32_const_expr, value_bits); + CALLBACK_CTX(on_opcode_uint32, value_bits); break; } @@ -1368,6 +1378,7 @@ static void read_function_body(Context* ctx, uint64_t value_bits = 0; in_f64(ctx, &value_bits, "f64.const value"); CALLBACK(on_f64_const_expr, value_bits); + CALLBACK_CTX(on_opcode_uint64, value_bits); break; } @@ -1375,6 +1386,7 @@ static void read_function_body(Context* ctx, 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; } @@ -1382,6 +1394,7 @@ static void read_function_body(Context* ctx, 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; } @@ -1389,6 +1402,7 @@ static void read_function_body(Context* ctx, 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; } @@ -1396,6 +1410,7 @@ static void read_function_body(Context* ctx, 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; } @@ -1405,6 +1420,7 @@ static void read_function_body(Context* ctx, RAISE_ERROR_UNLESS(func_index < num_total_funcs(ctx), "invalid call_function function index"); CALLBACK(on_call_expr, func_index); + CALLBACK_CTX(on_opcode_uint32, func_index); break; } @@ -1414,6 +1430,7 @@ static void read_function_body(Context* ctx, RAISE_ERROR_UNLESS(sig_index < ctx->num_signatures, "invalid call_indirect signature index"); CALLBACK(on_call_indirect_expr, sig_index); + CALLBACK_CTX(on_opcode_uint32, sig_index); break; } @@ -1421,6 +1438,7 @@ static void read_function_body(Context* ctx, 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; } @@ -1444,6 +1462,7 @@ static void read_function_body(Context* ctx, 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; } @@ -1462,15 +1481,18 @@ static void read_function_body(Context* ctx, 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 WASM_OPCODE_CURRENT_MEMORY: CALLBACK0(on_current_memory_expr); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_GROW_MEMORY: CALLBACK0(on_grow_memory_expr); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_I32_ADD: @@ -1518,6 +1540,7 @@ static void read_function_body(Context* ctx, case WASM_OPCODE_F64_MAX: case WASM_OPCODE_F64_COPYSIGN: CALLBACK(on_binary_expr, opcode); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_I32_EQ: @@ -1553,6 +1576,7 @@ static void read_function_body(Context* ctx, case WASM_OPCODE_F64_GT: case WASM_OPCODE_F64_GE: CALLBACK(on_compare_expr, opcode); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_I32_CLZ: @@ -1576,6 +1600,7 @@ static void read_function_body(Context* ctx, case WASM_OPCODE_F64_NEAREST: case WASM_OPCODE_F64_SQRT: CALLBACK(on_unary_expr, opcode); + CALLBACK_CTX0(on_opcode_bare); break; case WASM_OPCODE_I32_TRUNC_S_F32: @@ -1606,6 +1631,7 @@ static void read_function_body(Context* ctx, case WASM_OPCODE_I32_EQZ: case WASM_OPCODE_I64_EQZ: CALLBACK(on_convert_expr, opcode); + CALLBACK_CTX0(on_opcode_bare); break; default: @@ -1614,8 +1640,7 @@ static void read_function_body(Context* ctx, } 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"); + RAISE_ERROR_UNLESS(seen_end_opcode, "function body must end with END opcode"); } WasmResult wasm_read_binary(WasmAllocator* allocator, @@ -1659,8 +1684,8 @@ WasmResult wasm_read_binary(WasmAllocator* allocator, uint32_t version; in_u32(ctx, &version, "version"); RAISE_ERROR_UNLESS(version == WASM_BINARY_VERSION, - "bad wasm file version: %#x (expected %#x)", - version, WASM_BINARY_VERSION); + "bad wasm file version: %#x (expected %#x)", version, + WASM_BINARY_VERSION); /* type */ uint32_t section_size; @@ -1763,7 +1788,6 @@ WasmResult wasm_read_binary(WasmAllocator* allocator, default: RAISE_ERROR("invalid import kind: %d", kind); } - } CALLBACK_CTX0(end_import_section); } @@ -1912,8 +1936,7 @@ WasmResult wasm_read_binary(WasmAllocator* allocator, uint32_t j, num_function_indexes; in_u32_leb128(ctx, &num_function_indexes, "elem segment function index count"); - CALLBACK(on_elem_segment_function_index_count, i, - num_function_indexes); + CALLBACK(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"); diff --git a/src/wasm-binary-reader.h b/src/wasm-binary-reader.h index 35874386..3dcc576e 100644 --- a/src/wasm-binary-reader.h +++ b/src/wasm-binary-reader.h @@ -51,7 +51,8 @@ typedef struct WasmBinaryReader { /* signatures section */ /* TODO(binji): rename to "type" section */ - WasmResult (*begin_signature_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_signature_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_signature_count)(uint32_t count, void* user_data); WasmResult (*on_signature)(uint32_t index, uint32_t param_count, @@ -62,7 +63,8 @@ typedef struct WasmBinaryReader { WasmResult (*end_signature_section)(WasmBinaryReaderContext* ctx); /* import section */ - WasmResult (*begin_import_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_import_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_import_count)(uint32_t count, void* user_data); WasmResult (*on_import)(uint32_t index, WasmStringSlice module_name, @@ -86,7 +88,8 @@ typedef struct WasmBinaryReader { /* function signatures section */ /* TODO(binji): rename to "function" section */ - WasmResult (*begin_function_signatures_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_function_signatures_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_function_signatures_count)(uint32_t count, void* user_data); WasmResult (*on_function_signature)(uint32_t index, uint32_t sig_index, @@ -94,7 +97,8 @@ typedef struct WasmBinaryReader { WasmResult (*end_function_signatures_section)(WasmBinaryReaderContext* ctx); /* table section */ - WasmResult (*begin_table_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_table_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_table_count)(uint32_t count, void* user_data); WasmResult (*on_table)(uint32_t index, uint32_t elem_type, @@ -103,7 +107,8 @@ typedef struct WasmBinaryReader { WasmResult (*end_table_section)(WasmBinaryReaderContext* ctx); /* memory section */ - WasmResult (*begin_memory_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_memory_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_memory_count)(uint32_t count, void* user_data); WasmResult (*on_memory)(uint32_t index, const WasmLimits* limits, @@ -111,7 +116,8 @@ typedef struct WasmBinaryReader { WasmResult (*end_memory_section)(WasmBinaryReaderContext* ctx); /* global section */ - WasmResult (*begin_global_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_global_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_global_count)(uint32_t count, void* user_data); WasmResult (*begin_global)(uint32_t index, WasmType type, @@ -123,7 +129,8 @@ typedef struct WasmBinaryReader { WasmResult (*end_global_section)(WasmBinaryReaderContext* ctx); /* exports section */ - WasmResult (*begin_export_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_export_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_export_count)(uint32_t count, void* user_data); WasmResult (*on_export)(uint32_t index, WasmExternalKind kind, @@ -133,13 +140,15 @@ typedef struct WasmBinaryReader { WasmResult (*end_export_section)(WasmBinaryReaderContext* ctx); /* start section */ - WasmResult (*begin_start_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_start_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_start_function)(uint32_t func_index, void* user_data); WasmResult (*end_start_section)(WasmBinaryReaderContext* ctx); /* function bodies section */ /* TODO(binji): rename to code section */ - WasmResult (*begin_function_bodies_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_function_bodies_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_function_bodies_count)(uint32_t count, void* user_data); WasmResult (*begin_function_body_pass)(uint32_t index, uint32_t pass, @@ -154,16 +163,25 @@ typedef struct WasmBinaryReader { /* function expressions; called between begin_function_body and end_function_body */ WasmResult (*on_opcode)(WasmBinaryReaderContext* ctx, WasmOpcode Opcode); + WasmResult (*on_opcode_bare)(WasmBinaryReaderContext* ctx); + WasmResult (*on_opcode_uint32)(WasmBinaryReaderContext* ctx, uint32_t value); + WasmResult (*on_opcode_uint32_uint32)(WasmBinaryReaderContext* ctx, + uint32_t value, + uint32_t value2); + WasmResult (*on_opcode_uint64)(WasmBinaryReaderContext* ctx, uint64_t value); + WasmResult (*on_opcode_block_sig)(WasmBinaryReaderContext* ctx, + uint32_t num_types, + WasmType* sig_types); WasmResult (*on_binary_expr)(WasmOpcode opcode, void* user_data); WasmResult (*on_block_expr)(uint32_t num_types, WasmType* sig_types, void* user_data); WasmResult (*on_br_expr)(uint32_t depth, void* user_data); WasmResult (*on_br_if_expr)(uint32_t depth, void* user_data); - WasmResult (*on_br_table_expr)(uint32_t num_targets, + WasmResult (*on_br_table_expr)(WasmBinaryReaderContext* ctx, + uint32_t num_targets, uint32_t* target_depths, - uint32_t default_target_depth, - void* user_data); + uint32_t default_target_depth); WasmResult (*on_call_expr)(uint32_t func_index, void* user_data); WasmResult (*on_call_import_expr)(uint32_t import_index, void* user_data); WasmResult (*on_call_indirect_expr)(uint32_t sig_index, void* user_data); @@ -241,7 +259,8 @@ typedef struct WasmBinaryReader { WasmResult (*end_data_section)(WasmBinaryReaderContext* ctx); /* names section */ - WasmResult (*begin_names_section)(WasmBinaryReaderContext* ctx, uint32_t size); + WasmResult (*begin_names_section)(WasmBinaryReaderContext* ctx, + uint32_t size); WasmResult (*on_function_names_count)(uint32_t count, void* user_data); WasmResult (*on_function_name)(uint32_t index, WasmStringSlice name, diff --git a/src/wasm-common.c b/src/wasm-common.c index 9a70e6f1..1df2e335 100644 --- a/src/wasm-common.c +++ b/src/wasm-common.c @@ -34,10 +34,13 @@ WasmOpcodeInfo g_wasm_opcode_info[] = {WASM_FOREACH_OPCODE(V)}; #undef V +const char* g_wasm_kind_name[] = {"func", "table", "memory", "global"}; +WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(g_wasm_kind_name) == + WASM_NUM_EXTERNAL_KINDS); + WasmBool wasm_is_naturally_aligned(WasmOpcode opcode, uint32_t alignment) { uint32_t opcode_align = wasm_get_opcode_memory_size(opcode); - return alignment == WASM_USE_NATURAL_ALIGNMENT || - alignment == opcode_align; + return alignment == WASM_USE_NATURAL_ALIGNMENT || alignment == opcode_align; } uint32_t wasm_get_opcode_alignment(WasmOpcode opcode, uint32_t alignment) { diff --git a/src/wasm-common.h b/src/wasm-common.h index 71f8a044..365572da 100644 --- a/src/wasm-common.h +++ b/src/wasm-common.h @@ -151,6 +151,13 @@ typedef enum WasmExternalKind { WASM_NUM_EXTERNAL_KINDS, } WasmExternalKind; +extern const char* g_wasm_kind_name[]; + +static WASM_INLINE const char* wasm_get_kind_name(WasmExternalKind kind) { + assert(kind < WASM_NUM_EXTERNAL_KINDS); + return g_wasm_kind_name[kind]; +} + typedef struct WasmLimits { uint64_t initial; uint64_t max; diff --git a/src/wasmdump.c b/src/wasmdump.c new file mode 100644 index 00000000..4a6fa0ca --- /dev/null +++ b/src/wasmdump.c @@ -0,0 +1,137 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "wasm-allocator.h" +#include "wasm-common.h" +#include "wasm-option-parser.h" +#include "wasm-stream.h" +#include "wasm-writer.h" +#include "wasm-binary-reader.h" +#include "wasm-binary-reader-objdump.h" + +#define PROGRAM_NAME "wasmdump" + +enum { + FLAG_HEADERS, + FLAG_RAW, + FLAG_DISASSEMBLE, + FLAG_VERBOSE, + FLAG_DEBUG, + FLAG_HELP, + NUM_FLAGS +}; + +static const char s_description[] = + " Print information about the contents of a wasm binary file.\n" + "\n" + "examples:\n" + " $ wasmdump test.wasm\n"; + +static WasmOption s_options[] = { + {FLAG_HEADERS, 'h', "headers", NULL, WASM_OPTION_NO_ARGUMENT, + "print headers"}, + {FLAG_RAW, 'r', "raw", NULL, WASM_OPTION_NO_ARGUMENT, + "print raw section contents"}, + {FLAG_DISASSEMBLE, 'd', "disassemble", NULL, WASM_OPTION_NO_ARGUMENT, + "disassemble function bodies"}, + {FLAG_DEBUG, '\0', "debug", NULL, WASM_OPTION_NO_ARGUMENT, + "disassemble function bodies"}, + {FLAG_VERBOSE, 'v', "verbose", NULL, WASM_OPTION_NO_ARGUMENT, + "Verbose output"}, + {FLAG_HELP, 'h', "help", NULL, WASM_OPTION_NO_ARGUMENT, + "print this help message"}, +}; +WASM_STATIC_ASSERT(NUM_FLAGS == WASM_ARRAY_SIZE(s_options)); + +static const char* s_infile; +static WasmObjdumpOptions s_objdump_options; + +static void on_argument(struct WasmOptionParser* parser, const char* argument) { + s_infile = argument; +} + +static void on_option(struct WasmOptionParser* parser, + struct WasmOption* option, + const char* argument) { + switch (option->id) { + case FLAG_HEADERS: + s_objdump_options.headers = WASM_TRUE; + break; + + case FLAG_RAW: + s_objdump_options.raw = WASM_TRUE; + break; + + case FLAG_DEBUG: + s_objdump_options.debug = WASM_TRUE; + + case FLAG_DISASSEMBLE: + s_objdump_options.disassemble = WASM_TRUE; + break; + + case FLAG_VERBOSE: + s_objdump_options.verbose = WASM_TRUE; + break; + + case FLAG_HELP: + wasm_print_help(parser, PROGRAM_NAME); + exit(0); + break; + } +} + +static void on_option_error(struct WasmOptionParser* parser, + const char* message) { + WASM_FATAL("%s\n", message); +} + +static void parse_options(int argc, char** argv) { + WasmOptionParser parser; + WASM_ZERO_MEMORY(parser); + parser.description = s_description; + parser.options = s_options; + parser.num_options = WASM_ARRAY_SIZE(s_options); + parser.on_option = on_option; + parser.on_argument = on_argument; + parser.on_error = on_option_error; + wasm_parse_options(&parser, argc, argv); + + if (!s_infile) { + wasm_print_help(&parser, PROGRAM_NAME); + WASM_FATAL("No filename given.\n"); + } +} + +int main(int argc, char** argv) { + wasm_init_stdio(); + + parse_options(argc, argv); + WasmAllocator* allocator = &g_wasm_libc_allocator; + + void* data; + size_t size; + WasmResult result = wasm_read_file(allocator, s_infile, &data, &size); + if (WASM_FAILED(result)) + return result; + + result = wasm_read_binary_objdump(allocator, data, size, &s_objdump_options); + wasm_free(allocator, data); + return result; +} |