mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-09 15:19:07 +00:00
dwarf: track type relocation state in Dwarf module
This commit is contained in:
parent
4ca9b4c44a
commit
366ec21052
11 changed files with 435 additions and 517 deletions
|
|
@ -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_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
|
||||||
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
|
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
// TODO Look into using the DWARF special opcodes to compress this data.
|
// TODO Look into using the DWARF special opcodes to compress this data.
|
||||||
// It lets you emit single-byte opcodes that add different numbers to
|
// It lets you emit single-byte opcodes that add different numbers to
|
||||||
// both the PC and the line number at the same time.
|
// both the PC and the line number at the same time.
|
||||||
try dbg_out.dbg_line.ensureUnusedCapacity(11);
|
const dbg_line = dw.getDeclDebugLineBuffer();
|
||||||
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
|
try dbg_line.ensureUnusedCapacity(11);
|
||||||
leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
|
dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
|
||||||
|
leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
|
||||||
if (delta_line != 0) {
|
if (delta_line != 0) {
|
||||||
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
|
dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
|
||||||
leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
|
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_pc = self.code.items.len;
|
||||||
self.prev_di_line = line;
|
self.prev_di_line = line;
|
||||||
self.prev_di_column = column;
|
self.prev_di_column = column;
|
||||||
|
|
@ -586,8 +587,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||||
|
|
||||||
fn mirDebugPrologueEnd(self: *Emit) !void {
|
fn mirDebugPrologueEnd(self: *Emit) !void {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
|
try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
|
||||||
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
|
|
@ -597,8 +598,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void {
|
||||||
|
|
||||||
fn mirDebugEpilogueBegin(self: *Emit) !void {
|
fn mirDebugEpilogueBegin(self: *Emit) !void {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
|
try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin);
|
||||||
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
|
|
|
||||||
|
|
@ -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_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
|
||||||
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
|
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
// TODO Look into using the DWARF special opcodes to compress this data.
|
// TODO Look into using the DWARF special opcodes to compress this data.
|
||||||
// It lets you emit single-byte opcodes that add different numbers to
|
// It lets you emit single-byte opcodes that add different numbers to
|
||||||
// both the PC and the line number at the same time.
|
// both the PC and the line number at the same time.
|
||||||
try dbg_out.dbg_line.ensureUnusedCapacity(11);
|
const dbg_line = dw.getDeclDebugLineBuffer();
|
||||||
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
|
try dbg_line.ensureUnusedCapacity(11);
|
||||||
leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
|
dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
|
||||||
|
leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
|
||||||
if (delta_line != 0) {
|
if (delta_line != 0) {
|
||||||
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
|
dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
|
||||||
leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
|
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_pc = self.code.items.len;
|
||||||
self.prev_di_line = line;
|
self.prev_di_line = line;
|
||||||
self.prev_di_column = column;
|
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.
|
/// after codegen for this symbol is done.
|
||||||
fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
|
fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
assert(ty.hasRuntimeBits());
|
assert(ty.hasRuntimeBits());
|
||||||
const index = dbg_out.dbg_info.items.len;
|
const dbg_info = dw.getDeclDebugInfoBuffer();
|
||||||
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
|
const index = dbg_info.items.len;
|
||||||
|
try 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.* });
|
const atom = switch (self.bin_file.tag) {
|
||||||
if (!gop.found_existing) {
|
.elf => &self.function.mod_fn.owner_decl.link.elf.dbg_info_atom,
|
||||||
gop.value_ptr.* = .{
|
.macho => unreachable,
|
||||||
.off = undefined,
|
else => unreachable,
|
||||||
.relocs = .{},
|
};
|
||||||
};
|
try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
|
||||||
}
|
|
||||||
try gop.value_ptr.relocs.append(self.bin_file.allocator, @intCast(u32, index));
|
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
.none => {},
|
.none => {},
|
||||||
|
|
@ -409,16 +408,17 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
|
||||||
switch (mcv) {
|
switch (mcv) {
|
||||||
.register => |reg| {
|
.register => |reg| {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_info.ensureUnusedCapacity(3);
|
const dbg_info = dw.getDeclDebugInfoBuffer();
|
||||||
dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
|
try dbg_info.ensureUnusedCapacity(3);
|
||||||
dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
|
dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
|
||||||
|
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
|
||||||
1, // ULEB128 dwarf expression length
|
1, // ULEB128 dwarf expression length
|
||||||
reg.dwarfLocOp(),
|
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
|
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 => {},
|
.plan9 => {},
|
||||||
.none => {},
|
.none => {},
|
||||||
|
|
@ -428,7 +428,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
|
||||||
.stack_argument_offset,
|
.stack_argument_offset,
|
||||||
=> {
|
=> {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {
|
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)});
|
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,
|
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
|
// Get length of the LEB128 stack offset
|
||||||
var counting_writer = std.io.countingWriter(std.io.null_writer);
|
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
|
// DW.AT.location, DW.FORM.exprloc
|
||||||
// ULEB128 dwarf expression length
|
// ULEB128 dwarf expression length
|
||||||
try leb128.writeULEB128(dbg_out.dbg_info.writer(), counting_writer.bytes_written + 1);
|
try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1);
|
||||||
try dbg_out.dbg_info.append(DW.OP.breg11);
|
try dbg_info.append(DW.OP.breg11);
|
||||||
try leb128.writeILEB128(dbg_out.dbg_info.writer(), adjusted_stack_offset);
|
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
|
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 => {},
|
.plan9 => {},
|
||||||
.none => {},
|
.none => {},
|
||||||
|
|
@ -558,8 +559,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||||
|
|
||||||
fn mirDebugPrologueEnd(emit: *Emit) !void {
|
fn mirDebugPrologueEnd(emit: *Emit) !void {
|
||||||
switch (emit.debug_output) {
|
switch (emit.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
|
try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
|
||||||
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
|
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
|
|
@ -569,8 +570,8 @@ fn mirDebugPrologueEnd(emit: *Emit) !void {
|
||||||
|
|
||||||
fn mirDebugEpilogueBegin(emit: *Emit) !void {
|
fn mirDebugEpilogueBegin(emit: *Emit) !void {
|
||||||
switch (emit.debug_output) {
|
switch (emit.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
|
try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin);
|
||||||
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
|
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
|
|
|
||||||
|
|
@ -745,21 +745,17 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
|
||||||
/// after codegen for this symbol is done.
|
/// after codegen for this symbol is done.
|
||||||
fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
|
fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
assert(ty.hasRuntimeBits());
|
assert(ty.hasRuntimeBits());
|
||||||
const index = dbg_out.dbg_info.items.len;
|
const dbg_info = dw.getDeclDebugInfoBuffer();
|
||||||
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
|
const index = dbg_info.items.len;
|
||||||
|
try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
|
||||||
const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.gpa, ty, .{
|
const atom = switch (self.bin_file.tag) {
|
||||||
.target = self.target.*,
|
.elf => &self.mod_fn.owner_decl.link.elf.dbg_info_atom,
|
||||||
});
|
.macho => unreachable,
|
||||||
if (!gop.found_existing) {
|
else => unreachable,
|
||||||
gop.value_ptr.* = .{
|
};
|
||||||
.off = undefined,
|
try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
|
||||||
.relocs = .{},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index));
|
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
.none => {},
|
.none => {},
|
||||||
|
|
@ -1573,16 +1569,17 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32
|
||||||
switch (mcv) {
|
switch (mcv) {
|
||||||
.register => |reg| {
|
.register => |reg| {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_info.ensureUnusedCapacity(3);
|
const dbg_info = dw.getDeclDebugInfoBuffer();
|
||||||
dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
|
try dbg_info.ensureUnusedCapacity(3);
|
||||||
dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
|
dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
|
||||||
|
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
|
||||||
1, // ULEB128 dwarf expression length
|
1, // ULEB128 dwarf expression length
|
||||||
reg.dwarfLocOp(),
|
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
|
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 => {},
|
.plan9 => {},
|
||||||
.none => {},
|
.none => {},
|
||||||
|
|
|
||||||
|
|
@ -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_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
|
||||||
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
|
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
// TODO Look into using the DWARF special opcodes to compress this data.
|
// TODO Look into using the DWARF special opcodes to compress this data.
|
||||||
// It lets you emit single-byte opcodes that add different numbers to
|
// It lets you emit single-byte opcodes that add different numbers to
|
||||||
// both the PC and the line number at the same time.
|
// both the PC and the line number at the same time.
|
||||||
try dbg_out.dbg_line.ensureUnusedCapacity(11);
|
const dbg_line = dw.getDeclDebugLineBuffer();
|
||||||
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
|
try dbg_line.ensureUnusedCapacity(11);
|
||||||
leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
|
dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
|
||||||
|
leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
|
||||||
if (delta_line != 0) {
|
if (delta_line != 0) {
|
||||||
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
|
dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
|
||||||
leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
|
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_pc = self.code.items.len;
|
||||||
self.prev_di_line = line;
|
self.prev_di_line = line;
|
||||||
self.prev_di_column = column;
|
self.prev_di_column = column;
|
||||||
|
|
@ -182,8 +183,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||||
|
|
||||||
fn mirDebugPrologueEnd(self: *Emit) !void {
|
fn mirDebugPrologueEnd(self: *Emit) !void {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
|
try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
|
||||||
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
|
|
@ -193,8 +194,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void {
|
||||||
|
|
||||||
fn mirDebugEpilogueBegin(self: *Emit) !void {
|
fn mirDebugEpilogueBegin(self: *Emit) !void {
|
||||||
switch (self.debug_output) {
|
switch (self.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
|
try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin);
|
||||||
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,7 @@ pub fn generate(
|
||||||
var emit = Emit{
|
var emit = Emit{
|
||||||
.mir = mir,
|
.mir = mir,
|
||||||
.bin_file = bin_file,
|
.bin_file = bin_file,
|
||||||
|
.function = &function,
|
||||||
.debug_output = debug_output,
|
.debug_output = debug_output,
|
||||||
.target = &bin_file.options.target,
|
.target = &bin_file.options.target,
|
||||||
.src_loc = src_loc,
|
.src_loc = src_loc,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ const testing = std.testing;
|
||||||
|
|
||||||
const Air = @import("../../Air.zig");
|
const Air = @import("../../Air.zig");
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
const CodeGen = @import("CodeGen.zig");
|
||||||
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
|
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
|
||||||
const DW = std.dwarf;
|
const DW = std.dwarf;
|
||||||
const Encoder = bits.Encoder;
|
const Encoder = bits.Encoder;
|
||||||
|
|
@ -29,6 +30,7 @@ const Type = @import("../../type.zig").Type;
|
||||||
|
|
||||||
mir: Mir,
|
mir: Mir,
|
||||||
bin_file: *link.File,
|
bin_file: *link.File,
|
||||||
|
function: *const CodeGen,
|
||||||
debug_output: DebugInfoOutput,
|
debug_output: DebugInfoOutput,
|
||||||
target: *const std.Target,
|
target: *const std.Target,
|
||||||
err_msg: ?*ErrorMsg = null,
|
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;
|
const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
|
||||||
log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });
|
log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });
|
||||||
switch (emit.debug_output) {
|
switch (emit.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
// TODO Look into using the DWARF special opcodes to compress this data.
|
// TODO Look into using the DWARF special opcodes to compress this data.
|
||||||
// It lets you emit single-byte opcodes that add different numbers to
|
// It lets you emit single-byte opcodes that add different numbers to
|
||||||
// both the PC and the line number at the same time.
|
// both the PC and the line number at the same time.
|
||||||
try dbg_out.dbg_line.ensureUnusedCapacity(11);
|
const dbg_line = dw.getDeclDebugLineBuffer();
|
||||||
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
|
try dbg_line.ensureUnusedCapacity(11);
|
||||||
leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;
|
dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
|
||||||
|
leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
|
||||||
if (delta_line != 0) {
|
if (delta_line != 0) {
|
||||||
dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
|
dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
|
||||||
leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
|
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_line = line;
|
||||||
emit.prev_di_column = column;
|
emit.prev_di_column = column;
|
||||||
emit.prev_di_pc = emit.code.items.len;
|
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];
|
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||||
assert(tag == .dbg_prologue_end);
|
assert(tag == .dbg_prologue_end);
|
||||||
switch (emit.debug_output) {
|
switch (emit.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
|
try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
|
||||||
log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column });
|
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);
|
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];
|
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||||
assert(tag == .dbg_epilogue_begin);
|
assert(tag == .dbg_epilogue_begin);
|
||||||
switch (emit.debug_output) {
|
switch (emit.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
|
try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin);
|
||||||
log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column });
|
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);
|
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) {
|
switch (mcv) {
|
||||||
.register => |reg| {
|
.register => |reg| {
|
||||||
switch (emit.debug_output) {
|
switch (emit.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
try dbg_out.dbg_info.ensureUnusedCapacity(3);
|
const dbg_info = dw.getDeclDebugInfoBuffer();
|
||||||
dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
|
try dbg_info.ensureUnusedCapacity(3);
|
||||||
dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
|
dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
|
||||||
|
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
|
||||||
1, // ULEB128 dwarf expression length
|
1, // ULEB128 dwarf expression length
|
||||||
reg.dwarfLocOp(),
|
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
|
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 => {},
|
.plan9 => {},
|
||||||
.none => {},
|
.none => {},
|
||||||
|
|
@ -1080,25 +1084,26 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32
|
||||||
},
|
},
|
||||||
.stack_offset => |off| {
|
.stack_offset => |off| {
|
||||||
switch (emit.debug_output) {
|
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
|
// 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
|
// rbp as the start of function frame minus 8 bytes for caller's rbp preserved in the
|
||||||
// prologue, and 8 bytes for return address.
|
// 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
|
// 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.
|
// for example when -fomit-frame-pointer is set.
|
||||||
const disp = @intCast(i32, max_stack) - off + 16;
|
const disp = @intCast(i32, max_stack) - off + 16;
|
||||||
try dbg_out.dbg_info.ensureUnusedCapacity(8);
|
const dbg_info = dw.getDeclDebugInfoBuffer();
|
||||||
dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
|
try dbg_info.ensureUnusedCapacity(8);
|
||||||
const fixup = dbg_out.dbg_info.items.len;
|
dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
|
||||||
dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
|
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
|
1, // we will backpatch it after we encode the displacement in LEB128
|
||||||
DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
|
DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
|
||||||
});
|
});
|
||||||
leb128.writeILEB128(dbg_out.dbg_info.writer(), disp) catch unreachable;
|
leb128.writeILEB128(dbg_info.writer(), disp) catch unreachable;
|
||||||
dbg_out.dbg_info.items[fixup] += @intCast(u8, dbg_out.dbg_info.items.len - fixup - 2);
|
dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
|
||||||
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
|
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 => {},
|
.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.
|
/// after codegen for this symbol is done.
|
||||||
fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
|
fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
|
||||||
switch (emit.debug_output) {
|
switch (emit.debug_output) {
|
||||||
.dwarf => |dbg_out| {
|
.dwarf => |dw| {
|
||||||
assert(ty.hasRuntimeBits());
|
assert(ty.hasRuntimeBits());
|
||||||
const index = dbg_out.dbg_info.items.len;
|
const dbg_info = dw.getDeclDebugInfoBuffer();
|
||||||
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
|
const index = dbg_info.items.len;
|
||||||
|
try 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, .{
|
const atom = switch (emit.bin_file.tag) {
|
||||||
.target = emit.target.*,
|
.elf => &emit.function.mod_fn.owner_decl.link.elf.dbg_info_atom,
|
||||||
});
|
.macho => &emit.function.mod_fn.owner_decl.link.macho.dbg_info_atom,
|
||||||
if (!gop.found_existing) {
|
else => unreachable,
|
||||||
gop.value_ptr.* = .{
|
};
|
||||||
.off = undefined,
|
try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
|
||||||
.relocs = .{},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
try gop.value_ptr.relocs.append(emit.bin_file.allocator, @intCast(u32, index));
|
|
||||||
},
|
},
|
||||||
.plan9 => {},
|
.plan9 => {},
|
||||||
.none => {},
|
.none => {},
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,7 @@ pub const GenerateSymbolError = error{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const DebugInfoOutput = union(enum) {
|
pub const DebugInfoOutput = union(enum) {
|
||||||
dwarf: struct {
|
dwarf: *link.File.Dwarf,
|
||||||
dbg_line: *std.ArrayList(u8),
|
|
||||||
dbg_info: *std.ArrayList(u8),
|
|
||||||
dbg_info_type_relocs: *link.File.Dwarf.DbgInfoTypeRelocsTable,
|
|
||||||
},
|
|
||||||
/// the plan9 debuginfo output is a bytecode with 4 opcodes
|
/// the plan9 debuginfo output is a bytecode with 4 opcodes
|
||||||
/// assume all numbers/variables are bytes
|
/// 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
|
/// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,22 @@ atom_last: ?*Atom = null,
|
||||||
|
|
||||||
abbrev_table_offset: ?u64 = null,
|
abbrev_table_offset: ?u64 = null,
|
||||||
|
|
||||||
|
/// TODO replace with InternArena
|
||||||
/// Table of debug symbol names.
|
/// Table of debug symbol names.
|
||||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||||
|
|
||||||
deferred_error_sets_relocs: std.ArrayListUnmanaged(u32) = .{},
|
/// 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.
|
/// List of atoms that are owned directly by the DWARF module.
|
||||||
/// TODO convert links in DebugInfoAtom into indices and make
|
/// TODO convert links in DebugInfoAtom into indices and make
|
||||||
/// sure every atom is owned by this module.
|
/// sure every atom is owned by this module.
|
||||||
managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
|
managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
|
||||||
|
|
||||||
|
global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
|
||||||
|
|
||||||
pub const Atom = struct {
|
pub const Atom = struct {
|
||||||
/// Previous/next linked list pointers.
|
/// Previous/next linked list pointers.
|
||||||
/// This is the linked list node for this Decl's corresponding .debug_info tag.
|
/// This is the linked list node for this Decl's corresponding .debug_info tag.
|
||||||
|
|
@ -60,6 +66,54 @@ pub const Atom = struct {
|
||||||
len: u32,
|
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 {
|
pub const SrcFn = struct {
|
||||||
/// Offset from the beginning of the Debug Line Program header that contains this function.
|
/// Offset from the beginning of the Debug Line Program header that contains this function.
|
||||||
off: u32,
|
off: u32,
|
||||||
|
|
@ -82,22 +136,6 @@ pub const SrcFn = struct {
|
||||||
|
|
||||||
pub const PtrWidth = enum { p32, p64 };
|
pub const PtrWidth = enum { p32, p64 };
|
||||||
|
|
||||||
pub const DbgInfoTypeRelocsTable = std.ArrayHashMapUnmanaged(
|
|
||||||
Type,
|
|
||||||
DbgInfoTypeReloc,
|
|
||||||
Type.HashContext32,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
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),
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const abbrev_compile_unit = 1;
|
pub const abbrev_compile_unit = 1;
|
||||||
pub const abbrev_subprogram = 2;
|
pub const abbrev_subprogram = 2;
|
||||||
pub const abbrev_subprogram_retvoid = 3;
|
pub const abbrev_subprogram_retvoid = 3;
|
||||||
|
|
@ -143,7 +181,7 @@ pub fn deinit(self: *Dwarf) void {
|
||||||
self.dbg_line_fn_free_list.deinit(gpa);
|
self.dbg_line_fn_free_list.deinit(gpa);
|
||||||
self.atom_free_list.deinit(gpa);
|
self.atom_free_list.deinit(gpa);
|
||||||
self.strtab.deinit(gpa);
|
self.strtab.deinit(gpa);
|
||||||
self.deferred_error_sets_relocs.deinit(gpa);
|
self.global_abbrev_relocs.deinit(gpa);
|
||||||
|
|
||||||
for (self.managed_atoms.items) |atom| {
|
for (self.managed_atoms.items) |atom| {
|
||||||
gpa.destroy(atom);
|
gpa.destroy(atom);
|
||||||
|
|
@ -151,25 +189,22 @@ pub fn deinit(self: *Dwarf) void {
|
||||||
self.managed_atoms.deinit(gpa);
|
self.managed_atoms.deinit(gpa);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DeclDebugBuffers = struct {
|
/// Initializes Decl's state and its matching output buffers.
|
||||||
dbg_line_buffer: std.ArrayList(u8),
|
/// Call this before `commitDeclState`.
|
||||||
dbg_info_buffer: std.ArrayList(u8),
|
pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !void {
|
||||||
dbg_info_type_relocs: DbgInfoTypeRelocsTable,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {
|
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
const decl_name = try decl.getFullyQualifiedName(self.allocator);
|
const decl_name = try decl.getFullyQualifiedName(self.allocator);
|
||||||
defer self.allocator.free(decl_name);
|
defer self.allocator.free(decl_name);
|
||||||
|
|
||||||
log.debug("initDeclDebugInfo {s}{*}", .{ decl_name, decl });
|
log.debug("initDeclState {s}{*}", .{ decl_name, decl });
|
||||||
|
|
||||||
const gpa = self.allocator;
|
const gpa = self.allocator;
|
||||||
var dbg_line_buffer = std.ArrayList(u8).init(gpa);
|
assert(self.decl_state == null);
|
||||||
var dbg_info_buffer = std.ArrayList(u8).init(gpa);
|
self.decl_state = DeclState.init(gpa);
|
||||||
var dbg_info_type_relocs: DbgInfoTypeRelocsTable = .{};
|
const dbg_line_buffer = &self.decl_state.?.dbg_line;
|
||||||
|
const dbg_info_buffer = &self.decl_state.?.dbg_info;
|
||||||
|
|
||||||
assert(decl.has_tv);
|
assert(decl.has_tv);
|
||||||
|
|
||||||
|
|
@ -232,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
|
dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT.low_pc, DW.FORM.addr
|
||||||
assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
|
assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
|
||||||
dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
|
dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
|
||||||
|
//
|
||||||
if (fn_ret_has_bits) {
|
if (fn_ret_has_bits) {
|
||||||
const gop = try dbg_info_type_relocs.getOrPutContext(gpa, fn_ret_type, .{
|
const atom = switch (self.tag) {
|
||||||
.target = self.target,
|
.elf => &decl.link.elf.dbg_info_atom,
|
||||||
});
|
.macho => &decl.link.macho.dbg_info_atom,
|
||||||
if (!gop.found_existing) {
|
else => unreachable,
|
||||||
gop.value_ptr.* = .{
|
};
|
||||||
.off = undefined,
|
try self.addTypeReloc(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len), null);
|
||||||
.relocs = .{},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
try gop.value_ptr.relocs.append(gpa, @intCast(u32, dbg_info_buffer.items.len));
|
|
||||||
dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
|
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
|
dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
@ -252,30 +285,28 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {
|
||||||
// TODO implement .debug_info for global variables
|
// 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,
|
self: *Dwarf,
|
||||||
file: *File,
|
file: *File,
|
||||||
module: *Module,
|
module: *Module,
|
||||||
decl: *Module.Decl,
|
decl: *Module.Decl,
|
||||||
sym_addr: u64,
|
sym_addr: u64,
|
||||||
sym_size: u64,
|
sym_size: u64,
|
||||||
debug_buffers: *DeclDebugBuffers,
|
|
||||||
) !void {
|
) !void {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
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;
|
const gpa = self.allocator;
|
||||||
var dbg_line_buffer = &debug_buffers.dbg_line_buffer;
|
var dbg_line_buffer = &self.decl_state.?.dbg_line;
|
||||||
var dbg_info_buffer = &debug_buffers.dbg_info_buffer;
|
var dbg_info_buffer = &self.decl_state.?.dbg_info;
|
||||||
var dbg_info_type_relocs = &debug_buffers.dbg_info_type_relocs;
|
|
||||||
|
|
||||||
const target_endian = self.target.cpu.arch.endian();
|
const target_endian = self.target.cpu.arch.endian();
|
||||||
|
|
||||||
|
|
@ -473,25 +504,21 @@ pub fn commitDeclDebugInfo(
|
||||||
if (dbg_info_buffer.items.len == 0)
|
if (dbg_info_buffer.items.len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We need this for the duration of this function only so that for composite
|
const atom = switch (self.tag) {
|
||||||
// types such as []const u32, if the type *u32 is non-existent, we create
|
.elf => &decl.link.elf.dbg_info_atom,
|
||||||
// it synthetically and store the backing bytes in this arena. After we are
|
.macho => &decl.link.macho.dbg_info_atom,
|
||||||
// done with the relocations, we can safely deinit the entire memory slab.
|
else => unreachable,
|
||||||
// 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,
|
const decl_state = &self.decl_state.?;
|
||||||
// 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();
|
|
||||||
{
|
{
|
||||||
// Now we emit the .debug_info types of the Decl. These will count towards the size of
|
// 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
|
// the buffer, so we have to do it before computing the offset, and we can't perform the actual
|
||||||
// relocations yet.
|
// relocations yet.
|
||||||
var it: usize = 0;
|
var sym_index: usize = 0;
|
||||||
while (it < dbg_info_type_relocs.count()) : (it += 1) {
|
while (sym_index < decl_state.abbrev_table.items.len) : (sym_index += 1) {
|
||||||
const ty = dbg_info_type_relocs.keys()[it];
|
const symbol = &decl_state.abbrev_table.items[sym_index];
|
||||||
|
const ty = symbol.@"type";
|
||||||
const deferred: bool = blk: {
|
const deferred: bool = blk: {
|
||||||
if (ty.isAnyError()) break :blk true;
|
if (ty.isAnyError()) break :blk true;
|
||||||
switch (ty.tag()) {
|
switch (ty.tag()) {
|
||||||
|
|
@ -504,68 +531,38 @@ pub fn commitDeclDebugInfo(
|
||||||
};
|
};
|
||||||
if (deferred) continue;
|
if (deferred) continue;
|
||||||
|
|
||||||
const value_ptr = dbg_info_type_relocs.getPtrContext(ty, .{
|
symbol.offset = @intCast(u32, dbg_info_buffer.items.len);
|
||||||
.target = self.target,
|
try self.addDbgInfoType(decl_state.abbrev_type_arena.allocator(), module, atom, ty, dbg_info_buffer);
|
||||||
}).?;
|
|
||||||
value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
|
|
||||||
try self.addDbgInfoType(
|
|
||||||
dbg_type_arena.allocator(),
|
|
||||||
module,
|
|
||||||
ty,
|
|
||||||
dbg_info_buffer,
|
|
||||||
dbg_info_type_relocs,
|
|
||||||
&nested_ref4_relocs,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
|
||||||
|
|
||||||
{
|
while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
|
||||||
// Now that we have the offset assigned we can finally perform type relocations.
|
const symbol = decl_state.abbrev_table.items[reloc.target];
|
||||||
for (dbg_info_type_relocs.keys()) |ty| {
|
const ty = symbol.@"type";
|
||||||
const value = dbg_info_type_relocs.getContext(ty, .{
|
const deferred: bool = blk: {
|
||||||
.target = self.target,
|
if (ty.isAnyError()) break :blk true;
|
||||||
}).?;
|
switch (ty.tag()) {
|
||||||
for (value.relocs.items) |off| {
|
.error_set_inferred => {
|
||||||
const deferred: bool = blk: {
|
if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true;
|
||||||
if (ty.isAnyError()) break :blk true;
|
},
|
||||||
switch (ty.tag()) {
|
else => {},
|
||||||
.error_set_inferred => {
|
|
||||||
if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true;
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
break :blk false;
|
|
||||||
};
|
|
||||||
if (deferred) {
|
|
||||||
// Defer until later
|
|
||||||
try self.deferred_error_sets_relocs.append(self.allocator, atom.off + off);
|
|
||||||
} else {
|
|
||||||
mem.writeInt(
|
|
||||||
u32,
|
|
||||||
dbg_info_buffer.items[off..][0..4],
|
|
||||||
atom.off + value.off,
|
|
||||||
target_endian,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
break :blk false;
|
||||||
// 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
|
if (deferred) {
|
||||||
// relocated cell.
|
try self.global_abbrev_relocs.append(gpa, .{
|
||||||
// TODO Should probably generalise this with type relocs.
|
.target = undefined,
|
||||||
for (nested_ref4_relocs.items) |off| {
|
.offset = reloc.offset,
|
||||||
const addend = mem.readInt(u32, dbg_info_buffer.items[off..][0..4], target_endian);
|
.atom = reloc.atom,
|
||||||
|
.addend = reloc.addend,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
mem.writeInt(
|
mem.writeInt(
|
||||||
u32,
|
u32,
|
||||||
dbg_info_buffer.items[off..][0..4],
|
dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
|
||||||
atom.off + addend,
|
symbol.atom.off + symbol.offset + reloc.addend,
|
||||||
target_endian,
|
target_endian,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -574,77 +571,6 @@ pub fn commitDeclDebugInfo(
|
||||||
try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
|
try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commitErrorSetDebugInfo(self: *Dwarf, file: *File, module: *Module) !void {
|
|
||||||
if (self.deferred_error_sets_relocs.items.len == 0) return; // Nothing to do
|
|
||||||
|
|
||||||
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 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;
|
|
||||||
|
|
||||||
var dbg_info_buffer = std.ArrayList(u8).init(arena);
|
|
||||||
try self.addDbgInfoErrorSet(arena, module, ty, &dbg_info_buffer);
|
|
||||||
|
|
||||||
const atom = try gpa.create(Atom);
|
|
||||||
errdefer gpa.destroy(atom);
|
|
||||||
atom.* = .{
|
|
||||||
.prev = null,
|
|
||||||
.next = null,
|
|
||||||
.off = 0,
|
|
||||||
.len = 0,
|
|
||||||
};
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const target_endian = self.target.cpu.arch.endian();
|
|
||||||
var buf: [@sizeOf(u32)]u8 = undefined;
|
|
||||||
while (self.deferred_error_sets_relocs.popOrNull()) |reloc| {
|
|
||||||
mem.writeInt(u32, &buf, atom.off, target_endian);
|
|
||||||
|
|
||||||
switch (self.tag) {
|
|
||||||
.elf => {
|
|
||||||
const elf_file = file.cast(File.Elf).?;
|
|
||||||
try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc);
|
|
||||||
},
|
|
||||||
.macho => {
|
|
||||||
const macho_file = file.cast(File.MachO).?;
|
|
||||||
const d_sym = &macho_file.d_sym.?;
|
|
||||||
try d_sym.file.pwriteAll(&buf, file_pos + reloc);
|
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u32) !void {
|
fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u32) !void {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
@ -904,14 +830,12 @@ fn addDbgInfoType(
|
||||||
self: *Dwarf,
|
self: *Dwarf,
|
||||||
arena: Allocator,
|
arena: Allocator,
|
||||||
module: *Module,
|
module: *Module,
|
||||||
|
atom: *Atom,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
dbg_info_buffer: *std.ArrayList(u8),
|
dbg_info_buffer: *std.ArrayList(u8),
|
||||||
dbg_info_type_relocs: *DbgInfoTypeRelocsTable,
|
|
||||||
nested_ref4_relocs: *std.ArrayList(u32),
|
|
||||||
) error{OutOfMemory}!void {
|
) error{OutOfMemory}!void {
|
||||||
const target = self.target;
|
const target = self.target;
|
||||||
const target_endian = self.target.cpu.arch.endian();
|
const target_endian = self.target.cpu.arch.endian();
|
||||||
var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena);
|
|
||||||
|
|
||||||
switch (ty.zigTypeTag()) {
|
switch (ty.zigTypeTag()) {
|
||||||
.NoReturn => unreachable,
|
.NoReturn => unreachable,
|
||||||
|
|
@ -970,7 +894,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
var index = dbg_info_buffer.items.len;
|
var index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
try dbg_info_buffer.ensureUnusedCapacity(6);
|
try dbg_info_buffer.ensureUnusedCapacity(6);
|
||||||
dbg_info_buffer.appendAssumeCapacity(0);
|
dbg_info_buffer.appendAssumeCapacity(0);
|
||||||
|
|
@ -982,7 +906,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
index = dbg_info_buffer.items.len;
|
index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
const offset = abi_size - payload_ty.abiSize(target);
|
const offset = abi_size - payload_ty.abiSize(target);
|
||||||
try leb128.writeULEB128(dbg_info_buffer.writer(), offset);
|
try leb128.writeULEB128(dbg_info_buffer.writer(), offset);
|
||||||
|
|
@ -1011,7 +935,7 @@ fn addDbgInfoType(
|
||||||
try dbg_info_buffer.resize(index + 4);
|
try dbg_info_buffer.resize(index + 4);
|
||||||
var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
|
var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
|
||||||
const ptr_ty = ty.slicePtrFieldType(buf);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
try dbg_info_buffer.ensureUnusedCapacity(6);
|
try dbg_info_buffer.ensureUnusedCapacity(6);
|
||||||
dbg_info_buffer.appendAssumeCapacity(0);
|
dbg_info_buffer.appendAssumeCapacity(0);
|
||||||
|
|
@ -1023,7 +947,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
index = dbg_info_buffer.items.len;
|
index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
try dbg_info_buffer.ensureUnusedCapacity(2);
|
try dbg_info_buffer.ensureUnusedCapacity(2);
|
||||||
dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize));
|
dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize));
|
||||||
|
|
@ -1035,7 +959,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
const index = dbg_info_buffer.items.len;
|
const index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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: {
|
.Struct => blk: {
|
||||||
|
|
@ -1059,7 +983,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
var index = dbg_info_buffer.items.len;
|
var index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
const field_off = ty.structFieldOffset(field_index, target);
|
const field_off = ty.structFieldOffset(field_index, target);
|
||||||
try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
|
try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
|
||||||
|
|
@ -1090,7 +1014,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
var index = dbg_info_buffer.items.len;
|
var index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
const field_off = ty.structFieldOffset(field_index, target);
|
const field_off = ty.structFieldOffset(field_index, target);
|
||||||
try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
|
try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
|
||||||
|
|
@ -1169,14 +1093,8 @@ fn addDbgInfoType(
|
||||||
dbg_info_buffer.appendAssumeCapacity(0);
|
dbg_info_buffer.appendAssumeCapacity(0);
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
const inner_union_index = dbg_info_buffer.items.len;
|
const inner_union_index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.ensureUnusedCapacity(4);
|
try dbg_info_buffer.resize(inner_union_index + 4);
|
||||||
mem.writeInt(
|
try self.addTypeReloc(atom, ty, @intCast(u32, inner_union_index), 5);
|
||||||
u32,
|
|
||||||
dbg_info_buffer.addManyAsArrayAssumeCapacity(4),
|
|
||||||
@intCast(u32, inner_union_index + 5),
|
|
||||||
target_endian,
|
|
||||||
);
|
|
||||||
try nested_ref4_relocs.append(@intCast(u32, inner_union_index));
|
|
||||||
// DW.AT.data_member_location, DW.FORM.sdata
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
|
try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
|
||||||
}
|
}
|
||||||
|
|
@ -1203,7 +1121,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
const index = dbg_info_buffer.items.len;
|
const index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
try dbg_info_buffer.append(0);
|
try dbg_info_buffer.append(0);
|
||||||
}
|
}
|
||||||
|
|
@ -1220,7 +1138,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
const index = dbg_info_buffer.items.len;
|
const index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
|
try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
|
||||||
|
|
||||||
|
|
@ -1229,7 +1147,40 @@ fn addDbgInfoType(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.ErrorSet => {
|
.ErrorSet => {
|
||||||
try self.addDbgInfoErrorSet(arena, module, ty, dbg_info_buffer);
|
// 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 => {
|
.ErrorUnion => {
|
||||||
const error_ty = ty.errorUnionSet();
|
const error_ty = ty.errorUnionSet();
|
||||||
|
|
@ -1255,7 +1206,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
var index = dbg_info_buffer.items.len;
|
var index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
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
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
|
try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
|
||||||
|
|
||||||
|
|
@ -1268,7 +1219,7 @@ fn addDbgInfoType(
|
||||||
// DW.AT.type, DW.FORM.ref4
|
// DW.AT.type, DW.FORM.ref4
|
||||||
index = dbg_info_buffer.items.len;
|
index = dbg_info_buffer.items.len;
|
||||||
try dbg_info_buffer.resize(index + 4);
|
try dbg_info_buffer.resize(index + 4);
|
||||||
try relocs.append(.{ .ty = error_ty, .reloc = @intCast(u32, index) });
|
try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null);
|
||||||
// DW.AT.data_member_location, DW.FORM.sdata
|
// DW.AT.data_member_location, DW.FORM.sdata
|
||||||
try dbg_info_buffer.append(0);
|
try dbg_info_buffer.append(0);
|
||||||
|
|
||||||
|
|
@ -1280,65 +1231,6 @@ fn addDbgInfoType(
|
||||||
try dbg_info_buffer.append(abbrev_pad1);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn addDbgInfoErrorSet(
|
|
||||||
self: *Dwarf,
|
|
||||||
arena: Allocator,
|
|
||||||
module: *Module,
|
|
||||||
ty: Type,
|
|
||||||
dbg_info_buffer: *std.ArrayList(u8),
|
|
||||||
) error{OutOfMemory}!void {
|
|
||||||
const target = self.target;
|
|
||||||
const target_endian = self.target.cpu.arch.endian();
|
|
||||||
|
|
||||||
// DW.AT.enumeration_type
|
|
||||||
try dbg_info_buffer.append(abbrev_enum_type);
|
|
||||||
// DW.AT.byte_size, DW.FORM.sdata
|
|
||||||
const abi_size = ty.abiSize(target);
|
|
||||||
try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
|
|
||||||
// DW.AT.name, DW.FORM.string
|
|
||||||
const name = try ty.nameAllocArena(arena, target);
|
|
||||||
try dbg_info_buffer.writer().print("{s}\x00", .{name});
|
|
||||||
|
|
||||||
// DW.AT.enumerator
|
|
||||||
const no_error = "(no error)";
|
|
||||||
try dbg_info_buffer.ensureUnusedCapacity(no_error.len + 2 + @sizeOf(u64));
|
|
||||||
dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant);
|
|
||||||
// DW.AT.name, DW.FORM.string
|
|
||||||
dbg_info_buffer.appendSliceAssumeCapacity(no_error);
|
|
||||||
dbg_info_buffer.appendAssumeCapacity(0);
|
|
||||||
// DW.AT.const_value, DW.FORM.data8
|
|
||||||
mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian);
|
|
||||||
|
|
||||||
const error_names = ty.errorSetNames();
|
|
||||||
for (error_names) |error_name| {
|
|
||||||
const kv = module.getErrorValue(error_name) catch unreachable;
|
|
||||||
// DW.AT.enumerator
|
|
||||||
try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64));
|
|
||||||
dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant);
|
|
||||||
// DW.AT.name, DW.FORM.string
|
|
||||||
dbg_info_buffer.appendSliceAssumeCapacity(error_name);
|
|
||||||
dbg_info_buffer.appendAssumeCapacity(0);
|
|
||||||
// DW.AT.const_value, DW.FORM.data8
|
|
||||||
mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), kv.value, target_endian);
|
|
||||||
}
|
|
||||||
|
|
||||||
// DW.AT.enumeration_type delimit children
|
|
||||||
try dbg_info_buffer.append(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
|
pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
|
||||||
|
|
@ -2059,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
|
return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
|
||||||
std.math.maxInt(@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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -958,8 +958,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
|
||||||
const target_endian = self.base.options.target.cpu.arch.endian();
|
const target_endian = self.base.options.target.cpu.arch.endian();
|
||||||
const foreign_endian = target_endian != builtin.cpu.arch.endian();
|
const foreign_endian = target_endian != builtin.cpu.arch.endian();
|
||||||
|
|
||||||
if (self.dwarf) |*dwarf| {
|
if (self.dwarf) |*dw| {
|
||||||
try dwarf.commitErrorSetDebugInfo(&self.base, module);
|
try dw.flushModule(&self.base, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -2232,13 +2232,6 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinitRelocs(gpa: Allocator, table: *link.File.Dwarf.DbgInfoTypeRelocsTable) void {
|
|
||||||
for (table.values()) |*value| {
|
|
||||||
value.relocs.deinit(gpa);
|
|
||||||
}
|
|
||||||
table.deinit(gpa);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 {
|
fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 {
|
||||||
const ty = decl.ty;
|
const ty = decl.ty;
|
||||||
const zig_ty = ty.zigTypeTag();
|
const zig_ty = ty.zigTypeTag();
|
||||||
|
|
@ -2346,26 +2339,13 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
|
||||||
const decl = func.owner_decl;
|
const decl = func.owner_decl;
|
||||||
self.freeUnnamedConsts(decl);
|
self.freeUnnamedConsts(decl);
|
||||||
|
|
||||||
var debug_buffers_buf: Dwarf.DeclDebugBuffers = undefined;
|
if (self.dwarf) |*dw| {
|
||||||
const debug_buffers = if (self.dwarf) |*dw| blk: {
|
try dw.initDeclState(decl);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = if (debug_buffers) |dbg|
|
const res = if (self.dwarf) |*dw|
|
||||||
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
|
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
|
||||||
.dwarf = .{
|
.dwarf = dw,
|
||||||
.dbg_line = &dbg.dbg_line_buffer,
|
|
||||||
.dbg_info = &dbg.dbg_info_buffer,
|
|
||||||
.dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
|
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
|
||||||
|
|
@ -2379,15 +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);
|
const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC);
|
||||||
if (debug_buffers) |dbg| {
|
if (self.dwarf) |*dw| {
|
||||||
try self.dwarf.?.commitDeclDebugInfo(
|
try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size);
|
||||||
&self.base,
|
|
||||||
module,
|
|
||||||
decl,
|
|
||||||
local_sym.st_value,
|
|
||||||
local_sym.st_size,
|
|
||||||
dbg,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
|
// Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
|
||||||
|
|
@ -2421,31 +2394,18 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||||
defer code_buffer.deinit();
|
defer code_buffer.deinit();
|
||||||
|
|
||||||
var debug_buffers_buf: Dwarf.DeclDebugBuffers = undefined;
|
if (self.dwarf) |*dw| {
|
||||||
const debug_buffers = if (self.dwarf) |*dw| blk: {
|
try dw.initDeclState(decl);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO implement .debug_info for global variables
|
// TODO implement .debug_info for global variables
|
||||||
const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
|
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(), .{
|
try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
|
||||||
.ty = decl.ty,
|
.ty = decl.ty,
|
||||||
.val = decl_val,
|
.val = decl_val,
|
||||||
}, &code_buffer, .{
|
}, &code_buffer, .{
|
||||||
.dwarf = .{
|
.dwarf = dw,
|
||||||
.dbg_line = &dbg.dbg_line_buffer,
|
|
||||||
.dbg_info = &dbg.dbg_info_buffer,
|
|
||||||
.dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
|
|
||||||
},
|
|
||||||
}, .{
|
}, .{
|
||||||
.parent_atom_index = decl.link.elf.local_sym_index,
|
.parent_atom_index = decl.link.elf.local_sym_index,
|
||||||
})
|
})
|
||||||
|
|
@ -2468,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);
|
const local_sym = try self.updateDeclCode(decl, code, elf.STT_OBJECT);
|
||||||
if (debug_buffers) |dbg| {
|
if (self.dwarf) |*dw| {
|
||||||
try self.dwarf.?.commitDeclDebugInfo(&self.base, module, decl, local_sym.st_value, local_sym.st_size, dbg);
|
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.
|
// Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
|
||||||
|
|
|
||||||
|
|
@ -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 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});
|
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
|
// 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.
|
// will not be part of the linker line anyway.
|
||||||
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
|
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);
|
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||||
defer code_buffer.deinit();
|
defer code_buffer.deinit();
|
||||||
|
|
||||||
var debug_buffers_buf: link.File.Dwarf.DeclDebugBuffers = undefined;
|
if (self.d_sym) |*d_sym| {
|
||||||
const debug_buffers = if (self.d_sym) |*d_sym| blk: {
|
try d_sym.dwarf.initDeclState(decl);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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, .{
|
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
|
||||||
.dwarf = .{
|
.dwarf = &d_sym.dwarf,
|
||||||
.dbg_line = &dbg.dbg_line_buffer,
|
|
||||||
.dbg_info = &dbg.dbg_info_buffer,
|
|
||||||
.dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
|
try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
|
||||||
|
|
||||||
switch (res) {
|
switch (res) {
|
||||||
.appended => {
|
.appended => {
|
||||||
try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);
|
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| {
|
||||||
if (self.d_sym) |*d_sym| {
|
try d_sym.dwarf.commitDeclState(&self.base, module, decl, symbol.n_value, decl.link.macho.size);
|
||||||
try d_sym.commitDeclDebugInfo(module, decl, db);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we updated the vaddr and the size, each corresponding export symbol also
|
// 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);
|
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||||
defer code_buffer.deinit();
|
defer code_buffer.deinit();
|
||||||
|
|
||||||
var debug_buffers_buf: link.File.Dwarf.DeclDebugBuffers = undefined;
|
if (self.d_sym) |*d_sym| {
|
||||||
const debug_buffers = if (self.d_sym) |*d_sym| blk: {
|
try d_sym.dwarf.initDeclState(decl);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
|
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(), .{
|
try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
|
||||||
.ty = decl.ty,
|
.ty = decl.ty,
|
||||||
.val = decl_val,
|
.val = decl_val,
|
||||||
}, &code_buffer, .{
|
}, &code_buffer, .{
|
||||||
.dwarf = .{
|
.dwarf = &d_sym.dwarf,
|
||||||
.dbg_line = &dbg.dbg_line_buffer,
|
|
||||||
.dbg_info = &dbg.dbg_info_buffer,
|
|
||||||
.dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
|
|
||||||
},
|
|
||||||
}, .{
|
}, .{
|
||||||
.parent_atom_index = decl.link.macho.local_sym_index,
|
.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
|
// Since we updated the vaddr and the size, each corresponding export symbol also
|
||||||
// needs to be updated.
|
// 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 {
|
pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
|
||||||
|
_ = module;
|
||||||
if (self.d_sym) |*d_sym| {
|
if (self.d_sym) |*d_sym| {
|
||||||
try d_sym.updateDeclLineNumber(module, decl);
|
try d_sym.dwarf.updateDeclLineNumber(&self.base, decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -645,25 +645,3 @@ fn writeStringTable(self: *DebugSymbols) !void {
|
||||||
|
|
||||||
self.load_commands_dirty = true;
|
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);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue