debug_runtime_values.c master
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 30 Aug 2022 15:36:38 +0000 (10:36 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 30 Aug 2022 15:36:38 +0000 (10:36 -0500)
src/debug/debug_runtime_values.c [new file with mode: 0644]

diff --git a/src/debug/debug_runtime_values.c b/src/debug/debug_runtime_values.c
new file mode 100644 (file)
index 0000000..2edde56
--- /dev/null
@@ -0,0 +1,279 @@
+
+#include "ovm_debug.h"
+#include "vm.h"
+
+static char write_buf[4096];
+
+#define WRITE(str) do {    \
+        bh_buffer_write_string(&builder->output, str); \
+    } while (0);
+
+#define WRITE_FORMAT(format, ...) do {    \
+        u32 len = snprintf(write_buf, 4096, format, __VA_ARGS__); \
+        bh_buffer_append(&builder->output, write_buf, len); \
+    } while (0);
+
+static bool lookup_register_in_frame(ovm_state_t *state, ovm_stack_frame_t *frame, u32 reg, ovm_value_t *out) {
+
+    u32 val_num_base;
+    if (frame == &bh_arr_last(state->stack_frames)) {
+        val_num_base = state->value_number_offset;
+    } else {
+        val_num_base = (frame + 1)->value_number_base;
+    }
+
+    *out = state->numbered_values[val_num_base + reg];
+    return true;
+}
+
+static void append_value_from_memory_with_type(debug_runtime_value_builder_t *builder, void *base, u32 type_id) {
+    debug_type_info_t *type = &builder->info->types[type_id];
+
+    switch (type->kind) {
+        case debug_type_kind_primitive:
+            switch (type->primitive.primitive_kind) {
+                case debug_type_primitive_kind_void: WRITE("void"); break;
+                case debug_type_primitive_kind_signed_integer:
+                    switch (type->size) {
+                        case 1: WRITE_FORMAT("%hhd", *(i8 *)  base); break;
+                        case 2: WRITE_FORMAT("%hd",  *(i16 *) base); break;
+                        case 4: WRITE_FORMAT("%d",   *(i32 *) base); break;
+                        case 8: WRITE_FORMAT("%ld",  *(i64 *) base); break;
+                        default: WRITE("(err)"); break;
+                    }
+                    break;
+
+                case debug_type_primitive_kind_unsigned_integer:
+                    switch (type->size) {
+                        case 1: WRITE_FORMAT("%hhu", *(u8 *) base); break;
+                        case 2: WRITE_FORMAT("%hu",  *(u16 *) base); break;
+                        case 4: WRITE_FORMAT("%u",   *(u32 *) base); break;
+                        case 8: WRITE_FORMAT("%lu",  *(u64 *) base); break;
+                        default: WRITE("(err)"); break;
+                    }
+                    break;
+
+                case debug_type_primitive_kind_float:
+                    switch (type->size) {
+                        case 4: WRITE_FORMAT("%f",   *(f32 *) base); break;
+                        case 8: WRITE_FORMAT("%f",   *(f64 *) base); break;
+                        default: WRITE("(err)"); break;
+                    }
+                    break;
+
+                case debug_type_primitive_kind_boolean:
+                    if ((*(u8 *) base) != 0) { WRITE("true"); }
+                    else                     { WRITE("false"); }
+                    break;
+
+                default:
+                    WRITE("(err)");
+            }
+            break;
+
+        case debug_type_kind_modifier:
+            switch (type->modifier.modifier_kind) {
+                case debug_type_modifier_kind_pointer:
+                    switch (type->size) {
+                        case 4: WRITE_FORMAT("0x%x",   *(u32 *) base); break;
+                        case 8: WRITE_FORMAT("0x%lx",  *(u64 *) base); break;
+                        default: WRITE("(err)"); break;
+                    }
+                    break;
+
+                default:
+                    append_value_from_memory_with_type(builder, base, type->modifier.modified_type);
+                    break;
+            }
+            break;
+
+        case debug_type_kind_alias:
+            append_value_from_memory_with_type(builder, base, type->alias.aliased_type);
+            break;
+
+        case debug_type_kind_function:
+            WRITE_FORMAT("func[%d]", *(u32 *) base);
+            break;
+
+        case debug_type_kind_structure: {
+            WRITE("{ ");
+
+            fori (i, 0, (i32) type->structure.member_count) {
+                if (i != 0) WRITE(", ");
+
+                WRITE_FORMAT("%s=", type->structure.members[i].name);
+
+                u32 offset  = type->structure.members[i].offset;
+                u32 type_id = type->structure.members[i].type;
+                append_value_from_memory_with_type(builder, bh_pointer_add(base, offset), type_id);
+            }
+
+            WRITE(" }");
+            break;
+        }
+
+        case debug_type_kind_array: {
+            WRITE("[");
+
+            debug_type_info_t *elem_type = &builder->info->types[type->array.type];
+            fori (i, 0, (i32) type->array.count) {
+                if (i != 0) WRITE(", ");
+
+                append_value_from_memory_with_type(builder, bh_pointer_add(base, i * elem_type->size), elem_type->id);
+            }
+
+            WRITE("]");
+            break;
+        }
+
+        default: WRITE("(unknown)"); break;
+    }
+}
+
+static void append_ovm_value_with_type(debug_runtime_value_builder_t *builder, ovm_value_t value, u32 type_id) {
+    debug_type_info_t *type = &builder->info->types[type_id];
+
+    switch (type->kind) {
+        case debug_type_kind_primitive:
+            switch (type->primitive.primitive_kind) {
+                case debug_type_primitive_kind_void: WRITE("void"); break;
+                case debug_type_primitive_kind_signed_integer:
+                    switch (type->size) {
+                        case 1: WRITE_FORMAT("%hhd", value.i8); break;
+                        case 2: WRITE_FORMAT("%hd",  value.i16); break;
+                        case 4: WRITE_FORMAT("%d",   value.i32); break;
+                        case 8: WRITE_FORMAT("%ld",  value.i64); break;
+                        default: WRITE("(err)"); break;
+                    }
+                    break;
+
+                case debug_type_primitive_kind_unsigned_integer:
+                    switch (type->size) {
+                        case 1: WRITE_FORMAT("%hhu", value.u8); break;
+                        case 2: WRITE_FORMAT("%hu",  value.u16); break;
+                        case 4: WRITE_FORMAT("%u",   value.u32); break;
+                        case 8: WRITE_FORMAT("%lu",  value.u64); break;
+                        default: WRITE("(err)"); break;
+                    }
+                    break;
+
+                case debug_type_primitive_kind_float:
+                    switch (type->size) {
+                        case 4: WRITE_FORMAT("%f",   value.f32); break;
+                        case 8: WRITE_FORMAT("%f",   value.f64); break;
+                        default: WRITE("(err)"); break;
+                    }
+                    break;
+
+                case debug_type_primitive_kind_boolean:
+                    if (value.u64 != 0) { WRITE("true"); }
+                    else                { WRITE("false"); }
+                    break;
+
+                default:
+                    WRITE("(err)");
+            }
+            break;
+
+        case debug_type_kind_modifier:
+            switch (type->modifier.modifier_kind) {
+                case debug_type_modifier_kind_pointer:
+                    switch (type->size) {
+                        case 4: WRITE_FORMAT("0x%x",   value.u32); break;
+                        case 8: WRITE_FORMAT("0x%lx",  value.u64); break;
+                        default: WRITE("(err)"); break;
+                    }
+                    break;
+
+                default:
+                    append_ovm_value_with_type(builder, value, type->modifier.modified_type);
+                    break;
+            }
+            break;
+
+        case debug_type_kind_alias:
+            append_ovm_value_with_type(builder, value, type->alias.aliased_type);
+            break;
+
+        case debug_type_kind_function:
+            WRITE_FORMAT("func[%d]", value.u32);
+            break;
+
+        case debug_type_kind_array: {
+            void *base = bh_pointer_add(builder->state->ovm_engine->memory, value.u32);
+            append_value_from_memory_with_type(builder, base, type_id);
+            break;
+        }
+
+        default: WRITE("(unknown)"); break;
+    }
+}
+
+static void append_value_from_stack(debug_runtime_value_builder_t *builder, u32 offset, u32 type_id) {
+    ovm_value_t stack_ptr;
+    if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->func_info.stack_ptr_idx, &stack_ptr)) {
+        WRITE("(no stack ptr)");
+        return;
+    }
+
+    void *base = bh_pointer_add(builder->state->ovm_engine->memory, stack_ptr.u32 + offset);
+
+    append_value_from_memory_with_type(builder, base, type_id);
+}
+
+static void append_value_from_register(debug_runtime_value_builder_t *builder, u32 reg, u32 type_id) {
+    ovm_value_t value;
+
+    debug_type_info_t *type = &builder->info->types[type_id];
+    if (type->kind == debug_type_kind_structure) {
+        WRITE("{ ");
+
+        fori (i, 0, (i32) type->structure.member_count) {
+            if (i != 0) WRITE(", ");
+
+            WRITE_FORMAT("%s=", type->structure.members[i].name);
+
+            if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, reg + i, &value)) {
+                WRITE("(err)")
+                continue;
+            }
+
+            append_ovm_value_with_type(builder, value, type->structure.members[i].type);
+        }
+
+        WRITE(" }");
+        return;
+    }
+
+    if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, reg, &value)) {
+        WRITE("(err)")
+        return;
+    }
+
+    append_ovm_value_with_type(builder, value, type_id);
+}
+
+
+
+
+void debug_runtime_value_build_init(debug_runtime_value_builder_t *builder, bh_allocator alloc) {
+    bh_buffer_init(&builder->output, alloc, 1024);
+}
+
+void debug_runtime_value_build_free(debug_runtime_value_builder_t *builder) {
+    bh_buffer_free(&builder->output);
+}
+
+void debug_runtime_value_build_string(debug_runtime_value_builder_t *builder) {
+    if (builder->sym_info.loc_kind == debug_sym_loc_register) {
+        append_value_from_register(builder, builder->sym_info.loc, builder->sym_info.type);
+        return;
+    }
+
+    if (builder->sym_info.loc_kind == debug_sym_loc_stack) {
+        append_value_from_stack(builder, builder->sym_info.loc, builder->sym_info.type);
+        return;
+    }
+
+    WRITE("(location unknown)");
+}