authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-08 00:20:19+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-09 09:24:25+01:00
log4c38ba7d1b64ac69bbb7cc612503bd32661cbbe5
treeee295aa5e94e549129b02cb539d9826773cb8b17
parentbe2b85f670d5fd1d3a8b5cea60bfc8a7b5f2e1e0

dwarf: move SrcFns if debug_line header exceeded its padding


1 files changed, 62 insertions(+), 15 deletions(-)

src/link/Dwarf.zig+62-15
...@@ -1138,8 +1138,7 @@ pub fn commitDeclState(...@@ -1138,8 +1138,7 @@ pub fn commitDeclState(
1138 self.dbg_line_fn_first = src_fn;1138 self.dbg_line_fn_first = src_fn;
1139 self.dbg_line_fn_last = src_fn;1139 self.dbg_line_fn_last = src_fn;
11401140
1141 // TODO TEXME JK1141 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));
1142 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}) * 100);
1143 }1142 }
11441143
1145 const last_src_fn = self.dbg_line_fn_last.?;1144 const last_src_fn = self.dbg_line_fn_last.?;
...@@ -2277,6 +2276,8 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {...@@ -2277,6 +2276,8 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2277}2276}
22782277
2279pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {2278pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
2279 const gpa = self.allocator;
2280
2280 const ptr_width_bytes: u8 = self.ptrWidthBytes();2281 const ptr_width_bytes: u8 = self.ptrWidthBytes();
2281 const target_endian = self.target.cpu.arch.endian();2282 const target_endian = self.target.cpu.arch.endian();
2282 const init_len_size: usize = if (self.bin_file.tag == .macho)2283 const init_len_size: usize = if (self.bin_file.tag == .macho)
...@@ -2287,11 +2288,10 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {...@@ -2287,11 +2288,10 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
2287 };2288 };
22882289
2289 const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return;2290 const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return;
2290 const dbg_line_prg_end = self.getDebugLineProgramEnd().?;2291 assert(self.getDebugLineProgramEnd().? != 0);
2291 assert(dbg_line_prg_end != 0);
22922292
2293 // Convert all input DI files into a set of include dirs and file names.2293 // Convert all input DI files into a set of include dirs and file names.
2294 var arena = std.heap.ArenaAllocator.init(self.allocator);2294 var arena = std.heap.ArenaAllocator.init(gpa);
2295 defer arena.deinit();2295 defer arena.deinit();
2296 const paths = try self.genIncludeDirsAndFileNames(arena.allocator(), module);2296 const paths = try self.genIncludeDirsAndFileNames(arena.allocator(), module);
22972297
...@@ -2299,25 +2299,25 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {...@@ -2299,25 +2299,25 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
2299 // files, and padding. We have a function to compute the upper bound size, however,2299 // files, and padding. We have a function to compute the upper bound size, however,
2300 // because it's needed for determining where to put the offset of the first `SrcFn`.2300 // because it's needed for determining where to put the offset of the first `SrcFn`.
2301 const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files);2301 const needed_bytes = self.dbgLineNeededHeaderBytes(paths.dirs, paths.files);
2302 var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes);2302 var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes);
2303 defer di_buf.deinit();2303 defer di_buf.deinit();
23042304
2305 // initial length - length of the .debug_line contribution for this compilation unit,2305 // initial length - length of the .debug_line contribution for this compilation unit,
2306 // not including the initial length itself.2306 // not including the initial length itself.
2307 const after_init_len = di_buf.items.len + init_len_size;2307 // We will backpatch this value later so just remember where we need to write it.
2308 const init_len = dbg_line_prg_end - after_init_len;2308 const before_init_len = di_buf.items.len;
23092309
2310 switch (self.bin_file.tag) {2310 switch (self.bin_file.tag) {
2311 .macho => {2311 .macho => {
2312 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len));2312 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0));
2313 },2313 },
2314 else => switch (self.ptr_width) {2314 else => switch (self.ptr_width) {
2315 .p32 => {2315 .p32 => {
2316 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);2316 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0), target_endian);
2317 },2317 },
2318 .p64 => {2318 .p64 => {
2319 di_buf.appendNTimesAssumeCapacity(0xff, 4);2319 di_buf.appendNTimesAssumeCapacity(0xff, 4);
2320 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);2320 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), @as(u64, 0), target_endian);
2321 },2321 },
2322 },2322 },
2323 }2323 }
...@@ -2400,12 +2400,59 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {...@@ -2400,12 +2400,59 @@ pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void {
24002400
2401 assert(needed_bytes == di_buf.items.len);2401 assert(needed_bytes == di_buf.items.len);
24022402
2403 // We use NOPs because consumers empirically do not respect the header length field.
2404 if (di_buf.items.len > dbg_line_prg_off) {2403 if (di_buf.items.len > dbg_line_prg_off) {
2405 // Move the first N files to the end to make more padding for the header.2404 const needed_with_padding = padToIdeal(needed_bytes);
2406 @panic("TODO: handle .debug_line header exceeding its padding");2405 const delta = needed_with_padding - dbg_line_prg_off;
2406
2407 const macho_file = self.bin_file.cast(File.MachO).?;
2408 const d_sym = &macho_file.d_sym.?;
2409 const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?];
2410 const needed_size = debug_line_sect.size + delta;
2411
2412 if (needed_size > d_sym.allocatedSize(debug_line_sect.offset)) {
2413 @panic("TODO grow debug_line section");
2414 }
2415
2416 var src_fn = self.dbg_line_fn_first.?;
2417 const last_fn = self.dbg_line_fn_last.?;
2418 const file_pos = debug_line_sect.offset + src_fn.off;
2419
2420 var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - src_fn.off);
2421 defer gpa.free(buffer);
2422 const amt = try d_sym.file.preadAll(buffer, file_pos);
2423 if (amt != buffer.len) return error.InputOutput;
2424
2425 try d_sym.file.pwriteAll(buffer, file_pos + delta);
2426
2427 debug_line_sect.size = needed_size;
2428
2429 while (true) {
2430 src_fn.off += delta;
2431
2432 if (src_fn.next) |next| {
2433 src_fn = next;
2434 } else break;
2435 }
2436 }
2437
2438 // Backpatch actual length of the debug line program
2439 const init_len = self.getDebugLineProgramEnd().? - before_init_len - init_len_size;
2440 switch (self.bin_file.tag) {
2441 .macho => {
2442 mem.writeIntLittle(u32, di_buf.items[before_init_len..][0..4], @intCast(u32, init_len));
2443 },
2444 else => switch (self.ptr_width) {
2445 .p32 => {
2446 mem.writeInt(u32, di_buf.items[before_init_len..][0..4], @intCast(u32, init_len), target_endian);
2447 },
2448 .p64 => {
2449 mem.writeInt(u64, di_buf.items[before_init_len + 4 ..][0..8], init_len, target_endian);
2450 },
2451 },
2407 }2452 }
2408 const jmp_amt = dbg_line_prg_off - di_buf.items.len;2453
2454 // We use NOPs because consumers empirically do not respect the header length field.
2455 const jmp_amt = self.getDebugLineProgramOff().? - di_buf.items.len;
2409 switch (self.bin_file.tag) {2456 switch (self.bin_file.tag) {
2410 .elf => {2457 .elf => {
2411 const elf_file = self.bin_file.cast(File.Elf).?;2458 const elf_file = self.bin_file.cast(File.Elf).?;