aboutsummaryrefslogtreecommitdiff
path: root/src/link/Dwarf.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-12-08 00:20:19 +0100
committerJakub Konka <kubkon@jakubkonka.com>2022-12-09 09:24:25 +0100
commit4c38ba7d1b64ac69bbb7cc612503bd32661cbbe5 (patch)
treeee295aa5e94e549129b02cb539d9826773cb8b17 /src/link/Dwarf.zig
parentbe2b85f670d5fd1d3a8b5cea60bfc8a7b5f2e1e0 (diff)
downloadzig-4c38ba7d1b64ac69bbb7cc612503bd32661cbbe5.tar.gz
zig-4c38ba7d1b64ac69bbb7cc612503bd32661cbbe5.zip
dwarf: move SrcFns if debug_line header exceeded its padding
Diffstat (limited to 'src/link/Dwarf.zig')
-rw-r--r--src/link/Dwarf.zig77
1 files changed, 62 insertions, 15 deletions
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
index 26d08b708e..1a3c1f93f3 100644
--- a/src/link/Dwarf.zig
+++ b/src/link/Dwarf.zig
@@ -1138,8 +1138,7 @@ pub fn commitDeclState(
self.dbg_line_fn_first = src_fn;
self.dbg_line_fn_last = src_fn;
- // TODO TEXME JK
- src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}) * 100);
+ src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));
}
const last_src_fn = self.dbg_line_fn_last.?;
@@ -2277,6 +2276,8 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
}
pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
+ const gpa = self.allocator;
+
const ptr_width_bytes: u8 = self.ptrWidthBytes();
const target_endian = self.target.cpu.arch.endian();
const init_len_size: usize = if (self.bin_file.tag == .macho)
@@ -2287,11 +2288,10 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
};
const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return;
- const dbg_line_prg_end = self.getDebugLineProgramEnd().?;
- assert(dbg_line_prg_end != 0);
+ assert(self.getDebugLineProgramEnd().? != 0);
// Convert all input DI files into a set of include dirs and file names.
- var arena = std.heap.ArenaAllocator.init(self.allocator);
+ var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
const paths = try self.genIncludeDirsAndFileNames(arena.allocator(), module);
@@ -2299,25 +2299,25 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
// files, and padding. We have a function to compute the upper bound size, however,
// because it's needed for determining where to put the offset of the first `SrcFn`.
const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files);
- var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes);
+ var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes);
defer di_buf.deinit();
// initial length - length of the .debug_line contribution for this compilation unit,
// not including the initial length itself.
- const after_init_len = di_buf.items.len + init_len_size;
- const init_len = dbg_line_prg_end - after_init_len;
+ // We will backpatch this value later so just remember where we need to write it.
+ const before_init_len = di_buf.items.len;
switch (self.bin_file.tag) {
.macho => {
- mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len));
+ mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0));
},
else => switch (self.ptr_width) {
.p32 => {
- mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
+ mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0), target_endian);
},
.p64 => {
di_buf.appendNTimesAssumeCapacity(0xff, 4);
- mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);
+ mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), @as(u64, 0), target_endian);
},
},
}
@@ -2400,12 +2400,59 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
assert(needed_bytes == di_buf.items.len);
- // We use NOPs because consumers empirically do not respect the header length field.
if (di_buf.items.len > dbg_line_prg_off) {
- // Move the first N files to the end to make more padding for the header.
- @panic("TODO: handle .debug_line header exceeding its padding");
+ const needed_with_padding = padToIdeal(needed_bytes);
+ const delta = needed_with_padding - dbg_line_prg_off;
+
+ const macho_file = self.bin_file.cast(File.MachO).?;
+ const d_sym = &macho_file.d_sym.?;
+ const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?];
+ const needed_size = debug_line_sect.size + delta;
+
+ if (needed_size > d_sym.allocatedSize(debug_line_sect.offset)) {
+ @panic("TODO grow debug_line section");
+ }
+
+ var src_fn = self.dbg_line_fn_first.?;
+ const last_fn = self.dbg_line_fn_last.?;
+ const file_pos = debug_line_sect.offset + src_fn.off;
+
+ var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - src_fn.off);
+ defer gpa.free(buffer);
+ const amt = try d_sym.file.preadAll(buffer, file_pos);
+ if (amt != buffer.len) return error.InputOutput;
+
+ try d_sym.file.pwriteAll(buffer, file_pos + delta);
+
+ debug_line_sect.size = needed_size;
+
+ while (true) {
+ src_fn.off += delta;
+
+ if (src_fn.next) |next| {
+ src_fn = next;
+ } else break;
+ }
+ }
+
+ // Backpatch actual length of the debug line program
+ const init_len = self.getDebugLineProgramEnd().? - before_init_len - init_len_size;
+ switch (self.bin_file.tag) {
+ .macho => {
+ mem.writeIntLittle(u32, di_buf.items[before_init_len..][0..4], @intCast(u32, init_len));
+ },
+ else => switch (self.ptr_width) {
+ .p32 => {
+ mem.writeInt(u32, di_buf.items[before_init_len..][0..4], @intCast(u32, init_len), target_endian);
+ },
+ .p64 => {
+ mem.writeInt(u64, di_buf.items[before_init_len + 4 ..][0..8], init_len, target_endian);
+ },
+ },
}
- const jmp_amt = dbg_line_prg_off - di_buf.items.len;
+
+ // We use NOPs because consumers empirically do not respect the header length field.
+ const jmp_amt = self.getDebugLineProgramOff().? - di_buf.items.len;
switch (self.bin_file.tag) {
.elf => {
const elf_file = self.bin_file.cast(File.Elf).?;