aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-03-28 07:40:33 +0200
committerGitHub <noreply@github.com>2022-03-28 07:40:33 +0200
commitb8cd56dc94f68cda6616b4d9411d0419d2bb909f (patch)
tree57ff6e57dc9b041826e31e6ad7e652b605bedd91 /src
parent7be340e3cc62285d77cbd13f19f4ff0a2a982e82 (diff)
parent366ec2105249050fe88e5fa9f241e14f708db891 (diff)
downloadzig-b8cd56dc94f68cda6616b4d9411d0419d2bb909f.tar.gz
zig-b8cd56dc94f68cda6616b4d9411d0419d2bb909f.zip
Merge pull request #11300 from ziglang/stage2-debug-error-sets
Diffstat (limited to 'src')
-rw-r--r--src/arch/aarch64/Emit.zig23
-rw-r--r--src/arch/arm/Emit.zig73
-rw-r--r--src/arch/riscv64/CodeGen.zig37
-rw-r--r--src/arch/riscv64/Emit.zig23
-rw-r--r--src/arch/x86_64/CodeGen.zig1
-rw-r--r--src/arch/x86_64/Emit.zig81
-rw-r--r--src/codegen.zig38
-rw-r--r--src/link.zig38
-rw-r--r--src/link/Dwarf.zig508
-rw-r--r--src/link/Elf.zig63
-rw-r--r--src/link/MachO.zig72
-rw-r--r--src/link/MachO/Atom.zig2
-rw-r--r--src/link/MachO/DebugSymbols.zig22
13 files changed, 557 insertions, 424 deletions
diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig
index 3eb25dda7b..2a4e6cb985 100644
--- a/src/arch/aarch64/Emit.zig
+++ b/src/arch/aarch64/Emit.zig
@@ -386,18 +386,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
switch (self.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
// 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.
- try dbg_out.dbg_line.ensureUnusedCapacity(11);
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
- leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
+ const dbg_line = dw.getDeclDebugLineBuffer();
+ try dbg_line.ensureUnusedCapacity(11);
+ dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
+ leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
if (delta_line != 0) {
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
- leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
+ dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
+ leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
}
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
+ dbg_line.appendAssumeCapacity(DW.LNS.copy);
self.prev_di_pc = self.code.items.len;
self.prev_di_line = line;
self.prev_di_column = column;
@@ -586,8 +587,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirDebugPrologueEnd(self: *Emit) !void {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
+ .dwarf => |dw| {
+ try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
},
.plan9 => {},
@@ -597,8 +598,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void {
fn mirDebugEpilogueBegin(self: *Emit) !void {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
+ .dwarf => |dw| {
+ try dw.getDeclDebugLineBuffer().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 1e03c4649b..62705651a6 100644
--- a/src/arch/arm/Emit.zig
+++ b/src/arch/arm/Emit.zig
@@ -328,18 +328,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
switch (self.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
// 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.
- try dbg_out.dbg_line.ensureUnusedCapacity(11);
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
- leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
+ const dbg_line = dw.getDeclDebugLineBuffer();
+ try dbg_line.ensureUnusedCapacity(11);
+ dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
+ leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
if (delta_line != 0) {
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
- leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
+ dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
+ leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
}
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
+ dbg_line.appendAssumeCapacity(DW.LNS.copy);
self.prev_di_pc = self.code.items.len;
self.prev_di_line = line;
self.prev_di_column = column;
@@ -379,19 +380,17 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
/// after codegen for this symbol is done.
fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
assert(ty.hasRuntimeBits());
- const index = dbg_out.dbg_info.items.len;
- try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
-
- const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.bin_file.allocator, ty, .{ .target = self.target.* });
- if (!gop.found_existing) {
- gop.value_ptr.* = .{
- .off = undefined,
- .relocs = .{},
- };
- }
- try gop.value_ptr.relocs.append(self.bin_file.allocator, @intCast(u32, index));
+ const dbg_info = dw.getDeclDebugInfoBuffer();
+ 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) {
+ .elf => &self.function.mod_fn.owner_decl.link.elf.dbg_info_atom,
+ .macho => unreachable,
+ else => unreachable,
+ };
+ try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
},
.plan9 => {},
.none => {},
@@ -409,16 +408,17 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
switch (mcv) {
.register => |reg| {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_info.ensureUnusedCapacity(3);
- dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
- dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ .dwarf => |dw| {
+ const dbg_info = dw.getDeclDebugInfoBuffer();
+ try dbg_info.ensureUnusedCapacity(3);
+ dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
});
- try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
@@ -428,7 +428,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
.stack_argument_offset,
=> {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {
return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(target)});
};
@@ -442,7 +442,8 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
else => unreachable,
};
- try dbg_out.dbg_info.append(link.File.Dwarf.abbrev_parameter);
+ const dbg_info = dw.getDeclDebugInfoBuffer();
+ try dbg_info.append(link.File.Dwarf.abbrev_parameter);
// Get length of the LEB128 stack offset
var counting_writer = std.io.countingWriter(std.io.null_writer);
@@ -450,13 +451,13 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
// DW.AT.location, DW.FORM.exprloc
// ULEB128 dwarf expression length
- try leb128.writeULEB128(dbg_out.dbg_info.writer(), counting_writer.bytes_written + 1);
- try dbg_out.dbg_info.append(DW.OP.breg11);
- try leb128.writeILEB128(dbg_out.dbg_info.writer(), adjusted_stack_offset);
+ try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1);
+ try dbg_info.append(DW.OP.breg11);
+ try leb128.writeILEB128(dbg_info.writer(), adjusted_stack_offset);
- try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
@@ -558,8 +559,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirDebugPrologueEnd(emit: *Emit) !void {
switch (emit.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
+ .dwarf => |dw| {
+ try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
},
.plan9 => {},
@@ -569,8 +570,8 @@ fn mirDebugPrologueEnd(emit: *Emit) !void {
fn mirDebugEpilogueBegin(emit: *Emit) !void {
switch (emit.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
+ .dwarf => |dw| {
+ try dw.getDeclDebugLineBuffer().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 8b697677c1..fa243819cf 100644
--- a/src/arch/riscv64/CodeGen.zig
+++ b/src/arch/riscv64/CodeGen.zig
@@ -745,21 +745,17 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
/// after codegen for this symbol is done.
fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
assert(ty.hasRuntimeBits());
- const index = dbg_out.dbg_info.items.len;
- try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
-
- const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.gpa, ty, .{
- .target = self.target.*,
- });
- if (!gop.found_existing) {
- gop.value_ptr.* = .{
- .off = undefined,
- .relocs = .{},
- };
- }
- try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index));
+ const dbg_info = dw.getDeclDebugInfoBuffer();
+ 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) {
+ .elf => &self.mod_fn.owner_decl.link.elf.dbg_info_atom,
+ .macho => unreachable,
+ else => unreachable,
+ };
+ try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
},
.plan9 => {},
.none => {},
@@ -1573,16 +1569,17 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32
switch (mcv) {
.register => |reg| {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_info.ensureUnusedCapacity(3);
- dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
- dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ .dwarf => |dw| {
+ const dbg_info = dw.getDeclDebugInfoBuffer();
+ try dbg_info.ensureUnusedCapacity(3);
+ dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
});
- try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig
index c34d2f4ff4..bfa4e00d00 100644
--- a/src/arch/riscv64/Emit.zig
+++ b/src/arch/riscv64/Emit.zig
@@ -89,18 +89,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
switch (self.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
// 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.
- try dbg_out.dbg_line.ensureUnusedCapacity(11);
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
- leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
+ const dbg_line = dw.getDeclDebugLineBuffer();
+ try dbg_line.ensureUnusedCapacity(11);
+ dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
+ leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
if (delta_line != 0) {
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
- leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
+ dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
+ leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
}
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
+ dbg_line.appendAssumeCapacity(DW.LNS.copy);
self.prev_di_pc = self.code.items.len;
self.prev_di_line = line;
self.prev_di_column = column;
@@ -182,8 +183,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirDebugPrologueEnd(self: *Emit) !void {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
+ .dwarf => |dw| {
+ try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
},
.plan9 => {},
@@ -193,8 +194,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void {
fn mirDebugEpilogueBegin(self: *Emit) !void {
switch (self.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
+ .dwarf => |dw| {
+ try dw.getDeclDebugLineBuffer().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/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 5b252b6c0a..c95e86a424 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -350,6 +350,7 @@ pub fn generate(
var emit = Emit{
.mir = mir,
.bin_file = bin_file,
+ .function = &function,
.debug_output = debug_output,
.target = &bin_file.options.target,
.src_loc = src_loc,
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 3ce77ffb73..4616d3ff3a 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -16,6 +16,7 @@ const testing = std.testing;
const Air = @import("../../Air.zig");
const Allocator = mem.Allocator;
+const CodeGen = @import("CodeGen.zig");
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
const DW = std.dwarf;
const Encoder = bits.Encoder;
@@ -29,6 +30,7 @@ const Type = @import("../../type.zig").Type;
mir: Mir,
bin_file: *link.File,
+function: *const CodeGen,
debug_output: DebugInfoOutput,
target: *const std.Target,
err_msg: ?*ErrorMsg = null,
@@ -963,18 +965,19 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {
const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });
switch (emit.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
// 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.
- try dbg_out.dbg_line.ensureUnusedCapacity(11);
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
- leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
+ const dbg_line = dw.getDeclDebugLineBuffer();
+ try dbg_line.ensureUnusedCapacity(11);
+ dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
+ leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
if (delta_line != 0) {
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
- leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
+ dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
+ leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
}
- dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
+ dbg_line.appendAssumeCapacity(DW.LNS.copy);
emit.prev_di_line = line;
emit.prev_di_column = column;
emit.prev_di_pc = emit.code.items.len;
@@ -1022,8 +1025,8 @@ fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .dbg_prologue_end);
switch (emit.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
+ .dwarf => |dw| {
+ try dw.getDeclDebugLineBuffer().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);
},
@@ -1036,8 +1039,8 @@ fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
const tag = emit.mir.instructions.items(.tag)[inst];
assert(tag == .dbg_epilogue_begin);
switch (emit.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
+ .dwarf => |dw| {
+ try dw.getDeclDebugLineBuffer().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);
},
@@ -1063,16 +1066,17 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32
switch (mcv) {
.register => |reg| {
switch (emit.debug_output) {
- .dwarf => |dbg_out| {
- try dbg_out.dbg_info.ensureUnusedCapacity(3);
- dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
- dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ .dwarf => |dw| {
+ const dbg_info = dw.getDeclDebugInfoBuffer();
+ try dbg_info.ensureUnusedCapacity(3);
+ dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
});
- try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
@@ -1080,25 +1084,26 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32
},
.stack_offset => |off| {
switch (emit.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
// we add here +16 like we do in airArg in CodeGen since we refer directly to
// rbp as the start of function frame minus 8 bytes for caller's rbp preserved in the
// prologue, and 8 bytes for return address.
// 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;
- try dbg_out.dbg_info.ensureUnusedCapacity(8);
- dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
- const fixup = dbg_out.dbg_info.items.len;
- dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ const dbg_info = dw.getDeclDebugInfoBuffer();
+ try dbg_info.ensureUnusedCapacity(8);
+ dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
+ const fixup = dbg_info.items.len;
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // we will backpatch it after we encode the displacement in LEB128
DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
});
- leb128.writeILEB128(dbg_out.dbg_info.writer(), disp) catch unreachable;
- dbg_out.dbg_info.items[fixup] += @intCast(u8, dbg_out.dbg_info.items.len - fixup - 2);
- try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ leb128.writeILEB128(dbg_info.writer(), disp) catch unreachable;
+ dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
@@ -1113,21 +1118,17 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32
/// after codegen for this symbol is done.
fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
switch (emit.debug_output) {
- .dwarf => |dbg_out| {
+ .dwarf => |dw| {
assert(ty.hasRuntimeBits());
- const index = dbg_out.dbg_info.items.len;
- try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
-
- const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(emit.bin_file.allocator, ty, .{
- .target = emit.target.*,
- });
- if (!gop.found_existing) {
- gop.value_ptr.* = .{
- .off = undefined,
- .relocs = .{},
- };
- }
- try gop.value_ptr.relocs.append(emit.bin_file.allocator, @intCast(u32, index));
+ const dbg_info = dw.getDeclDebugInfoBuffer();
+ 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) {
+ .elf => &emit.function.mod_fn.owner_decl.link.elf.dbg_info_atom,
+ .macho => &emit.function.mod_fn.owner_decl.link.macho.dbg_info_atom,
+ else => unreachable,
+ };
+ try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
},
.plan9 => {},
.none => {},
diff --git a/src/codegen.zig b/src/codegen.zig
index cc7014a136..fa84ad0d52 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -1,26 +1,25 @@
const std = @import("std");
+const build_options = @import("build_options");
const builtin = @import("builtin");
+const assert = std.debug.assert;
+const leb128 = std.leb;
+const link = @import("link.zig");
+const log = std.log.scoped(.codegen);
const mem = std.mem;
const math = std.math;
-const assert = std.debug.assert;
+const trace = @import("tracy.zig").trace;
+
const Air = @import("Air.zig");
-const Zir = @import("Zir.zig");
-const Liveness = @import("Liveness.zig");
-const Type = @import("type.zig").Type;
-const Value = @import("value.zig").Value;
-const TypedValue = @import("TypedValue.zig");
-const link = @import("link.zig");
-const Module = @import("Module.zig");
+const Allocator = mem.Allocator;
const Compilation = @import("Compilation.zig");
const ErrorMsg = Module.ErrorMsg;
+const Liveness = @import("Liveness.zig");
+const Module = @import("Module.zig");
const Target = std.Target;
-const Allocator = mem.Allocator;
-const trace = @import("tracy.zig").trace;
-const DW = std.dwarf;
-const leb128 = std.leb;
-const log = std.log.scoped(.codegen);
-const build_options = @import("build_options");
-const RegisterManager = @import("register_manager.zig").RegisterManager;
+const Type = @import("type.zig").Type;
+const TypedValue = @import("TypedValue.zig");
+const Value = @import("value.zig").Value;
+const Zir = @import("Zir.zig");
pub const FnResult = union(enum) {
/// The `code` parameter passed to `generateSymbol` has the value appended.
@@ -43,11 +42,7 @@ pub const GenerateSymbolError = error{
};
pub const DebugInfoOutput = union(enum) {
- dwarf: struct {
- dbg_line: *std.ArrayList(u8),
- dbg_info: *std.ArrayList(u8),
- dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
- },
+ dwarf: *link.File.Dwarf,
/// 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
@@ -573,7 +568,6 @@ pub fn generateSymbol(
return Result{ .appended = {} };
},
.Union => {
- // TODO generate debug info for unions
const union_obj = typed_value.val.castTag(.@"union").?.data;
const layout = typed_value.ty.unionGetLayout(target);
@@ -695,7 +689,6 @@ pub fn generateSymbol(
return Result{ .appended = {} };
},
.ErrorUnion => {
- // TODO generate debug info for error unions
const error_ty = typed_value.ty.errorUnionSet();
const payload_ty = typed_value.ty.errorUnionPayload();
const is_payload = typed_value.val.errorUnionIsPayload();
@@ -749,7 +742,6 @@ pub fn generateSymbol(
return Result{ .appended = {} };
},
.ErrorSet => {
- // TODO generate debug info for error sets
switch (typed_value.val.tag()) {
.@"error" => {
const name = typed_value.val.getError().?;
diff --git a/src/link.zig b/src/link.zig
index 0fd6797153..7c135a7405 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -1,22 +1,22 @@
const std = @import("std");
+const build_options = @import("build_options");
const builtin = @import("builtin");
-const mem = std.mem;
-const Allocator = std.mem.Allocator;
+const assert = std.debug.assert;
const fs = std.fs;
+const mem = std.mem;
const log = std.log.scoped(.link);
-const assert = std.debug.assert;
+const trace = @import("tracy.zig").trace;
+const wasi_libc = @import("wasi_libc.zig");
+const Air = @import("Air.zig");
+const Allocator = std.mem.Allocator;
+const Cache = @import("Cache.zig");
const Compilation = @import("Compilation.zig");
+const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
+const Liveness = @import("Liveness.zig");
const Module = @import("Module.zig");
-const trace = @import("tracy.zig").trace;
const Package = @import("Package.zig");
const Type = @import("type.zig").Type;
-const Cache = @import("Cache.zig");
-const build_options = @import("build_options");
-const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
-const wasi_libc = @import("wasi_libc.zig");
-const Air = @import("Air.zig");
-const Liveness = @import("Liveness.zig");
const TypedValue = @import("TypedValue.zig");
pub const SystemLib = struct {
@@ -245,24 +245,6 @@ pub const File = struct {
nvptx: void,
};
- /// For DWARF .debug_info.
- pub const DbgInfoTypeRelocsTable = std.ArrayHashMapUnmanaged(
- Type,
- DbgInfoTypeReloc,
- Type.HashContext32,
- true,
- );
-
- /// For DWARF .debug_info.
- pub const DbgInfoTypeReloc = struct {
- /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
- /// This is where the .debug_info tag for the type is.
- off: u32,
- /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
- /// List of DW.AT.type / DW.FORM.ref4 that points to the type.
- relocs: std.ArrayListUnmanaged(u32),
- };
-
/// Attempts incremental linking, if the file already exists. If
/// incremental linking fails, falls back to truncating the file and
/// rewriting it. A malicious file is detected as incremental link failure
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
index 370aac2734..83222090c0 100644
--- a/src/link/Dwarf.zig
+++ b/src/link/Dwarf.zig
@@ -31,27 +31,89 @@ dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{},
dbg_line_fn_first: ?*SrcFn = null,
dbg_line_fn_last: ?*SrcFn = null,
-/// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity. /// This is the same concept as `text_block_free_list`; see those doc comments.
-dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*DebugInfoAtom, void) = .{},
-dbg_info_decl_first: ?*DebugInfoAtom = null,
-dbg_info_decl_last: ?*DebugInfoAtom = null,
+/// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity.
+/// This is the same concept as `text_block_free_list`; see those doc comments.
+atom_free_list: std.AutoHashMapUnmanaged(*Atom, void) = .{},
+atom_first: ?*Atom = null,
+atom_last: ?*Atom = null,
abbrev_table_offset: ?u64 = null,
+/// TODO replace with InternArena
/// Table of debug symbol names.
strtab: std.ArrayListUnmanaged(u8) = .{},
-pub const DebugInfoAtom = struct {
+/// 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.
+managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
+
+global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
+
+pub const Atom = struct {
/// Previous/next linked list pointers.
/// This is the linked list node for this Decl's corresponding .debug_info tag.
- prev: ?*DebugInfoAtom,
- next: ?*DebugInfoAtom,
+ prev: ?*Atom,
+ next: ?*Atom,
/// Offset into .debug_info pointing to the tag for this Decl.
off: u32,
/// Size of the .debug_info tag for this Decl, not including padding.
len: u32,
};
+/// Represents state of the analysed Decl.
+/// Includes Decl's abbrev table of type Types, matching arena
+/// 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 {
+ dbg_line: std.ArrayList(u8),
+ dbg_info: std.ArrayList(u8),
+ abbrev_type_arena: std.heap.ArenaAllocator,
+ abbrev_table: std.ArrayListUnmanaged(AbbrevEntry) = .{},
+ abbrev_resolver: std.HashMapUnmanaged(
+ Type,
+ u32,
+ Type.HashContext64,
+ std.hash_map.default_max_load_percentage,
+ ) = .{},
+ abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
+
+ fn init(gpa: Allocator) DeclState {
+ return .{
+ .dbg_line = std.ArrayList(u8).init(gpa),
+ .dbg_info = std.ArrayList(u8).init(gpa),
+ .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),
+ };
+ }
+
+ fn deinit(self: *DeclState, gpa: Allocator) 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);
+ }
+};
+
+pub const AbbrevEntry = struct {
+ atom: *const Atom,
+ @"type": Type,
+ offset: u32,
+};
+
+pub const AbbrevRelocation = struct {
+ target: u32,
+ atom: *const Atom,
+ offset: u32,
+ addend: u32,
+};
+
pub const SrcFn = struct {
/// Offset from the beginning of the Debug Line Program header that contains this function.
off: u32,
@@ -117,29 +179,32 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf {
pub fn deinit(self: *Dwarf) void {
const gpa = self.allocator;
self.dbg_line_fn_free_list.deinit(gpa);
- self.dbg_info_decl_free_list.deinit(gpa);
+ self.atom_free_list.deinit(gpa);
self.strtab.deinit(gpa);
-}
+ self.global_abbrev_relocs.deinit(gpa);
-pub const DeclDebugBuffers = struct {
- dbg_line_buffer: std.ArrayList(u8),
- dbg_info_buffer: std.ArrayList(u8),
- dbg_info_type_relocs: File.DbgInfoTypeRelocsTable,
-};
+ for (self.managed_atoms.items) |atom| {
+ gpa.destroy(atom);
+ }
+ self.managed_atoms.deinit(gpa);
+}
-pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {
+/// Initializes Decl's state and its matching output buffers.
+/// Call this before `commitDeclState`.
+pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !void {
const tracy = trace(@src());
defer tracy.end();
const decl_name = try decl.getFullyQualifiedName(self.allocator);
defer self.allocator.free(decl_name);
- log.debug("initDeclDebugInfo {s}{*}", .{ decl_name, decl });
+ log.debug("initDeclState {s}{*}", .{ decl_name, decl });
const gpa = self.allocator;
- var dbg_line_buffer = std.ArrayList(u8).init(gpa);
- var dbg_info_buffer = std.ArrayList(u8).init(gpa);
- var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
+ 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;
assert(decl.has_tv);
@@ -202,19 +267,17 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {
dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT.low_pc, DW.FORM.addr
assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
+ //
if (fn_ret_has_bits) {
- const gop = try dbg_info_type_relocs.getOrPutContext(gpa, fn_ret_type, .{
- .target = self.target,
- });
- if (!gop.found_existing) {
- gop.value_ptr.* = .{
- .off = undefined,
- .relocs = .{},
- };
- }
- try gop.value_ptr.relocs.append(gpa, @intCast(u32, dbg_info_buffer.items.len));
+ const atom = switch (self.tag) {
+ .elf => &decl.link.elf.dbg_info_atom,
+ .macho => &decl.link.macho.dbg_info_atom,
+ else => unreachable,
+ };
+ try self.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
}
+
dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string
},
@@ -222,30 +285,28 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {
// TODO implement .debug_info for global variables
},
}
-
- return DeclDebugBuffers{
- .dbg_info_buffer = dbg_info_buffer,
- .dbg_line_buffer = dbg_line_buffer,
- .dbg_info_type_relocs = dbg_info_type_relocs,
- };
}
-pub fn commitDeclDebugInfo(
+pub fn commitDeclState(
self: *Dwarf,
file: *File,
module: *Module,
decl: *Module.Decl,
sym_addr: u64,
sym_size: u64,
- debug_buffers: *DeclDebugBuffers,
) !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 = &debug_buffers.dbg_line_buffer;
- var dbg_info_buffer = &debug_buffers.dbg_info_buffer;
- var dbg_info_type_relocs = &debug_buffers.dbg_info_type_relocs;
+ var dbg_line_buffer = &self.decl_state.?.dbg_line;
+ var dbg_info_buffer = &self.decl_state.?.dbg_info;
const target_endian = self.target.cpu.arch.endian();
@@ -443,68 +504,65 @@ pub fn commitDeclDebugInfo(
if (dbg_info_buffer.items.len == 0)
return;
- // We need this for the duration of this function only so that for composite
- // types such as []const u32, if the type *u32 is non-existent, we create
- // it synthetically and store the backing bytes in this arena. After we are
- // done with the relocations, we can safely deinit the entire memory slab.
- // TODO currently, we do not store the relocations for future use, however,
- // if that is the case, we should move memory management to a higher scope,
- // such as linker scope, or whatnot.
- var dbg_type_arena = std.heap.ArenaAllocator.init(gpa);
- defer dbg_type_arena.deinit();
-
- var nested_ref4_relocs = std.ArrayList(u32).init(gpa);
- defer nested_ref4_relocs.deinit();
+ const atom = switch (self.tag) {
+ .elf => &decl.link.elf.dbg_info_atom,
+ .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
// the buffer, so we have to do it before computing the offset, and we can't perform the actual
// relocations yet.
- var it: usize = 0;
- while (it < dbg_info_type_relocs.count()) : (it += 1) {
- const ty = dbg_info_type_relocs.keys()[it];
- const value_ptr = dbg_info_type_relocs.getPtrContext(ty, .{
- .target = self.target,
- }).?;
- value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
- try self.addDbgInfoType(
- dbg_type_arena.allocator(),
- ty,
- dbg_info_buffer,
- dbg_info_type_relocs,
- &nested_ref4_relocs,
- );
+ var sym_index: usize = 0;
+ while (sym_index < decl_state.abbrev_table.items.len) : (sym_index += 1) {
+ const symbol = &decl_state.abbrev_table.items[sym_index];
+ const ty = symbol.@"type";
+ const deferred: bool = blk: {
+ if (ty.isAnyError()) break :blk true;
+ switch (ty.tag()) {
+ .error_set_inferred => {
+ if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true;
+ },
+ else => {},
+ }
+ break :blk false;
+ };
+ 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);
}
}
- const atom = switch (self.tag) {
- .elf => &decl.link.elf.dbg_info_atom,
- .macho => &decl.link.macho.dbg_info_atom,
- else => unreachable,
- };
try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
- {
- // Now that we have the offset assigned we can finally perform type relocations.
- for (dbg_info_type_relocs.values()) |value| {
- for (value.relocs.items) |off| {
- mem.writeInt(
- u32,
- dbg_info_buffer.items[off..][0..4],
- atom.off + value.off,
- target_endian,
- );
+ while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
+ const symbol = decl_state.abbrev_table.items[reloc.target];
+ const ty = symbol.@"type";
+ const deferred: bool = blk: {
+ if (ty.isAnyError()) break :blk true;
+ switch (ty.tag()) {
+ .error_set_inferred => {
+ if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true;
+ },
+ else => {},
}
- }
- // Offsets to positions with known a priori relative displacement values.
- // Here, we just need to add the offset of the atom to the read value in the
- // relocated cell.
- // TODO Should probably generalise this with type relocs.
- for (nested_ref4_relocs.items) |off| {
- const addend = mem.readInt(u32, dbg_info_buffer.items[off..][0..4], target_endian);
+ break :blk false;
+ };
+ if (deferred) {
+ try self.global_abbrev_relocs.append(gpa, .{
+ .target = undefined,
+ .offset = reloc.offset,
+ .atom = reloc.atom,
+ .addend = reloc.addend,
+ });
+ } else {
mem.writeInt(
u32,
- dbg_info_buffer.items[off..][0..4],
- atom.off + addend,
+ dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
+ symbol.atom.off + symbol.offset + reloc.addend,
target_endian,
);
}
@@ -513,7 +571,7 @@ pub fn commitDeclDebugInfo(
try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
}
-fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom, len: u32) !void {
+fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u32) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -523,14 +581,14 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom
const gpa = self.allocator;
atom.len = len;
- if (self.dbg_info_decl_last) |last| blk: {
+ if (self.atom_last) |last| blk: {
if (atom == last) break :blk;
if (atom.next) |next| {
// Update existing Decl - non-last item.
if (atom.off + atom.len + min_nop_size > next.off) {
// It grew too big, so we move it to a new location.
if (atom.prev) |prev| {
- self.dbg_info_decl_free_list.put(gpa, prev, {}) catch {};
+ self.atom_free_list.put(gpa, prev, {}) catch {};
prev.next = atom.next;
}
next.prev = atom.prev;
@@ -556,7 +614,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom
// TODO Look at the free list before appending at the end.
atom.prev = last;
last.next = atom;
- self.dbg_info_decl_last = atom;
+ self.atom_last = atom;
atom.off = last.off + padToIdeal(last.len);
}
@@ -565,20 +623,20 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom
// TODO Look at the free list before appending at the end.
atom.prev = last;
last.next = atom;
- self.dbg_info_decl_last = atom;
+ self.atom_last = atom;
atom.off = last.off + padToIdeal(last.len);
}
} else {
// This is the first Decl of the .debug_info
- self.dbg_info_decl_first = atom;
- self.dbg_info_decl_last = atom;
+ self.atom_first = atom;
+ self.atom_last = atom;
atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes()));
}
}
-fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *DebugInfoAtom, dbg_info_buf: []const u8) !void {
+fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []const u8) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -587,7 +645,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *DebugInfoAtom, dbg_info_
// probably need to edit that logic too.
const gpa = self.allocator;
- const last_decl = self.dbg_info_decl_last.?;
+ const last_decl = self.atom_last.?;
// +1 for a trailing zero to end the children of the decl tag.
const needed_size = last_decl.off + last_decl.len + 1;
const prev_padding_size: u32 = if (atom.prev) |prev| atom.off - (prev.off + prev.len) else 0;
@@ -712,13 +770,13 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)
}
}
-pub fn freeAtom(self: *Dwarf, atom: *DebugInfoAtom) void {
- if (self.dbg_info_decl_first == atom) {
- self.dbg_info_decl_first = atom.next;
+pub fn freeAtom(self: *Dwarf, atom: *Atom) void {
+ if (self.atom_first == atom) {
+ self.atom_first = atom.next;
}
- if (self.dbg_info_decl_last == atom) {
+ if (self.atom_last == atom) {
// TODO shrink the .debug_info section size here
- self.dbg_info_decl_last = atom.prev;
+ self.atom_last = atom.prev;
}
if (atom.prev) |prev| {
@@ -771,14 +829,13 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {
fn addDbgInfoType(
self: *Dwarf,
arena: Allocator,
+ module: *Module,
+ atom: *Atom,
ty: Type,
dbg_info_buffer: *std.ArrayList(u8),
- dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
- nested_ref4_relocs: *std.ArrayList(u32),
) error{OutOfMemory}!void {
const target = self.target;
const target_endian = self.target.cpu.arch.endian();
- var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena);
switch (ty.zigTypeTag()) {
.NoReturn => unreachable,
@@ -837,7 +894,7 @@ fn addDbgInfoType(
// DW.AT.type, DW.FORM.ref4
var index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = Type.bool, .reloc = @intCast(u32, index) });
+ 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);
@@ -849,7 +906,7 @@ fn addDbgInfoType(
// DW.AT.type, DW.FORM.ref4
index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = payload_ty, .reloc = @intCast(u32, index) });
+ 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);
@@ -878,7 +935,7 @@ fn addDbgInfoType(
try dbg_info_buffer.resize(index + 4);
var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
const ptr_ty = ty.slicePtrFieldType(buf);
- try relocs.append(.{ .ty = ptr_ty, .reloc = @intCast(u32, index) });
+ 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);
@@ -890,7 +947,7 @@ fn addDbgInfoType(
// DW.AT.type, DW.FORM.ref4
index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = Type.initTag(.usize), .reloc = @intCast(u32, index) });
+ 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));
@@ -902,7 +959,7 @@ fn addDbgInfoType(
// DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = ty.childType(), .reloc = @intCast(u32, index) });
+ try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);
}
},
.Struct => blk: {
@@ -926,7 +983,7 @@ fn addDbgInfoType(
// DW.AT.type, DW.FORM.ref4
var index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = field, .reloc = @intCast(u32, index) });
+ 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);
@@ -957,7 +1014,7 @@ fn addDbgInfoType(
// DW.AT.type, DW.FORM.ref4
var index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) });
+ 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);
@@ -1036,14 +1093,8 @@ fn addDbgInfoType(
dbg_info_buffer.appendAssumeCapacity(0);
// DW.AT.type, DW.FORM.ref4
const inner_union_index = dbg_info_buffer.items.len;
- try dbg_info_buffer.ensureUnusedCapacity(4);
- mem.writeInt(
- u32,
- dbg_info_buffer.addManyAsArrayAssumeCapacity(4),
- @intCast(u32, inner_union_index + 5),
- target_endian,
- );
- try nested_ref4_relocs.append(@intCast(u32, inner_union_index));
+ 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);
}
@@ -1070,7 +1121,7 @@ fn addDbgInfoType(
// DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) });
+ try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null);
// DW.AT.data_member_location, DW.FORM.sdata
try dbg_info_buffer.append(0);
}
@@ -1087,7 +1138,7 @@ fn addDbgInfoType(
// DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4);
- try relocs.append(.{ .ty = union_obj.tag_ty, .reloc = @intCast(u32, index) });
+ 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);
@@ -1095,24 +1146,91 @@ fn addDbgInfoType(
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);
},
}
-
- for (relocs.items) |rel| {
- const gop = try dbg_info_type_relocs.getOrPutContext(self.allocator, rel.ty, .{
- .target = self.target,
- });
- if (!gop.found_existing) {
- gop.value_ptr.* = .{
- .off = undefined,
- .relocs = .{},
- };
- }
- try gop.value_ptr.relocs.append(self.allocator, rel.reloc);
- }
}
pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
@@ -1763,12 +1881,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
}
fn getDebugInfoOff(self: Dwarf) ?u32 {
- const first = self.dbg_info_decl_first orelse return null;
+ const first = self.atom_first orelse return null;
return first.off;
}
fn getDebugInfoEnd(self: Dwarf) ?u32 {
- const last = self.dbg_info_decl_last orelse return null;
+ const last = self.atom_last orelse return null;
return last.off + last.len;
}
@@ -1833,3 +1951,115 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
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;
+ var arena_alloc = std.heap.ArenaAllocator.init(gpa);
+ defer arena_alloc.deinit();
+ const arena = arena_alloc.allocator();
+
+ const error_set = try arena.create(Module.ErrorSet);
+ const error_ty = try Type.Tag.error_set.create(arena, error_set);
+ var names = Module.ErrorSet.NameMap{};
+ try names.ensureUnusedCapacity(arena, module.global_error_set.count());
+ var it = module.global_error_set.keyIterator();
+ while (it.next()) |key| {
+ names.putAssumeCapacityNoClobber(key.*, {});
+ }
+ error_set.names = names;
+
+ const atom = try gpa.create(Atom);
+ errdefer gpa.destroy(atom);
+ atom.* = .{
+ .prev = null,
+ .next = null,
+ .off = 0,
+ .len = 0,
+ };
+
+ var dbg_info_buffer = std.ArrayList(u8).init(arena);
+ try self.addDbgInfoType(arena, module, atom, error_ty, &dbg_info_buffer);
+
+ try self.managed_atoms.append(gpa, atom);
+ try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
+ try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
+
+ const file_pos = blk: {
+ switch (self.tag) {
+ .elf => {
+ const elf_file = file.cast(File.Elf).?;
+ const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
+ break :blk debug_info_sect.sh_offset;
+ },
+ .macho => {
+ const macho_file = file.cast(File.MachO).?;
+ const d_sym = &macho_file.d_sym.?;
+ const dwarf_segment = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;
+ const debug_info_sect = &dwarf_segment.sections.items[d_sym.debug_info_section_index.?];
+ break :blk debug_info_sect.offset;
+ },
+ else => unreachable,
+ }
+ };
+
+ var buf: [@sizeOf(u32)]u8 = undefined;
+ mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian());
+
+ while (self.global_abbrev_relocs.popOrNull()) |reloc| {
+ switch (self.tag) {
+ .elf => {
+ const elf_file = file.cast(File.Elf).?;
+ try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
+ },
+ .macho => {
+ const macho_file = file.cast(File.MachO).?;
+ const d_sym = &macho_file.d_sym.?;
+ try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
+ },
+ else => unreachable,
+ }
+ }
+ }
+
+ assert(self.decl_state == null);
+}
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 64d6df6756..771a57b26e 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -207,7 +207,7 @@ pub const TextBlock = struct {
prev: ?*TextBlock,
next: ?*TextBlock,
- dbg_info_atom: Dwarf.DebugInfoAtom,
+ dbg_info_atom: Dwarf.Atom,
pub const empty = TextBlock{
.local_sym_index = 0,
@@ -958,6 +958,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
const target_endian = self.base.options.target.cpu.arch.endian();
const foreign_endian = target_endian != builtin.cpu.arch.endian();
+ if (self.dwarf) |*dw| {
+ try dw.flushModule(&self.base, module);
+ }
+
{
var it = self.relocs.iterator();
while (it.next()) |entry| {
@@ -2228,13 +2232,6 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
}
}
-fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {
- for (table.values()) |*value| {
- value.relocs.deinit(gpa);
- }
- table.deinit(gpa);
-}
-
fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 {
const ty = decl.ty;
const zig_ty = ty.zigTypeTag();
@@ -2342,26 +2339,13 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
const decl = func.owner_decl;
self.freeUnnamedConsts(decl);
- var debug_buffers_buf: Dwarf.DeclDebugBuffers = undefined;
- const debug_buffers = if (self.dwarf) |*dw| blk: {
- debug_buffers_buf = try dw.initDeclDebugInfo(decl);
- break :blk &debug_buffers_buf;
- } else null;
- defer {
- if (debug_buffers) |dbg| {
- dbg.dbg_line_buffer.deinit();
- dbg.dbg_info_buffer.deinit();
- deinitRelocs(self.base.allocator, &dbg.dbg_info_type_relocs);
- }
+ if (self.dwarf) |*dw| {
+ try dw.initDeclState(decl);
}
- const res = if (debug_buffers) |dbg|
+ const res = if (self.dwarf) |*dw|
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
- .dwarf = .{
- .dbg_line = &dbg.dbg_line_buffer,
- .dbg_info = &dbg.dbg_info_buffer,
- .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
- },
+ .dwarf = dw,
})
else
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
@@ -2375,8 +2359,8 @@ 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 (debug_buffers) |dbg| {
- try self.dwarf.?.commitDeclDebugInfo(&self.base, module, decl, local_sym.st_value, local_sym.st_size, dbg);
+ if (self.dwarf) |*dw| {
+ try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size);
}
// Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
@@ -2410,31 +2394,18 @@ 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();
- var debug_buffers_buf: Dwarf.DeclDebugBuffers = undefined;
- const debug_buffers = if (self.dwarf) |*dw| blk: {
- debug_buffers_buf = try dw.initDeclDebugInfo(decl);
- break :blk &debug_buffers_buf;
- } else null;
- defer {
- if (debug_buffers) |dbg| {
- dbg.dbg_line_buffer.deinit();
- dbg.dbg_info_buffer.deinit();
- deinitRelocs(self.base.allocator, &dbg.dbg_info_type_relocs);
- }
+ if (self.dwarf) |*dw| {
+ try dw.initDeclState(decl);
}
// 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 (debug_buffers) |dbg|
+ const res = if (self.dwarf) |*dw|
try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
.ty = decl.ty,
.val = decl_val,
}, &code_buffer, .{
- .dwarf = .{
- .dbg_line = &dbg.dbg_line_buffer,
- .dbg_info = &dbg.dbg_info_buffer,
- .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
- },
+ .dwarf = dw,
}, .{
.parent_atom_index = decl.link.elf.local_sym_index,
})
@@ -2457,8 +2428,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
};
const local_sym = try self.updateDeclCode(decl, code, elf.STT_OBJECT);
- if (debug_buffers) |dbg| {
- try self.dwarf.?.commitDeclDebugInfo(&self.base, module, decl, local_sym.st_value, local_sym.st_size, dbg);
+ if (self.dwarf) |*dw| {
+ try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size);
}
// 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 e613772f22..31ada3b4ee 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -453,6 +453,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
+ if (self.d_sym) |*d_sym| {
+ if (self.base.options.module) |module| {
+ try d_sym.dwarf.flushModule(&self.base, module);
+ }
+ }
+
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
@@ -3670,32 +3676,17 @@ 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();
- var debug_buffers_buf: link.File.Dwarf.DeclDebugBuffers = undefined;
- const debug_buffers = if (self.d_sym) |*d_sym| blk: {
- debug_buffers_buf = try d_sym.initDeclDebugInfo(module, decl);
- break :blk &debug_buffers_buf;
- } else null;
- defer {
- if (debug_buffers) |dbg| {
- dbg.dbg_line_buffer.deinit();
- dbg.dbg_info_buffer.deinit();
- for (dbg.dbg_info_type_relocs.values()) |*value| {
- value.relocs.deinit(self.base.allocator);
- }
- dbg.dbg_info_type_relocs.deinit(self.base.allocator);
- }
+ if (self.d_sym) |*d_sym| {
+ try d_sym.dwarf.initDeclState(decl);
}
- const res = if (debug_buffers) |dbg|
+ const res = if (self.d_sym) |*d_sym|
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
- .dwarf = .{
- .dbg_line = &dbg.dbg_line_buffer,
- .dbg_info = &dbg.dbg_info_buffer,
- .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
- },
+ .dwarf = &d_sym.dwarf,
})
else
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
+
switch (res) {
.appended => {
try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);
@@ -3707,12 +3698,10 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
},
}
- _ = try self.placeDecl(decl, decl.link.macho.code.items.len);
+ const symbol = try self.placeDecl(decl, decl.link.macho.code.items.len);
- if (debug_buffers) |db| {
- if (self.d_sym) |*d_sym| {
- try d_sym.commitDeclDebugInfo(module, decl, db);
- }
+ if (self.d_sym) |*d_sym| {
+ try d_sym.dwarf.commitDeclState(&self.base, module, decl, symbol.n_value, decl.link.macho.size);
}
// Since we updated the vaddr and the size, each corresponding export symbol also
@@ -3812,33 +3801,17 @@ 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();
- var debug_buffers_buf: link.File.Dwarf.DeclDebugBuffers = undefined;
- const debug_buffers = if (self.d_sym) |*d_sym| blk: {
- debug_buffers_buf = try d_sym.initDeclDebugInfo(module, decl);
- break :blk &debug_buffers_buf;
- } else null;
- defer {
- if (debug_buffers) |dbg| {
- dbg.dbg_line_buffer.deinit();
- dbg.dbg_info_buffer.deinit();
- for (dbg.dbg_info_type_relocs.values()) |*value| {
- value.relocs.deinit(self.base.allocator);
- }
- dbg.dbg_info_type_relocs.deinit(self.base.allocator);
- }
+ if (self.d_sym) |*d_sym| {
+ try d_sym.dwarf.initDeclState(decl);
}
const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
- const res = if (debug_buffers) |dbg|
+ const res = if (self.d_sym) |*d_sym|
try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
.ty = decl.ty,
.val = decl_val,
}, &code_buffer, .{
- .dwarf = .{
- .dbg_line = &dbg.dbg_line_buffer,
- .dbg_info = &dbg.dbg_info_buffer,
- .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
- },
+ .dwarf = &d_sym.dwarf,
}, .{
.parent_atom_index = decl.link.macho.local_sym_index,
})
@@ -3870,7 +3843,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
},
}
};
- _ = try self.placeDecl(decl, code.len);
+ 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);
+ }
// Since we updated the vaddr and the size, each corresponding export symbol also
// needs to be updated.
@@ -4084,8 +4061,9 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
}
pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
+ _ = module;
if (self.d_sym) |*d_sym| {
- try d_sym.updateDeclLineNumber(module, decl);
+ try d_sym.dwarf.updateDeclLineNumber(&self.base, decl);
}
}
diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig
index 4e58946735..dd2dc3c1f1 100644
--- a/src/link/MachO/Atom.zig
+++ b/src/link/MachO/Atom.zig
@@ -72,7 +72,7 @@ stab: ?Stab = null,
next: ?*Atom,
prev: ?*Atom,
-dbg_info_atom: Dwarf.DebugInfoAtom,
+dbg_info_atom: Dwarf.Atom,
dirty: bool = true,
diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig
index 9fc2828ea1..885f0ca6a8 100644
--- a/src/link/MachO/DebugSymbols.zig
+++ b/src/link/MachO/DebugSymbols.zig
@@ -645,25 +645,3 @@ fn writeStringTable(self: *DebugSymbols) !void {
self.load_commands_dirty = true;
}
-
-pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const Module.Decl) !void {
- _ = module;
- return self.dwarf.updateDeclLineNumber(&self.base.base, decl);
-}
-
-/// Caller owns the returned memory.
-pub fn initDeclDebugInfo(self: *DebugSymbols, module: *Module, decl: *Module.Decl) !Dwarf.DeclDebugBuffers {
- _ = module;
- return self.dwarf.initDeclDebugInfo(decl);
-}
-
-pub fn commitDeclDebugInfo(
- self: *DebugSymbols,
- module: *Module,
- decl: *Module.Decl,
- debug_buffers: *Dwarf.DeclDebugBuffers,
-) !void {
- const symbol = self.base.locals.items[decl.link.macho.local_sym_index];
- const atom = &decl.link.macho;
- return self.dwarf.commitDeclDebugInfo(&self.base.base, module, decl, symbol.n_value, atom.size, debug_buffers);
-}