diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-12-06 19:29:23 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-12-09 09:24:25 +0100 |
| commit | f5c764d8923d301bb7e46b50cb034285640fcca2 (patch) | |
| tree | e573f5faca2995d766b56e1e001989a343ff08b3 /src | |
| parent | 4c4821d9939447d65966b897a5780e39eb22334b (diff) | |
| download | zig-f5c764d8923d301bb7e46b50cb034285640fcca2.tar.gz zig-f5c764d8923d301bb7e46b50cb034285640fcca2.zip | |
dwarf: track source files via *const Module.File pointers
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Dwarf.zig | 267 | ||||
| -rw-r--r-- | src/link/Elf.zig | 16 | ||||
| -rw-r--r-- | src/link/MachO.zig | 8 | ||||
| -rw-r--r-- | src/link/MachO/DebugSymbols.zig | 8 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 15 |
5 files changed, 162 insertions, 152 deletions
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index e4d6b8ae05..12b34a070b 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -22,7 +22,7 @@ const Value = @import("../value.zig").Value; const Type = @import("../type.zig").Type; allocator: Allocator, -tag: File.Tag, +bin_file: *File, ptr_width: PtrWidth, target: std.Target, @@ -44,10 +44,9 @@ abbrev_table_offset: ?u64 = null, /// Table of debug symbol names. strtab: std.ArrayListUnmanaged(u8) = .{}, -file_names_buffer: std.ArrayListUnmanaged(u8) = .{}, -file_names: std.ArrayListUnmanaged(u32) = .{}, -file_names_free_list: std.ArrayListUnmanaged(u28) = .{}, -file_names_lookup: std.AutoHashMapUnmanaged(*Module.File, u28) = .{}, +di_files: std.ArrayListUnmanaged(DIFile) = .{}, +di_files_free_list: std.ArrayListUnmanaged(u28) = .{}, +di_files_lookup: std.AutoHashMapUnmanaged(*const Module.File, u28) = .{}, /// List of atoms that are owned directly by the DWARF module. /// TODO convert links in DebugInfoAtom into indices and make @@ -56,6 +55,15 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, +const DIFile = struct { + file_source: *const Module.File, + ref_count: u32, + + fn getFullPath(dif: DIFile, allocator: Allocator) ![]const u8 { + return dif.file_source.fullPath(allocator); + } +}; + pub const Atom = struct { /// Previous/next linked list pointers. /// This is the linked list node for this Decl's corresponding .debug_info tag. @@ -892,7 +900,7 @@ const min_nop_size = 2; /// actual_capacity + (actual_capacity / ideal_factor) const ideal_factor = 3; -pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf { +pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf { const ptr_width: PtrWidth = switch (target.cpu.arch.ptrBitWidth()) { 0...32 => .p32, 33...64 => .p64, @@ -900,7 +908,7 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf { }; return Dwarf{ .allocator = allocator, - .tag = tag, + .bin_file = bin_file, .ptr_width = ptr_width, .target = target, }; @@ -911,10 +919,9 @@ pub fn deinit(self: *Dwarf) void { self.dbg_line_fn_free_list.deinit(gpa); self.atom_free_list.deinit(gpa); self.strtab.deinit(gpa); - self.file_names_buffer.deinit(gpa); - self.file_names.deinit(gpa); - self.file_names_free_list.deinit(gpa); - self.file_names_lookup.deinit(gpa); + self.di_files.deinit(gpa); + self.di_files_free_list.deinit(gpa); + self.di_files_lookup.deinit(gpa); self.global_abbrev_relocs.deinit(gpa); for (self.managed_atoms.items) |atom| { @@ -977,7 +984,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); // Once we support more than one source file, this will have the ability to be more // than one possible value. - const file_index = try self.addFileName(mod, decl_index); + const file_index = try self.addDIFile(mod, decl_index); leb128.writeUnsignedFixed( 4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), @@ -1008,7 +1015,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 // if (fn_ret_has_bits) { - const atom = getDbgInfoAtom(self.tag, mod, decl_index); + const atom = getDbgInfoAtom(self.bin_file.tag, mod, decl_index); try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len)); dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 } @@ -1026,7 +1033,6 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) pub fn commitDeclState( self: *Dwarf, - file: *File, module: *Module, decl_index: Module.Decl.Index, sym_addr: u64, @@ -1082,7 +1088,7 @@ pub fn commitDeclState( // 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 src_fn = switch (self.tag) { + const src_fn = switch (self.bin_file.tag) { .elf => &decl.fn_link.elf, .macho => &decl.fn_link.macho, .wasm => &decl.fn_link.wasm.src_fn, @@ -1103,22 +1109,22 @@ pub fn commitDeclState( next.prev = src_fn.prev; src_fn.next = null; // Populate where it used to be with NOPs. - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?]; const file_pos = debug_line_sect.sh_offset + src_fn.off; try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len); }, .macho => { - const macho_file = file.cast(File.MachO).?; + 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 file_pos = debug_line_sect.offset + src_fn.off; try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len); }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_line = wasm_file.debug_line_atom.?.code; writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len); }, @@ -1156,9 +1162,9 @@ pub fn commitDeclState( // We only have support for one compilation unit so far, so the offsets are directly // from the .debug_line section. - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?]; if (needed_size != debug_line_sect.sh_size) { if (needed_size > elf_file.allocatedSize(debug_line_sect.sh_offset)) { @@ -1193,7 +1199,7 @@ pub fn commitDeclState( }, .macho => { - const macho_file = file.cast(File.MachO).?; + 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.?]; if (needed_size != debug_line_sect.size) { @@ -1228,7 +1234,7 @@ pub fn commitDeclState( }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const atom = wasm_file.debug_line_atom.?; const debug_line = &atom.code; const segment_size = debug_line.items.len; @@ -1261,7 +1267,7 @@ pub fn commitDeclState( if (dbg_info_buffer.items.len == 0) return; - const atom = getDbgInfoAtom(self.tag, module, decl_index); + const atom = getDbgInfoAtom(self.bin_file.tag, module, decl_index); if (decl_state.abbrev_table.items.len > 0) { // Now we emit the .debug_info types of the Decl. These will count towards the size of // the buffer, so we have to do it before computing the offset, and we can't perform the actual @@ -1288,7 +1294,7 @@ pub fn commitDeclState( } log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name}); - try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len)); + try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len)); while (decl_state.abbrev_relocs.popOrNull()) |reloc| { if (reloc.target) |target| { @@ -1333,9 +1339,9 @@ pub fn commitDeclState( } while (decl_state.exprloc_relocs.popOrNull()) |reloc| { - switch (self.tag) { + switch (self.bin_file.tag) { .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = &macho_file.d_sym.?; try d_sym.relocs.append(d_sym.allocator, .{ .type = switch (reloc.type) { @@ -1353,10 +1359,10 @@ pub fn commitDeclState( } log.debug("writeDeclDebugInfo for '{s}", .{decl.name}); - try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items); + try self.writeDeclDebugInfo(atom, dbg_info_buffer.items); } -fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u32) !void { +fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1379,22 +1385,22 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3 next.prev = atom.prev; atom.next = null; // Populate where it used to be with NOPs. - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?]; const file_pos = debug_info_sect.sh_offset + atom.off; try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false); }, .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = &macho_file.d_sym.?; const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?]; const file_pos = debug_info_sect.offset + atom.off; try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false); }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_info = &wasm_file.debug_info_atom.?.code; try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false); }, @@ -1425,7 +1431,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3 } } -fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []const u8) !void { +fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1445,9 +1451,9 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co // We only have support for one compilation unit so far, so the offsets are directly // from the .debug_info section. - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?]; if (needed_size != debug_info_sect.sh_size) { if (needed_size > elf_file.allocatedSize(debug_info_sect.sh_offset)) { @@ -1483,7 +1489,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co }, .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = &macho_file.d_sym.?; const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?]; if (needed_size != debug_info_sect.size) { @@ -1519,7 +1525,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const info_atom = wasm_file.debug_info_atom.?; const debug_info = &info_atom.code; const segment_size = debug_info.items.len; @@ -1549,7 +1555,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co } } -pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl) !void { +pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1563,22 +1569,22 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl) var data: [4]u8 = undefined; leb128.writeUnsignedFixed(4, &data, line); - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?]; const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); try elf_file.base.file.?.pwriteAll(&data, file_pos); }, .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = macho_file.d_sym.?; const sect = d_sym.sections.items[d_sym.debug_line_section_index.?]; const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff(); try d_sym.file.pwriteAll(&data, file_pos); }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff(); const atom = wasm_file.debug_line_atom.?; mem.copy(u8, atom.code.items[offset..], &data); @@ -1615,7 +1621,7 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void { // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing // is desired for both. const gpa = self.allocator; - const fn_link = switch (self.tag) { + const fn_link = switch (self.bin_file.tag) { .elf => &decl.fn_link.elf, .macho => &decl.fn_link.macho, .wasm => &decl.fn_link.wasm.src_fn, @@ -1641,9 +1647,19 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void { if (self.dbg_line_fn_last == fn_link) { self.dbg_line_fn_last = fn_link.prev; } + + const file_source = decl.getFileScope(); + if (self.di_files_lookup.get(file_source)) |dif_index| { + const dif = &self.di_files.items[dif_index]; + dif.ref_count -= 1; + if (dif.ref_count == 0) { + self.di_files_free_list.append(gpa, dif_index) catch {}; + } + _ = self.di_files_lookup.remove(file_source); + } } -pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { +pub fn writeDbgAbbrev(self: *Dwarf) !void { // These are LEB encoded but since the values are all less than 127 // we can simply append these bytes. const abbrev_buf = [_]u8{ @@ -1777,9 +1793,9 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { self.abbrev_table_offset = abbrev_offset; const needed_size = abbrev_buf.len; - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_abbrev_sect = &elf_file.sections.items[elf_file.debug_abbrev_section_index.?]; const allocated_size = elf_file.allocatedSize(debug_abbrev_sect.sh_offset); if (needed_size > allocated_size) { @@ -1796,7 +1812,7 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos); }, .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = &macho_file.d_sym.?; const dwarf_segment = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?]; const debug_abbrev_sect = &d_sym.sections.items[d_sym.debug_abbrev_section_index.?]; @@ -1816,7 +1832,7 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { try d_sym.file.pwriteAll(&abbrev_buf, file_pos); }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code; try debug_abbrev.resize(wasm_file.base.allocator, needed_size); mem.copy(u8, debug_abbrev.items, &abbrev_buf); @@ -1830,7 +1846,7 @@ fn dbgInfoHeaderBytes(self: *Dwarf) usize { return 120; } -pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u64, high_pc: u64) !void { +pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u64) !void { // If this value is null it means there is an error in the module; // leave debug_info_header_dirty=true. const first_dbg_info_off = self.getDebugInfoOff() orelse return; @@ -1842,7 +1858,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 defer di_buf.deinit(); const target_endian = self.target.cpu.arch.endian(); - const init_len_size: usize = if (self.tag == .macho) + const init_len_size: usize = if (self.bin_file.tag == .macho) 4 else switch (self.ptr_width) { .p32 => @as(usize, 4), @@ -1856,7 +1872,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 // +1 for the final 0 that ends the compilation unit children. const dbg_info_end = self.getDebugInfoEnd().? + 1; const init_len = dbg_info_end - after_init_len; - if (self.tag == .macho) { + if (self.bin_file.tag == .macho) { mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len)); } else switch (self.ptr_width) { .p32 => { @@ -1869,7 +1885,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 } mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version const abbrev_offset = self.abbrev_table_offset.?; - if (self.tag == .macho) { + if (self.bin_file.tag == .macho) { mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset)); di_buf.appendAssumeCapacity(8); // address size } else switch (self.ptr_width) { @@ -1888,7 +1904,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 const producer_strp = try self.makeString(link.producer_string); di_buf.appendAssumeCapacity(@enumToInt(AbbrevKind.compile_unit)); - if (self.tag == .macho) { + if (self.bin_file.tag == .macho) { mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT.stmt_list, DW.FORM.sec_offset mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), low_pc); mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), high_pc); @@ -1913,22 +1929,22 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 @panic("TODO: handle .debug_info header exceeding its padding"); } const jmp_amt = first_dbg_info_off - di_buf.items.len; - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_info_sect = elf_file.sections.items[elf_file.debug_info_section_index.?]; const file_pos = debug_info_sect.sh_offset; try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false); }, .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = &macho_file.d_sym.?; const debug_info_sect = d_sym.sections.items[d_sym.debug_info_section_index.?]; const file_pos = debug_info_sect.offset; try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false); }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_info = &wasm_file.debug_info_atom.?.code; try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false); }, @@ -2158,9 +2174,9 @@ fn writeDbgInfoNopsToArrayList( } } -pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { +pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { const target_endian = self.target.cpu.arch.endian(); - const init_len_size: usize = if (self.tag == .macho) + const init_len_size: usize = if (self.bin_file.tag == .macho) 4 else switch (self.ptr_width) { .p32 => @as(usize, 4), @@ -2182,7 +2198,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version // When more than one compilation unit is supported, this will be the offset to it. // For now it is always at offset 0 in .debug_info. - if (self.tag == .macho) { + if (self.bin_file.tag == .macho) { mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // __debug_info offset } else { self.writeAddrAssumeCapacity(&di_buf, 0); // .debug_info offset @@ -2205,7 +2221,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { // Go back and populate the initial length. const init_len = di_buf.items.len - after_init_len; - if (self.tag == .macho) { + if (self.bin_file.tag == .macho) { mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len)); } else switch (self.ptr_width) { .p32 => { @@ -2220,9 +2236,9 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { } const needed_size = di_buf.items.len; - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_aranges_sect = &elf_file.sections.items[elf_file.debug_aranges_section_index.?]; const allocated_size = elf_file.allocatedSize(debug_aranges_sect.sh_offset); if (needed_size > allocated_size) { @@ -2238,7 +2254,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos); }, .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = &macho_file.d_sym.?; const dwarf_seg = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?]; const debug_aranges_sect = &d_sym.sections.items[d_sym.debug_aranges_section_index.?]; @@ -2258,7 +2274,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { try d_sym.file.pwriteAll(di_buf.items, file_pos); }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_ranges = &wasm_file.debug_ranges_atom.?.code; try debug_ranges.resize(wasm_file.base.allocator, needed_size); mem.copy(u8, debug_ranges.items, di_buf.items); @@ -2267,10 +2283,10 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { } } -pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { +pub fn writeDbgLineHeader(self: *Dwarf, module: *Module) !void { const ptr_width_bytes: u8 = self.ptrWidthBytes(); const target_endian = self.target.cpu.arch.endian(); - const init_len_size: usize = if (self.tag == .macho) + const init_len_size: usize = if (self.bin_file.tag == .macho) 4 else switch (self.ptr_width) { .p32 => @as(usize, 4), @@ -2293,7 +2309,7 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { // 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; - if (self.tag == .macho) { + if (self.bin_file.tag == .macho) { mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len)); } else switch (self.ptr_width) { .p32 => { @@ -2312,7 +2328,7 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { // Therefore we rely on the NOP jump at the beginning of the Line Number Program for // padding rather than this field. const before_header_len = di_buf.items.len; - di_buf.items.len += if (self.tag == .macho) @sizeOf(u32) else ptr_width_bytes; // We will come back and write this. + di_buf.items.len += if (self.bin_file.tag == .macho) @sizeOf(u32) else ptr_width_bytes; // We will come back and write this. const after_header_len = di_buf.items.len; const opcode_base = DW.LNS.set_isa + 1; @@ -2340,20 +2356,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { 1, // `DW.LNS.set_isa` 0, // include_directories (none except the compilation unit cwd) }); - // // file_names[0] - // di_buf.appendSliceAssumeCapacity(module.root_pkg.root_src_path); // relative path name - // di_buf.appendSliceAssumeCapacity(&[_]u8{ - // 0, // null byte for the relative path name - // 0, // directory_index - // 0, // mtime (TODO supply this) - // 0, // file size bytes (TODO supply this) - // 0, // file_names sentinel - // }); - - for (self.file_names.items) |off, i| { - const file_name = self.getFileName(off); - log.debug("file_name[{d}] = {s}", .{ i + 1, file_name }); - di_buf.appendSliceAssumeCapacity(file_name); + + for (self.di_files.items) |dif, i| { + const full_path = try dif.getFullPath(self.allocator); + defer self.allocator.free(full_path); + log.debug("adding new file name at {d} of '{s}'", .{ i + 1, full_path }); + di_buf.appendSliceAssumeCapacity(full_path); di_buf.appendSliceAssumeCapacity(&[_]u8{ 0, // null byte for the relative path name 0, // directory_index @@ -2364,7 +2372,7 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { di_buf.appendAssumeCapacity(0); // file names sentinel const header_len = di_buf.items.len - after_header_len; - if (self.tag == .macho) { + if (self.bin_file.tag == .macho) { mem.writeIntLittle(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len)); } else switch (self.ptr_width) { .p32 => { @@ -2381,22 +2389,22 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { @panic("TODO: handle .debug_line header exceeding its padding"); } const jmp_amt = dbg_line_prg_off - di_buf.items.len; - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_line_sect = elf_file.sections.items[elf_file.debug_line_section_index.?]; const file_pos = debug_line_sect.sh_offset; try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt); }, .macho => { - const macho_file = file.cast(File.MachO).?; + 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 file_pos = debug_line_sect.offset; try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt); }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_line = wasm_file.debug_line_atom.?.code; writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt); }, @@ -2436,15 +2444,21 @@ fn dbgLineNeededHeaderBytes(self: Dwarf, module: *Module) u32 { const directory_entry_format_count = 1; const file_name_entry_format_count = 1; const directory_count = 1; - const file_name_count = self.file_names.items.len; + const file_name_count = self.di_files.items.len; const root_src_dir_path_len = if (module.root_pkg.root_src_directory.path) |p| p.len else 1; // "." + var file_names_len: usize = 0; + for (self.di_files.items) |dif| { + const dir_path = dif.file_source.pkg.root_src_directory.path orelse "."; + file_names_len += dir_path.len + dif.file_source.sub_file_path.len + 1; + } + return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 + directory_count * 8 + file_name_count * 8 + // These are encoded as DW.FORM.string rather than DW.FORM.strp as we would like // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. root_src_dir_path_len + - self.file_names_buffer.items.len); + file_names_len); } /// The reloc offset for the line offset of a function from the previous function's line. @@ -2476,7 +2490,7 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { std.math.maxInt(@TypeOf(actual_size)); } -pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { +pub fn flushModule(self: *Dwarf, module: *Module) !void { if (self.global_abbrev_relocs.items.len > 0) { const gpa = self.allocator; var arena_alloc = std.heap.ArenaAllocator.init(gpa); @@ -2507,19 +2521,19 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { try self.managed_atoms.append(gpa, atom); log.debug("updateDeclDebugInfoAllocation in flushModule", .{}); - try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len)); + try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len)); log.debug("writeDeclDebugInfo in flushModule", .{}); - try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items); + try self.writeDeclDebugInfo(atom, dbg_info_buffer.items); const file_pos = blk: { - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?]; break :blk debug_info_sect.sh_offset; }, .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = &macho_file.d_sym.?; const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?]; break :blk debug_info_sect.offset; @@ -2534,18 +2548,18 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian()); while (self.global_abbrev_relocs.popOrNull()) |reloc| { - switch (self.tag) { + switch (self.bin_file.tag) { .elf => { - const elf_file = file.cast(File.Elf).?; + const elf_file = self.bin_file.cast(File.Elf).?; try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset); }, .macho => { - const macho_file = file.cast(File.MachO).?; + const macho_file = self.bin_file.cast(File.MachO).?; const d_sym = &macho_file.d_sym.?; try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset); }, .wasm => { - const wasm_file = file.cast(File.Wasm).?; + const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_info = wasm_file.debug_info_atom.?.code; mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf); }, @@ -2555,17 +2569,17 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { } } -fn allocateFileIndex(self: *Dwarf) !u28 { - try self.file_names.ensureUnusedCapacity(self.allocator, 1); +fn allocateDIFileIndex(self: *Dwarf) !u28 { + try self.di_files.ensureUnusedCapacity(self.allocator, 1); const index = blk: { - if (self.file_names_free_list.popOrNull()) |index| { - log.debug(" (reusing file name index {d})", .{index}); + if (self.di_files_free_list.popOrNull()) |index| { + log.debug(" (reusing DIFile index {d})", .{index}); break :blk index; } else { - const index = @intCast(u28, self.file_names.items.len); - log.debug(" (allocating file name index {d})", .{index}); - _ = self.file_names.addOneAssumeCapacity(); + const index = @intCast(u28, self.di_files.items.len); + log.debug(" (allocating DIFile index {d})", .{index}); + _ = self.di_files.addOneAssumeCapacity(); break :blk index; } }; @@ -2573,27 +2587,28 @@ fn allocateFileIndex(self: *Dwarf) !u28 { return index; } -fn addFileName(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !u28 { +fn addDIFile(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !u28 { const decl = mod.declPtr(decl_index); const file_scope = decl.getFileScope(); - if (self.file_names_lookup.get(file_scope)) |file_index| { - return file_index; - } - const index = try self.allocateFileIndex(); - const file_name = try file_scope.fullPath(self.allocator); - defer self.allocator.free(file_name); - try self.file_names_buffer.ensureUnusedCapacity(self.allocator, file_name.len + 1); - const off = @intCast(u32, self.file_names_buffer.items.len); - self.file_names_buffer.appendSliceAssumeCapacity(file_name); - self.file_names_buffer.appendAssumeCapacity(0); - self.file_names.items[index] = off; - try self.file_names_lookup.putNoClobber(self.allocator, file_scope, index); - return index; -} + const gop = try self.di_files_lookup.getOrPut(self.allocator, file_scope); + if (!gop.found_existing) { + gop.value_ptr.* = try self.allocateDIFileIndex(); + self.di_files.items[gop.value_ptr.*] = .{ + .file_source = file_scope, + .ref_count = 1, + }; -fn getFileName(self: Dwarf, off: u32) []const u8 { - assert(off < self.file_names_buffer.items.len); - return mem.sliceTo(@ptrCast([*:0]const u8, self.file_names_buffer.items.ptr) + off, 0); + switch (self.bin_file.tag) { + .elf => self.bin_file.cast(File.Elf).?.debug_line_header_dirty = true, + .macho => self.bin_file.cast(File.MachO).?.d_sym.?.debug_line_header_dirty = true, + .wasm => {}, + else => unreachable, + } + } else { + const dif = &self.di_files.items[gop.value_ptr.*]; + dif.ref_count += 1; + } + return gop.value_ptr.*; } fn addDbgInfoErrorSet( diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b7968b3f1c..7557af8090 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -312,7 +312,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { }; var dwarf: ?Dwarf = if (!options.strip and options.module != null) - Dwarf.init(gpa, .elf, options.target) + Dwarf.init(gpa, &self.base, options.target) else null; @@ -972,7 +972,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node const foreign_endian = target_endian != builtin.cpu.arch.endian(); if (self.dwarf) |*dw| { - try dw.flushModule(&self.base, module); + try dw.flushModule(module); } { @@ -1020,7 +1020,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node if (self.dwarf) |*dw| { if (self.debug_abbrev_section_dirty) { - try dw.writeDbgAbbrev(&self.base); + try dw.writeDbgAbbrev(); 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_abbrev_section_index.?); @@ -1034,7 +1034,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node const text_phdr = &self.program_headers.items[self.phdr_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, module, low_pc, high_pc); + try dw.writeDbgInfoHeader(module, low_pc, high_pc); self.debug_info_header_dirty = false; } @@ -1042,7 +1042,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // 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.program_headers.items[self.phdr_load_re_index.?]; - try dw.writeDbgAranges(&self.base, text_phdr.p_vaddr, text_phdr.p_memsz); + try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); 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_aranges_section_index.?); @@ -1051,7 +1051,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } if (self.debug_line_header_dirty) { - try dw.writeDbgLineHeader(&self.base, module); + try dw.writeDbgLineHeader(module); self.debug_line_header_dirty = false; } } @@ -2422,7 +2422,6 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC); if (decl_state) |*ds| { try self.dwarf.?.commitDeclState( - &self.base, module, decl_index, local_sym.st_value, @@ -2499,7 +2498,6 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT); if (decl_state) |*ds| { try self.dwarf.?.commitDeclState( - &self.base, module, decl_index, local_sym.st_value, @@ -2692,7 +2690,7 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl) if (self.llvm_object) |_| return; if (self.dwarf) |*dw| { - try dw.updateDeclLineNumber(&self.base, decl); + try dw.updateDeclLineNumber(decl); } } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 8c9e5329f2..8eaf6bbb66 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -347,7 +347,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { self.d_sym = .{ .allocator = allocator, - .dwarf = link.File.Dwarf.init(allocator, .macho, options.target), + .dwarf = link.File.Dwarf.init(allocator, &self.base, options.target), .file = d_sym_file, .page_size = self.page_size, }; @@ -449,7 +449,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; if (self.d_sym) |*d_sym| { - try d_sym.dwarf.flushModule(&self.base, module); + try d_sym.dwarf.flushModule(module); } var libs = std.StringArrayHashMap(link.SystemLib).init(arena); @@ -2213,7 +2213,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv if (decl_state) |*ds| { try self.d_sym.?.dwarf.commitDeclState( - &self.base, module, decl_index, addr, @@ -2364,7 +2363,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) if (decl_state) |*ds| { try self.d_sym.?.dwarf.commitDeclState( - &self.base, module, decl_index, addr, @@ -2603,7 +2601,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void { _ = module; if (self.d_sym) |*d_sym| { - try d_sym.dwarf.updateDeclLineNumber(&self.base, decl); + try d_sym.dwarf.updateDeclLineNumber(decl); } } diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index c4ce8e4223..e198f474c8 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -213,7 +213,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { } if (self.debug_abbrev_section_dirty) { - try self.dwarf.writeDbgAbbrev(&macho_file.base); + try self.dwarf.writeDbgAbbrev(); self.debug_abbrev_section_dirty = false; } @@ -223,7 +223,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?]; const low_pc = text_section.addr; const high_pc = text_section.addr + text_section.size; - try self.dwarf.writeDbgInfoHeader(&macho_file.base, module, low_pc, high_pc); + try self.dwarf.writeDbgInfoHeader(module, low_pc, high_pc); self.debug_info_header_dirty = false; } @@ -231,12 +231,12 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { // 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_section = macho_file.sections.items(.header)[macho_file.text_section_index.?]; - try self.dwarf.writeDbgAranges(&macho_file.base, text_section.addr, text_section.size); + try self.dwarf.writeDbgAranges(text_section.addr, text_section.size); self.debug_aranges_section_dirty = false; } if (self.debug_line_header_dirty) { - try self.dwarf.writeDbgLineHeader(&macho_file.base, module); + try self.dwarf.writeDbgLineHeader(module); self.debug_line_header_dirty = false; } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 4a9db75c98..f8821d796f 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -361,7 +361,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option } if (!options.strip and options.module != null) { - wasm_bin.dwarf = Dwarf.init(allocator, .wasm, options.target); + wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target); try wasm_bin.initDebugSections(); } @@ -910,7 +910,6 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes if (wasm.dwarf) |*dwarf| { try dwarf.commitDeclState( - &wasm.base, mod, decl_index, // Actual value will be written after relocation. @@ -990,7 +989,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl: *const Module.Decl) defer wasm.base.allocator.free(decl_name); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); - try dw.updateDeclLineNumber(&wasm.base, decl); + try dw.updateDeclLineNumber(decl); } } @@ -2299,7 +2298,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod } if (wasm.dwarf) |*dwarf| { - try dwarf.flushModule(&wasm.base, wasm.base.options.module.?); + try dwarf.flushModule(wasm.base.options.module.?); } } @@ -2668,12 +2667,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod if (!wasm.base.options.strip) { if (wasm.dwarf) |*dwarf| { const mod = wasm.base.options.module.?; - try dwarf.writeDbgAbbrev(&wasm.base); + try dwarf.writeDbgAbbrev(); // for debug info and ranges, the address is always 0, // as locations are always offsets relative to 'code' section. - try dwarf.writeDbgInfoHeader(&wasm.base, mod, 0, code_section_size); - try dwarf.writeDbgAranges(&wasm.base, 0, code_section_size); - try dwarf.writeDbgLineHeader(&wasm.base, mod); + try dwarf.writeDbgInfoHeader(mod, 0, code_section_size); + try dwarf.writeDbgAranges(0, code_section_size); + try dwarf.writeDbgLineHeader(mod); } var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator); |
