From: Brendan Hansen Date: Fri, 12 Aug 2022 01:18:17 +0000 (-0500) Subject: added thread info and symbol info to debug info X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=ab4651d89a5c938c02bd98754c88d82075b9ee15;p=onyx.git added thread info and symbol info to debug info --- diff --git a/include/astnodes.h b/include/astnodes.h index 0f833501..51acba0a 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -1206,6 +1206,8 @@ struct AstFunction { // for this particular function. OnyxToken* exported_name; + OnyxToken* closing_brace; + union { OnyxToken* intrinsic_name; diff --git a/include/wasm_emit.h b/include/wasm_emit.h index 7c607295..5fde5772 100644 --- a/include/wasm_emit.h +++ b/include/wasm_emit.h @@ -645,6 +645,7 @@ typedef enum DeferredStmtType { typedef struct DeferredStmt { DeferredStmtType type; u32 depth; + AstDefer *defer_node; union { AstNode *stmt; @@ -820,12 +821,29 @@ typedef struct DebugFileInfo { u32 line_count; } DebugFileInfo; +typedef enum DebugSymLoc { + DSL_REGISTER = 1, + DSL_STACK = 2, + DSL_GLOBAL = 3, +} DebugSymLoc; + +typedef struct DebugSymInfo { + u32 sym_id; + u32 location_type; + u32 location_num; + char *name; + u32 type; +} DebugSymInfo; + typedef struct DebugContext { bh_allocator allocator; Table(DebugFileInfo) file_info; u32 next_file_id; + bh_arr(DebugSymInfo) sym_info; + u32 next_sym_id; + bh_arr(DebugFuncContext) funcs; bh_buffer op_buffer; diff --git a/lib/linux_x86_64/lib/libovmwasm.so b/lib/linux_x86_64/lib/libovmwasm.so index e7177dd4..a2c40239 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 958ce8d2..1a8df041 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 08e088e2..e7e95a70 100644 --- a/misc/vscode/out/ovmDebug.js +++ b/misc/vscode/out/ovmDebug.js @@ -20,6 +20,8 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession { super("ovm-debug-log.txt"); this._configurationDone = new await_notify_1.Subject(); this._clientConnectedNotifier = new await_notify_1.Subject(); + this._variableReferences = new debugadapter_1.Handles(); + this._frameReferences = new debugadapter_1.Handles(); this.setDebuggerLinesStartAt1(true); this.setDebuggerColumnsStartAt1(true); this._loadedSources = new Map(); @@ -98,14 +100,11 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession { this.sendEvent(new debugadapter_1.InitializedEvent()); } configurationDoneRequest(response, args, request) { - console.log("CONFIGURATION DONE"); super.configurationDoneRequest(response, args); this._configurationDone.notify(); } disconnectRequest(response, args, request) { - console.log(`disconnectRequest suspend: ${args.suspendDebuggee}, terminate: ${args.terminateDebuggee}`); if (args.terminateDebuggee) { - console.log("TERMINATE"); if (this.running_process) { this.running_process.kill('SIGTERM'); } @@ -117,7 +116,6 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession { } setBreakPointsRequest(response, args, request) { return __awaiter(this, void 0, void 0, function* () { - console.log("BREAKPOINTS", args, response); while (!this._clientConnected) { yield this._clientConnectedNotifier.wait(); } @@ -147,31 +145,49 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession { this._loadedSources.set(source.name, source); this.sendEvent(new debugadapter_1.LoadedSourceEvent("new", source)); } - return new debugadapter_1.StackFrame(i, f.funcname, source, f.line); + let frameRef = this._frameReferences.create({ + threadId: args.threadId, + frameIndex: i + }); + return new debugadapter_1.StackFrame(frameRef, f.funcname, source, f.line); }) }; this.sendResponse(response); }); } threadsRequest(response, request) { - console.log("THREADS"); - response.body = { - threads: [ - new debugadapter_1.Thread(1, "main thread"), - ] - }; - this.sendResponse(response); + return __awaiter(this, void 0, void 0, function* () { + let threads = yield this.debugger.threads(); + response.body = { + threads: threads.map(t => new debugadapter_1.Thread(t.id, t.name)) + }; + this.sendResponse(response); + }); } scopesRequest(response, args, request) { - console.log("SCOPES"); + let frameId = args.frameId; + let frameRef = this._frameReferences.get(frameId); + let varRef = this._variableReferences.create(frameRef); response.body = { scopes: [ - new debugadapter_1.Scope("Locals", 1, false), - new debugadapter_1.Scope("Globals", 2, true) + new debugadapter_1.Scope("Locals", varRef, false), ] }; this.sendResponse(response); } + variablesRequest(response, args, request) { + return __awaiter(this, void 0, void 0, function* () { + const frameRef = this._variableReferences.get(args.variablesReference, { frameIndex: 0, threadId: 0 }); + let vs = (yield this.debugger.variables(frameRef.frameIndex, frameRef.threadId)) + .map(v => { + let nv = new debugadapter_1.Variable(v.name, v.value); + nv.type = v.type; + return nv; + }); + response.body = { variables: vs }; + this.sendResponse(response); + }); + } launchRequest(response, args, request) { this.running_process = child_process.spawn("onyx-run", ["--debug", args.wasmFile], { "cwd": args.workingDir, @@ -184,7 +200,6 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession { } attachRequest(response, args, request) { return __awaiter(this, void 0, void 0, function* () { - console.log("ATTACH"); yield this._configurationDone.wait(1000); yield this.debugger.connect(args.socketPath); this._clientConnected = true; @@ -232,6 +247,8 @@ var OVMCommand; OVMCommand[OVMCommand["CLR_BRK"] = 3] = "CLR_BRK"; OVMCommand[OVMCommand["STEP"] = 5] = "STEP"; OVMCommand[OVMCommand["TRACE"] = 6] = "TRACE"; + OVMCommand[OVMCommand["THREADS"] = 7] = "THREADS"; + OVMCommand[OVMCommand["VARS"] = 8] = "VARS"; })(OVMCommand || (OVMCommand = {})); var OVMEvent; (function (OVMEvent) { @@ -335,6 +352,28 @@ class OVMDebugger extends EventEmitter { this.pending_responses[cmd_id] = OVMCommand.TRACE; return this.preparePromise(cmd_id); } + threads() { + let data = new ArrayBuffer(8); + let view = new DataView(data); + let cmd_id = this.next_command_id; + view.setUint32(0, cmd_id, true); + view.setUint32(4, OVMCommand.THREADS, true); + this.client.write(new Uint8Array(data)); + this.pending_responses[cmd_id] = OVMCommand.THREADS; + return this.preparePromise(cmd_id); + } + variables(frame_index, thread_id) { + let data = new ArrayBuffer(16); + let view = new DataView(data); + let cmd_id = this.next_command_id; + view.setUint32(0, cmd_id, true); + view.setUint32(4, OVMCommand.VARS, true); + view.setUint32(8, frame_index, true); + view.setUint32(12, thread_id, true); + this.client.write(new Uint8Array(data)); + this.pending_responses[cmd_id] = OVMCommand.VARS; + return this.preparePromise(cmd_id); + } parseIncoming(data) { let parser = new DataParser(data); while (parser.offset != data.length) { @@ -413,6 +452,28 @@ class OVMDebugger extends EventEmitter { this.resolvePromise(msg_id, result); break; } + case OVMCommand.THREADS: { + let result = new Array(); + let count = parser.parseUint32(); + for (let i = 0; i < count; i++) { + let id = parser.parseUint32(); + let name = parser.parseString(); + result.push({ id, name }); + } + this.resolvePromise(msg_id, result); + break; + } + case OVMCommand.VARS: { + let result = new Array(); + while (parser.parseInt32() == 0) { + let name = parser.parseString(); + let value = parser.parseString(); + let type = parser.parseString(); + result.push({ name, value, type }); + } + this.resolvePromise(msg_id, result); + break; + } default: console.log("Unrecognized command. ", cmd_id, msg_id); } @@ -449,14 +510,17 @@ class DataParser { constructor(data) { this.data = data; this.view = new DataView(data.buffer); - console.log("PARSING", this.data); this.offset = 0; } parseInt32() { + if (this.offset >= this.data.length) + return 0; this.offset += 4; return this.view.getInt32(this.offset - 4, true); } parseUint32() { + if (this.offset >= this.data.length) + return 0; this.offset += 4; return this.view.getUint32(this.offset - 4, true); } @@ -470,6 +534,8 @@ class DataParser { return str; } parseBool() { + if (this.offset >= this.data.length) + return 0; this.offset += 1; return this.view.getUint8(this.offset - 1) != 0; } diff --git a/misc/vscode/ovmDebug.ts b/misc/vscode/ovmDebug.ts index f5020a4e..9c622851 100644 --- a/misc/vscode/ovmDebug.ts +++ b/misc/vscode/ovmDebug.ts @@ -3,7 +3,7 @@ import { LoggingDebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, BreakpointEvent, OutputEvent, ProgressStartEvent, ProgressUpdateEvent, ProgressEndEvent, InvalidatedEvent, - Thread, StackFrame, Scope, Source, Handles, Breakpoint, MemoryEvent, ThreadEvent, LoadedSourceEvent + Thread, StackFrame, Scope, Source, Handles, Breakpoint, MemoryEvent, ThreadEvent, LoadedSourceEvent, Variable } from '@vscode/debugadapter'; import { DebugProtocol } from '@vscode/debugprotocol'; import EventEmitter = require('node:events'); @@ -12,7 +12,6 @@ import { Subject } from "await-notify"; import * as net from "node:net"; import * as child_process from "node:child_process"; import { ChildProcess } from 'node:child_process'; -import { Message } from '@vscode/debugadapter/lib/messages'; interface IOVMAttachRequestArguments extends DebugProtocol.AttachRequestArguments { @@ -26,6 +25,11 @@ interface IOVMLaunchRequestArguments extends DebugProtocol.AttachRequestArgument stopOnEntry?: boolean; } +interface IFrameReference { + frameIndex: number; + threadId: number; +} + export class OVMDebugSession extends LoggingDebugSession { private debugger: OVMDebugger; @@ -37,6 +41,9 @@ export class OVMDebugSession extends LoggingDebugSession { private _loadedSources: Map; + private _variableReferences = new Handles(); + private _frameReferences = new Handles(); + public constructor() { super("ovm-debug-log.txt"); @@ -143,18 +150,13 @@ export class OVMDebugSession extends LoggingDebugSession { } protected configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.ConfigurationDoneArguments, request?: DebugProtocol.Request): void { - console.log("CONFIGURATION DONE"); super.configurationDoneRequest(response, args); this._configurationDone.notify(); } protected disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments, request?: DebugProtocol.Request): void { - console.log(`disconnectRequest suspend: ${args.suspendDebuggee}, terminate: ${args.terminateDebuggee}`); - if (args.terminateDebuggee) { - console.log("TERMINATE"); - if (this.running_process) { this.running_process.kill('SIGTERM'); } @@ -168,8 +170,6 @@ export class OVMDebugSession extends LoggingDebugSession { } protected async setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments, request?: DebugProtocol.Request): Promise { - console.log("BREAKPOINTS", args, response); - while (!this._clientConnected) { await this._clientConnectedNotifier.wait(); } @@ -211,37 +211,54 @@ export class OVMDebugSession extends LoggingDebugSession { this.sendEvent(new LoadedSourceEvent("new", source)); } - return new StackFrame(i, f.funcname, source, f.line); + let frameRef = this._frameReferences.create({ + threadId: args.threadId, + frameIndex: i + }); + return new StackFrame(frameRef, f.funcname, source, f.line); }) }; this.sendResponse(response); } - protected threadsRequest(response: DebugProtocol.ThreadsResponse, request?: DebugProtocol.Request): void { - console.log("THREADS"); + protected async threadsRequest(response: DebugProtocol.ThreadsResponse, request?: DebugProtocol.Request): Promise { + let threads = await this.debugger.threads(); response.body = { - threads: [ - new Thread(1, "main thread"), - ] + threads: threads.map(t => new Thread(t.id, t.name)) }; this.sendResponse(response); } protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments, request?: DebugProtocol.Request): void { - console.log("SCOPES"); + let frameId = args.frameId; + + let frameRef = this._frameReferences.get(frameId); + let varRef = this._variableReferences.create(frameRef); response.body = { scopes: [ - new Scope("Locals", 1, false), - new Scope("Globals", 2, true) + new Scope("Locals", varRef, false), ] }; this.sendResponse(response); } + protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments, request?: DebugProtocol.Request): Promise { + const frameRef = this._variableReferences.get(args.variablesReference, {frameIndex: 0, threadId: 0}); + let vs: Variable[] = (await this.debugger.variables(frameRef.frameIndex, frameRef.threadId)) + .map(v => { + let nv = new Variable(v.name, v.value) as DebugProtocol.Variable; + nv.type = v.type; + return nv; + }); + + response.body = { variables: vs }; + this.sendResponse(response); + } + protected launchRequest(response: DebugProtocol.LaunchResponse, args: IOVMLaunchRequestArguments, request?: DebugProtocol.Request): void { this.running_process = child_process.spawn("onyx-run", ["--debug", args.wasmFile], { "cwd": args.workingDir, @@ -256,7 +273,6 @@ export class OVMDebugSession extends LoggingDebugSession { } protected async attachRequest(response: DebugProtocol.AttachResponse, args: IOVMAttachRequestArguments, request?: DebugProtocol.Request): Promise { - console.log("ATTACH"); await this._configurationDone.wait(1000); await this.debugger.connect(args.socketPath); @@ -318,13 +334,26 @@ interface IBreakpointValidation { line: number; } +interface IThreadInfo { + id: number; + name: string; +} + +interface IVariableInfo { + name: string; + value: string; + type: string; +} + enum OVMCommand { NOP = 0, RES = 1, BRK = 2, CLR_BRK = 3, STEP = 5, - TRACE = 6 + TRACE = 6, + THREADS = 7, + VARS = 8 } enum OVMEvent { @@ -461,6 +490,40 @@ class OVMDebugger extends EventEmitter { return this.preparePromise(cmd_id); } + threads(): Promise { + let data = new ArrayBuffer(8); + let view = new DataView(data); + + let cmd_id = this.next_command_id; + + view.setUint32(0, cmd_id, true); + view.setUint32(4, OVMCommand.THREADS, true); + + this.client.write(new Uint8Array(data)); + + this.pending_responses[cmd_id] = OVMCommand.THREADS; + + return this.preparePromise(cmd_id); + } + + variables(frame_index: number, thread_id: number): Promise { + let data = new ArrayBuffer(16); + let view = new DataView(data); + + let cmd_id = this.next_command_id; + + view.setUint32(0, cmd_id, true); + view.setUint32(4, OVMCommand.VARS, true); + view.setUint32(8, frame_index, true); + view.setUint32(12, thread_id, true); + + this.client.write(new Uint8Array(data)); + + this.pending_responses[cmd_id] = OVMCommand.VARS; + + return this.preparePromise(cmd_id); + } + private parseIncoming(data: Buffer): void { let parser = new DataParser(data); @@ -557,6 +620,34 @@ class OVMDebugger extends EventEmitter { break; } + case OVMCommand.THREADS: { + let result = new Array(); + + let count = parser.parseUint32(); + for (let i = 0; i < count; i++) { + let id = parser.parseUint32(); + let name = parser.parseString(); + result.push({id, name}); + } + + this.resolvePromise(msg_id, result); + break; + } + + case OVMCommand.VARS: { + let result = new Array(); + + while (parser.parseInt32() == 0) { + let name = parser.parseString(); + let value = parser.parseString(); + let type = parser.parseString(); + result.push({name, value, type}); + } + + this.resolvePromise(msg_id, result); + break; + } + default: console.log("Unrecognized command. ", cmd_id, msg_id); } @@ -604,16 +695,19 @@ class DataParser { constructor(data: Buffer) { this.data = data; this.view = new DataView(data.buffer); - console.log("PARSING", this.data); this.offset = 0; } parseInt32() { + if (this.offset >= this.data.length) return 0; + this.offset += 4; return this.view.getInt32(this.offset - 4, true); } parseUint32() { + if (this.offset >= this.data.length) return 0; + this.offset += 4; return this.view.getUint32(this.offset - 4, true); } @@ -630,6 +724,8 @@ class DataParser { } parseBool() { + if (this.offset >= this.data.length) return 0; + this.offset += 1; return this.view.getUint8(this.offset - 1) != 0; } diff --git a/src/onyxrun.c b/src/onyxrun.c index 1f9bb190..5200090b 100644 --- a/src/onyxrun.c +++ b/src/onyxrun.c @@ -18,7 +18,7 @@ int main(int argc, char *argv[]) { wasm_file_idx = 2; } - if (argc < 3) { + if (debug && argc < 3) { fprintf(stderr, "Expected a WASM file to run.\n"); return 1; } @@ -38,5 +38,5 @@ int main(int argc, char *argv[]) { bh_buffer data; data.data = wasm_data.data; data.length = wasm_data.length; - return onyx_run_wasm(data, argc - 1, argv + 1); + return onyx_run_wasm(data, argc - 1 - debug, argv + 1 + debug); } diff --git a/src/parser.c b/src/parser.c index 22fcf9d8..e7a08a2a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2465,6 +2465,9 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok func_def->body = parse_block(parser, 1, name); + // :LinearTokenDependent + func_def->closing_brace = parser->curr - 1; + function_defined: if (bh_arr_length(polymorphic_vars) > 0) { func_def->kind = Ast_Kind_Polymorphic_Proc; diff --git a/src/wasm_emit.c b/src/wasm_emit.c index a1df61e3..173614c1 100644 --- a/src/wasm_emit.c +++ b/src/wasm_emit.c @@ -219,6 +219,35 @@ 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) { + + u32 id = mod->debug_context->next_sym_id++; + + DebugSymInfo sym_info; + sym_info.sym_id = id; + sym_info.location_type = loc; + sym_info.location_num = num; + sym_info.type = type->id; + + if (token) { + token_toggle_end(token); + sym_info.name = bh_strdup(context.ast_alloc, token->text); + token_toggle_end(token); + } else { + sym_info.name = NULL; + } + + bh_arr_push(mod->debug_context->sym_info, sym_info); + + bh_buffer_write_byte(&mod->debug_context->op_buffer, DOT_SYM); + u32 leb_len=0; + u8 *bytes = uint_to_uleb128(id, &leb_len); + bh_buffer_append(&mod->debug_context->op_buffer, bytes, leb_len); + + mod->debug_context->last_op_was_rep = 0; + return id; +} + static u32 debug_get_file_id(OnyxWasmModule *mod, const char *name) { assert(mod && mod->debug_context); @@ -360,13 +389,26 @@ static void debug_end_function(OnyxWasmModule *mod) { mod->debug_context->last_token = NULL; } +static void debug_enter_symbol_frame(OnyxWasmModule *mod) { + bh_buffer_write_byte(&mod->debug_context->op_buffer, DOT_PUSHF); + mod->debug_context->last_op_was_rep = 0; +} + +static void debug_leave_symbol_frame(OnyxWasmModule *mod) { + bh_buffer_write_byte(&mod->debug_context->op_buffer, DOT_POPF); + mod->debug_context->last_op_was_rep = 0; +} + #else +#define debug_introduce_symbol(mod, name, loc, num, type) (void)0 #define debug_get_file_id(mod, name) (void)0 #define debug_set_position(mod, token) (void)0 #define debug_emit_instruction(mod, token) (void)0 #define debug_begin_function(mod, idx, token, name) (void)0 #define debug_end_function(mod) (void)0 +#define debug_enter_symbol_frame(mod) (void)0 +#define debug_leave_symbol_frame(mod) (void)0 #endif @@ -492,6 +534,7 @@ EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers) { ? SBT_Return_Block : SBT_Breakable_Block, block->token); + debug_enter_symbol_frame(mod); } forll (AstNode, stmt, block->body, next) { @@ -511,8 +554,10 @@ EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers) { emit_free_local_allocations(mod, &code); } - if (generate_block_headers) + if (generate_block_headers) { emit_leave_structured_block(mod, &code); + debug_leave_symbol_frame(mod); + } *pcode = code; } @@ -646,6 +691,12 @@ EMIT_FUNC(local_allocation, AstTyped* stmt) { u64 local_idx = local_allocate(mod->local_alloc, stmt); bh_imap_put(&mod->local_map, (u64) stmt, local_idx); + if (local_is_wasm_local(stmt)) { + debug_introduce_symbol(mod, stmt->token, DSL_REGISTER, local_idx, stmt->type); + } else { + debug_introduce_symbol(mod, stmt->token, DSL_STACK, local_idx, stmt->type); + } + if (stmt->kind == Ast_Kind_Local && !(stmt->flags & Ast_Flag_Decl_Followed_By_Init)) { bh_arr(WasmInstruction) code = *pcode; if (local_is_wasm_local(stmt)) { @@ -1409,6 +1460,11 @@ EMIT_FUNC(for, AstFor* for_node) { u64 iter_local = local_allocate(mod->local_alloc, (AstTyped *) var); bh_imap_put(&mod->local_map, (u64) var, iter_local); + debug_enter_symbol_frame(mod); + debug_introduce_symbol(mod, var->token, + local_is_wasm_local((AstTyped *) var) ? DSL_REGISTER : DSL_STACK, + iter_local, var->type); + emit_expression(mod, &code, for_node->iter); switch (for_node->loop_type) { @@ -1425,6 +1481,7 @@ EMIT_FUNC(for, AstFor* for_node) { } local_free(mod->local_alloc, (AstTyped *) var); + debug_leave_symbol_frame(mod); *pcode = code; } @@ -1512,7 +1569,10 @@ EMIT_FUNC(switch, AstSwitch* switch_node) { u64 bn = bh_imap_get(&block_map, (u64) sc->block); + // Maybe the Symbol Frame idea should be controlled as a block_flag? + debug_enter_symbol_frame(mod); emit_block(mod, &code, sc->block, 0); + debug_leave_symbol_frame(mod); if (bh_arr_last(code).type != WI_JUMP) WID(NULL, WI_JUMP, block_num - bn); @@ -1536,6 +1596,7 @@ EMIT_FUNC(defer, AstDefer* defer) { bh_arr_push(mod->deferred_stmts, ((DeferredStmt) { .type = Deferred_Stmt_Node, .depth = bh_arr_length(mod->structured_jump_target), + .defer_node= defer, .stmt = defer->stmt, })); } @@ -1544,6 +1605,7 @@ EMIT_FUNC(defer_code, WasmInstruction* deferred_code, u32 code_count) { bh_arr_push(mod->deferred_stmts, ((DeferredStmt) { .type = Deferred_Stmt_Code, .depth = bh_arr_length(mod->structured_jump_target), + .defer_node= NULL, .instructions = deferred_code, .instruction_count = code_count, })); @@ -1552,6 +1614,10 @@ EMIT_FUNC(defer_code, WasmInstruction* deferred_code, u32 code_count) { EMIT_FUNC(deferred_stmt, DeferredStmt deferred_stmt) { bh_arr(WasmInstruction) code = *pcode; + if (deferred_stmt.defer_node) { + WI(deferred_stmt.defer_node->token, WI_NOP); + } + switch (deferred_stmt.type) { case Deferred_Stmt_Node: emit_statement(mod, &code, deferred_stmt.stmt); break; case Deferred_Stmt_Code: { @@ -3639,6 +3705,7 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { 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); bh_imap_put(&mod->local_map, (u64) param->local, localidx | LOCAL_IS_WASM); localidx += type_structlike_mem_count(param->local->type); @@ -3648,6 +3715,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); bh_imap_put(&mod->local_map, (u64) param->local, localidx++ | LOCAL_IS_WASM); break; } @@ -3701,6 +3769,11 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { WasmFuncType* ft = mod->types[type_idx]; emit_zero_value(mod, &wasm_func.code, ft->return_type); + if (fd->closing_brace) { + debug_emit_instruction(mod, fd->closing_brace); + bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_NOP, 0x00 })); + } + debug_emit_instruction(mod, NULL); bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_BLOCK_END, 0x00 })); @@ -4210,9 +4283,11 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { module.debug_context = bh_alloc_item(context.ast_alloc, DebugContext); module.debug_context->allocator = global_heap_allocator; module.debug_context->next_file_id = 0; + module.debug_context->next_sym_id = 0; module.debug_context->last_token = NULL; 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->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 8f9ccc4a..1e2b6007 100644 --- a/src/wasm_output.h +++ b/src/wasm_output.h @@ -821,6 +821,34 @@ static i32 output_ovm_debug_sections(OnyxWasmModule* module, bh_buffer* buff) { bh_buffer_concat(buff, section_buff); } + { + // ovm_debug_syms sections + bh_buffer_clear(§ion_buff); + bh_buffer_write_byte(buff, WASM_SECTION_ID_CUSTOM); + + output_custom_section_name("ovm_debug_syms", §ion_buff); + + i32 sym_count = bh_arr_length(ctx->sym_info); + output_unsigned_integer(sym_count, §ion_buff); + + fori (i, 0, sym_count) { + DebugSymInfo *sym = &ctx->sym_info[i]; + output_unsigned_integer(sym->sym_id, §ion_buff); + if (sym->name) { + output_name(sym->name, strlen(sym->name), §ion_buff); + } else { + output_unsigned_integer(0, §ion_buff); + } + output_unsigned_integer(sym->location_type, §ion_buff); + output_unsigned_integer(sym->location_num, §ion_buff); + output_unsigned_integer(sym->type, §ion_buff); + } + + output_unsigned_integer(section_buff.length, buff); + + bh_buffer_concat(buff, section_buff); + } + { // ovm_debug_ops section bh_buffer_clear(§ion_buff);