From 5fad6837919c683b48d11987e55948b7f25d67cd Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 13 Oct 2023 23:01:48 +0200 Subject: [PATCH] elf: emit (broken) debug sections --- src/link/Elf.zig | 115 +++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 43 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index c3628661d6..19a7b840cd 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1515,6 +1515,47 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // Scan and create missing synthetic entries such as GOT indirection. try self.scanRelocs(); + // TODO I need to re-think how to handle ZigModule's debug sections AND debug sections + // extracted from input object files correctly. + if (self.dwarf) |*dw| { + if (self.debug_abbrev_section_dirty) { + try dw.writeDbgAbbrev(); + self.debug_abbrev_section_dirty = false; + } + + if (self.debug_info_header_dirty) { + // Currently only one compilation unit is supported, so the address range is simply + // identical to the main program header virtual address and memory size. + const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?]; + const low_pc = text_phdr.p_vaddr; + const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; + try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc); + self.debug_info_header_dirty = false; + } + + if (self.debug_aranges_section_dirty) { + // Currently only one compilation unit is supported, so the address range is simply + // identical to the main program header virtual address and memory size. + const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?]; + try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); + self.debug_aranges_section_dirty = false; + } + + if (self.debug_line_header_dirty) { + try dw.writeDbgLineHeader(); + self.debug_line_header_dirty = false; + } + + if (self.debug_str_section_index) |shndx| { + if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) { + try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false); + const shdr = self.shdrs.items[shndx]; + try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset); + self.debug_strtab_dirty = false; + } + } + } + // Generate and emit non-incremental sections. try self.initSections(); try self.initSpecialPhdrs(); @@ -1531,7 +1572,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node self.allocatePhdrTable(); try self.allocateAllocSections(); - self.allocateNonAllocSections(); + try self.allocateNonAllocSections(); self.allocateSpecialPhdrs(); self.allocateAtoms(); self.allocateLinkerDefinedSymbols(); @@ -1574,45 +1615,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node }; try self.base.file.?.pwriteAll(code, file_offset); } - - if (self.dwarf) |*dw| { - if (self.debug_abbrev_section_dirty) { - try dw.writeDbgAbbrev(); - self.debug_abbrev_section_dirty = false; - } - - if (self.debug_info_header_dirty) { - // Currently only one compilation unit is supported, so the address range is simply - // identical to the main program header virtual address and memory size. - const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?]; - const low_pc = text_phdr.p_vaddr; - const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; - try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc); - self.debug_info_header_dirty = false; - } - - if (self.debug_aranges_section_dirty) { - // Currently only one compilation unit is supported, so the address range is simply - // identical to the main program header virtual address and memory size. - const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?]; - try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); - self.debug_aranges_section_dirty = false; - } - - if (self.debug_line_header_dirty) { - try dw.writeDbgLineHeader(); - self.debug_line_header_dirty = false; - } - - if (self.debug_str_section_index) |shndx| { - if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) { - try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false); - const shdr = self.shdrs.items[shndx]; - try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset); - self.debug_strtab_dirty = false; - } - } - } } try self.writePhdrTable(); @@ -4601,14 +4603,26 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { } /// Allocates non-alloc sections (debug info, symtabs, etc.). -fn allocateNonAllocSections(self: *Elf) void { - for (self.shdrs.items) |*shdr| { +fn allocateNonAllocSections(self: *Elf) !void { + for (self.shdrs.items, 0..) |*shdr, shndx| { if (shdr.sh_type == elf.SHT_NULL) continue; if (shdr.sh_flags & elf.SHF_ALLOC != 0) continue; const needed_size = shdr.sh_size; if (needed_size > self.allocatedSize(shdr.sh_offset)) { shdr.sh_size = 0; - shdr.sh_offset = self.findFreeSpace(needed_size, shdr.sh_addralign); + const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign); + + if (self.isDebugSection(@intCast(shndx))) { + const amt = try self.base.file.?.copyRangeAll( + shdr.sh_offset, + self.base.file.?, + new_offset, + needed_size, // TODO this will copy too much but ah well + ); + if (amt != needed_size) return error.InputOutput; + } + + shdr.sh_offset = new_offset; } shdr.sh_size = needed_size; } @@ -5354,6 +5368,21 @@ pub fn isZigSection(self: Elf, shndx: u16) bool { return false; } +pub fn isDebugSection(self: Elf, shndx: u16) bool { + inline for (&[_]?u16{ + self.debug_info_section_index, + self.debug_abbrev_section_index, + self.debug_str_section_index, + self.debug_aranges_section_index, + self.debug_line_section_index, + }) |maybe_index| { + if (maybe_index) |index| { + if (index == shndx) return true; + } + } + return false; +} + fn addPhdr(self: *Elf, opts: struct { type: u32 = 0, flags: u32 = 0,