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);
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);
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;
// 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 *);
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);
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;
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
#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);
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;
#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
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);
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;
//
// 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) {
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;
}
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;
}
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); \
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);
}
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;