diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 9c90aa0afa..cb2578bee9 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -882,6 +882,8 @@ fn genFunc(self: *Self) InnerError!void { self.args = cc_result.args; self.return_value = cc_result.return_value; + try self.addTag(.dbg_prologue_end); + // Generate MIR for function body try self.genBody(self.air.getMainBody()); // In case we have a return value, but the last instruction is a noreturn (such as a while loop) @@ -896,6 +898,8 @@ fn genFunc(self: *Self) InnerError!void { // End of function body try self.addTag(.end); + try self.addTag(.dbg_epilogue_begin); + // check if we have to initialize and allocate anything into the stack frame. // If so, create enough stack space and insert the instructions at the front of the list. if (self.stack_size > 0) { @@ -942,6 +946,10 @@ fn genFunc(self: *Self) InnerError!void { .code = self.code, .locals = self.locals.items, .decl = self.decl, + .dbg_output = self.debug_output, + .prev_di_line = 0, + .prev_di_column = 0, + .prev_di_offset = 0, }; emit.emitMir() catch |err| switch (err) { diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index bcbff8d195..0081dc4d5d 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -6,6 +6,7 @@ const std = @import("std"); const Mir = @import("Mir.zig"); const link = @import("../../link.zig"); const Module = @import("../../Module.zig"); +const codegen = @import("../../codegen.zig"); const leb128 = std.leb; /// Contains our list of instructions @@ -22,6 +23,16 @@ locals: []const u8, /// The declaration that code is being generated for. decl: *Module.Decl, +// Debug information +/// Holds the debug information for this emission +dbg_output: codegen.DebugInfoOutput, +/// Previous debug info line +prev_di_line: u32, +/// Previous debug info column +prev_di_column: u32, +/// Previous offset relative to code section +prev_di_offset: u32, + const InnerError = error{ OutOfMemory, EmitFail, @@ -40,6 +51,10 @@ pub fn emitMir(emit: *Emit) InnerError!void { .block => try emit.emitBlock(tag, inst), .loop => try emit.emitBlock(tag, inst), + .dbg_line => try emit.emitDbgLine(inst), + .dbg_epilogue_begin => try emit.emitDbgEpilogueBegin(), + .dbg_prologue_end => try emit.emitDbgPrologueEnd(), + // branch instructions .br_if => try emit.emitLabel(tag, inst), .br_table => try emit.emitBrTable(inst), @@ -419,3 +434,43 @@ fn emitMemFill(emit: *Emit) !void { // For now we will always emit index 0. try leb128.writeULEB128(emit.code.writer(), @as(u32, 0)); } + +fn emitDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { + const extra_index = emit.mir.instructions.items(.data)[inst].payload; + const dbg_line = emit.mir.extraData(Mir.DbgLineColumn, extra_index).data; + try emit.dbgAdvancePCAndLine(dbg_line.line, dbg_line.column); +} + +fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { + if (emit.dbg_output != .dwarf) return; + + const dbg_line = &emit.dbg_output.dwarf.dbg_line; + try dbg_line.ensureUnusedCapacity(11); + dbg_line.appendAssumeCapacity(std.dwarf.LNS.advance_pc); + // TODO: This must emit a relocation to calculate the offset relative + // to the code section start. + leb128.writeULEB128(dbg_line.writer(), emit.offset() - emit.prev_di_offset) catch unreachable; + const delta_line = @intCast(i32, line) - @intCast(i32, emit.prev_di_line); + if (delta_line != 0) { + dbg_line.appendAssumeCapacity(std.dwarf.LNS.advance_line); + leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable; + } + dbg_line.appendAssumeCapacity(std.dwarf.LNS.copy); + emit.prev_di_line = line; + emit.prev_di_column = column; + emit.prev_di_offset = emit.offset(); +} + +fn emitDbgPrologueEnd(emit: *Emit) !void { + if (emit.dbg_output != .dwarf) return; + + try emit.dbg_output.dwarf.dbg_line.append(std.dwarf.LNS.set_prologue_end); + try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); +} + +fn emitDbgEpilogueBegin(emit: *Emit) !void { + if (emit.dbg_output != .dwarf) return; + + try emit.dbg_output.dwarf.dbg_line.append(std.dwarf.LNS.set_epilogue_begin); + try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); +} diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig index 87e64ce9e0..6cf43c1e03 100644 --- a/src/arch/wasm/Mir.zig +++ b/src/arch/wasm/Mir.zig @@ -47,6 +47,19 @@ pub const Inst = struct { /// /// Type of the loop is given in data `block_type` loop = 0x03, + /// Inserts debug information about the current line and column + /// of the source code + /// + /// Uses `payload` of which the payload type is `DbgLineColumn` + dbg_line = 0x06, + /// Emits epilogue begin debug information + /// + /// Uses `nop` + dbg_epilogue_begin = 0x07, + /// Emits prologue end debug information + /// + /// Uses `nop` + dbg_prologue_end = 0x08, /// Represents the end of a function body or an initialization expression /// /// Payload is `nop` @@ -645,3 +658,9 @@ pub const Memory = struct { pointer: u32, offset: u32, }; + +/// Maps a source line with wasm bytecode +pub const DbgLineColumn = struct { + line: u32, + column: u32, +};