authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-01 16:32:48+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-09 18:51:46+02:00
logd46cdb539620a2f3647507ffed519908a1c31647
treebf67f0d7e826b9b4b2397a8a3f22b682c799fd18
parent33b2f4f382234c95e8e10cf1b17d1621bb402bf1

wasm: Debug information for locals

Implements very basic debug information for locals. For now it only implements debug info when the variable is stored within a Wasm local. The goal is to support those that live in the data section (virtual stack).

1 files changed, 59 insertions(+), 3 deletions(-)

src/arch/wasm/CodeGen.zig+59-3
......@@ -1478,15 +1478,17 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
14781478 .get_union_tag => self.airGetUnionTag(inst),
14791479
14801480 // TODO
1481 .dbg_stmt,
14821481 .dbg_inline_begin,
14831482 .dbg_inline_end,
14841483 .dbg_block_begin,
14851484 .dbg_block_end,
1486 .dbg_var_ptr,
1487 .dbg_var_val,
14881485 => WValue.none,
14891486
1487 .dbg_var_ptr => self.airDbgVar(inst, true),
1488 .dbg_var_val => self.airDbgVar(inst, false),
1489
1490 .dbg_stmt => self.airDbgStmt(inst),
1491
14901492 .call => self.airCall(inst, .auto),
14911493 .call_always_tail => self.airCall(inst, .always_tail),
14921494 .call_never_tail => self.airCall(inst, .never_tail),
......@@ -4277,3 +4279,57 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
42774279 try self.addLabel(.local_set, result.local);
42784280 return result;
42794281}
4282
4283fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !WValue {
4284 if (self.debug_output != .dwarf) return WValue{ .none = {} };
4285
4286 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4287 const ty = self.air.typeOf(pl_op.operand);
4288 const operand = try self.resolveInst(pl_op.operand);
4289 const op_ty = if (is_ptr) ty.childType() else ty;
4290
4291 log.debug("airDbgVar: %{d}: {}, {}", .{ inst, op_ty.fmtDebug(), operand });
4292
4293 const name = self.air.nullTerminatedString(pl_op.payload);
4294 log.debug(" var name = ({s})", .{name});
4295
4296 const dbg_info = &self.debug_output.dwarf.dbg_info;
4297 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
4298 switch (operand) {
4299 .local => |local| {
4300 const leb_size = link.File.Wasm.getULEB128Size(local);
4301 try dbg_info.ensureUnusedCapacity(2 + leb_size);
4302 // wasm locals are encoded as follow:
4303 // DW_OP_WASM_location wasm-op
4304 // where wasm-op is defined as
4305 // wasm-op := wasm-local | wasm-global | wasm-operand_stack
4306 // where wasm-local is encoded as
4307 // wasm-local := 0x00 i:uleb128
4308 dbg_info.appendSliceAssumeCapacity(&.{
4309 std.dwarf.OP.WASM_location,
4310 std.dwarf.OP.WASM_local,
4311 });
4312 leb.writeULEB128(dbg_info.writer(), local) catch unreachable;
4313 },
4314 else => {}, // TODO
4315 }
4316
4317 try dbg_info.ensureUnusedCapacity(5 + name.len + 1);
4318 try self.addDbgInfoTypeReloc(op_ty);
4319 dbg_info.appendSliceAssumeCapacity(name);
4320 dbg_info.appendAssumeCapacity(0);
4321 try return WValue{ .none = {} };
4322}
4323
4324fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !WValue {
4325 if (self.debug_output != .dwarf) return WValue{ .none = {} };
4326
4327 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
4328 try self.addInst(.{ .tag = .dbg_line, .data = .{
4329 .payload = try self.addExtra(Mir.DbgLineColumn{
4330 .line = dbg_stmt.line,
4331 .column = dbg_stmt.column,
4332 }),
4333 } });
4334 return WValue{ .none = {} };
4335}