From 1cb11c40ce33f0b8b74f106e38b0d9b3d03b14ef Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sat, 20 Aug 2022 22:26:41 -0500 Subject: [PATCH] added debug type information processing --- include/bh.h | 10 +++- include/ovm_debug.h | 110 +++++++++++++++++++++++++++++++++++++- src/debug/debug_host.c | 3 +- src/debug/debug_info.c | 79 +++++++++++++++++++++++++++ src/debug/debug_thread.c | 37 +++++++++++-- src/vm/vm.c | 26 ++++----- src/wasm/engine.c | 4 +- src/wasm/module_parsing.h | 4 ++ 8 files changed, 251 insertions(+), 22 deletions(-) diff --git a/include/bh.h b/include/bh.h index ef09cf6..a5189ff 100644 --- a/include/bh.h +++ b/include/bh.h @@ -548,6 +548,7 @@ BH_DEF void bh_buffer_concat(bh_buffer* buffer, bh_buffer other); BH_DEF void bh_buffer_write_byte(bh_buffer* buffer, u8 byte); BH_DEF void bh_buffer_write_u32(bh_buffer* buffer, u32 i); BH_DEF void bh_buffer_write_u64(bh_buffer* buffer, u64 i); +BH_DEF void bh_buffer_write_string(bh_buffer* buffer, char *str); BH_DEF void bh_buffer_align(bh_buffer* buffer, u32 alignment); @@ -2349,18 +2350,23 @@ BH_DEF void bh_buffer_write_byte(bh_buffer* buffer, u8 byte) { buffer->data[buffer->length++] = byte; } -void bh_buffer_write_u32(bh_buffer* buffer, u32 i) { +BH_DEF void bh_buffer_write_u32(bh_buffer* buffer, u32 i) { bh_buffer_grow(buffer, buffer->length + 4); *((u32 *) bh_pointer_add(buffer->data, buffer->length)) = i; buffer->length += 4; } -void bh_buffer_write_u64(bh_buffer* buffer, u64 i) { +BH_DEF void bh_buffer_write_u64(bh_buffer* buffer, u64 i) { bh_buffer_grow(buffer, buffer->length + 8); *((u64 *) bh_pointer_add(buffer->data, buffer->length)) = i; buffer->length += 8; } +BH_DEF void bh_buffer_write_string(bh_buffer* buffer, char *str) { + u32 len = strlen(str); + bh_buffer_append(buffer, (const char *) str, len); +} + void bh_buffer_align(bh_buffer* buffer, u32 alignment) { if (buffer->length % alignment != 0) { u32 difference = alignment - (buffer->length % alignment); diff --git a/include/ovm_debug.h b/include/ovm_debug.h index 68ca597..ac112c2 100644 --- a/include/ovm_debug.h +++ b/include/ovm_debug.h @@ -48,6 +48,88 @@ typedef struct debug_sym_scope_t { i32 parent; // -1 for root } debug_sym_scope_t; +typedef enum debug_type_kind_t { + debug_type_kind_primitive = 1, + debug_type_kind_modifier = 2, + debug_type_kind_structure = 3, + debug_type_kind_array = 4, + debug_type_kind_alias = 5, + debug_type_kind_function = 6, +} debug_type_kind_t; + +typedef enum debug_type_primitive_kind_t { + debug_type_primitive_kind_void = 0, + debug_type_primitive_kind_signed_integer = 1, + debug_type_primitive_kind_unsigned_integer = 2, + debug_type_primitive_kind_float = 3, + debug_type_primitive_kind_boolean = 4, + debug_type_primitive_kind_character = 5, + debug_type_primitive_kind_vector = 6, +} debug_primitive_kind_t; + +typedef struct debug_type_primitive_t { + debug_primitive_kind_t primitive_kind; +} debug_type_primitive_t; + +typedef enum debug_type_modifier_kind_t { + debug_type_modifier_kind_pointer = 1, + debug_type_modifier_kind_const = 2, + debug_type_modifier_kind_restrict = 3, +} debug_type_modifier_kind_t; + +typedef struct debug_type_modifier_t { + debug_type_modifier_kind_t modifier_kind; + u32 modified_type; +} debug_type_modifier_t; + +typedef struct debug_type_structure_member_t { + u32 offset; + u32 type; + char *name; +} debug_type_structure_member_t; + +typedef struct debug_type_structure_t { + u32 member_count; + debug_type_structure_member_t *members; +} debug_type_structure_t; + +typedef struct debug_type_array_t { + u32 count; + u32 type; +} debug_type_array_t; + +typedef enum debug_type_alias_kind_t { + debug_type_alias_kind_transparent = 1, + debug_type_alias_kind_distinct = 2 +} debug_type_alias_kind_t; + +typedef struct debug_type_alias_t { + debug_type_alias_kind_t alias_kind; + u32 aliased_type; +} debug_type_alias_t; + +typedef struct debug_type_function_t { + u32 param_count; + u32 *param_types; + u32 return_type; +} debug_type_function_t; + +typedef struct debug_type_info_t { + u32 id; + char *name; + u32 size; + debug_type_kind_t kind; + + union { + debug_type_primitive_t primitive; + debug_type_modifier_t modifier; + debug_type_structure_t structure; + debug_type_array_t array; + debug_type_alias_t alias; + debug_type_function_t function; + }; +} debug_type_info_t; + typedef struct debug_info_t { bh_allocator alloc; @@ -73,6 +155,9 @@ typedef struct debug_info_t { // scope id -> symbol scope bh_arr(debug_sym_scope_t) symbol_scopes; + + // type id -> type info + bh_arr(debug_type_info_t) types; } debug_info_t; void debug_info_init(debug_info_t *); @@ -80,6 +165,7 @@ void debug_info_free(debug_info_t *); void debug_info_import_file_info(debug_info_t *, u8 *data, u32 len); void debug_info_import_func_info(debug_info_t *, u8 *data, u32 len); void debug_info_import_sym_info(debug_info_t *, u8 *data, u32 len); +void debug_info_import_type_info(debug_info_t *, u8 *data, u32 len); bool debug_info_lookup_location(debug_info_t *info, u32 instruction, debug_loc_info_t *out); bool debug_info_lookup_file(debug_info_t *info, u32 file_id, debug_file_info_t *out); @@ -168,6 +254,7 @@ typedef struct debug_state_t { bh_allocator tmp_alloc; debug_info_t *info; + struct ovm_engine_t *ovm_engine; bh_arr(debug_thread_state_t *) threads; u32 next_thread_id; @@ -185,12 +272,33 @@ typedef struct debug_state_t { u32 state_change_pipes[2]; } debug_state_t; -void debug_host_init(debug_state_t *debug); +void debug_host_init(debug_state_t *debug, struct ovm_engine_t *ovm_engine); void debug_host_start(debug_state_t *debug); void debug_host_stop(debug_state_t *debug); u32 debug_host_register_thread(debug_state_t *debug, struct ovm_state_t *ovm_state); debug_thread_state_t *debug_host_lookup_thread(debug_state_t *debug, u32 id); + + +typedef struct debug_runtime_value_builder_t { + debug_state_t *state; + debug_info_t *info; + + bh_buffer output; + struct ovm_state_t *ovm_state; + struct ovm_stack_frame_t *ovm_frame; + + debug_sym_scope_t sym_scope; + debug_func_info_t func_info; + debug_file_info_t file_info; + debug_loc_info_t loc_info; + debug_sym_info_t sym_info; +} debug_runtime_value_builder_t; + +void debug_runtime_value_build_init(debug_runtime_value_builder_t *builder, bh_allocator alloc); +void debug_runtime_value_build_free(debug_runtime_value_builder_t *builder); +void debug_runtime_value_build_string(debug_runtime_value_builder_t *builder); + void *__debug_thread_entry(void *); #endif diff --git a/src/debug/debug_host.c b/src/debug/debug_host.c index b306afd..8ae0ce1 100644 --- a/src/debug/debug_host.c +++ b/src/debug/debug_host.c @@ -2,9 +2,10 @@ #include "ovm_debug.h" #include "vm.h" -void debug_host_init(debug_state_t *debug) { +void debug_host_init(debug_state_t *debug, struct ovm_engine_t *ovm_engine) { memset(debug, 0, sizeof(*debug)); debug->alloc = bh_heap_allocator(); + debug->ovm_engine = ovm_engine; bh_arena_init(&debug->tmp_arena, bh_heap_allocator(), 16 * 1024); debug->tmp_alloc = bh_arena_allocator(&debug->tmp_arena); diff --git a/src/debug/debug_info.c b/src/debug/debug_info.c index 7db2090..6f10003 100644 --- a/src/debug/debug_info.c +++ b/src/debug/debug_info.c @@ -113,6 +113,85 @@ void debug_info_import_sym_info(debug_info_t *info, u8 *data, u32 len) { assert(offset == len); } +void debug_info_import_type_info(debug_info_t *info, u8 *data, u32 len) { + u32 offset = 0; + info->has_debug_info = true; + + i32 count = uleb128_to_uint(data, &offset); + fori (i, 0, count) { + debug_type_info_t type; + type.id = uleb128_to_uint(data, &offset); + + u32 name_length = uleb128_to_uint(data, &offset); + if (name_length == 0) { + type.name = NULL; + } else { + type.name = bh_alloc_array(info->alloc, char, name_length + 1); + memcpy(type.name, data + offset, name_length); + type.name[name_length] = 0; + offset += name_length; + } + + type.size = uleb128_to_uint(data, &offset); + type.kind = uleb128_to_uint(data, &offset); + + switch (type.kind) { + case debug_type_kind_primitive: + type.primitive.primitive_kind = uleb128_to_uint(data, &offset); + break; + + case debug_type_kind_modifier: + type.modifier.modifier_kind = uleb128_to_uint(data, &offset); + type.modifier.modified_type = uleb128_to_uint(data, &offset); + break; + + case debug_type_kind_structure: + type.structure.member_count = uleb128_to_uint(data, &offset); + type.structure.members = bh_alloc_array(info->alloc, debug_type_structure_member_t, type.structure.member_count); + + fori (i, 0, type.structure.member_count) { + type.structure.members[i].offset = uleb128_to_uint(data, &offset); + type.structure.members[i].type = uleb128_to_uint(data, &offset); + + u32 name_length = uleb128_to_uint(data, &offset); + type.structure.members[i].name = bh_alloc_array(info->alloc, char, name_length + 1); + memcpy(type.structure.members[i].name, data + offset, name_length); + type.structure.members[i].name[name_length] = 0; + offset += name_length; + } + break; + + case debug_type_kind_array: + type.array.count = uleb128_to_uint(data, &offset); + type.array.type = uleb128_to_uint(data, &offset); + break; + + case debug_type_kind_alias: + type.alias.alias_kind = uleb128_to_uint(data, &offset); + type.alias.aliased_type = uleb128_to_uint(data, &offset); + break; + + case debug_type_kind_function: + type.function.param_count = uleb128_to_uint(data, &offset); + type.function.param_types = bh_alloc_array(info->alloc, u32, type.function.param_count); + + fori (i, 0, type.function.param_count) { + type.function.param_types[i] = uleb128_to_uint(data, &offset); + } + + type.function.return_type = uleb128_to_uint(data, &offset); + break; + + // Error handling + default: assert(("Unrecognized type kind", 0)); + } + + bh_arr_set_at(info->types, type.id, type); + } + + assert(offset == len); +} + bool debug_info_lookup_location(debug_info_t *info, u32 instruction, debug_loc_info_t *out) { if (!info || !info->has_debug_info) return false; diff --git a/src/debug/debug_thread.c b/src/debug/debug_thread.c index 6abc544..ba0fa28 100644 --- a/src/debug/debug_thread.c +++ b/src/debug/debug_thread.c @@ -11,8 +11,9 @@ #define CMD_NOP 0 #define CMD_RES 1 -#define CMD_BRK 2 -#define CMD_CLR_BRK 3 +#define CMD_PAUSE 2 +#define CMD_BRK 3 +#define CMD_CLR_BRK 4 #define CMD_STEP 5 #define CMD_TRACE 6 #define CMD_THREADS 7 @@ -147,6 +148,17 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { break; } + case CMD_PAUSE: { + u32 thread_id = parse_int(debug, ctx); + + ON_THREAD(thread_id) { + (*thread)->run_count = 0; + } + + send_response_header(debug, msg_id); + break; + } + case CMD_BRK: { char *filename = parse_string(debug, ctx); unsigned int line = parse_int(debug, ctx); @@ -358,8 +370,25 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { send_int(debug, 0); send_string(debug, sym->name); - send_string(debug, "???"); - send_string(debug, "unknown type"); + + debug_runtime_value_builder_t builder; + builder.state = debug; + builder.info = debug->info; + builder.ovm_state = (*thread)->ovm_state; + builder.ovm_frame = frame; + builder.sym_scope = sym_scope; + builder.func_info = func_info; + builder.file_info = file_info; + builder.loc_info = loc_info; + builder.sym_info = *sym; + + debug_runtime_value_build_init(&builder, bh_heap_allocator()); + debug_runtime_value_build_string(&builder); + send_bytes(debug, builder.output.data, builder.output.length); + debug_runtime_value_build_free(&builder); + + debug_type_info_t *type = &debug->info->types[sym->type]; + send_string(debug, type->name); } symbol_scope = sym_scope.parent; diff --git a/src/vm/vm.c b/src/vm/vm.c index 6567caa..28a4262 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -558,6 +558,12 @@ static inline void ovm__func_setup_stack_frame(ovm_engine_t *engine, ovm_state_t // // Setup value numbers bh_arr_insert_end(state->numbered_values, func->value_number_count); + + // + // Modify debug state so step over works + if (state->debug) { + state->debug->extra_frames_since_last_pause++; + } } static inline ovm_stack_frame_t ovm__func_teardown_stack_frame(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program) { @@ -570,6 +576,13 @@ static inline ovm_stack_frame_t ovm__func_teardown_stack_frame(ovm_engine_t *eng state->value_number_offset = bh_arr_last(state->stack_frames).value_number_base; } + if (state->debug) { + state->debug->extra_frames_since_last_pause--; + if (state->debug->extra_frames_since_last_pause < 0) { + state->debug->pause_within = -1; + } + } + return frame; } @@ -1082,13 +1095,6 @@ ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t ovm_stack_frame_t frame = ovm__func_teardown_stack_frame(engine, state, program); state->pc = frame.return_address; - if (state->debug) { - state->debug->extra_frames_since_last_pause--; - if (state->debug->extra_frames_since_last_pause < 0) { - state->debug->pause_within = -1; - } - } - if (bh_arr_length(state->stack_frames) == 0) { return val; } @@ -1116,19 +1122,15 @@ ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t ovm_func_t *func = &program->funcs[fidx]; \ i32 extra_params = bh_arr_length(state->params) - func->param_count; \ ovm_assert(extra_params >= 0); \ + ovm__func_setup_stack_frame(engine, state, program, fidx, instr.r); \ if (func->kind == OVM_FUNC_INTERNAL) { \ - ovm__func_setup_stack_frame(engine, state, program, fidx, instr.r); \ - \ fori (i, 0, func->param_count) { \ VAL(i) = state->params[i + extra_params]; \ } \ bh_arr_fastdeleten(state->params, func->param_count); \ \ - if (state->debug) state->debug->extra_frames_since_last_pause++; \ state->pc = func->start_instr; \ } else { \ - ovm__func_setup_stack_frame(engine, state, program, fidx, instr.r); \ - \ ovm_value_t result = {0}; \ ovm_external_func_t external_func = state->external_funcs[func->external_func_idx]; \ external_func.native_func(external_func.userdata, &state->params[extra_params], &result); \ diff --git a/src/wasm/engine.c b/src/wasm/engine.c index 55df041..db4fbea 100644 --- a/src/wasm/engine.c +++ b/src/wasm/engine.c @@ -19,10 +19,10 @@ wasm_engine_t *wasm_engine_new_with_config(wasm_config_t *config) { if (config && config->debug_enabled) { // This should maybe be moved elsewhere? - debug_state_t *debug = bh_alloc_item(store->heap_allocator, debug_state_t); + debug_state_t *debug = bh_alloc_item(store->heap_allocator, debug_state_t); engine->engine->debug = debug; - debug_host_init(engine->engine->debug); + debug_host_init(engine->engine->debug, engine->engine); debug_host_start(engine->engine->debug); } diff --git a/src/wasm/module_parsing.h b/src/wasm/module_parsing.h index 75b5fcd..8eade30 100644 --- a/src/wasm/module_parsing.h +++ b/src/wasm/module_parsing.h @@ -95,6 +95,10 @@ static void parse_custom_section(build_context *ctx) { if (!strcmp(name, "ovm_debug_syms")) { debug_info_import_sym_info(ctx->debug_builder.info, cs.data, cs.size); } + + if (!strcmp(name, "ovm_debug_types")) { + debug_info_import_type_info(ctx->debug_builder.info, cs.data, cs.size); + } } ctx->offset = end_of_section; -- 2.25.1