dwarf: extract common logic for generating func var dbg info

This commit is contained in:
Jakub Konka 2022-12-01 15:28:22 +01:00
parent 7d0af639d8
commit 00016ab6a0
3 changed files with 206 additions and 172 deletions

View File

@ -184,15 +184,8 @@ const DbgInfoReloc = struct {
else => unreachable,
}
}
fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {
const mod = function.bin_file.options.module.?;
const fn_owner_decl = mod.declPtr(function.mod_fn.owner_decl);
const atom = switch (function.bin_file.tag) {
.elf => &fn_owner_decl.link.elf.dbg_info_atom,
.macho => &fn_owner_decl.link.macho.dbg_info_atom,
else => unreachable,
};
const atom = function.getDbgInfoAtomPtr();
switch (function.debug_output) {
.dwarf => |dw| switch (reloc.mcv) {
@ -230,6 +223,7 @@ const DbgInfoReloc = struct {
.dbg_var_val => reloc.ty,
else => unreachable,
};
// const atom= function.getDbgInfoAtomPtr();
switch (function.debug_output) {
.dwarf => |dw| {
@ -368,6 +362,17 @@ const DbgInfoReloc = struct {
}
};
fn getDbgInfoAtomPtr(self: Self) *link.File.Dwarf.Atom {
const mod = self.bin_file.options.module.?;
const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
const atom = switch (self.bin_file.tag) {
.elf => &fn_owner_decl.link.elf.dbg_info_atom,
.macho => &fn_owner_decl.link.macho.dbg_info_atom,
else => unreachable,
};
return atom;
}
const Branch = struct {
inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{},

View File

@ -3818,13 +3818,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
}
fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
const mod = self.bin_file.options.module.?;
const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
const atom = switch (self.bin_file.tag) {
.elf => &fn_owner_decl.link.elf.dbg_info_atom,
.macho => &fn_owner_decl.link.macho.dbg_info_atom,
else => unreachable,
};
const atom = self.getDbgInfoAtomPtr();
switch (self.debug_output) {
.dwarf => |dw| switch (mcv) {
@ -3845,6 +3839,64 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
}
}
fn genVarDbgInfo(
self: Self,
tag: Air.Inst.Tag,
ty: Type,
mcv: MCValue,
name: [:0]const u8,
) !void {
const is_ptr = switch (tag) {
.dbg_var_ptr => true,
.dbg_var_val => false,
else => unreachable,
};
const atom = self.getDbgInfoAtomPtr();
switch (self.debug_output) {
.dwarf => |dw| {
const loc: link.File.Dwarf.DeclState.VarArgDbgInfoLoc = switch (mcv) {
.register => |reg| .{
.register = reg.dwarfLocOp(),
},
.ptr_stack_offset,
.stack_offset,
=> |off| .{ .stack = .{
.fp_register = Register.rbp.dwarfLocOpDeref(),
.offset = -off,
} },
.memory => |address| .{
.memory = .{
.address = address,
.is_ptr = is_ptr,
},
},
.immediate => |x| .{ .immediate = x },
.undef => .undef,
.none => .none,
else => blk: {
log.debug("TODO generate debug info for {}", .{mcv});
break :blk .nop;
},
};
try dw.genVarDbgInfo(name, ty, atom, loc);
},
.plan9 => {},
.none => {},
}
}
fn getDbgInfoAtomPtr(self: Self) *link.File.Dwarf.Atom {
const mod = self.bin_file.options.module.?;
const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
const atom = switch (self.bin_file.tag) {
.elf => &fn_owner_decl.link.elf.dbg_info_atom,
.macho => &fn_owner_decl.link.macho.dbg_info_atom,
else => unreachable,
};
return atom;
}
fn airBreakpoint(self: *Self) !void {
_ = try self.addInst(.{
.tag = .interrupt,
@ -4413,163 +4465,6 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .dead, .{ operand, .none, .none });
}
fn genVarDbgInfo(
self: Self,
tag: Air.Inst.Tag,
ty: Type,
mcv: MCValue,
name: [:0]const u8,
) !void {
const name_with_null = name.ptr[0 .. name.len + 1];
switch (self.debug_output) {
.dwarf => |dw| {
const dbg_info = &dw.dbg_info;
try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
const endian = self.target.cpu.arch.endian();
switch (mcv) {
.register => |reg| {
try dbg_info.ensureUnusedCapacity(2);
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
});
},
.ptr_stack_offset,
.stack_offset,
=> |off| {
try dbg_info.ensureUnusedCapacity(7);
const fixup = dbg_info.items.len;
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // we will backpatch it after we encode the displacement in LEB128
Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer
});
leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
},
.memory,
.linker_load,
=> {
const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
const is_ptr = switch (tag) {
.dbg_var_ptr => true,
.dbg_var_val => false,
else => unreachable,
};
try dbg_info.ensureUnusedCapacity(2 + ptr_width);
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1 + ptr_width + @boolToInt(is_ptr),
DW.OP.addr, // literal address
});
const offset = @intCast(u32, dbg_info.items.len);
const addr = switch (mcv) {
.memory => |addr| addr,
else => 0,
};
switch (ptr_width) {
0...4 => {
try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
},
5...8 => {
try dbg_info.writer().writeInt(u64, addr, endian);
},
else => unreachable,
}
if (is_ptr) {
// We need deref the address as we point to the value via GOT entry.
try dbg_info.append(DW.OP.deref);
}
switch (mcv) {
.linker_load => |load_struct| try dw.addExprlocReloc(
load_struct.sym_index,
offset,
is_ptr,
),
else => {},
}
},
.immediate => |x| {
try dbg_info.ensureUnusedCapacity(2);
const fixup = dbg_info.items.len;
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1,
if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
});
if (ty.isSignedInt()) {
try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
} else {
try leb128.writeULEB128(dbg_info.writer(), x);
}
try dbg_info.append(DW.OP.stack_value);
dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
},
.undef => {
// DW.AT.location, DW.FORM.exprloc
// uleb128(exprloc_len)
// DW.OP.implicit_value uleb128(len_of_bytes) bytes
const abi_size = @intCast(u32, ty.abiSize(self.target.*));
var implicit_value_len = std.ArrayList(u8).init(self.gpa);
defer implicit_value_len.deinit();
try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
try dbg_info.ensureUnusedCapacity(total_exprloc_len);
dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
},
.none => {
try dbg_info.ensureUnusedCapacity(3);
dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
2, DW.OP.lit0, DW.OP.stack_value,
});
},
else => {
try dbg_info.ensureUnusedCapacity(2);
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, DW.OP.nop,
});
log.debug("TODO generate debug info for {}", .{mcv});
},
}
try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
}
/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
/// after codegen for this symbol is done.
fn addDbgInfoTypeReloc(self: Self, ty: Type) !void {
switch (self.debug_output) {
.dwarf => |dw| {
const dbg_info = &dw.dbg_info;
const index = dbg_info.items.len;
try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
const mod = self.bin_file.options.module.?;
const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
const atom = switch (self.bin_file.tag) {
.elf => &fn_owner_decl.link.elf.dbg_info_atom,
.macho => &fn_owner_decl.link.macho.dbg_info_atom,
else => unreachable,
};
try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
},
.plan9 => {},
.none => {},
}
}
fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
const abi_size = ty.abiSize(self.target.*);
switch (mcv) {

View File

@ -606,6 +606,140 @@ pub const DeclState = struct {
},
}
}
pub const VarArgDbgInfoLoc = union(enum) {
register: u8,
stack: struct {
fp_register: u8,
offset: i32,
},
memory: struct {
address: u64,
is_ptr: bool,
linker_load: ?struct {
type: enum { got, direct, import },
sym_index: u32,
} = null,
},
immediate: u64,
undef,
none,
nop,
};
pub fn genVarDbgInfo(
self: *DeclState,
name: [:0]const u8,
ty: Type,
atom: *Atom,
loc: VarArgDbgInfoLoc,
) error{OutOfMemory}!void {
const dbg_info = &self.dbg_info;
const name_with_null = name.ptr[0 .. name.len + 1];
try dbg_info.append(@enumToInt(AbbrevKind.variable));
const target = self.mod.getTarget();
const endian = target.cpu.arch.endian();
switch (loc) {
.register => |reg| {
try dbg_info.ensureUnusedCapacity(2);
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg,
});
},
.stack => |info| {
try dbg_info.ensureUnusedCapacity(7);
const fixup = dbg_info.items.len;
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // we will backpatch it after we encode the displacement in LEB128
info.fp_register,
});
leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable;
dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
},
.memory => |info| {
const ptr_width = @intCast(u8, @divExact(target.cpu.arch.ptrBitWidth(), 8));
try dbg_info.ensureUnusedCapacity(2 + ptr_width);
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1 + ptr_width + @boolToInt(info.is_ptr),
DW.OP.addr, // literal address
});
const offset = @intCast(u32, dbg_info.items.len);
switch (ptr_width) {
0...4 => {
try dbg_info.writer().writeInt(u32, @intCast(u32, info.address), endian);
},
5...8 => {
try dbg_info.writer().writeInt(u64, info.address, endian);
},
else => unreachable,
}
if (info.is_ptr) {
// We need deref the address as we point to the value via GOT entry.
try dbg_info.append(DW.OP.deref);
}
if (info.linker_load) |load_struct| try self.addExprlocReloc(
load_struct.sym_index,
offset,
info.is_ptr,
);
},
.immediate => |x| {
try dbg_info.ensureUnusedCapacity(2);
const fixup = dbg_info.items.len;
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1,
if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
});
if (ty.isSignedInt()) {
try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
} else {
try leb128.writeULEB128(dbg_info.writer(), x);
}
try dbg_info.append(DW.OP.stack_value);
dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
},
.undef => {
// DW.AT.location, DW.FORM.exprloc
// uleb128(exprloc_len)
// DW.OP.implicit_value uleb128(len_of_bytes) bytes
const abi_size = @intCast(u32, ty.abiSize(target));
var implicit_value_len = std.ArrayList(u8).init(self.gpa);
defer implicit_value_len.deinit();
try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
try dbg_info.ensureUnusedCapacity(total_exprloc_len);
dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
},
.none => {
try dbg_info.ensureUnusedCapacity(3);
dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
2, DW.OP.lit0, DW.OP.stack_value,
});
},
.nop => {
try dbg_info.ensureUnusedCapacity(2);
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, DW.OP.nop,
});
},
}
try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
const index = dbg_info.items.len;
try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
}
};
pub const AbbrevEntry = struct {