From 00016ab6a0bd31bed77c86074a6666822b8d0f20 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 1 Dec 2022 15:28:22 +0100 Subject: [PATCH] dwarf: extract common logic for generating func var dbg info --- src/arch/aarch64/CodeGen.zig | 21 ++-- src/arch/x86_64/CodeGen.zig | 223 +++++++++-------------------------- src/link/Dwarf.zig | 134 +++++++++++++++++++++ 3 files changed, 206 insertions(+), 172 deletions(-) diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 6bbbd00275..d258fe2e28 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -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) = .{}, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 289df8d4f1..f15f394f8c 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -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) { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 299bb57d7e..31b7d5b6e6 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -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 {