added debug type info
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 21 Aug 2022 03:24:13 +0000 (22:24 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 21 Aug 2022 03:24:13 +0000 (22:24 -0500)
core/net/tcp.onyx
include/wasm_emit.h
lib/linux_x86_64/lib/libovmwasm.so
misc/vscode/onyx-0.0.3.vsix
misc/vscode/out/ovmDebug.js
misc/vscode/ovmDebug.ts
src/checker.c
src/wasm_emit.c
src/wasm_output.h

index e130ef7fe55ead3661861fecdb2b845cf585f84c..b7da3ead8f2a0b95f96ffff3276ae00663059b33 100644 (file)
@@ -236,7 +236,7 @@ tcp_server_pulse :: (use server: ^TCP_Server) -> bool {
         return cast(i32) a.state - cast(i32) b.state;
     });
 
-    client_count = array.count_where(clients, x => x != null);
+    client_count = array.count_where(clients, #(it != null));
 
     return server.alive;
 }
index 5fde5772381b4c9736d05cc1c256ba02d313f38a..3a79e5494d1613cab741706cfed1fec18f410da7 100644 (file)
@@ -830,18 +830,25 @@ typedef enum DebugSymLoc {
 typedef struct DebugSymInfo {
     u32 sym_id;
     u32 location_type;
-    u32 location_num;
+    u64 location_num;
     char *name;
     u32 type;
 } DebugSymInfo;
 
+typedef struct DebugSymPatch {
+    u32 func_idx;
+    u32 sym_id;
+    u64 local_idx;
+} DebugSymPatch;
+
 typedef struct DebugContext {
     bh_allocator allocator;
 
     Table(DebugFileInfo) file_info;
     u32 next_file_id;
 
-    bh_arr(DebugSymInfo) sym_info;
+    bh_arr(DebugSymInfo)  sym_info;
+    bh_arr(DebugSymPatch) sym_patches;
     u32 next_sym_id;
 
     bh_arr(DebugFuncContext) funcs;
index a2c402399d031ccf244cb4710ceb478e102f400a..d1d39b4aa7427d33ff1442fc1b21544cb389c190 100755 (executable)
Binary files a/lib/linux_x86_64/lib/libovmwasm.so and b/lib/linux_x86_64/lib/libovmwasm.so differ
index 1a8df041dded5244c71198733895b8abbcbeaa27..bb16dd8f166e31aac7f5146906ba632e79d7e98f 100644 (file)
Binary files a/misc/vscode/onyx-0.0.3.vsix and b/misc/vscode/onyx-0.0.3.vsix differ
index e7e95a70db78e98be07437968ceb0d875cd73697..38de655aa3afa2b9597fe6d4935b80696338f58d 100644 (file)
@@ -38,7 +38,6 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
         });
     }
     initializeRequest(response, args) {
-        console.log("INITIALIZE");
         response.body = response.body || {};
         // the adapter implements the configurationDone request.
         response.body.supportsConfigurationDoneRequest = true;
@@ -211,6 +210,10 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
             }
         });
     }
+    pauseRequest(response, args, request) {
+        this.debugger.pause(args.threadId);
+        this.sendResponse(response);
+    }
     continueRequest(response, args, request) {
         let thread_id = args.threadId;
         if (!args.singleThread) {
@@ -243,8 +246,9 @@ var OVMCommand;
 (function (OVMCommand) {
     OVMCommand[OVMCommand["NOP"] = 0] = "NOP";
     OVMCommand[OVMCommand["RES"] = 1] = "RES";
-    OVMCommand[OVMCommand["BRK"] = 2] = "BRK";
-    OVMCommand[OVMCommand["CLR_BRK"] = 3] = "CLR_BRK";
+    OVMCommand[OVMCommand["PAUSE"] = 2] = "PAUSE";
+    OVMCommand[OVMCommand["BRK"] = 3] = "BRK";
+    OVMCommand[OVMCommand["CLR_BRK"] = 4] = "CLR_BRK";
     OVMCommand[OVMCommand["STEP"] = 5] = "STEP";
     OVMCommand[OVMCommand["TRACE"] = 6] = "TRACE";
     OVMCommand[OVMCommand["THREADS"] = 7] = "THREADS";
@@ -274,6 +278,16 @@ class OVMDebugger extends EventEmitter {
             this.client.on("connect", res);
         });
     }
+    pause(thread_id = 0xffffffff) {
+        let data = new ArrayBuffer(12);
+        let view = new DataView(data);
+        let cmd_id = this.next_command_id;
+        view.setUint32(0, cmd_id, true);
+        view.setUint32(4, OVMCommand.PAUSE, true);
+        view.setUint32(8, thread_id, true);
+        this.client.write(new Uint8Array(data));
+        this.pending_responses[cmd_id] = OVMCommand.PAUSE;
+    }
     resume(thread_id = 0xffffffff) {
         let data = new ArrayBuffer(12);
         let view = new DataView(data);
@@ -409,7 +423,7 @@ class OVMDebugger extends EventEmitter {
                     break;
                 }
                 default:
-                    console.log("Unknown event: ", event_id, data);
+                // console.log("Unknown event: ", event_id, data);
             }
         }
     }
@@ -475,7 +489,7 @@ class OVMDebugger extends EventEmitter {
                 break;
             }
             default:
-                console.log("Unrecognized command. ", cmd_id, msg_id);
+            // console.log("Unrecognized command. ", cmd_id, msg_id);
         }
     }
     preparePromise(msg_id) {
index 9c6228515645fc54072c91a4706078acce7c9d9d..c24237c3f094e68db4227e4366d53ebd70edd617 100644 (file)
@@ -69,8 +69,6 @@ export class OVMDebugSession extends LoggingDebugSession {
     }
 
     protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
-               console.log("INITIALIZE");
-
         response.body = response.body || {};
 
         // the adapter implements the configurationDone request.
@@ -288,6 +286,11 @@ export class OVMDebugSession extends LoggingDebugSession {
                }
     }
 
+    protected pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments, request?: DebugProtocol.Request): void {
+       this.debugger.pause(args.threadId);
+       this.sendResponse(response);
+    }
+
        protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments, request?: DebugProtocol.Request): void {
                let thread_id = args.threadId;
                if (!args.singleThread) {
@@ -348,8 +351,9 @@ interface IVariableInfo {
 enum OVMCommand {
        NOP     = 0,
        RES     = 1,
-       BRK     = 2,
-       CLR_BRK = 3,
+       PAUSE   = 2,
+       BRK     = 3,
+       CLR_BRK = 4,
        STEP    = 5,
        TRACE   = 6,
        THREADS = 7,
@@ -393,6 +397,21 @@ class OVMDebugger extends EventEmitter {
                });
        }
 
+       pause(thread_id: number = 0xffffffff): void {
+        let data = new ArrayBuffer(12);
+        let view = new DataView(data);
+
+        let cmd_id = this.next_command_id;
+
+        view.setUint32(0, cmd_id, true);
+        view.setUint32(4, OVMCommand.PAUSE, true);
+        view.setUint32(8, thread_id, true);
+
+        this.client.write(new Uint8Array(data));
+
+        this.pending_responses[cmd_id] = OVMCommand.PAUSE;
+       }
+
     resume(thread_id: number = 0xffffffff): void {
         let data = new ArrayBuffer(12);
         let view = new DataView(data);
@@ -564,7 +583,7 @@ class OVMDebugger extends EventEmitter {
                                }
 
                                default:
-                                       console.log("Unknown event: ", event_id, data);
+                                       // console.log("Unknown event: ", event_id, data);
                        }
                }
        }
@@ -649,7 +668,7 @@ class OVMDebugger extends EventEmitter {
                        }
 
                        default:
-                               console.log("Unrecognized command. ", cmd_id, msg_id);
+                               // console.log("Unrecognized command. ", cmd_id, msg_id);
                }
        }
 
index 65e562c975e44cd81053baff382d327041a48656..fb54439901fa9a77c222077f50826010b9a9d401 100644 (file)
@@ -2244,6 +2244,11 @@ CheckStatus check_struct(AstStructType* s_node) {
         CHECK(constraint_context, &s_node->constraints, s_node->scope, pos);
     }
 
+    //
+    // This ensures that all procedures defined inside of a structure are
+    // not pruned and omitted from the binary. This is because a large
+    // use-case of procedures in structures is dynamically linking them
+    // using the type info data.
     if (s_node->scope) {
         fori (i, 0, shlen(s_node->scope->symbols)) {
             AstNode* node = s_node->scope->symbols[i].value;
index 173614c12f2bf4e69705f61febf3fb7d8859a65e..0dc1c4a6b769c18d58170822c68fa25a32ce5c6a 100644 (file)
@@ -219,7 +219,7 @@ static inline b32 should_emit_function(AstFunction* fd) {
 
 #ifdef ENABLE_DEBUG_INFO
 
-static u32 debug_introduce_symbol(OnyxWasmModule *mod, OnyxToken *token, DebugSymLoc loc, u32 num, Type* type) {
+static u32 debug_introduce_symbol(OnyxWasmModule *mod, OnyxToken *token, DebugSymLoc loc, u64 num, Type* type) {
 
     u32 id = mod->debug_context->next_sym_id++;
 
@@ -239,6 +239,15 @@ static u32 debug_introduce_symbol(OnyxWasmModule *mod, OnyxToken *token, DebugSy
 
     bh_arr_push(mod->debug_context->sym_info, sym_info);
 
+    if (loc == DSL_REGISTER) {
+        assert(mod->local_alloc);
+        DebugSymPatch patch;
+        patch.func_idx = mod->current_func_idx;
+        patch.sym_id = id;
+        patch.local_idx = num;
+        bh_arr_push(mod->debug_context->sym_patches, patch);
+    }
+
     bh_buffer_write_byte(&mod->debug_context->op_buffer, DOT_SYM);
     u32 leb_len=0;
     u8 *bytes = uint_to_uleb128(id, &leb_len);
@@ -3699,13 +3708,15 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) {
     }
 
     if (fd->body != NULL) {
+        mod->local_alloc = &wasm_func.locals;
+
         // NOTE: Generate the local map
         u64 localidx = 0;
         bh_arr_each(AstParam, param, fd->params) {
             switch (type_get_param_pass(param->local->type)) {
                 case Param_Pass_By_Value: {
                     if (type_is_structlike_strict(param->local->type)) {
-                        debug_introduce_symbol(mod, param->local->token, DSL_REGISTER, localidx, param->local->type);
+                        debug_introduce_symbol(mod, param->local->token, DSL_REGISTER, localidx | LOCAL_IS_WASM, param->local->type);
                         bh_imap_put(&mod->local_map, (u64) param->local, localidx | LOCAL_IS_WASM);
                         localidx += type_structlike_mem_count(param->local->type);
 
@@ -3715,7 +3726,7 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) {
                 }
 
                 case Param_Pass_By_Implicit_Pointer: {
-                    debug_introduce_symbol(mod, param->local->token, DSL_REGISTER, localidx, param->local->type);
+                    debug_introduce_symbol(mod, param->local->token, DSL_REGISTER, localidx | LOCAL_IS_WASM, param->local->type);
                     bh_imap_put(&mod->local_map, (u64) param->local, localidx++ | LOCAL_IS_WASM);
                     break;
                 }
@@ -3724,7 +3735,6 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) {
             }
         }
 
-        mod->local_alloc = &wasm_func.locals;
         mod->local_alloc->param_count = localidx;
 
         mod->curr_cc = type_function_get_cc(fd->type);
@@ -4288,6 +4298,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
 
     sh_new_arena(module.debug_context->file_info);
     bh_arr_new(global_heap_allocator, module.debug_context->sym_info, 32);
+    bh_arr_new(global_heap_allocator, module.debug_context->sym_patches, 32);
     bh_arr_new(global_heap_allocator, module.debug_context->funcs, 16);
 
     bh_buffer_init(&module.debug_context->op_buffer, global_heap_allocator, 1024);
index 1e2b60075a2116ef2f68433a258ddd858aac85e4..74213c576c83e7e95342d73e4e3751231e0824e6 100644 (file)
@@ -812,7 +812,15 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) {
             output_name(func->name, func->name_length, &section_buff);
             output_unsigned_integer(1, &section_buff);
             output_unsigned_integer(func->op_offset, &section_buff);
-            output_unsigned_integer(func->stack_ptr_idx, &section_buff);
+
+            LocalAllocator *locals = &module->funcs[i].locals;
+            if (func->stack_ptr_idx > 0) {
+                u32 local_idx = local_lookup_idx(locals, func->stack_ptr_idx);
+                output_unsigned_integer(local_idx, &section_buff);
+            } else {
+                output_unsigned_integer(0, &section_buff);
+            }
+
             output_unsigned_integer(0, &section_buff);
         }
 
@@ -822,7 +830,19 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) {
     }
 
     {
-        // ovm_debug_syms sections
+        // ovm_debug_syms section
+
+        // First, apply patches for register locations
+        bh_arr_each(DebugSymPatch, patch, ctx->sym_patches) {
+            // CLEANUP: This is (kind of) incorrect, as there is nothing guarenteeing
+            // that the symbol with id a will be a position a, other than the way
+            // that this has been implemented right now.
+            assert(ctx->sym_info[patch->sym_id].location_type == DSL_REGISTER);
+
+            LocalAllocator *locals = &module->funcs[patch->func_idx - module->foreign_function_count].locals;
+            ctx->sym_info[patch->sym_id].location_num = local_lookup_idx(locals, patch->local_idx);
+        }
+
         bh_buffer_clear(&section_buff);
         bh_buffer_write_byte(buff, WASM_SECTION_ID_CUSTOM);
 
@@ -849,6 +869,141 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) {
         bh_buffer_concat(buff, section_buff);
     }
 
+    {
+        // ovm_debug_types section
+        bh_buffer_clear(&section_buff);
+        bh_buffer_write_byte(buff, WASM_SECTION_ID_CUSTOM);
+
+        output_custom_section_name("ovm_debug_types", &section_buff);
+
+        i32 type_count = bh_arr_length(type_map.entries);
+        output_unsigned_integer(type_count, &section_buff);
+
+        bh_arr_each(bh__imap_entry, entry, type_map.entries) {
+            u32 id     = entry->key;
+            Type *type = (Type *) entry->value;
+            const char *name = type_get_name(type);
+
+            output_unsigned_integer(id, &section_buff);
+            output_name(name, strlen(name), &section_buff);
+            output_unsigned_integer(type_size_of(type), &section_buff);
+
+            if (type->kind == Type_Kind_Basic) {
+                // Type indicies are special because they are encoded
+                // as a "distinct" unsigned 32-bit integer, which is
+                // effectively how they are used in the code anyway.
+                //
+                // This is probably a change that will be made throughout
+                // the entire compiler, but for now they will remain as
+                // a special type.
+                if (type->Basic.kind == Basic_Kind_Type_Index) {
+                    output_unsigned_integer(5, &section_buff);
+                    output_unsigned_integer(2, &section_buff);
+                    output_unsigned_integer(basic_types[Basic_Kind_U32].id, &section_buff);
+                    continue;
+                }
+
+                if (type->Basic.kind == Basic_Kind_Rawptr) {
+                    // rawptr -> ^void
+                    output_unsigned_integer(2, &section_buff);
+                    output_unsigned_integer(1, &section_buff);
+                    output_unsigned_integer(basic_types[Basic_Kind_Void].id, &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);
+                else if (type_is_integer(type)) {
+                    if (type->Basic.flags & Basic_Flag_Unsigned) output_unsigned_integer(2, &section_buff);
+                    else                                         output_unsigned_integer(1, &section_buff);
+                }
+                else if (type->Basic.flags & Basic_Flag_Float)   output_unsigned_integer(3, &section_buff);
+                else if (type_is_simd(type))                     output_unsigned_integer(6, &section_buff);
+                else {
+                    output_unsigned_integer(0, &section_buff);
+                }
+
+                continue;
+            }
+
+            if (type->kind == Type_Kind_Pointer) {
+                output_unsigned_integer(2, &section_buff);
+                output_unsigned_integer(1, &section_buff);
+                output_unsigned_integer(type->Pointer.elem->id, &section_buff);
+                continue; 
+            }
+
+            if (type->kind == Type_Kind_Enum) {
+                output_unsigned_integer(5, &section_buff);
+                output_unsigned_integer(2, &section_buff);
+                output_unsigned_integer(type->Enum.backing->id, &section_buff);
+                continue;
+            }
+
+            if (type->kind == Type_Kind_Array) {
+                output_unsigned_integer(4, &section_buff);
+                output_unsigned_integer(type->Array.count, &section_buff);
+                output_unsigned_integer(type->Array.elem->id, &section_buff);
+                continue;
+            }
+
+            if (type_is_structlike_strict(type)) {
+                output_unsigned_integer(3, &section_buff);
+
+                i32 mem_count = type_structlike_mem_count(type);
+                output_unsigned_integer(mem_count, &section_buff);
+
+                fori (i, 0, mem_count) {
+                    StructMember smem;
+                    type_lookup_member_by_idx(type, i, &smem);
+
+                    output_unsigned_integer(smem.offset, &section_buff);
+                    output_unsigned_integer(smem.type->id, &section_buff);
+                    output_name(smem.name, strlen(smem.name), &section_buff);
+                }
+
+                continue;
+            }
+
+            if (type->kind == Type_Kind_Function) {
+                output_unsigned_integer(6, &section_buff);
+                output_unsigned_integer(type->Function.param_count, &section_buff);
+
+                fori (i, 0, (i32) type->Function.param_count) {
+                    output_unsigned_integer(type->Function.params[i]->id, &section_buff);
+                }
+
+                output_unsigned_integer(type->Function.return_type->id, &section_buff);
+                continue;
+            }
+
+            if (type->kind == Type_Kind_Distinct) {
+                output_unsigned_integer(5, &section_buff);
+                output_unsigned_integer(2, &section_buff);
+                output_unsigned_integer(type->Distinct.base_type->id, &section_buff);
+                continue;
+            }
+
+            // No debug information will be given about the poly struct
+            // or compound types.
+            // Outside of runtime type information, they provide no useful
+            // debugging information (I don't think at least...).
+            if (type->kind == Type_Kind_PolyStruct ||
+                type->kind == Type_Kind_Compound) {
+                output_unsigned_integer(1, &section_buff);
+                output_unsigned_integer(0, &section_buff);
+                continue;
+            }
+
+            assert(("Unhandled type", 0));
+        }
+
+        output_unsigned_integer(section_buff.length, buff);
+
+        bh_buffer_concat(buff, section_buff);
+    }
+
     {
         // ovm_debug_ops section
         bh_buffer_clear(&section_buff);