Commit 33b2f4f382

Luuk de Gram <luuk@degram.dev>
2022-04-30 20:52:13
wasm: Implement debug info for parameters
1 parent 8e1c220
Changed files (3)
lib
std
dwarf
src
arch
link
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;
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
+            // <opcode> 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;
 }
 
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);