Commit d46cdb5396

Luuk de Gram <luuk@degram.dev>
2022-05-01 16:32:48
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 parent 33b2f4f
Changed files (1)
src
arch
src/arch/wasm/CodeGen.zig
@@ -1478,15 +1478,17 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .get_union_tag => self.airGetUnionTag(inst),
 
         // TODO
-        .dbg_stmt,
         .dbg_inline_begin,
         .dbg_inline_end,
         .dbg_block_begin,
         .dbg_block_end,
-        .dbg_var_ptr,
-        .dbg_var_val,
         => WValue.none,
 
+        .dbg_var_ptr => self.airDbgVar(inst, true),
+        .dbg_var_val => self.airDbgVar(inst, false),
+
+        .dbg_stmt => self.airDbgStmt(inst),
+
         .call => self.airCall(inst, .auto),
         .call_always_tail => self.airCall(inst, .always_tail),
         .call_never_tail => self.airCall(inst, .never_tail),
@@ -4277,3 +4279,57 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     try self.addLabel(.local_set, result.local);
     return result;
 }
+
+fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !WValue {
+    if (self.debug_output != .dwarf) return WValue{ .none = {} };
+
+    const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+    const ty = self.air.typeOf(pl_op.operand);
+    const operand = try self.resolveInst(pl_op.operand);
+    const op_ty = if (is_ptr) ty.childType() else ty;
+
+    log.debug("airDbgVar: %{d}: {}, {}", .{ inst, op_ty.fmtDebug(), operand });
+
+    const name = self.air.nullTerminatedString(pl_op.payload);
+    log.debug(" var name = ({s})", .{name});
+
+    const dbg_info = &self.debug_output.dwarf.dbg_info;
+    try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
+    switch (operand) {
+        .local => |local| {
+            const leb_size = link.File.Wasm.getULEB128Size(local);
+            try dbg_info.ensureUnusedCapacity(2 + leb_size);
+            // wasm locals 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 wasm-local is encoded as
+            // wasm-local := 0x00 i:uleb128
+            dbg_info.appendSliceAssumeCapacity(&.{
+                std.dwarf.OP.WASM_location,
+                std.dwarf.OP.WASM_local,
+            });
+            leb.writeULEB128(dbg_info.writer(), local) catch unreachable;
+        },
+        else => {}, // TODO
+    }
+
+    try dbg_info.ensureUnusedCapacity(5 + name.len + 1);
+    try self.addDbgInfoTypeReloc(op_ty);
+    dbg_info.appendSliceAssumeCapacity(name);
+    dbg_info.appendAssumeCapacity(0);
+    try return WValue{ .none = {} };
+}
+
+fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !WValue {
+    if (self.debug_output != .dwarf) return WValue{ .none = {} };
+
+    const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
+    try self.addInst(.{ .tag = .dbg_line, .data = .{
+        .payload = try self.addExtra(Mir.DbgLineColumn{
+            .line = dbg_stmt.line,
+            .column = dbg_stmt.column,
+        }),
+    } });
+    return WValue{ .none = {} };
+}