dwarf: pass DeclState around instead of storing a temp global in Dwarf

Avoids many pitfalls connected with premature/early return in case
there are errors with Decl, etc. This is effectively bringing back
the old design however in a much nicer packaging, where every
mechanism related to tracking Decl's debug info is now nicely
wrapped in a single struct (aka the `DeclState`). This includes
relocation table, type arena, etc. It is now the caller's
responsibility to deinit the state (so that no memory is leaked)
after `Decl` has been analysed (or errored out). The caller here
is typically a linker such as `Elf` or `MachO`.
This commit is contained in:
Jakub Konka 2022-03-30 11:03:50 +02:00 committed by Andrew Kelley
parent b73cf97c93
commit f5d9160f1b
9 changed files with 567 additions and 531 deletions

View File

@ -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 => {},

View File

@ -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 => {},

View File

@ -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

View File

@ -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 => {},

View File

@ -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) {

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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.

View File

@ -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