debugger code cleanup; added enum and slice types (proper strings wooo!)
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 14 Dec 2022 21:20:51 +0000 (15:20 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 14 Dec 2022 21:20:51 +0000 (15:20 -0600)
compiler/src/wasm_output.h
interpreter/include/ovm_debug.h
interpreter/src/debug/debug_info.c
interpreter/src/debug/debug_runtime_values.c

index 964d1d8b01f09812a8c145429bb36ecadc1db409..b6e061441fda16c275dbecff95fda1312345d362 100644 (file)
@@ -911,6 +911,12 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) {
                     continue;
                 }
 
+                if (type->Basic.kind == Basic_Kind_U8) {
+                    output_unsigned_integer(1, &section_buff);
+                    output_unsigned_integer(5, &section_buff);
+                    continue;
+                }
+
                 output_unsigned_integer(1, &section_buff);
                 if      (type->Basic.kind == Basic_Kind_Void) output_unsigned_integer(0, &section_buff);
                 else if (type_is_bool(type))                  output_unsigned_integer(4, &section_buff);
@@ -935,9 +941,20 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) {
             }
 
             if (type->kind == Type_Kind_Enum) {
-                output_unsigned_integer(5, &section_buff);
-                output_unsigned_integer(2, &section_buff);
+                output_unsigned_integer(8, &section_buff);
                 output_unsigned_integer(type->Enum.backing->id, &section_buff);
+
+                AstEnumType *e_type = (AstEnumType *) type->ast_type;
+                assert(e_type->kind == Ast_Kind_Enum_Type);
+
+                output_unsigned_integer(bh_arr_length(e_type->values), &section_buff);
+                bh_arr_each(AstEnumValue *, pev, e_type->values) {
+                    AstEnumValue *ev = *pev;
+
+                    output_unsigned_integer(get_expression_integer_value(ev->value, NULL), &section_buff);
+                    output_unsigned_integer(ev->token->length, &section_buff);
+                    bh_buffer_append(&section_buff, ev->token->text, ev->token->length);
+                }
                 continue;
             }
 
@@ -948,6 +965,12 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) {
                 continue;
             }
 
+            if (type->kind == Type_Kind_Slice) {
+                output_unsigned_integer(7, &section_buff);
+                output_unsigned_integer(type->Slice.elem->id, &section_buff);
+                continue;
+            }
+
             if (type_is_structlike_strict(type)) {
                 output_unsigned_integer(3, &section_buff);
 
index 2b8a70a469abd190538b948d94430a1ee8a7ac60..c09f0b4ce2f850c9e2c59ceb920acb0479e3f2e4 100644 (file)
@@ -56,6 +56,8 @@ typedef enum debug_type_kind_t {
     debug_type_kind_array     = 4,
     debug_type_kind_alias     = 5,
     debug_type_kind_function  = 6,
+    debug_type_kind_slice     = 7,
+    debug_type_kind_enum      = 8,
 } debug_type_kind_t;
 
 typedef enum debug_type_primitive_kind_t {
@@ -115,6 +117,21 @@ typedef struct debug_type_function_t {
     u32  return_type;
 } debug_type_function_t;
 
+typedef struct debug_type_slice_t {
+    u32 type; 
+} debug_type_slice_t;
+
+typedef struct debug_type_enum_value_t {
+    u64 value;
+    char *name;
+} debug_type_enum_value_t;
+
+typedef struct debug_type_enum_t {
+    u32 backing_type;
+    u32 value_count;
+    debug_type_enum_value_t *values;
+} debug_type_enum_t;
+
 typedef struct debug_type_info_t {
     u32 id;
     char *name;
@@ -128,6 +145,8 @@ typedef struct debug_type_info_t {
         debug_type_array_t     array;
         debug_type_alias_t     alias;
         debug_type_function_t  function;
+        debug_type_slice_t     slice;
+        debug_type_enum_t      enumeration;
     };
 } debug_type_info_t;
 
@@ -174,6 +193,8 @@ bool debug_info_lookup_file_by_name(debug_info_t *info, char *name, debug_file_i
 bool debug_info_lookup_func(debug_info_t *info, u32 func_id, debug_func_info_t *out);
 i32  debug_info_lookup_instr_by_file_line(debug_info_t *info, char *filename, u32 line);
 
+char *debug_info_type_enum_find_name(debug_info_t *info, u32 enum_type, u64 value);
+
 //
 // This builder is used in conjunction with code builder to output
 // debug information for each instruction that is generated in OVM.
index e9fc60d94d5011466fe77725712330b7df977872..0be08ce4521ac892f31e525c42db18833afd412b 100644 (file)
@@ -182,6 +182,26 @@ void debug_info_import_type_info(debug_info_t *info, u8 *data, u32 len) {
                 type.function.return_type = uleb128_to_uint(data, &offset);
                 break;
 
+            case debug_type_kind_slice:
+                type.slice.type = uleb128_to_uint(data, &offset);
+                break;
+
+            case debug_type_kind_enum:
+                type.enumeration.backing_type = uleb128_to_uint(data, &offset);
+                type.enumeration.value_count = uleb128_to_uint(data, &offset);
+                type.enumeration.values = bh_alloc_array(info->alloc, debug_type_enum_value_t, type.enumeration.value_count);
+
+                fori (i, 0, type.enumeration.value_count) {
+                    type.enumeration.values[i].value = uleb128_to_uint(data, &offset);
+
+                    u32 name_length = uleb128_to_uint(data, &offset);
+                    type.enumeration.values[i].name = bh_alloc_array(info->alloc, char, name_length + 1);
+                    memcpy(type.enumeration.values[i].name, data + offset, name_length);
+                    type.enumeration.values[i].name[name_length] = 0;
+                    offset += name_length;
+                }
+                break;
+
             // Error handling
             default: assert(("Unrecognized type kind", 0));
         }
@@ -236,6 +256,19 @@ i32 debug_info_lookup_instr_by_file_line(debug_info_t *info, char *filename, u32
     return instr;
 }
 
+char *debug_info_type_enum_find_name(debug_info_t *info, u32 enum_type, u64 value) {
+    debug_type_info_t *type = &info->types[enum_type];
+    if (type->kind != debug_type_kind_enum) return NULL;
+
+    fori (i, 0, type->enumeration.value_count) {
+        if (type->enumeration.values[i].value == value) {
+            return type->enumeration.values[i].name;
+        }
+    }
+
+    return NULL;
+}
+
 //
 // For now, this is going to compare the strings exactly. In the future, it might be a good
 // to do a levenschtein distance or something, so the full path isn't needed.
index 0c28316140f9a489b86cc4f41028eff2edf04e38..7d383c5c2332933f4a28b9192b6967cde3e68f6c 100644 (file)
@@ -2,6 +2,8 @@
 #include "ovm_debug.h"
 #include "vm.h"
 
+#include <ctype.h>
+
 static char write_buf[4096];
 
 #define WRITE(str) do {    \
@@ -36,6 +38,8 @@ static bool lookup_stack_pointer(debug_runtime_value_builder_t *builder, u32 *ou
     return true;
 }
 
+static void append_slice_from_memory(debug_runtime_value_builder_t *builder, void *elem_data, u32 count, u32 type_id);
+
 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];
 
@@ -76,6 +80,16 @@ static void append_value_from_memory_with_type(debug_runtime_value_builder_t *bu
                     else                     { WRITE("false"); }
                     break;
 
+                case debug_type_primitive_kind_character: {
+                    unsigned char c = *(u8 *) base;
+                    if (!iscntrl(c) && isascii(c)) {
+                        WRITE_FORMAT("%c", c);
+                    } else {
+                        WRITE_FORMAT("\\x%02hhx", c);
+                    }
+                    break;
+                }
+
                 default:
                     WRITE("(err)");
             }
@@ -136,10 +150,74 @@ static void append_value_from_memory_with_type(debug_runtime_value_builder_t *bu
             break;
         }
 
+        case debug_type_kind_slice: {
+            void *elem_data = bh_pointer_add(builder->state->ovm_engine->memory, *(u32 *) base);
+            u32 count = *(u32 *) bh_pointer_add(base, 4);
+            u32 type_id = type->slice.type;
+
+            append_slice_from_memory(builder, elem_data, count, type_id);
+            break;
+        }
+
+        case debug_type_kind_enum: {
+            debug_type_info_t *backing_type = &builder->info->types[type->enumeration.backing_type];
+
+            u64 value = 0;
+            switch (backing_type->size) {
+                case 1: value = *(u8  *) base; break;
+                case 2: value = *(u16 *) base; break;
+                case 4: value = *(u32 *) base; break;
+                case 8: value = *(u64 *) base; break;
+            }
+
+            char *name = debug_info_type_enum_find_name(builder->info, type_id, value);
+            if (name) {
+                WRITE(name);
+            } else {
+                WRITE_FORMAT("%lu", value);
+            }
+
+            break;
+        }
+
         default: WRITE("(unknown)"); break;
     }
 }
 
+static void append_slice_from_memory(debug_runtime_value_builder_t *builder, void *elem_data, u32 count, u32 type_id) {
+    debug_type_info_t *elem_type = &builder->info->types[type_id];
+
+    b32 count_overflowed = 0;
+    if (count > 256) {
+        count = 256;
+        count_overflowed = 1;
+    }
+
+    if (elem_type->kind == debug_type_kind_primitive &&
+        elem_type->primitive.primitive_kind == debug_type_primitive_kind_character) {
+        WRITE("\"");
+
+        fori (i, 0, (i32) count) {
+            append_value_from_memory_with_type(builder, bh_pointer_add(elem_data, i * elem_type->size), elem_type->id);
+        }
+
+        if (count_overflowed) WRITE("...");
+        WRITE("\"");
+        return;
+    }
+
+    WRITE("[");
+
+    fori (i, 0, (i32) count) {
+        if (i != 0) WRITE(", ");
+        append_value_from_memory_with_type(builder, bh_pointer_add(elem_data, i * elem_type->size), elem_type->id);
+    }
+
+    if (count_overflowed) WRITE("...");
+    WRITE("]");
+}
+
+
 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];
 
@@ -220,6 +298,17 @@ static void append_ovm_value_with_type(debug_runtime_value_builder_t *builder, o
             break;
         }
 
+        case debug_type_kind_enum: {
+            char *name = debug_info_type_enum_find_name(builder->info, type_id, value.u64);
+            if (name == NULL) {
+                WRITE_FORMAT("%lu", value.u64);
+            } else {
+                WRITE(name);
+            }
+
+            break;
+        }
+
         default: WRITE("(unknown)"); break;
     }
 }
@@ -260,6 +349,20 @@ static void append_value_from_register(debug_runtime_value_builder_t *builder, u
         return;
     }
 
+    if (type->kind == debug_type_kind_slice) {
+        ovm_value_t base_reg;
+        ovm_value_t count_reg;
+
+        if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, reg, &base_reg)) return;
+        if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, reg + 1, &count_reg)) return;
+
+        void *elem_data = bh_pointer_add(builder->state->ovm_engine->memory, base_reg.u32);
+        u32 count = count_reg.u32;
+
+        append_slice_from_memory(builder, elem_data, count, type->slice.type);
+        return;
+    }
+
     if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, reg, &value)) {
         WRITE("(err)")
         return;
@@ -272,7 +375,8 @@ static u32 get_subvalues_for_type(debug_runtime_value_builder_t *builder, u32 ty
     debug_type_info_t *t = &builder->info->types[type];
     switch (t->kind) {
         case debug_type_kind_primitive: return 0;
-        case debug_type_kind_function: return 0;
+        case debug_type_kind_function:  return 0;
+        case debug_type_kind_enum:      return 0;
 
         case debug_type_kind_modifier:
             if (t->modifier.modifier_kind == debug_type_modifier_kind_pointer) return 1;
@@ -285,6 +389,36 @@ static u32 get_subvalues_for_type(debug_runtime_value_builder_t *builder, u32 ty
             return t->structure.member_count;
         
         case debug_type_kind_array: return t->array.count;
+
+        case debug_type_kind_slice: {
+            // :Refactor
+            u32 count = 0;
+            if (builder->base_loc_kind == debug_sym_loc_register) {
+                ovm_value_t value;
+                if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->base_loc + 1, &value)) {
+                    return 0;
+                }
+
+                count = value.u32;
+            }
+
+            else if (builder->base_loc_kind == debug_sym_loc_stack) {
+                u32 stack_ptr;
+                if (!lookup_stack_pointer(builder, &stack_ptr)) {
+                    return 0;
+                }    
+
+                u32 *ptr_loc = bh_pointer_add(builder->state->ovm_engine->memory, stack_ptr + builder->base_loc + 4);
+                count = *ptr_loc;
+            }
+
+            else if (builder->base_loc_kind == debug_sym_loc_global) {
+                u32 *ptr_loc = bh_pointer_add(builder->state->ovm_engine->memory, builder->base_loc + 4);
+                count = *ptr_loc;
+            }
+
+            return count;
+        }
     }
 }
 
@@ -311,19 +445,14 @@ void debug_runtime_value_build_set_location(debug_runtime_value_builder_t *build
 }
 
 void debug_runtime_value_build_descend(debug_runtime_value_builder_t *builder, u32 index) {
-    builder->it_index = 0;
-
     debug_type_info_t *type = &builder->info->types[builder->base_type];
+
     if (type->kind == debug_type_kind_modifier && type->modifier.modifier_kind == debug_type_modifier_kind_pointer) {
         if (index > 0) {
             goto bad_case;
         }
 
         builder->base_type = type->modifier.modified_type;
-        type = &builder->info->types[builder->base_type];
-
-        builder->max_index = get_subvalues_for_type(builder, builder->base_type);
-        builder->it_index = 0;
 
         if (builder->base_loc_kind == debug_sym_loc_register) {
             ovm_value_t value;
@@ -350,8 +479,6 @@ void debug_runtime_value_build_descend(debug_runtime_value_builder_t *builder, u
             u32 *ptr_loc = bh_pointer_add(builder->state->ovm_engine->memory, builder->base_loc);
             builder->base_loc = *ptr_loc;
         }
-
-        return;
     }
 
     if (type->kind == debug_type_kind_structure) {
@@ -361,7 +488,6 @@ void debug_runtime_value_build_descend(debug_runtime_value_builder_t *builder, u
 
         debug_type_structure_member_t *mem = &type->structure.members[index];
         builder->base_type = mem->type;
-        builder->max_index = get_subvalues_for_type(builder, builder->base_type);
         builder->it_name = mem->name;
 
         if (builder->base_loc_kind == debug_sym_loc_register) {
@@ -371,24 +497,13 @@ void debug_runtime_value_build_descend(debug_runtime_value_builder_t *builder, u
         else if (builder->base_loc_kind == debug_sym_loc_stack || builder->base_loc_kind == debug_sym_loc_global) {
             builder->base_loc += mem->offset;
         }
-
-        return;
     }
 
     if (type->kind == debug_type_kind_array) {
         builder->base_type = type->array.type;
-        builder->max_index = get_subvalues_for_type(builder, builder->base_type);
 
         debug_type_info_t *sub_type = &builder->info->types[builder->base_type];
 
-        // Double buffering here so if there are multiple
-        // pointer descentions, the names don't get mangled.
-        static char name_buffer[2048];
-        static char tmp_buffer[2048];
-        snprintf(tmp_buffer, 2048, "[%d]", index);
-        strncpy(name_buffer, tmp_buffer, 2048);
-        builder->it_name = name_buffer;
-
         if (builder->base_loc_kind == debug_sym_loc_register) {
             ovm_value_t value;
             if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->base_loc, &value)) {
@@ -402,10 +517,44 @@ void debug_runtime_value_build_descend(debug_runtime_value_builder_t *builder, u
         else if (builder->base_loc_kind == debug_sym_loc_stack || builder->base_loc_kind == debug_sym_loc_global) {
             builder->base_loc += sub_type->size * index;
         }
+    }
 
-        return;
+    if (type->kind == debug_type_kind_slice) {
+        builder->base_type = type->slice.type;
+        debug_type_info_t *sub_type = &builder->info->types[builder->base_type];
+
+        if (builder->base_loc_kind == debug_sym_loc_register) {
+            ovm_value_t value;
+            if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->base_loc, &value)) {
+                goto bad_case;
+            }
+
+            builder->base_loc_kind = debug_sym_loc_global;
+            builder->base_loc = value.u32 + sub_type->size * index;
+        }
+
+        else if (builder->base_loc_kind == debug_sym_loc_stack) {
+            u32 stack_ptr;
+            if (!lookup_stack_pointer(builder, &stack_ptr)) {
+                goto bad_case;
+            }    
+
+            u32 *data_loc = bh_pointer_add(builder->state->ovm_engine->memory, stack_ptr + builder->base_loc);
+
+            builder->base_loc_kind = debug_sym_loc_global;
+            builder->base_loc = *data_loc + index * sub_type->size;
+        }
+
+        else if (builder->base_loc_kind == debug_sym_loc_global) {
+            u32 *data_loc = bh_pointer_add(builder->state->ovm_engine->memory, builder->base_loc);
+            builder->base_loc = *data_loc + index * sub_type->size;
+        }
     }
 
+    builder->max_index = get_subvalues_for_type(builder, builder->base_type);
+    builder->it_index = 0;
+    return;
+
   bad_case:
     builder->base_loc_kind = debug_sym_loc_unknown;
     return;        
@@ -424,16 +573,46 @@ bool debug_runtime_value_build_step(debug_runtime_value_builder_t *builder) {
         snprintf(tmp_buffer, 2048, "*%s", builder->it_name);
         strncpy(name_buffer, tmp_buffer, 2048);
 
-        builder->it_loc_kind = builder->base_loc_kind;
-        builder->it_loc = builder->base_loc;
         builder->it_name = name_buffer;
         builder->it_type = type->modifier.modified_type;
         builder->it_has_children = get_subvalues_for_type(builder, builder->it_type) > 0;
+
+        // builder->it_loc_kind = debug_sym_loc_global;
+        // builder->it_loc = builder->base_loc;
+        if (builder->base_loc_kind == debug_sym_loc_register) {
+            ovm_value_t value;
+            if (lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->base_loc, &value)) {
+                builder->it_loc_kind = debug_sym_loc_global;
+                builder->it_loc = value.u32;
+            }
+        }
+
+        if (builder->base_loc_kind == debug_sym_loc_stack) {
+            u32 stack_ptr;
+            if (!lookup_stack_pointer(builder, &stack_ptr)) {
+                return false;
+            }    
+
+            u32 *data_loc = bh_pointer_add(builder->state->ovm_engine->memory, stack_ptr + builder->base_loc);
+
+            builder->it_loc_kind = debug_sym_loc_global;
+            builder->it_loc = *data_loc;
+        }
+
+        if (builder->base_loc_kind == debug_sym_loc_global) {
+            u32 *data_loc = bh_pointer_add(builder->state->ovm_engine->memory, builder->base_loc);
+
+            builder->it_loc_kind = debug_sym_loc_global;
+            builder->it_loc = *data_loc;
+        }
     }
 
     if (type->kind == debug_type_kind_structure) {
         debug_type_structure_member_t *mem = &type->structure.members[builder->it_index];
-        builder->it_name = mem->name;
+        snprintf(tmp_buffer, 2048, "%s", mem->name);
+        strncpy(name_buffer, tmp_buffer, 2048);
+
+        builder->it_name = name_buffer;
         builder->it_has_children = get_subvalues_for_type(builder, mem->type) > 0;
         builder->it_type = mem->type;
 
@@ -481,6 +660,42 @@ bool debug_runtime_value_build_step(debug_runtime_value_builder_t *builder) {
         }
     }
 
+    if (type->kind == debug_type_kind_slice) {
+        snprintf(tmp_buffer, 2048, "[%d]", builder->it_index);
+        strncpy(name_buffer, tmp_buffer, 2048);
+        builder->it_name = name_buffer;
+        builder->it_type = type->slice.type;
+        builder->it_has_children = get_subvalues_for_type(builder, builder->it_type) > 0;
+
+        debug_type_info_t *sub_type = &builder->info->types[builder->it_type];
+
+        if (builder->base_loc_kind == debug_sym_loc_register) {
+            ovm_value_t value;
+            if (lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->base_loc, &value)) {
+                builder->it_loc_kind = debug_sym_loc_global;
+                builder->it_loc = value.u32 + sub_type->size * builder->it_index;
+            }
+        }
+
+        if (builder->base_loc_kind == debug_sym_loc_stack) {
+            u32 stack_ptr;
+            if (!lookup_stack_pointer(builder, &stack_ptr)) {
+                return false;
+            }    
+
+            u32 *data_loc = bh_pointer_add(builder->state->ovm_engine->memory, stack_ptr + builder->base_loc);
+
+            builder->it_loc_kind = debug_sym_loc_global;
+            builder->it_loc = *data_loc + sub_type->size * builder->it_index;
+        }
+
+        if (builder->base_loc_kind == debug_sym_loc_global) {
+            u32 *data_loc = bh_pointer_add(builder->state->ovm_engine->memory, builder->base_loc);
+
+            builder->it_loc_kind = debug_sym_loc_global;
+            builder->it_loc = *data_loc + sub_type->size * builder->it_index;
+        }
+    }
 
     builder->it_index++;
     return true;