authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 12:38:40+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:06+02:00
logee1c3c70580bc8d0259a495cf67c3090196983b5
tree3810b12e3b66754fee915f0dfd3293e183eede35
parentb0e2c6323bfa8f5991546cb96122a29a599e0365

elf: correctly copy and write out debug sections


2 files changed, 64 insertions(+), 15 deletions(-)

src/link/Dwarf.zig+2-3
...@@ -1851,8 +1851,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u...@@ -1851,8 +1851,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
1851 // not including the initial length itself.1851 // not including the initial length itself.
1852 // We have to come back and write it later after we know the size.1852 // We have to come back and write it later after we know the size.
1853 const after_init_len = di_buf.items.len + init_len_size;1853 const after_init_len = di_buf.items.len + init_len_size;
1854 // +1 for the final 0 that ends the compilation unit children.1854 const dbg_info_end = self.getDebugInfoEnd().?;
1855 const dbg_info_end = self.getDebugInfoEnd().? + 1;
1856 const init_len = dbg_info_end - after_init_len;1855 const init_len = dbg_info_end - after_init_len;
1857 if (self.bin_file.tag == .macho) {1856 if (self.bin_file.tag == .macho) {
1858 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(init_len)));1857 mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(init_len)));
...@@ -2501,7 +2500,7 @@ fn getDebugInfoOff(self: Dwarf) ?u32 {...@@ -2501,7 +2500,7 @@ fn getDebugInfoOff(self: Dwarf) ?u32 {
2501fn getDebugInfoEnd(self: Dwarf) ?u32 {2500fn getDebugInfoEnd(self: Dwarf) ?u32 {
2502 const last_index = self.di_atom_last_index orelse return null;2501 const last_index = self.di_atom_last_index orelse return null;
2503 const last = self.getAtom(.di_atom, last_index);2502 const last = self.getAtom(.di_atom, last_index);
2504 return last.off + last.len;2503 return last.off + last.len + 1;
2505}2504}
25062505
2507fn getDebugLineProgramOff(self: Dwarf) ?u32 {2506fn getDebugLineProgramOff(self: Dwarf) ?u32 {
src/link/Elf.zig+62-12
...@@ -108,12 +108,21 @@ zig_rodata_section_index: ?u16 = null,...@@ -108,12 +108,21 @@ zig_rodata_section_index: ?u16 = null,
108zig_data_section_index: ?u16 = null,108zig_data_section_index: ?u16 = null,
109zig_bss_section_index: ?u16 = null,109zig_bss_section_index: ?u16 = null,
110zig_got_section_index: ?u16 = null,110zig_got_section_index: ?u16 = null,
111
111debug_info_section_index: ?u16 = null,112debug_info_section_index: ?u16 = null,
112debug_abbrev_section_index: ?u16 = null,113debug_abbrev_section_index: ?u16 = null,
113debug_str_section_index: ?u16 = null,114debug_str_section_index: ?u16 = null,
114debug_aranges_section_index: ?u16 = null,115debug_aranges_section_index: ?u16 = null,
115debug_line_section_index: ?u16 = null,116debug_line_section_index: ?u16 = null,
116117
118/// Size contribution of Zig's metadata to each debug section.
119/// Used to track start of metadata from input object files.
120debug_info_section_zig_size: u64 = 0,
121debug_abbrev_section_zig_size: u64 = 0,
122debug_str_section_zig_size: u64 = 0,
123debug_aranges_section_zig_size: u64 = 0,
124debug_line_section_zig_size: u64 = 0,
125
117copy_rel_section_index: ?u16 = null,126copy_rel_section_index: ?u16 = null,
118dynamic_section_index: ?u16 = null,127dynamic_section_index: ?u16 = null,
119dynstrtab_section_index: ?u16 = null,128dynstrtab_section_index: ?u16 = null,
...@@ -924,7 +933,7 @@ pub fn growNonAllocSection(...@@ -924,7 +933,7 @@ pub fn growNonAllocSection(
924 shdr.sh_offset = new_offset;933 shdr.sh_offset = new_offset;
925 }934 }
926935
927 shdr.sh_size = needed_size; // anticipating adding the global symbols later936 shdr.sh_size = needed_size;
928937
929 self.markDirty(shdr_index);938 self.markDirty(shdr_index);
930}939}
...@@ -1522,8 +1531,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1522,8 +1531,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1522 }1531 }
15231532
1524 if (self.debug_info_header_dirty) {1533 if (self.debug_info_header_dirty) {
1525 // Currently only one compilation unit is supported, so the address range is simply
1526 // identical to the main program header virtual address and memory size.
1527 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];1534 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1528 const low_pc = text_phdr.p_vaddr;1535 const low_pc = text_phdr.p_vaddr;
1529 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;1536 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
...@@ -1532,8 +1539,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1532,8 +1539,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1532 }1539 }
15331540
1534 if (self.debug_aranges_section_dirty) {1541 if (self.debug_aranges_section_dirty) {
1535 // Currently only one compilation unit is supported, so the address range is simply
1536 // identical to the main program header virtual address and memory size.
1537 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];1542 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1538 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);1543 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1539 self.debug_aranges_section_dirty = false;1544 self.debug_aranges_section_dirty = false;
...@@ -1552,6 +1557,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1552,6 +1557,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1552 self.debug_strtab_dirty = false;1557 self.debug_strtab_dirty = false;
1553 }1558 }
1554 }1559 }
1560
1561 self.saveDebugSectionsSizes();
1555 }1562 }
15561563
1557 // Generate and emit non-incremental sections.1564 // Generate and emit non-incremental sections.
...@@ -4345,6 +4352,24 @@ fn sortShdrs(self: *Elf) !void {...@@ -4345,6 +4352,24 @@ fn sortShdrs(self: *Elf) !void {
4345 }4352 }
4346}4353}
43474354
4355fn saveDebugSectionsSizes(self: *Elf) void {
4356 if (self.debug_info_section_index) |shndx| {
4357 self.debug_info_section_zig_size = self.shdrs.items[shndx].sh_size;
4358 }
4359 if (self.debug_abbrev_section_index) |shndx| {
4360 self.debug_abbrev_section_zig_size = self.shdrs.items[shndx].sh_size;
4361 }
4362 if (self.debug_str_section_index) |shndx| {
4363 self.debug_str_section_zig_size = self.shdrs.items[shndx].sh_size;
4364 }
4365 if (self.debug_aranges_section_index) |shndx| {
4366 self.debug_aranges_section_zig_size = self.shdrs.items[shndx].sh_size;
4367 }
4368 if (self.debug_line_section_index) |shndx| {
4369 self.debug_line_section_zig_size = self.shdrs.items[shndx].sh_size;
4370 }
4371}
4372
4348fn updateSectionSizes(self: *Elf) !void {4373fn updateSectionSizes(self: *Elf) !void {
4349 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {4374 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
4350 if (atom_list.items.len == 0) continue;4375 if (atom_list.items.len == 0) continue;
...@@ -4675,18 +4700,31 @@ fn allocateNonAllocSections(self: *Elf) !void {...@@ -4675,18 +4700,31 @@ fn allocateNonAllocSections(self: *Elf) !void {
4675 const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign);4700 const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign);
46764701
4677 if (self.isDebugSection(@intCast(shndx))) {4702 if (self.isDebugSection(@intCast(shndx))) {
4703 log.debug("moving {s} from 0x{x} to 0x{x}", .{
4704 self.shstrtab.getAssumeExists(shdr.sh_name),
4705 shdr.sh_offset,
4706 new_offset,
4707 });
4708 const existing_size = blk: {
4709 if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;
4710 if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;
4711 if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;
4712 if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;
4713 if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;
4714 unreachable;
4715 };
4678 const amt = try self.base.file.?.copyRangeAll(4716 const amt = try self.base.file.?.copyRangeAll(
4679 shdr.sh_offset,4717 shdr.sh_offset,
4680 self.base.file.?,4718 self.base.file.?,
4681 new_offset,4719 new_offset,
4682 needed_size, // TODO this will copy too much but ah well4720 existing_size,
4683 );4721 );
4684 if (amt != needed_size) return error.InputOutput;4722 if (amt != existing_size) return error.InputOutput;
4685 }4723 }
46864724
4687 shdr.sh_offset = new_offset;4725 shdr.sh_offset = new_offset;
4726 shdr.sh_size = needed_size;
4688 }4727 }
4689 shdr.sh_size = needed_size;
4690 }4728 }
4691}4729}
46924730
...@@ -4771,7 +4809,19 @@ fn writeAtoms(self: *Elf) !void {...@@ -4771,7 +4809,19 @@ fn writeAtoms(self: *Elf) !void {
47714809
4772 log.debug("writing atoms in '{s}' section", .{self.shstrtab.getAssumeExists(shdr.sh_name)});4810 log.debug("writing atoms in '{s}' section", .{self.shstrtab.getAssumeExists(shdr.sh_name)});
47734811
4774 const buffer = try gpa.alloc(u8, shdr.sh_size);4812 // TODO really, really handle debug section separately
4813 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
4814 if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;
4815 if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;
4816 if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;
4817 if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;
4818 if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;
4819 unreachable;
4820 } else 0;
4821 const sh_offset = shdr.sh_offset + base_offset;
4822 const sh_size = shdr.sh_size - base_offset;
4823
4824 const buffer = try gpa.alloc(u8, sh_size);
4775 defer gpa.free(buffer);4825 defer gpa.free(buffer);
4776 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and4826 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
4777 shdr.sh_flags & elf.SHF_EXECINSTR != 0)4827 shdr.sh_flags & elf.SHF_EXECINSTR != 0)
...@@ -4785,9 +4835,9 @@ fn writeAtoms(self: *Elf) !void {...@@ -4785,9 +4835,9 @@ fn writeAtoms(self: *Elf) !void {
4785 assert(atom_ptr.flags.alive);4835 assert(atom_ptr.flags.alive);
47864836
4787 const object = atom_ptr.file(self).?.object;4837 const object = atom_ptr.file(self).?.object;
4788 const offset = atom_ptr.value - shdr.sh_addr;4838 const offset = atom_ptr.value - shdr.sh_addr - base_offset;
47894839
4790 log.debug("writing atom({d}) at 0x{x}", .{ atom_index, shdr.sh_offset + offset });4840 log.debug("writing atom({d}) at 0x{x}", .{ atom_index, sh_offset + offset });
47914841
4792 // TODO decompress directly into provided buffer4842 // TODO decompress directly into provided buffer
4793 const out_code = buffer[offset..][0..atom_ptr.size];4843 const out_code = buffer[offset..][0..atom_ptr.size];
...@@ -4808,7 +4858,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -4808,7 +4858,7 @@ fn writeAtoms(self: *Elf) !void {
4808 }4858 }
4809 }4859 }
48104860
4811 try self.base.file.?.pwriteAll(buffer, shdr.sh_offset);4861 try self.base.file.?.pwriteAll(buffer, sh_offset);
4812 }4862 }
48134863
4814 try self.reportUndefined(&undefs);4864 try self.reportUndefined(&undefs);