wasm: Implement debug info for parameters

This commit is contained in:
Luuk de Gram 2022-04-30 20:52:13 +02:00
parent 8e1c220be2
commit 33b2f4f382
3 changed files with 56 additions and 2 deletions

View file

@ -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;

View file

@ -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;
}

View file

@ -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);