added debug type information processing
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 21 Aug 2022 03:26:41 +0000 (22:26 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 21 Aug 2022 03:26:41 +0000 (22:26 -0500)
include/bh.h
include/ovm_debug.h
src/debug/debug_host.c
src/debug/debug_info.c
src/debug/debug_thread.c
src/vm/vm.c
src/wasm/engine.c
src/wasm/module_parsing.h

index ef09cf6f4bf950419c59759c3220c16dc97a3452..a5189ffd9be4737973c0677fd8ada539b2b53987 100644 (file)
@@ -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);
index 68ca5971e7a02147388e7d405c586e99ef1aa3d4..ac112c2e0a9f48bbb802a189898b76fd17bd4859 100644 (file)
@@ -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
index b306afd73d6cbc59674fce2ffd434ce04a986acc..8ae0ce1928e3383b5684fb6803a38c7dcc8c2d62 100644 (file)
@@ -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);
index 7db20908683742337f70617cc50d113234d8adf7..6f1000375b86cb8d8847e12278051a4a5fe03bf9 100644 (file)
@@ -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;
 
index 6abc5443b1a480e5d4a7ed27c2677f33df0f6d86..ba0fa285ec41d8e731b3c2074e8549510797f34f 100644 (file)
@@ -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;
index 6567caa574177d8a8aad83d6b9ef0ddc734e519c..28a42627bc63f30f884d517a761693e77da44186 100644 (file)
@@ -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); \
index 55df04199607d1a867337df4845b9ad095ef084c..db4fbeab468cd2c204ab430e8153080067aa3a1a 100644 (file)
@@ -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);
     }
 
index 75b5fcd8ae2621e9c53cab18d7eb81c11b49a6ba..8eade3047c42c2179f4958ed5ebd809db04e121d 100644 (file)
@@ -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;