Commit 7612931c80
Changed files (2)
src-self-hosted
src-self-hosted/codegen.zig
@@ -50,6 +50,7 @@ pub fn generateSymbol(
typed_value: TypedValue,
code: *std.ArrayList(u8),
dbg_line: *std.ArrayList(u8),
+ dbg_info: *std.ArrayList(u8),
) GenerateSymbolError!Result {
const tracy = trace(@src());
defer tracy.end();
@@ -57,61 +58,62 @@ pub fn generateSymbol(
switch (typed_value.ty.zigTypeTag()) {
.Fn => {
switch (bin_file.base.options.target.cpu.arch) {
- //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
- //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line),
+ //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
+ //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),
}
},
.Array => {
+ // TODO populate .debug_info for the array
if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
if (typed_value.ty.arraySentinel()) |sentinel| {
try code.ensureCapacity(code.items.len + payload.data.len + 1);
@@ -120,7 +122,7 @@ pub fn generateSymbol(
switch (try generateSymbol(bin_file, src, .{
.ty = typed_value.ty.elemType(),
.val = sentinel,
- }, code, dbg_line)) {
+ }, code, dbg_line, dbg_info)) {
.appended => return Result{ .appended = {} },
.externally_managed => |slice| {
code.appendSliceAssumeCapacity(slice);
@@ -142,6 +144,8 @@ pub fn generateSymbol(
};
},
.Pointer => {
+ // TODO populate .debug_info for the pointer
+
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
const decl = payload.decl;
if (decl.analysis != .complete) return error.AnalysisFail;
@@ -177,6 +181,8 @@ pub fn generateSymbol(
};
},
.Int => {
+ // TODO populate .debug_info for the integer
+
const info = typed_value.ty.intInfo(bin_file.base.options.target);
if (info.bits == 8 and !info.signed) {
const x = typed_value.val.toUnsignedInt();
@@ -218,6 +224,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
mod_fn: *const Module.Fn,
code: *std.ArrayList(u8),
dbg_line: *std.ArrayList(u8),
+ dbg_info: *std.ArrayList(u8),
err_msg: ?*ErrorMsg,
args: []MCValue,
ret_mcv: MCValue,
@@ -387,6 +394,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
typed_value: TypedValue,
code: *std.ArrayList(u8),
dbg_line: *std.ArrayList(u8),
+ dbg_info: *std.ArrayList(u8),
) GenerateSymbolError!Result {
const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
@@ -424,6 +432,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.mod_fn = module_fn,
.code = code,
.dbg_line = dbg_line,
+ .dbg_info = dbg_info,
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
.ret_mcv = undefined, // populated after `resolveCallingConventionValues`
src-self-hosted/link.zig
@@ -342,9 +342,10 @@ pub const File = struct {
shstrtab_dirty: bool = false,
debug_strtab_dirty: bool = false,
offset_table_count_dirty: bool = false,
- debug_info_section_dirty: bool = false,
debug_abbrev_section_dirty: bool = false,
debug_aranges_section_dirty: bool = false,
+
+ debug_info_header_dirty: bool = false,
debug_line_header_dirty: bool = false,
error_flags: ErrorFlags = ErrorFlags{},
@@ -364,7 +365,7 @@ pub const File = struct {
/// overcapacity can be negative. A simple way to have negative overcapacity is to
/// allocate a fresh text block, which will have ideal capacity, and then grow it
/// by 1 byte. It will then have -1 overcapacity.
- text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = std.ArrayListUnmanaged(*TextBlock){},
+ text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{},
last_text_block: ?*TextBlock = null,
/// A list of `SrcFn` whose Line Number Programs have surplus capacity.
@@ -373,6 +374,12 @@ pub const File = struct {
dbg_line_fn_first: ?*SrcFn = null,
dbg_line_fn_last: ?*SrcFn = null,
+ /// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity.
+ /// This is the same concept as `text_block_free_list`; see those doc comments.
+ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{},
+ dbg_info_decl_first: ?*TextBlock = null,
+ dbg_info_decl_last: ?*TextBlock = null,
+
/// `alloc_num / alloc_den` is the factor of padding when allocating.
const alloc_num = 4;
const alloc_den = 3;
@@ -398,11 +405,24 @@ pub const File = struct {
prev: ?*TextBlock,
next: ?*TextBlock,
+ /// Previous/next linked list pointers. This value is `next ^ prev`.
+ /// This is the linked list node for this Decl's corresponding .debug_info tag.
+ dbg_info_prev: ?*TextBlock,
+ dbg_info_next: ?*TextBlock,
+ /// Offset into .debug_info pointing to the tag for this Decl.
+ dbg_info_off: u32,
+ /// Size of the .debug_info tag for this Decl, not including padding.
+ dbg_info_len: u32,
+
pub const empty = TextBlock{
.local_sym_index = 0,
.offset_table_index = undefined,
.prev = null,
.next = null,
+ .dbg_info_prev = null,
+ .dbg_info_next = null,
+ .dbg_info_off = undefined,
+ .dbg_info_len = undefined,
};
/// Returns how much room there is to grow in virtual address space.
@@ -566,6 +586,7 @@ pub const File = struct {
self.offset_table_free_list.deinit(self.base.allocator);
self.text_block_free_list.deinit(self.base.allocator);
self.dbg_line_fn_free_list.deinit(self.base.allocator);
+ self.dbg_info_decl_free_list.deinit(self.base.allocator);
self.offset_table.deinit(self.base.allocator);
}
@@ -854,7 +875,7 @@ pub const File = struct {
.sh_entsize = 0,
});
self.shdr_table_dirty = true;
- self.debug_info_section_dirty = true;
+ self.debug_info_header_dirty = true;
}
if (self.debug_abbrev_section_index == null) {
self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
@@ -1019,21 +1040,36 @@ pub const File = struct {
self.debug_abbrev_section_dirty = false;
}
- if (self.debug_info_section_dirty) {
+
+ if (self.debug_info_header_dirty) debug_info: {
+ // If this value is null it means there is an error in the module;
+ // leave debug_info_header_dirty=true.
+ const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info;
+ const last_dbg_info_decl = self.dbg_info_decl_last.?;
const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
var di_buf = std.ArrayList(u8).init(self.base.allocator);
defer di_buf.deinit();
- // Enough for a 64-bit header and main compilation unit without resizing.
- try di_buf.ensureCapacity(100);
+ // We have a function to compute the upper bound size, because it's needed
+ // for determining where to put the offset of the first `LinkBlock`.
+ try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes());
// initial length - length of the .debug_info contribution for this compilation unit,
// not including the initial length itself.
// We have to come back and write it later after we know the size.
- const init_len_index = di_buf.items.len;
- di_buf.items.len += init_len_size;
- const after_init_len = di_buf.items.len;
+ const after_init_len = di_buf.items.len + init_len_size;
+ const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len;
+ const init_len = dbg_info_end - after_init_len;
+ switch (self.ptr_width) {
+ .p32 => {
+ mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
+ },
+ .p64 => {
+ di_buf.appendNTimesAssumeCapacity(0xff, 4);
+ mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);
+ },
+ }
mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version
const abbrev_offset = self.debug_abbrev_table_offset.?;
switch (self.ptr_width) {
@@ -1068,39 +1104,15 @@ pub const File = struct {
// Until then we say it is C99.
mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian);
- const init_len = di_buf.items.len - after_init_len;
- switch (self.ptr_width) {
- .p32 => {
- mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian);
- },
- .p64 => {
- // initial length - length of the .debug_info contribution for this compilation unit,
- // not including the initial length itself.
- di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff };
- mem.writeInt(u64, di_buf.items[init_len_index + 4..][0..8], init_len, target_endian);
- },
- }
-
- const needed_size = di_buf.items.len;
- const allocated_size = self.allocatedSize(debug_info_sect.sh_offset);
- if (needed_size > allocated_size) {
- debug_info_sect.sh_size = 0; // free the space
- debug_info_sect.sh_offset = self.findFreeSpace(needed_size, 1);
- }
- debug_info_sect.sh_size = needed_size;
- log.debug(.link, ".debug_info start=0x{x} end=0x{x}\n", .{
- debug_info_sect.sh_offset,
- debug_info_sect.sh_offset + needed_size,
- });
-
- try self.base.file.?.pwriteAll(di_buf.items, debug_info_sect.sh_offset);
- if (!self.shdr_table_dirty) {
- // Then it won't get written with the others and we need to do it.
- try self.writeSectHeader(self.debug_info_section_index.?);
+ if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) {
+ // Move the first N decls to the end to make more padding for the header.
+ @panic("TODO: handle .debug_info header exceeding its padding");
}
-
- self.debug_info_section_dirty = false;
+ const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len;
+ try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, debug_info_sect.sh_offset);
+ self.debug_info_header_dirty = false;
}
+
if (self.debug_aranges_section_dirty) {
const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?];
@@ -1266,7 +1278,7 @@ pub const File = struct {
@panic("TODO: handle .debug_line header exceeding its padding");
}
const jmp_amt = dbg_line_prg_off - di_buf.items.len;
- try self.pwriteWithNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset);
+ try self.pwriteDbgLineNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset);
self.debug_line_header_dirty = false;
}
@@ -1417,8 +1429,7 @@ pub const File = struct {
// The point of flush() is to commit changes, so in theory, nothing should
// be dirty after this. However, it is possible for some things to remain
// dirty because they fail to be written in the event of compile errors,
- // such as debug_line_header_dirty.
- assert(!self.debug_info_section_dirty);
+ // such as debug_line_header_dirty and debug_info_header_dirty.
assert(!self.debug_abbrev_section_dirty);
assert(!self.debug_aranges_section_dirty);
assert(!self.phdr_table_dirty);
@@ -1700,8 +1711,8 @@ pub const File = struct {
// The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
// range of the compilation unit. When we expand the text section, this range changes,
- // so the .debug_info section becomes dirty.
- self.debug_info_section_dirty = true;
+ // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty.
+ self.debug_info_header_dirty = true;
// This becomes dirty for the same reason. We could potentially make this more
// fine-grained with the addition of support for more compilation units. It is planned to
// model each package as a different compilation unit.
@@ -1815,6 +1826,9 @@ pub const File = struct {
var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
defer dbg_line_buffer.deinit();
+ var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
+ defer dbg_info_buffer.deinit();
+
const typed_value = decl.typed_value.most_recent.typed_value;
const is_fn: bool = switch (typed_value.ty.zigTypeTag()) {
.Fn => true,
@@ -1871,7 +1885,7 @@ pub const File = struct {
// do the work of setting prologue_end=true and epilogue_begin=true.
dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
}
- const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer);
+ const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer);
const code = switch (res) {
.externally_managed => |x| x,
.appended => code_buffer.items,
@@ -1937,6 +1951,8 @@ pub const File = struct {
const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
try self.base.file.?.pwriteAll(code, file_offset);
+ try self.updateDeclDebugInfo(module, decl, dbg_info_buffer.items);
+
// If the Decl is a function, we need to update the .debug_line program.
if (is_fn) {
// Perform the relocation based on vaddr.
@@ -1956,6 +1972,10 @@ pub const File = struct {
// Now we have the full contents and may allocate a region to store it.
+ // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
+ // `TextBlock` and the .debug_info. If you are editing this logic, you
+ // probably need to edit that logic too.
+
const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
const src_fn = &decl.fn_link.elf;
src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
@@ -1972,7 +1992,7 @@ pub const File = struct {
src_fn.next = null;
// Populate where it used to be with NOPs.
const file_pos = debug_line_sect.sh_offset + src_fn.off;
- try self.pwriteWithNops(0, &[0]u8{}, src_fn.len, file_pos);
+ try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
// TODO Look at the free list before appending at the end.
src_fn.prev = last;
last.next = src_fn;
@@ -2022,7 +2042,7 @@ pub const File = struct {
// We only have support for one compilation unit so far, so the offsets are directly
// from the .debug_line section.
const file_pos = debug_line_sect.sh_offset + src_fn.off;
- try self.pwriteWithNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
+ try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
}
// Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
@@ -2030,6 +2050,88 @@ pub const File = struct {
return self.updateDeclExports(module, decl, decl_exports);
}
+ pub fn updateDeclDebugInfo(self: *Elf, module: *Module, decl: *Module.Decl, dbg_info_buf: []const u8) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ // This logic is nearly identical to the logic above in `updateDecl` for
+ // `SrcFn` and the line number programs. If you are editing this logic, you
+ // probably need to edit that logic too.
+
+ const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
+ const text_block = &decl.link.elf;
+ if (self.dbg_info_decl_last) |last| {
+ if (text_block.dbg_info_next) |next| {
+ // Update existing Decl - non-last item.
+ if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {
+ // It grew too big, so we move it to a new location.
+ if (text_block.dbg_info_prev) |prev| {
+ _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {};
+ prev.dbg_info_next = text_block.dbg_info_next;
+ }
+ next.dbg_info_prev = text_block.dbg_info_prev;
+ text_block.dbg_info_next = null;
+ // Populate where it used to be with NOPs.
+ const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
+ try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, file_pos);
+ // TODO Look at the free list before appending at the end.
+ text_block.dbg_info_prev = last;
+ last.dbg_info_next = text_block;
+ self.dbg_info_decl_last = text_block;
+
+ text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den);
+ }
+ } else if (text_block.dbg_info_prev == null) {
+ // Append new Decl.
+ // TODO Look at the free list before appending at the end.
+ text_block.dbg_info_prev = last;
+ last.dbg_info_next = text_block;
+ self.dbg_info_decl_last = text_block;
+
+ text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den);
+ }
+ } else {
+ // This is the first Decl of the .debug_info
+ self.dbg_info_decl_first = text_block;
+ self.dbg_info_decl_last = text_block;
+
+ text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den;
+ }
+
+ const last_decl = self.dbg_info_decl_last.?;
+ const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len;
+ if (needed_size != debug_info_sect.sh_size) {
+ if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) {
+ const new_offset = self.findFreeSpace(needed_size, 1);
+ const existing_size = last_decl.dbg_info_off;
+ log.debug(.link, "moving .debug_info section: {} bytes from 0x{x} to 0x{x}\n", .{
+ existing_size,
+ debug_info_sect.sh_offset,
+ new_offset,
+ });
+ const amt = try self.base.file.?.copyRangeAll(debug_info_sect.sh_offset, self.base.file.?, new_offset, existing_size);
+ if (amt != existing_size) return error.InputOutput;
+ debug_info_sect.sh_offset = new_offset;
+ }
+ debug_info_sect.sh_size = needed_size;
+ self.shdr_table_dirty = true; // TODO look into making only the one section dirty
+ self.debug_info_header_dirty = true;
+ }
+ const prev_padding_size: u32 = if (text_block.dbg_info_prev) |prev|
+ text_block.dbg_info_off - (prev.dbg_info_off + prev.dbg_info_len)
+ else
+ 0;
+ const next_padding_size: u32 = if (text_block.dbg_info_next) |next|
+ next.dbg_info_off - (text_block.dbg_info_off + text_block.dbg_info_len)
+ else
+ 0;
+
+ // We only have support for one compilation unit so far, so the offsets are directly
+ // from the .debug_info section.
+ const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
+ try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, file_pos);
+ }
+
/// Must be called only after a successful call to `updateDecl`.
pub fn updateDeclExports(
self: *Elf,
@@ -2221,6 +2323,9 @@ pub const File = struct {
}
fn writeSymbol(self: *Elf, index: usize) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
const syms_sect = &self.sections.items[self.symtab_section_index.?];
// Make sure we are not pointlessly writing symbol data that will have to get relocated
// due to running out of space.
@@ -2361,18 +2466,27 @@ pub const File = struct {
}
+ fn dbgInfoNeededHeaderBytes(self: Elf) u32 {
+ return 120;
+ }
+
+ const min_nop_size = 2;
+
/// Writes to the file a buffer, prefixed and suffixed by the specified number of
/// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes
/// are less than 126,976 bytes (if this limit is ever reached, this function can be
/// improved to make more than one pwritev call, or the limit can be raised by a fixed
/// amount by increasing the length of `vecs`).
- fn pwriteWithNops(
+ fn pwriteDbgLineNops(
self: *Elf,
prev_padding_size: usize,
buf: []const u8,
next_padding_size: usize,
offset: usize,
) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096;
const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0};
var vecs: [32]std.os.iovec_const = undefined;
@@ -2439,7 +2553,66 @@ pub const File = struct {
try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
}
- const min_nop_size = 2;
+ /// Writes to the file a buffer, prefixed and suffixed by the specified number of
+ /// bytes of padding.
+ fn pwriteDbgInfoNops(
+ self: *Elf,
+ prev_padding_size: usize,
+ buf: []const u8,
+ next_padding_size: usize,
+ offset: usize,
+ ) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const page_of_nops = [1]u8{0} ** 4096;
+ var vecs: [32]std.os.iovec_const = undefined;
+ var vec_index: usize = 0;
+ {
+ var padding_left = prev_padding_size;
+ while (padding_left > page_of_nops.len) {
+ vecs[vec_index] = .{
+ .iov_base = &page_of_nops,
+ .iov_len = page_of_nops.len,
+ };
+ vec_index += 1;
+ padding_left -= page_of_nops.len;
+ }
+ if (padding_left > 0) {
+ vecs[vec_index] = .{
+ .iov_base = &page_of_nops,
+ .iov_len = padding_left,
+ };
+ vec_index += 1;
+ }
+ }
+
+ vecs[vec_index] = .{
+ .iov_base = buf.ptr,
+ .iov_len = buf.len,
+ };
+ vec_index += 1;
+
+ {
+ var padding_left = next_padding_size;
+ while (padding_left > page_of_nops.len) {
+ vecs[vec_index] = .{
+ .iov_base = &page_of_nops,
+ .iov_len = page_of_nops.len,
+ };
+ vec_index += 1;
+ padding_left -= page_of_nops.len;
+ }
+ if (padding_left > 0) {
+ vecs[vec_index] = .{
+ .iov_base = &page_of_nops,
+ .iov_len = padding_left,
+ };
+ vec_index += 1;
+ }
+ }
+ try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
+ }
};
};