diff --git a/lib/std/dwarf/OP.zig b/lib/std/dwarf/OP.zig index 57fb7b7532..678ef39396 100644 --- a/lib/std/dwarf/OP.zig +++ b/lib/std/dwarf/OP.zig @@ -205,3 +205,9 @@ pub const HP_unmod_range = 0xe5; pub const HP_tls = 0xe6; // PGI (STMicroelectronics) extensions. pub const PGI_omp_thread_num = 0xf8; +// Wasm extensions. +pub const WASM_location = 0xed; +pub const WASM_local = 0x00; +pub const WASM_global = 0x01; +pub const WASM_global_u32 = 0x03; +pub const WASM_operand_stack = 0x02; diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 9318b4ecca..1288721e07 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -546,6 +546,8 @@ block_depth: u32 = 0, air: Air, liveness: Liveness, gpa: mem.Allocator, +debug_output: codegen.DebugInfoOutput, +mod_fn: *const Module.Fn, /// Table to save `WValue`'s generated by an `Air.Inst` values: ValueTable, /// Mapping from Air.Inst.Index to block ids @@ -856,6 +858,8 @@ pub fn generate( .locals = .{}, .target = bin_file.options.target, .bin_file = bin_file.cast(link.File.Wasm).?, + .debug_output = debug_output, + .mod_fn = func, }; defer code_gen.deinit(); @@ -1022,6 +1026,23 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool } } +/// For a given `Type`, add debug information to .debug_info at the current position. +/// The actual bytes will be written to the position after relocation. +fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { + switch (self.debug_output) { + .dwarf => |dwarf| { + assert(ty.hasRuntimeBitsIgnoreComptime()); + const dbg_info = &dwarf.dbg_info; + const index = dbg_info.items.len; + try dbg_info.resize(index + 4); + const atom = &self.decl.link.wasm.dbg_info_atom; + try dwarf.addTypeReloc(atom, ty, @intCast(u32, index), null); + }, + .plan9 => unreachable, + .none => {}, + } +} + /// Lowers a Zig type and its value based on a given calling convention to ensure /// it matches the ABI. fn lowerArg(self: *Self, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void { @@ -1873,7 +1894,8 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { } fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { - const arg = self.args[self.arg_index]; + const arg_index = self.arg_index; + const arg = self.args[arg_index]; const cc = self.decl.ty.fnInfo().cc; if (cc == .C) { const ty = self.air.typeOfIndex(inst); @@ -1886,6 +1908,32 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { } else { self.arg_index += 1; } + + switch (self.debug_output) { + .dwarf => |dwarf| { + // TODO: Get the original arg index rather than wasm arg index + const name = self.mod_fn.getParamName(arg_index); + const leb_size = link.File.Wasm.getULEB128Size(arg.local); + const dbg_info = &dwarf.dbg_info; + try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1); + // wasm locations are encoded as follow: + // DW_OP_WASM_location wasm-op + // where wasm-op is defined as + // wasm-op := wasm-local | wasm-global | wasm-operand_stack + // where each argument is encoded as + // i:uleb128 + dbg_info.appendSliceAssumeCapacity(&.{ + @enumToInt(link.File.Dwarf.AbbrevKind.parameter), + std.dwarf.OP.WASM_location, + std.dwarf.OP.WASM_local, + }); + leb.writeULEB128(dbg_info.writer(), arg.local) catch unreachable; + try self.addDbgInfoTypeReloc(self.air.typeOfIndex(inst)); + dbg_info.appendSliceAssumeCapacity(name); + dbg_info.appendAssumeCapacity(0); + }, + else => {}, + } return arg; } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index f4bd962016..f9c40fd767 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -2668,7 +2668,7 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { try file.writevAll(&iovecs); } -fn getULEB128Size(uint_value: anytype) u32 { +pub fn getULEB128Size(uint_value: anytype) u32 { const T = @TypeOf(uint_value); const U = if (@typeInfo(T).Int.bits < 8) u8 else T; var value = @intCast(U, uint_value);