Commit f5d9160f1b
Changed files (9)
src
arch
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 => {},
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 => {},
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
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 => {},
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) {
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 {
}
}
}
+}
+
+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);
+ }
- assert(self.decl_state == null);
+ // DW.AT.enumeration_type delimit children
+ try dbg_info_buffer.append(0);
}
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.
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
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