diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index 2a4e6cb985..b62f9d8691 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -390,7 +390,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { // TODO Look into using the DWARF special opcodes to compress this data. // It lets you emit single-byte opcodes that add different numbers to // both the PC and the line number at the same time. - const dbg_line = dw.getDeclDebugLineBuffer(); + const dbg_line = &dw.dbg_line; try dbg_line.ensureUnusedCapacity(11); dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable; @@ -588,7 +588,7 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { fn mirDebugPrologueEnd(self: *Emit) !void { switch (self.debug_output) { .dwarf => |dw| { - try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end); + try dw.dbg_line.append(DW.LNS.set_prologue_end); try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); }, .plan9 => {}, @@ -599,7 +599,7 @@ fn mirDebugPrologueEnd(self: *Emit) !void { fn mirDebugEpilogueBegin(self: *Emit) !void { switch (self.debug_output) { .dwarf => |dw| { - try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin); + try dw.dbg_line.append(DW.LNS.set_epilogue_begin); try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); }, .plan9 => {}, diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index 62705651a6..45bcad485e 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -332,7 +332,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { // TODO Look into using the DWARF special opcodes to compress this data. // It lets you emit single-byte opcodes that add different numbers to // both the PC and the line number at the same time. - const dbg_line = dw.getDeclDebugLineBuffer(); + const dbg_line = &dw.dbg_line; try dbg_line.ensureUnusedCapacity(11); dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable; @@ -382,7 +382,7 @@ fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void { switch (self.debug_output) { .dwarf => |dw| { assert(ty.hasRuntimeBits()); - const dbg_info = dw.getDeclDebugInfoBuffer(); + 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 atom = switch (self.bin_file.tag) { @@ -409,7 +409,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void { .register => |reg| { switch (self.debug_output) { .dwarf => |dw| { - const dbg_info = dw.getDeclDebugInfoBuffer(); + const dbg_info = &dw.dbg_info; try dbg_info.ensureUnusedCapacity(3); dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc @@ -442,7 +442,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void { else => unreachable, }; - const dbg_info = dw.getDeclDebugInfoBuffer(); + const dbg_info = &dw.dbg_info; try dbg_info.append(link.File.Dwarf.abbrev_parameter); // Get length of the LEB128 stack offset @@ -560,7 +560,7 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { fn mirDebugPrologueEnd(emit: *Emit) !void { switch (emit.debug_output) { .dwarf => |dw| { - try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end); + try dw.dbg_line.append(DW.LNS.set_prologue_end); try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); }, .plan9 => {}, @@ -571,7 +571,7 @@ fn mirDebugPrologueEnd(emit: *Emit) !void { fn mirDebugEpilogueBegin(emit: *Emit) !void { switch (emit.debug_output) { .dwarf => |dw| { - try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin); + try dw.dbg_line.append(DW.LNS.set_epilogue_begin); try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); }, .plan9 => {}, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 2c8374fca1..bbc880f0bd 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -749,7 +749,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { switch (self.debug_output) { .dwarf => |dw| { assert(ty.hasRuntimeBits()); - const dbg_info = dw.getDeclDebugInfoBuffer(); + 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 atom = switch (self.bin_file.tag) { @@ -1572,7 +1572,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32 .register => |reg| { switch (self.debug_output) { .dwarf => |dw| { - const dbg_info = dw.getDeclDebugInfoBuffer(); + const dbg_info = &dw.dbg_info; try dbg_info.ensureUnusedCapacity(3); dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index bfa4e00d00..8190566c23 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -93,7 +93,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { // TODO Look into using the DWARF special opcodes to compress this data. // It lets you emit single-byte opcodes that add different numbers to // both the PC and the line number at the same time. - const dbg_line = dw.getDeclDebugLineBuffer(); + const dbg_line = &dw.dbg_line; try dbg_line.ensureUnusedCapacity(11); dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable; @@ -184,7 +184,7 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { fn mirDebugPrologueEnd(self: *Emit) !void { switch (self.debug_output) { .dwarf => |dw| { - try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end); + try dw.dbg_line.append(DW.LNS.set_prologue_end); try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); }, .plan9 => {}, @@ -195,7 +195,7 @@ fn mirDebugPrologueEnd(self: *Emit) !void { fn mirDebugEpilogueBegin(self: *Emit) !void { switch (self.debug_output) { .dwarf => |dw| { - try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin); + try dw.dbg_line.append(DW.LNS.set_epilogue_begin); try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); }, .plan9 => {}, diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index e8ea10bf29..3296339419 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -977,7 +977,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void { // TODO Look into using the DWARF special opcodes to compress this data. // It lets you emit single-byte opcodes that add different numbers to // both the PC and the line number at the same time. - const dbg_line = dw.getDeclDebugLineBuffer(); + const dbg_line = &dw.dbg_line; try dbg_line.ensureUnusedCapacity(11); dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable; @@ -1034,7 +1034,7 @@ fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { assert(tag == .dbg_prologue_end); switch (emit.debug_output) { .dwarf => |dw| { - try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end); + try dw.dbg_line.append(DW.LNS.set_prologue_end); log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column }); try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); }, @@ -1048,7 +1048,7 @@ fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { assert(tag == .dbg_epilogue_begin); switch (emit.debug_output) { .dwarf => |dw| { - try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin); + try dw.dbg_line.append(DW.LNS.set_epilogue_begin); log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column }); try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); }, @@ -1075,7 +1075,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32 .register => |reg| { switch (emit.debug_output) { .dwarf => |dw| { - const dbg_info = dw.getDeclDebugInfoBuffer(); + const dbg_info = &dw.dbg_info; try dbg_info.ensureUnusedCapacity(3); dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc @@ -1099,7 +1099,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32 // TODO we need to make this more generic if we don't use rbp as the frame pointer // for example when -fomit-frame-pointer is set. const disp = @intCast(i32, max_stack) - off + 16; - const dbg_info = dw.getDeclDebugInfoBuffer(); + const dbg_info = &dw.dbg_info; try dbg_info.ensureUnusedCapacity(8); dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); const fixup = dbg_info.items.len; @@ -1128,7 +1128,7 @@ fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void { switch (emit.debug_output) { .dwarf => |dw| { assert(ty.hasRuntimeBits()); - const dbg_info = dw.getDeclDebugInfoBuffer(); + 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 atom = switch (emit.bin_file.tag) { diff --git a/src/codegen.zig b/src/codegen.zig index fa84ad0d52..2ace45c8cb 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -42,7 +42,7 @@ pub const GenerateSymbolError = error{ }; pub const DebugInfoOutput = union(enum) { - dwarf: *link.File.Dwarf, + dwarf: *link.File.Dwarf.DeclState, /// the plan9 debuginfo output is a bytecode with 4 opcodes /// assume all numbers/variables are bytes /// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 7840b8d6a7..907a21b774 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -43,11 +43,6 @@ abbrev_table_offset: ?u64 = null, /// Table of debug symbol names. strtab: std.ArrayListUnmanaged(u8) = .{}, -/// Lives only as long as the analysed Decl. -/// Allocated with `initDeclState`. -/// Freed with `commitDeclState`. -decl_state: ?DeclState = null, - /// List of atoms that are owned directly by the DWARF module. /// TODO convert links in DebugInfoAtom into indices and make /// sure every atom is owned by this module. @@ -71,6 +66,8 @@ pub const Atom = struct { /// and a set of relocations that will be resolved once this /// Decl's inner Atom is assigned an offset within the DWARF section. pub const DeclState = struct { + gpa: Allocator, + target: std.Target, dbg_line: std.ArrayList(u8), dbg_info: std.ArrayList(u8), abbrev_type_arena: std.heap.ArenaAllocator, @@ -83,21 +80,438 @@ pub const DeclState = struct { ) = .{}, abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, - fn init(gpa: Allocator) DeclState { + fn init(gpa: Allocator, target: std.Target) DeclState { return .{ + .gpa = gpa, + .target = target, .dbg_line = std.ArrayList(u8).init(gpa), .dbg_info = std.ArrayList(u8).init(gpa), .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa), }; } - pub fn deinit(self: *DeclState, gpa: Allocator) void { + pub fn deinit(self: *DeclState) void { self.dbg_line.deinit(); self.dbg_info.deinit(); self.abbrev_type_arena.deinit(); - self.abbrev_table.deinit(gpa); - self.abbrev_resolver.deinit(gpa); - self.abbrev_relocs.deinit(gpa); + self.abbrev_table.deinit(self.gpa); + self.abbrev_resolver.deinit(self.gpa); + self.abbrev_relocs.deinit(self.gpa); + } + + pub fn addTypeReloc( + self: *DeclState, + atom: *const Atom, + ty: Type, + offset: u32, + addend: ?u32, + ) !void { + const resolv = self.abbrev_resolver.getContext(ty, .{ + .target = self.target, + }) orelse blk: { + const sym_index = @intCast(u32, self.abbrev_table.items.len); + try self.abbrev_table.append(self.gpa, .{ + .atom = atom, + .@"type" = ty, + .offset = undefined, + }); + log.debug("@{d}: {}", .{ sym_index, ty.fmtDebug() }); + try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{ + .target = self.target, + }); + break :blk self.abbrev_resolver.getContext(ty, .{ + .target = self.target, + }).?; + }; + const add: u32 = addend orelse 0; + + log.debug("{x}: @{d} + {x}", .{ offset, resolv, add }); + try self.abbrev_relocs.append(self.gpa, .{ + .target = resolv, + .atom = atom, + .offset = offset, + .addend = add, + }); + } + + fn addDbgInfoType( + self: *DeclState, + module: *Module, + atom: *Atom, + ty: Type, + ) error{OutOfMemory}!void { + const arena = self.abbrev_type_arena.allocator(); + const dbg_info_buffer = &self.dbg_info; + const target = self.target; + const target_endian = self.target.cpu.arch.endian(); + + switch (ty.zigTypeTag()) { + .NoReturn => unreachable, + .Void => { + try dbg_info_buffer.append(abbrev_pad1); + }, + .Bool => { + try dbg_info_buffer.appendSlice(&[_]u8{ + abbrev_base_type, + DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data1 + 1, // DW.AT.byte_size, DW.FORM.data1 + 'b', 'o', 'o', 'l', 0, // DW.AT.name, DW.FORM.string + }); + }, + .Int => { + const info = ty.intInfo(target); + try dbg_info_buffer.ensureUnusedCapacity(12); + dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); + // DW.AT.encoding, DW.FORM.data1 + dbg_info_buffer.appendAssumeCapacity(switch (info.signedness) { + .signed => DW.ATE.signed, + .unsigned => DW.ATE.unsigned, + }); + // DW.AT.byte_size, DW.FORM.data1 + dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target))); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); + }, + .Optional => { + if (ty.isPtrLikeOptional()) { + try dbg_info_buffer.ensureUnusedCapacity(12); + dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); + // DW.AT.encoding, DW.FORM.data1 + dbg_info_buffer.appendAssumeCapacity(DW.ATE.address); + // DW.AT.byte_size, DW.FORM.data1 + dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target))); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); + } else { + // Non-pointer optionals are structs: struct { .maybe = *, .val = * } + var buf = try arena.create(Type.Payload.ElemType); + const payload_ty = ty.optionalChild(buf); + // DW.AT.structure_type + try dbg_info_buffer.append(abbrev_struct_type); + // DW.AT.byte_size, DW.FORM.sdata + const abi_size = ty.abiSize(target); + try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(7); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("maybe"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + var index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, Type.bool, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + try dbg_info_buffer.ensureUnusedCapacity(6); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.member + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("val"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + const offset = abi_size - payload_ty.abiSize(target); + try leb128.writeULEB128(dbg_info_buffer.writer(), offset); + // DW.AT.structure_type delimit children + try dbg_info_buffer.append(0); + } + }, + .Pointer => { + if (ty.isSlice()) { + // Slices are structs: struct { .ptr = *, .len = N } + // DW.AT.structure_type + try dbg_info_buffer.ensureUnusedCapacity(2); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_type); + // DW.AT.byte_size, DW.FORM.sdata + dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize) * 2); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(5); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("ptr"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + var index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); + const ptr_ty = ty.slicePtrFieldType(buf); + try self.addTypeReloc(atom, ptr_ty, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + try dbg_info_buffer.ensureUnusedCapacity(6); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.member + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("len"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + try dbg_info_buffer.ensureUnusedCapacity(2); + dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize)); + // DW.AT.structure_type delimit children + dbg_info_buffer.appendAssumeCapacity(0); + } else { + try dbg_info_buffer.ensureUnusedCapacity(5); + dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type); + // DW.AT.type, DW.FORM.ref4 + const index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null); + } + }, + .Struct => blk: { + // DW.AT.structure_type + try dbg_info_buffer.append(abbrev_struct_type); + // DW.AT.byte_size, DW.FORM.sdata + const abi_size = ty.abiSize(target); + try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); + + switch (ty.tag()) { + .tuple, .anon_struct => { + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); + + const fields = ty.tupleFields(); + for (fields.types) |field, field_index| { + // DW.AT.member + try dbg_info_buffer.append(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); + // DW.AT.type, DW.FORM.ref4 + var index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, field, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + const field_off = ty.structFieldOffset(field_index, target); + try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); + } + }, + else => { + // DW.AT.name, DW.FORM.string + const struct_name = try ty.nameAllocArena(arena, target); + try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); + dbg_info_buffer.appendSliceAssumeCapacity(struct_name); + dbg_info_buffer.appendAssumeCapacity(0); + + const struct_obj = ty.castTag(.@"struct").?.data; + if (struct_obj.layout == .Packed) { + log.debug("TODO implement .debug_info for packed structs", .{}); + break :blk; + } + + const fields = ty.structFields(); + for (fields.keys()) |field_name, field_index| { + const field = fields.get(field_name).?; + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity(field_name); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + var index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + const field_off = ty.structFieldOffset(field_index, target); + try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); + } + }, + } + + // DW.AT.structure_type delimit children + try dbg_info_buffer.append(0); + }, + .Enum => { + // DW.AT.enumeration_type + try dbg_info_buffer.append(abbrev_enum_type); + // DW.AT.byte_size, DW.FORM.sdata + const abi_size = ty.abiSize(target); + try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); + // DW.AT.name, DW.FORM.string + const enum_name = try ty.nameAllocArena(arena, target); + try dbg_info_buffer.ensureUnusedCapacity(enum_name.len + 1); + dbg_info_buffer.appendSliceAssumeCapacity(enum_name); + dbg_info_buffer.appendAssumeCapacity(0); + + const fields = ty.enumFields(); + const values: ?Module.EnumFull.ValueMap = switch (ty.tag()) { + .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values, + .enum_simple => null, + .enum_numbered => ty.castTag(.enum_numbered).?.data.values, + else => unreachable, + }; + for (fields.keys()) |field_name, field_i| { + // DW.AT.enumerator + try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64)); + dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity(field_name); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.const_value, DW.FORM.data8 + const value: u64 = if (values) |vals| value: { + if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered + const value = vals.keys()[field_i]; + var int_buffer: Value.Payload.U64 = undefined; + break :value value.enumToInt(ty, &int_buffer).toUnsignedInt(target); + } else @intCast(u64, field_i); + mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); + } + + // DW.AT.enumeration_type delimit children + try dbg_info_buffer.append(0); + }, + .Union => { + const layout = ty.unionGetLayout(target); + const union_obj = ty.cast(Type.Payload.Union).?.data; + const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0; + const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size; + const is_tagged = layout.tag_size > 0; + const union_name = try ty.nameAllocArena(arena, target); + + // TODO this is temporary to match current state of unions in Zig - we don't yet have + // safety checks implemented meaning the implicit tag is not yet stored and generated + // for untagged unions. + if (is_tagged) { + // DW.AT.structure_type + try dbg_info_buffer.append(abbrev_struct_type); + // DW.AT.byte_size, DW.FORM.sdata + try leb128.writeULEB128(dbg_info_buffer.writer(), layout.abi_size); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.ensureUnusedCapacity(union_name.len + 1); + dbg_info_buffer.appendSliceAssumeCapacity(union_name); + dbg_info_buffer.appendAssumeCapacity(0); + + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(9); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("payload"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + const inner_union_index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(inner_union_index + 4); + try self.addTypeReloc(atom, ty, @intCast(u32, inner_union_index), 5); + // DW.AT.data_member_location, DW.FORM.sdata + try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset); + } + + // DW.AT.union_type + try dbg_info_buffer.append(abbrev_union_type); + // DW.AT.byte_size, DW.FORM.sdata, + try leb128.writeULEB128(dbg_info_buffer.writer(), layout.payload_size); + // DW.AT.name, DW.FORM.string + if (is_tagged) { + try dbg_info_buffer.writer().print("AnonUnion\x00", .{}); + } else { + try dbg_info_buffer.writer().print("{s}\x00", .{union_name}); + } + + const fields = ty.unionFields(); + for (fields.keys()) |field_name| { + const field = fields.get(field_name).?; + if (!field.ty.hasRuntimeBits()) continue; + // DW.AT.member + try dbg_info_buffer.append(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{s}\x00", .{field_name}); + // DW.AT.type, DW.FORM.ref4 + const index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + try dbg_info_buffer.append(0); + } + // DW.AT.union_type delimit children + try dbg_info_buffer.append(0); + + if (is_tagged) { + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(5); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("tag"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + const index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, union_obj.tag_ty, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset); + + // DW.AT.structure_type delimit children + try dbg_info_buffer.append(0); + } + }, + .ErrorSet => { + try addDbgInfoErrorSet( + self.abbrev_type_arena.allocator(), + module, + ty, + self.target, + &self.dbg_info, + ); + }, + .ErrorUnion => { + const error_ty = ty.errorUnionSet(); + const payload_ty = ty.errorUnionPayload(); + const abi_size = ty.abiSize(target); + const abi_align = ty.abiAlignment(target); + const payload_off = mem.alignForwardGeneric(u64, error_ty.abiSize(target), abi_align); + + // DW.AT.structure_type + try dbg_info_buffer.append(abbrev_struct_type); + // DW.AT.byte_size, DW.FORM.sdata + try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); + // DW.AT.name, DW.FORM.string + const name = try ty.nameAllocArena(arena, target); + try dbg_info_buffer.writer().print("{s}\x00", .{name}); + + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(7); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("value"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + var index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off); + + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(5); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("err"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null); + // DW.AT.data_member_location, DW.FORM.sdata + try dbg_info_buffer.append(0); + + // DW.AT.structure_type delimit children + try dbg_info_buffer.append(0); + }, + else => { + log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()}); + try dbg_info_buffer.append(abbrev_pad1); + }, + } } }; @@ -191,7 +605,7 @@ pub fn deinit(self: *Dwarf) void { /// Initializes Decl's state and its matching output buffers. /// Call this before `commitDeclState`. -pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !void { +pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !DeclState { const tracy = trace(@src()); defer tracy.end(); @@ -201,10 +615,10 @@ pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !void { log.debug("initDeclState {s}{*}", .{ decl_name, decl }); const gpa = self.allocator; - assert(self.decl_state == null); - self.decl_state = DeclState.init(gpa); - const dbg_line_buffer = &self.decl_state.?.dbg_line; - const dbg_info_buffer = &self.decl_state.?.dbg_info; + var decl_state = DeclState.init(gpa, self.target); + errdefer decl_state.deinit(); + const dbg_line_buffer = &decl_state.dbg_line; + const dbg_info_buffer = &decl_state.dbg_info; assert(decl.has_tv); @@ -274,7 +688,12 @@ pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !void { .macho => &decl.link.macho.dbg_info_atom, else => unreachable, }; - try self.addTypeReloc(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len), null); + try decl_state.addTypeReloc( + atom, + fn_ret_type, + @intCast(u32, dbg_info_buffer.items.len), + null, + ); dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 } @@ -285,6 +704,8 @@ pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !void { // TODO implement .debug_info for global variables }, } + + return decl_state; } pub fn commitDeclState( @@ -294,19 +715,14 @@ pub fn commitDeclState( decl: *Module.Decl, sym_addr: u64, sym_size: u64, + decl_state: *DeclState, ) !void { const tracy = trace(@src()); defer tracy.end(); - assert(self.decl_state != null); // Caller forgot to call `initDeclState` - defer { - self.decl_state.?.deinit(self.allocator); - self.decl_state = null; - } - const gpa = self.allocator; - var dbg_line_buffer = &self.decl_state.?.dbg_line; - var dbg_info_buffer = &self.decl_state.?.dbg_info; + var dbg_line_buffer = &decl_state.dbg_line; + var dbg_info_buffer = &decl_state.dbg_info; const target_endian = self.target.cpu.arch.endian(); @@ -509,7 +925,6 @@ pub fn commitDeclState( .macho => &decl.link.macho.dbg_info_atom, else => unreachable, }; - const decl_state = &self.decl_state.?; { // Now we emit the .debug_info types of the Decl. These will count towards the size of @@ -532,7 +947,7 @@ pub fn commitDeclState( if (deferred) continue; symbol.offset = @intCast(u32, dbg_info_buffer.items.len); - try self.addDbgInfoType(decl_state.abbrev_type_arena.allocator(), module, atom, ty, dbg_info_buffer); + try decl_state.addDbgInfoType(module, atom, ty); } } @@ -825,414 +1240,6 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void { } } -/// Asserts the type has codegen bits. -fn addDbgInfoType( - self: *Dwarf, - arena: Allocator, - module: *Module, - atom: *Atom, - ty: Type, - dbg_info_buffer: *std.ArrayList(u8), -) error{OutOfMemory}!void { - const target = self.target; - const target_endian = self.target.cpu.arch.endian(); - - switch (ty.zigTypeTag()) { - .NoReturn => unreachable, - .Void => { - try dbg_info_buffer.append(abbrev_pad1); - }, - .Bool => { - try dbg_info_buffer.appendSlice(&[_]u8{ - abbrev_base_type, - DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data1 - 1, // DW.AT.byte_size, DW.FORM.data1 - 'b', 'o', 'o', 'l', 0, // DW.AT.name, DW.FORM.string - }); - }, - .Int => { - const info = ty.intInfo(target); - try dbg_info_buffer.ensureUnusedCapacity(12); - dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); - // DW.AT.encoding, DW.FORM.data1 - dbg_info_buffer.appendAssumeCapacity(switch (info.signedness) { - .signed => DW.ATE.signed, - .unsigned => DW.ATE.unsigned, - }); - // DW.AT.byte_size, DW.FORM.data1 - dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target))); - // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); - }, - .Optional => { - if (ty.isPtrLikeOptional()) { - try dbg_info_buffer.ensureUnusedCapacity(12); - dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); - // DW.AT.encoding, DW.FORM.data1 - dbg_info_buffer.appendAssumeCapacity(DW.ATE.address); - // DW.AT.byte_size, DW.FORM.data1 - dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target))); - // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); - } else { - // Non-pointer optionals are structs: struct { .maybe = *, .val = * } - var buf = try arena.create(Type.Payload.ElemType); - const payload_ty = ty.optionalChild(buf); - // DW.AT.structure_type - try dbg_info_buffer.append(abbrev_struct_type); - // DW.AT.byte_size, DW.FORM.sdata - const abi_size = ty.abiSize(target); - try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); - // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); - // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(7); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity("maybe"); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, Type.bool, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - try dbg_info_buffer.ensureUnusedCapacity(6); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.member - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity("val"); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - const offset = abi_size - payload_ty.abiSize(target); - try leb128.writeULEB128(dbg_info_buffer.writer(), offset); - // DW.AT.structure_type delimit children - try dbg_info_buffer.append(0); - } - }, - .Pointer => { - if (ty.isSlice()) { - // Slices are structs: struct { .ptr = *, .len = N } - // DW.AT.structure_type - try dbg_info_buffer.ensureUnusedCapacity(2); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_type); - // DW.AT.byte_size, DW.FORM.sdata - dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize) * 2); - // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); - // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(5); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity("ptr"); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); - const ptr_ty = ty.slicePtrFieldType(buf); - try self.addTypeReloc(atom, ptr_ty, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - try dbg_info_buffer.ensureUnusedCapacity(6); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.member - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity("len"); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - try dbg_info_buffer.ensureUnusedCapacity(2); - dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize)); - // DW.AT.structure_type delimit children - dbg_info_buffer.appendAssumeCapacity(0); - } else { - try dbg_info_buffer.ensureUnusedCapacity(5); - dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type); - // DW.AT.type, DW.FORM.ref4 - const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null); - } - }, - .Struct => blk: { - // DW.AT.structure_type - try dbg_info_buffer.append(abbrev_struct_type); - // DW.AT.byte_size, DW.FORM.sdata - const abi_size = ty.abiSize(target); - try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); - - switch (ty.tag()) { - .tuple, .anon_struct => { - // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); - - const fields = ty.tupleFields(); - for (fields.types) |field, field_index| { - // DW.AT.member - try dbg_info_buffer.append(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); - // DW.AT.type, DW.FORM.ref4 - var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, field, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - const field_off = ty.structFieldOffset(field_index, target); - try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); - } - }, - else => { - // DW.AT.name, DW.FORM.string - const struct_name = try ty.nameAllocArena(arena, target); - try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); - dbg_info_buffer.appendSliceAssumeCapacity(struct_name); - dbg_info_buffer.appendAssumeCapacity(0); - - const struct_obj = ty.castTag(.@"struct").?.data; - if (struct_obj.layout == .Packed) { - log.debug("TODO implement .debug_info for packed structs", .{}); - break :blk; - } - - const fields = ty.structFields(); - for (fields.keys()) |field_name, field_index| { - const field = fields.get(field_name).?; - // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity(field_name); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - const field_off = ty.structFieldOffset(field_index, target); - try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); - } - }, - } - - // DW.AT.structure_type delimit children - try dbg_info_buffer.append(0); - }, - .Enum => { - // DW.AT.enumeration_type - try dbg_info_buffer.append(abbrev_enum_type); - // DW.AT.byte_size, DW.FORM.sdata - const abi_size = ty.abiSize(target); - try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); - // DW.AT.name, DW.FORM.string - const enum_name = try ty.nameAllocArena(arena, target); - try dbg_info_buffer.ensureUnusedCapacity(enum_name.len + 1); - dbg_info_buffer.appendSliceAssumeCapacity(enum_name); - dbg_info_buffer.appendAssumeCapacity(0); - - const fields = ty.enumFields(); - const values: ?Module.EnumFull.ValueMap = switch (ty.tag()) { - .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values, - .enum_simple => null, - .enum_numbered => ty.castTag(.enum_numbered).?.data.values, - else => unreachable, - }; - for (fields.keys()) |field_name, field_i| { - // DW.AT.enumerator - try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64)); - dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity(field_name); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.const_value, DW.FORM.data8 - const value: u64 = if (values) |vals| value: { - if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered - const value = vals.keys()[field_i]; - var int_buffer: Value.Payload.U64 = undefined; - break :value value.enumToInt(ty, &int_buffer).toUnsignedInt(target); - } else @intCast(u64, field_i); - mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); - } - - // DW.AT.enumeration_type delimit children - try dbg_info_buffer.append(0); - }, - .Union => { - const layout = ty.unionGetLayout(target); - const union_obj = ty.cast(Type.Payload.Union).?.data; - const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0; - const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size; - const is_tagged = layout.tag_size > 0; - const union_name = try ty.nameAllocArena(arena, target); - - // TODO this is temporary to match current state of unions in Zig - we don't yet have - // safety checks implemented meaning the implicit tag is not yet stored and generated - // for untagged unions. - if (is_tagged) { - // DW.AT.structure_type - try dbg_info_buffer.append(abbrev_struct_type); - // DW.AT.byte_size, DW.FORM.sdata - try leb128.writeULEB128(dbg_info_buffer.writer(), layout.abi_size); - // DW.AT.name, DW.FORM.string - try dbg_info_buffer.ensureUnusedCapacity(union_name.len + 1); - dbg_info_buffer.appendSliceAssumeCapacity(union_name); - dbg_info_buffer.appendAssumeCapacity(0); - - // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(9); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity("payload"); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - const inner_union_index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(inner_union_index + 4); - try self.addTypeReloc(atom, ty, @intCast(u32, inner_union_index), 5); - // DW.AT.data_member_location, DW.FORM.sdata - try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset); - } - - // DW.AT.union_type - try dbg_info_buffer.append(abbrev_union_type); - // DW.AT.byte_size, DW.FORM.sdata, - try leb128.writeULEB128(dbg_info_buffer.writer(), layout.payload_size); - // DW.AT.name, DW.FORM.string - if (is_tagged) { - try dbg_info_buffer.writer().print("AnonUnion\x00", .{}); - } else { - try dbg_info_buffer.writer().print("{s}\x00", .{union_name}); - } - - const fields = ty.unionFields(); - for (fields.keys()) |field_name| { - const field = fields.get(field_name).?; - if (!field.ty.hasRuntimeBits()) continue; - // DW.AT.member - try dbg_info_buffer.append(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{s}\x00", .{field_name}); - // DW.AT.type, DW.FORM.ref4 - const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - try dbg_info_buffer.append(0); - } - // DW.AT.union_type delimit children - try dbg_info_buffer.append(0); - - if (is_tagged) { - // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(5); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity("tag"); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, union_obj.tag_ty, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset); - - // DW.AT.structure_type delimit children - try dbg_info_buffer.append(0); - } - }, - .ErrorSet => { - // DW.AT.enumeration_type - try dbg_info_buffer.append(abbrev_enum_type); - // DW.AT.byte_size, DW.FORM.sdata - const abi_size = ty.abiSize(target); - try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); - // DW.AT.name, DW.FORM.string - const name = try ty.nameAllocArena(arena, target); - try dbg_info_buffer.writer().print("{s}\x00", .{name}); - - // DW.AT.enumerator - const no_error = "(no error)"; - try dbg_info_buffer.ensureUnusedCapacity(no_error.len + 2 + @sizeOf(u64)); - dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity(no_error); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.const_value, DW.FORM.data8 - mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian); - - const error_names = ty.errorSetNames(); - for (error_names) |error_name| { - const kv = module.getErrorValue(error_name) catch unreachable; - // DW.AT.enumerator - try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64)); - dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity(error_name); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.const_value, DW.FORM.data8 - mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), kv.value, target_endian); - } - - // DW.AT.enumeration_type delimit children - try dbg_info_buffer.append(0); - }, - .ErrorUnion => { - const error_ty = ty.errorUnionSet(); - const payload_ty = ty.errorUnionPayload(); - const abi_size = ty.abiSize(target); - const abi_align = ty.abiAlignment(target); - const payload_off = mem.alignForwardGeneric(u64, error_ty.abiSize(target), abi_align); - - // DW.AT.structure_type - try dbg_info_buffer.append(abbrev_struct_type); - // DW.AT.byte_size, DW.FORM.sdata - try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); - // DW.AT.name, DW.FORM.string - const name = try ty.nameAllocArena(arena, target); - try dbg_info_buffer.writer().print("{s}\x00", .{name}); - - // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(7); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity("value"); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off); - - // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(5); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity("err"); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null); - // DW.AT.data_member_location, DW.FORM.sdata - try dbg_info_buffer.append(0); - - // DW.AT.structure_type delimit children - try dbg_info_buffer.append(0); - }, - else => { - log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()}); - try dbg_info_buffer.append(abbrev_pad1); - }, - } -} - pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { // These are LEB encoded but since the values are all less than 127 // we can simply append these bytes. @@ -1952,45 +1959,6 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { std.math.maxInt(@TypeOf(actual_size)); } -pub fn addTypeReloc(self: *Dwarf, atom: *const Atom, ty: Type, offset: u32, addend: ?u32) !void { - const decl_state = &self.decl_state.?; - const gpa = self.allocator; - const resolv = decl_state.abbrev_resolver.getContext(ty, .{ - .target = self.target, - }) orelse blk: { - const sym_index = @intCast(u32, decl_state.abbrev_table.items.len); - try decl_state.abbrev_table.append(gpa, .{ - .atom = atom, - .@"type" = ty, - .offset = undefined, - }); - log.debug("@{d}: {}", .{ sym_index, ty.fmtDebug() }); - try decl_state.abbrev_resolver.putNoClobberContext(gpa, ty, sym_index, .{ - .target = self.target, - }); - break :blk decl_state.abbrev_resolver.getContext(ty, .{ - .target = self.target, - }).?; - }; - const add: u32 = addend orelse 0; - - log.debug("{x}: @{d} + {x}", .{ offset, resolv, add }); - try decl_state.abbrev_relocs.append(gpa, .{ - .target = resolv, - .atom = atom, - .offset = offset, - .addend = add, - }); -} - -pub fn getDeclDebugLineBuffer(self: *Dwarf) *std.ArrayList(u8) { - return &self.decl_state.?.dbg_line; -} - -pub fn getDeclDebugInfoBuffer(self: *Dwarf) *std.ArrayList(u8) { - return &self.decl_state.?.dbg_info; -} - pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { if (self.global_abbrev_relocs.items.len > 0) { const gpa = self.allocator; @@ -2018,7 +1986,7 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { }; var dbg_info_buffer = std.ArrayList(u8).init(arena); - try self.addDbgInfoType(arena, module, atom, error_ty, &dbg_info_buffer); + try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer); try self.managed_atoms.append(gpa, atom); try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len)); @@ -2060,6 +2028,49 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { } } } - - assert(self.decl_state == null); +} + +fn addDbgInfoErrorSet( + arena: Allocator, + module: *Module, + ty: Type, + target: std.Target, + dbg_info_buffer: *std.ArrayList(u8), +) !void { + const target_endian = target.cpu.arch.endian(); + + // DW.AT.enumeration_type + try dbg_info_buffer.append(abbrev_enum_type); + // DW.AT.byte_size, DW.FORM.sdata + const abi_size = ty.abiSize(target); + try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); + // DW.AT.name, DW.FORM.string + const name = try ty.nameAllocArena(arena, target); + try dbg_info_buffer.writer().print("{s}\x00", .{name}); + + // DW.AT.enumerator + const no_error = "(no error)"; + try dbg_info_buffer.ensureUnusedCapacity(no_error.len + 2 + @sizeOf(u64)); + dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity(no_error); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.const_value, DW.FORM.data8 + mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian); + + const error_names = ty.errorSetNames(); + for (error_names) |error_name| { + const kv = module.getErrorValue(error_name) catch unreachable; + // DW.AT.enumerator + try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64)); + dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity(error_name); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.const_value, DW.FORM.data8 + mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), kv.value, target_endian); + } + + // DW.AT.enumeration_type delimit children + try dbg_info_buffer.append(0); } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ece30c4347..636b2ba7df 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2339,19 +2339,12 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven const decl = func.owner_decl; self.freeUnnamedConsts(decl); - if (self.dwarf) |*dw| { - try dw.initDeclState(decl); - } - defer if (self.dwarf) |*dw| { - if (dw.decl_state) |*ds| { - ds.deinit(dw.allocator); - dw.decl_state = null; - } - }; + var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(decl) else null; + defer if (decl_state) |*ds| ds.deinit(); - const res = if (self.dwarf) |*dw| + const res = if (decl_state) |*ds| try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ - .dwarf = dw, + .dwarf = ds, }) else try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); @@ -2365,8 +2358,15 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven }, }; const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC); - if (self.dwarf) |*dw| { - try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size); + if (decl_state) |*ds| { + try self.dwarf.?.commitDeclState( + &self.base, + module, + decl, + local_sym.st_value, + local_sym.st_size, + ds, + ); } // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. @@ -2400,18 +2400,17 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - if (self.dwarf) |*dw| { - try dw.initDeclState(decl); - } + var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(decl) else null; + defer if (decl_state) |*ds| ds.deinit(); // TODO implement .debug_info for global variables const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; - const res = if (self.dwarf) |*dw| + const res = if (decl_state) |*ds| try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ .ty = decl.ty, .val = decl_val, }, &code_buffer, .{ - .dwarf = dw, + .dwarf = ds, }, .{ .parent_atom_index = decl.link.elf.local_sym_index, }) @@ -2434,8 +2433,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { }; const local_sym = try self.updateDeclCode(decl, code, elf.STT_OBJECT); - if (self.dwarf) |*dw| { - try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size); + if (decl_state) |*ds| { + try self.dwarf.?.commitDeclState( + &self.base, + module, + decl, + local_sym.st_value, + local_sym.st_size, + ds, + ); } // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 31ada3b4ee..1d75eb442a 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -27,6 +27,7 @@ const Atom = @import("MachO/Atom.zig"); const Cache = @import("../Cache.zig"); const CodeSignature = @import("MachO/CodeSignature.zig"); const Compilation = @import("../Compilation.zig"); +const Dwarf = File.Dwarf; const Dylib = @import("MachO/Dylib.zig"); const File = link.File; const Object = @import("MachO/Object.zig"); @@ -3676,13 +3677,15 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - if (self.d_sym) |*d_sym| { - try d_sym.dwarf.initDeclState(decl); - } + var decl_state = if (self.d_sym) |*d_sym| + try d_sym.dwarf.initDeclState(decl) + else + null; + defer if (decl_state) |*ds| ds.deinit(); - const res = if (self.d_sym) |*d_sym| + const res = if (decl_state) |*ds| try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ - .dwarf = &d_sym.dwarf, + .dwarf = ds, }) else try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); @@ -3700,8 +3703,15 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv const symbol = try self.placeDecl(decl, decl.link.macho.code.items.len); - if (self.d_sym) |*d_sym| { - try d_sym.dwarf.commitDeclState(&self.base, module, decl, symbol.n_value, decl.link.macho.size); + if (decl_state) |*ds| { + try self.d_sym.?.dwarf.commitDeclState( + &self.base, + module, + decl, + symbol.n_value, + decl.link.macho.size, + ds, + ); } // Since we updated the vaddr and the size, each corresponding export symbol also @@ -3801,17 +3811,19 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - if (self.d_sym) |*d_sym| { - try d_sym.dwarf.initDeclState(decl); - } + var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| + try d_sym.dwarf.initDeclState(decl) + else + null; + defer if (decl_state) |*ds| ds.deinit(); const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; - const res = if (self.d_sym) |*d_sym| + const res = if (decl_state) |*ds| try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ .ty = decl.ty, .val = decl_val, }, &code_buffer, .{ - .dwarf = &d_sym.dwarf, + .dwarf = ds, }, .{ .parent_atom_index = decl.link.macho.local_sym_index, }) @@ -3845,8 +3857,15 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { }; const symbol = try self.placeDecl(decl, code.len); - if (self.d_sym) |*d_sym| { - try d_sym.dwarf.commitDeclState(&self.base, module, decl, symbol.n_value, decl.link.macho.size); + if (decl_state) |*ds| { + try self.d_sym.?.dwarf.commitDeclState( + &self.base, + module, + decl, + symbol.n_value, + decl.link.macho.size, + ds, + ); } // Since we updated the vaddr and the size, each corresponding export symbol also