From: Brendan Hansen Date: Sun, 21 Aug 2022 03:24:13 +0000 (-0500) Subject: added debug type info X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=2adf7e95f3231ad49dd4214e8956c8f8c5c659e0;p=onyx.git added debug type info --- diff --git a/core/net/tcp.onyx b/core/net/tcp.onyx index e130ef7f..b7da3ead 100644 --- a/core/net/tcp.onyx +++ b/core/net/tcp.onyx @@ -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; } diff --git a/include/wasm_emit.h b/include/wasm_emit.h index 5fde5772..3a79e549 100644 --- a/include/wasm_emit.h +++ b/include/wasm_emit.h @@ -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; diff --git a/lib/linux_x86_64/lib/libovmwasm.so b/lib/linux_x86_64/lib/libovmwasm.so index a2c40239..d1d39b4a 100755 Binary files a/lib/linux_x86_64/lib/libovmwasm.so and b/lib/linux_x86_64/lib/libovmwasm.so differ diff --git a/misc/vscode/onyx-0.0.3.vsix b/misc/vscode/onyx-0.0.3.vsix index 1a8df041..bb16dd8f 100644 Binary files a/misc/vscode/onyx-0.0.3.vsix and b/misc/vscode/onyx-0.0.3.vsix differ diff --git a/misc/vscode/out/ovmDebug.js b/misc/vscode/out/ovmDebug.js index e7e95a70..38de655a 100644 --- a/misc/vscode/out/ovmDebug.js +++ b/misc/vscode/out/ovmDebug.js @@ -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) { diff --git a/misc/vscode/ovmDebug.ts b/misc/vscode/ovmDebug.ts index 9c622851..c24237c3 100644 --- a/misc/vscode/ovmDebug.ts +++ b/misc/vscode/ovmDebug.ts @@ -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); } } diff --git a/src/checker.c b/src/checker.c index 65e562c9..fb544399 100644 --- a/src/checker.c +++ b/src/checker.c @@ -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; diff --git a/src/wasm_emit.c b/src/wasm_emit.c index 173614c1..0dc1c4a6 100644 --- a/src/wasm_emit.c +++ b/src/wasm_emit.c @@ -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); diff --git a/src/wasm_output.h b/src/wasm_output.h index 1e2b6007..74213c57 100644 --- a/src/wasm_output.h +++ b/src/wasm_output.h @@ -812,7 +812,15 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) { output_name(func->name, func->name_length, §ion_buff); output_unsigned_integer(1, §ion_buff); output_unsigned_integer(func->op_offset, §ion_buff); - output_unsigned_integer(func->stack_ptr_idx, §ion_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, §ion_buff); + } else { + output_unsigned_integer(0, §ion_buff); + } + output_unsigned_integer(0, §ion_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(§ion_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(§ion_buff); + bh_buffer_write_byte(buff, WASM_SECTION_ID_CUSTOM); + + output_custom_section_name("ovm_debug_types", §ion_buff); + + i32 type_count = bh_arr_length(type_map.entries); + output_unsigned_integer(type_count, §ion_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, §ion_buff); + output_name(name, strlen(name), §ion_buff); + output_unsigned_integer(type_size_of(type), §ion_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, §ion_buff); + output_unsigned_integer(2, §ion_buff); + output_unsigned_integer(basic_types[Basic_Kind_U32].id, §ion_buff); + continue; + } + + if (type->Basic.kind == Basic_Kind_Rawptr) { + // rawptr -> ^void + output_unsigned_integer(2, §ion_buff); + output_unsigned_integer(1, §ion_buff); + output_unsigned_integer(basic_types[Basic_Kind_Void].id, §ion_buff); + continue; + } + + output_unsigned_integer(1, §ion_buff); + if (type->Basic.kind == Basic_Kind_Void) output_unsigned_integer(0, §ion_buff); + else if (type_is_bool(type)) output_unsigned_integer(4, §ion_buff); + else if (type_is_integer(type)) { + if (type->Basic.flags & Basic_Flag_Unsigned) output_unsigned_integer(2, §ion_buff); + else output_unsigned_integer(1, §ion_buff); + } + else if (type->Basic.flags & Basic_Flag_Float) output_unsigned_integer(3, §ion_buff); + else if (type_is_simd(type)) output_unsigned_integer(6, §ion_buff); + else { + output_unsigned_integer(0, §ion_buff); + } + + continue; + } + + if (type->kind == Type_Kind_Pointer) { + output_unsigned_integer(2, §ion_buff); + output_unsigned_integer(1, §ion_buff); + output_unsigned_integer(type->Pointer.elem->id, §ion_buff); + continue; + } + + if (type->kind == Type_Kind_Enum) { + output_unsigned_integer(5, §ion_buff); + output_unsigned_integer(2, §ion_buff); + output_unsigned_integer(type->Enum.backing->id, §ion_buff); + continue; + } + + if (type->kind == Type_Kind_Array) { + output_unsigned_integer(4, §ion_buff); + output_unsigned_integer(type->Array.count, §ion_buff); + output_unsigned_integer(type->Array.elem->id, §ion_buff); + continue; + } + + if (type_is_structlike_strict(type)) { + output_unsigned_integer(3, §ion_buff); + + i32 mem_count = type_structlike_mem_count(type); + output_unsigned_integer(mem_count, §ion_buff); + + fori (i, 0, mem_count) { + StructMember smem; + type_lookup_member_by_idx(type, i, &smem); + + output_unsigned_integer(smem.offset, §ion_buff); + output_unsigned_integer(smem.type->id, §ion_buff); + output_name(smem.name, strlen(smem.name), §ion_buff); + } + + continue; + } + + if (type->kind == Type_Kind_Function) { + output_unsigned_integer(6, §ion_buff); + output_unsigned_integer(type->Function.param_count, §ion_buff); + + fori (i, 0, (i32) type->Function.param_count) { + output_unsigned_integer(type->Function.params[i]->id, §ion_buff); + } + + output_unsigned_integer(type->Function.return_type->id, §ion_buff); + continue; + } + + if (type->kind == Type_Kind_Distinct) { + output_unsigned_integer(5, §ion_buff); + output_unsigned_integer(2, §ion_buff); + output_unsigned_integer(type->Distinct.base_type->id, §ion_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, §ion_buff); + output_unsigned_integer(0, §ion_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(§ion_buff);