From c5c037808e30d2c632bd3bd08ed17eef7fdd373e Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 9 Aug 2026 15:26:09 -0400 Subject: [PATCH] Dwarf2: start emitting some dwarf debug info --- lib/std/Io/Writer.zig | 11 +- src/codegen/x86_64/Emit.zig | 28 +- src/link/Dwarf2.zig | 637 +++++++++++++++++--------- src/link/Elf2.zig | 858 ++++++++++++++++++++++++++---------- 4 files changed, 1082 insertions(+), 452 deletions(-) diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index 492a6a03bea5a1b181fa71e5a656a06ca63488f6..27192cc60d4055525e5ce8aabbbcee7570464c1c 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -487,7 +487,7 @@ pub fn writableSliceGreedyPreserve(w: *Writer, preserve: usize, minimum_len: usi @branchHint(.likely); return w.buffer[w.end..]; } - try rebase(w, preserve, minimum_len); + try w.vtable.rebase(w, preserve, minimum_len); assert(w.buffer.len >= preserve + minimum_len); return w.buffer[w.end..]; } @@ -845,13 +845,10 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void { /// /// Asserts buffer capacity is at least `preserve`. pub fn writeBytePreserve(w: *Writer, preserve: usize, byte: u8) Error!void { - if (w.buffer.len - w.end != 0) { - @branchHint(.likely); - w.buffer[w.end] = byte; - w.end += 1; - return; + if (w.buffer.len - w.end == 0) { + @branchHint(.unlikely); + try w.vtable.rebase(w, preserve -| 1, 1); } - try w.vtable.rebase(w, preserve -| 1, 1); w.buffer[w.end] = byte; w.end += 1; } diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig index 34045d411f07df3519633cfb0c81e2e4e565028d..a585df85fca110675427de36b51a160c01381424 100644 --- a/src/codegen/x86_64/Emit.zig +++ b/src/codegen/x86_64/Emit.zig @@ -36,7 +36,7 @@ pub fn emitMir(emit: *Emit) Error!void { if (lowered_inst.prefix == .directive) { const start_offset: u32 = @intCast(emit.w.end); switch (emit.debug_output) { - inline .dwarf, .eh_frame, .dwarf2 => |dwarf| switch (lowered_inst.encoding.mnemonic) { + inline .dwarf, .dwarf2, .eh_frame => |dwarf| switch (lowered_inst.encoding.mnemonic) { .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{ .reg = lowered_inst.ops[0].reg.dwarfNum(), .off = lowered_inst.ops[1].imm.signed, @@ -475,15 +475,17 @@ pub fn emitMir(emit: *Emit) Error!void { .column = mir_inst.data.line_column.column, .is_stmt = false, }), - .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) { - inline .dwarf, .dwarf2 => |dwarf| { - try dwarf.setEpilogueBegin(); - log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ - emit.prev_di_loc.line, emit.prev_di_loc.column, - }); - try emit.dbgAdvancePcAndLine(emit.prev_di_loc); - }, - .eh_frame, .none => {}, + .pseudo_dbg_epilogue_begin_none => { + switch (emit.debug_output) { + inline .dwarf, .dwarf2 => |dwarf| { + try dwarf.setEpilogueBegin(); + log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ + emit.prev_di_loc.line, emit.prev_di_loc.column, + }); + }, + .eh_frame, .none => {}, + } + try emit.dbgAdvancePcAndLine(emit.prev_di_loc); }, .pseudo_dbg_enter_block_none => switch (emit.debug_output) { inline .dwarf, .dwarf2 => |dwarf| { @@ -976,11 +978,11 @@ const Loc = struct { }; fn dbgAdvancePcAndLine(emit: *Emit, loc: Loc) Error!void { - const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line); - const delta_pc: usize = emit.w.end - emit.prev_di_pc; - log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); switch (emit.debug_output) { inline .dwarf, .dwarf2 => |dwarf| { + const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line); + const delta_pc: usize = emit.w.end - emit.prev_di_pc; + log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt(); if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column); try dwarf.advancePcAndLine(delta_line, delta_pc); diff --git a/src/link/Dwarf2.zig b/src/link/Dwarf2.zig index 2d3c41849afca1a48a8cc834036acae704adc7fd..ca8d58b853dd223e93bade9fadadee1f27137c50 100644 --- a/src/link/Dwarf2.zig +++ b/src/link/Dwarf2.zig @@ -1,4 +1,4 @@ -tag: link.File.Tag, +lf: *link.File, format: DW.Format, endian: std.lang.Endian, address_size: AddressSize, @@ -12,15 +12,23 @@ values: std.ArrayList(struct { globals: std.array_hash_map.Auto(InternPool.Nav.Index, Global), funcs: std.array_hash_map.Auto(InternPool.Nav.Index, Func), +debug_abbrev: DebugAbbrev, frame: Frame, debug_info: DebugInfo, debug_line: DebugLine, +debug_line_str: String, +debug_str: String, +debug_str_offsets: StringOffsets, pub const AddressSize = enum(u8) { @"32" = 4, @"64" = 8, _ }; pub const Unit = struct { frame_ni: MappedFile.Node.Index.Optional, cie_ni: MappedFile.Node.Index.Optional, + debug_info_ni: MappedFile.Node.Index.Optional, + debug_info_header_ni: MappedFile.Node.Index.Optional, + debug_line_ni: MappedFile.Node.Index.Optional, + debug_line_header_ni: MappedFile.Node.Index.Optional, pub const Index = enum(u32) { _, @@ -71,7 +79,6 @@ pub const Func = struct { pub const Frame = struct { header: Header, - section_index: SectionIndex, pub const Header = struct { code_alignment_factor: u32, @@ -83,13 +90,16 @@ pub const Frame = struct { pub const Format = std.debug.Dwarf.Unwind.Section; }; -pub const DebugInfo = struct { - section_index: SectionIndex, +pub const DebugAbbrev = struct { + ni: MappedFile.Node.Index.Optional, + offset: usize, + set: std.enums.EnumSet(AbbrevCode), }; +pub const DebugInfo = struct {}; + pub const DebugLine = struct { header: Header, - section_index: SectionIndex, pub const Header = struct { minimum_instruction_length: u8, @@ -101,7 +111,49 @@ pub const DebugLine = struct { }; }; -pub const SectionIndex = enum(u32) { none = std.math.maxInt(u32), _ }; +pub const String = struct { + ni: MappedFile.Node.Index.Optional, + offset: usize, + map: std.AutoHashMapUnmanaged(usize, void), + + fn get( + s: *String, + gpa: std.mem.Allocator, + mf: *MappedFile, + string: []const u8, + ) MappedFile.Error!usize { + const ni = s.ni.unwrap().?; + const gop = try s.map.getOrPutAdapted(gpa, string, Adapter{ .slice = ni.sliceConst(mf) }); + if (!gop.found_existing) { + gop.key_ptr.* = s.offset; + try ni.ensureMinimumSize(mf, gpa, s.offset + string.len + 1); + const slice_mut = ni.slice(mf); + @memcpy(slice_mut[s.offset..][0..string.len], string); + s.offset += string.len; + slice_mut[s.offset] = 0; + s.offset += 1; + } + return gop.key_ptr.*; + } + + const Adapter = struct { + slice: []const u8, + pub fn hash(_: Adapter, key: []const u8) u32 { + return @truncate(std.hash.Wyhash.hash(0, key)); + } + pub fn eql(adapter: Adapter, key: []const u8, rhs_offset: usize) bool { + return std.mem.startsWith(u8, adapter.slice[rhs_offset..], key) and + adapter.slice[rhs_offset + key.len] == 0; + } + }; +}; + +pub const StringOffsets = struct { + ni: MappedFile.Node.Index.Optional, + offset: usize, +}; + +pub const SharedSection = enum { debug_abbrev, debug_line_str, debug_str, debug_str_offsets }; pub const Loc = union(enum) { empty, @@ -463,7 +515,7 @@ pub const WipNav = struct { }, frame_format: Frame.Format, fde_writer: MappedFile.Node.Writer, - frame_func_length_offset: usize, + frame_func_length: struct { offset: usize, size: AddressSize }, pub const Debug = struct { wip_nav: WipNav, @@ -477,22 +529,53 @@ pub const WipNav = struct { info_writer: MappedFile.Node.Writer, line_writer: MappedFile.Node.Writer, - pub fn deinit(debug: *Debug, gpa: Allocator) void { + pub fn deinit(debug: *Debug) void { + const gpa = debug.pt.zcu.gpa; debug.line_writer.deinit(); debug.info_writer.deinit(); debug.blocks.deinit(gpa); - debug.wip_nav.deinit(gpa); + debug.wip_nav.deinit(); debug.* = undefined; } - pub fn genFuncHeaders(debug: *Debug) link.Error!void { - try debug.wip_nav.genFuncHeaders(); + pub fn startDebugInfo(debug: *Debug) link.Error!void { + debug.startDebugInfoInner() catch |err| switch (err) { + error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + else => |e| return e, + }; + } + fn startDebugInfoInner(debug: *Debug) link.EmitError!void { + const dwarf = debug.wip_nav.dwarf; + const ip = &debug.pt.zcu.intern_pool; + const nav = ip.getNav(debug.wip_nav.func.?.nav(dwarf)); + const diw = &debug.info_writer.interface; + try diw.writeUleb128(try dwarf.refAbbrevCode(.decl_func)); + try debug.strp(nav.name.toSlice(ip)); + try debug.strp(nav.fqn.toSlice(ip)); } pub fn genDebugFrame(debug: *Debug, loc: u32, cfa: Cfa) link.Error!void { return debug.wip_nav.genDebugFrame(loc, cfa); } + pub fn finishFunc(debug: *Debug) link.Error!void { + assert(debug.wip_nav.func != null); + debug.finishDebugInfo() catch |err| switch (err) { + error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.info_writer), + else => |e| return e, + }; + const dlw = &debug.line_writer.interface; + dlw.rebase(dlw.end, comptime 1 + uleb128Bytes(1) + 1) catch |err| switch (err) { + error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), + }; + } + + fn finishDebugInfo(debug: *Debug) link.EmitError!void { + const diw = &debug.info_writer.interface; + try diw.writeUleb128(@backingInt(AbbrevCode.null)); + try debug.wip_nav.dwarf.genDebugInfoPadding(diw, diw.unusedCapacityLen()); + } + pub const LocalVarTag = enum { arg, local_var }; pub fn genLocalVarDebugInfo( debug: *Debug, @@ -675,7 +758,7 @@ pub const WipNav = struct { fn enterBlockInner(debug: *Debug, code_off: u64) link.EmitError!void { const dwarf = debug.wip_nav.dwarf; const diw = &debug.info_writer.interface; - const block = try debug.blocks.addOne(dwarf.linkFile().comp.gpa); + const block = try debug.blocks.addOne(dwarf.lf.comp.gpa); block.abbrev_code = @intCast(diw.end); try debug.abbrevCode(.block); @@ -767,17 +850,18 @@ pub const WipNav = struct { const dwarf = debug.wip_nav.dwarf; const inlined_func_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.inlined_func)); const block = debug.blocks.pop().?; + const diw = &debug.info_writer.interface; if (debug.any_children) - try debug.info_writer.interface.writeUleb128(@backingInt(AbbrevCode.null)) + try diw.writeUleb128(@backingInt(AbbrevCode.null)) else std.leb.writeUnsignedFixed( inlined_func_bytes, - debug.info_writer.interface.buffered()[block.abbrev_code..][0..inlined_func_bytes], + diw.buffered()[block.abbrev_code..][0..inlined_func_bytes], @intCast(try dwarf.refAbbrevCode(.empty_inlined_func)), ); std.mem.writeInt( u32, - debug.info_writer.interface.buffered()[block.high_pc..][0..4], + diw.buffered()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), dwarf.endian, ); @@ -806,7 +890,7 @@ pub const WipNav = struct { const dlw = &debug.line_writer.interface; if (zcu.comp.config.incremental) { - const new_func_gop = try dwarf.funcs.getOrPut(dwarf.gpa, new_func_info.owner_nav); + const new_func_gop = try dwarf.funcs.getOrPut(zcu.gpa, new_func_info.owner_nav); errdefer _ = if (!new_func_gop.found_existing) dwarf.funcs.pop(); if (!new_func_gop.found_existing) new_func_gop.value_ptr.* = .{ .frame_node = .none, @@ -822,8 +906,8 @@ pub const WipNav = struct { try dlw.writeByte(DW.LNS.extended_op); try dlw.writeUleb128(1 + section_offset_size); try dlw.writeByte(DW.LNE.ZIG_set_decl); - try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ - .source_off = @intCast(dlw.end), + try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(zcu.gpa, .{ + .source_off = @bitCast(@as(u64, dlw.end)), .target_sec = .debug_info, .target_unit = new_unit, .target_entry = new_func_gop.value_ptr.toOptional(), @@ -836,8 +920,8 @@ pub const WipNav = struct { const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav); if (old_file != new_file) { const mod_info = dwarf.getModInfo(wip_nav.unit); - try mod_info.dirs.put(dwarf.gpa, new_unit, {}); - const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file); + try mod_info.dirs.put(zcu.gpa, new_unit, {}); + const file_gop = try mod_info.files.getOrPut(zcu.gpa, new_file); try dlw.writeByte(DW.LNS.set_file); try dlw.writeUleb128(file_gop.index); @@ -854,57 +938,38 @@ pub const WipNav = struct { } fn abbrevCode(debug: *Debug, abbrev_code: AbbrevCode) link.EmitError!void { - try debug.info_writer.interface.writeUleb128(try debug.wip_nav.dwarf.refAbbrevCode(abbrev_code)); + try debug.info_writer.interface.writeUleb128( + try debug.wip_nav.dwarf.refAbbrevCode(abbrev_code), + ); } fn infoExternalReloc(debug: *Debug, reloc: struct { source_off: u32 = 0, target_si: link.File.SymbolId, target_off: u64 = 0, - }) Allocator.Error!void { + }) std.mem.Allocator.Error!void { if (true) @panic("TODO"); try debug.wip_nav.externalReloc(&debug.wip_nav.dwarf.debug_frame.section, reloc); } fn infoSectionOffset( debug: *Debug, - target: MappedFile.Node.Index, + target_ni: MappedFile.Node.Index, addend: i64, ) link.EmitError!void { - const dwarf = debug.wip_nav.dwarf; - const diw = &debug.info_writer.interface; - const offset = diw.end; - switch (dwarf.format) { - .@"32" => try diw.writeInt(u32, 0, dwarf.endian), - .@"64" => try diw.writeInt(u64, 0, dwarf.endian), - } - try dwarf.linkFile().cast(.elf2).?.addNodeReloc( - debug.info_writer.ni, - offset, - target, - addend, - switch (dwarf.format) { - .@"32" => .abs32, - .@"64" => .abs64, - }, - ); + try debug.wip_nav.dwarf.sectionOffset(&debug.info_writer, target_ni, addend); } fn strp(debug: *Debug, str: []const u8) link.EmitError!void { - if (true) @panic("TODO"); const dwarf = debug.wip_nav.dwarf; - try debug.infoSectionOffset(.debug_str, try dwarf.debug_str.addString(dwarf, str), 0); + try dwarf.strp(&dwarf.debug_str, &debug.info_writer, str); } - fn strpFmt( - debug: *Debug, - comptime fmt: []const u8, - args: anytype, - ) link.EmitError!void { - const gpa = &debug.wip_nav.dwarf.gpa; + fn strpFmt(debug: *Debug, comptime fmt: []const u8, args: anytype) link.EmitError!void { + const gpa = debug.pt.zcu.gpa; const str = try std.fmt.allocPrint(gpa, fmt, args); defer gpa.free(str); - return debug.strp(str); + try debug.strp(str); } fn infoExprLoc(debug: *Debug, loc: Loc) link.EmitError!void { @@ -923,10 +988,7 @@ pub const WipNav = struct { fn addrSym(ctx: @This(), si: link.File.SymbolId) link.EmitError!void { try ctx.debug.infoAddrSym(si, 0); } - fn infoEntry( - ctx: @This(), - node: MappedFile.Node.Index, - ) link.EmitError!void { + fn infoEntry(ctx: @This(), node: MappedFile.Node.Index) link.EmitError!void { try ctx.debug.infoSectionOffset(node, 0); } } = .{ .debug = debug }; @@ -941,7 +1003,7 @@ pub const WipNav = struct { ) link.EmitError!void { const diw = &debug.info_writer.interface; try debug.infoExternalReloc(.{ - .source_off = @intCast(diw.end), + .source_off = @bitCast(@as(u64, diw.end)), .target_si = si, .target_off = sym_off, }); @@ -957,7 +1019,6 @@ pub const WipNav = struct { } fn refValue(debug: *Debug, value: Value) link.EmitError!void { - if (true) @panic("TODO"); try debug.infoSectionOffset(.debug_info, try debug.getValueNode(value), 0); } @@ -978,7 +1039,7 @@ pub const WipNav = struct { if (size == 0) return; const old_end = diw.end; try codegen.generateSymbol( - debug.wip_nav.dwarf.linkFile(), + debug.wip_nav.dwarf.lf, debug.pt, val, diw, @@ -996,37 +1057,29 @@ pub const WipNav = struct { } }; - pub fn deinit(wip_nav: *WipNav, gpa: Allocator) void { - _ = gpa; + pub fn deinit(wip_nav: *WipNav) void { wip_nav.fde_writer.deinit(); wip_nav.* = undefined; } - pub fn genFuncHeaders(wip_nav: *WipNav) link.Error!void { - wip_nav.genDebugFrameHeader() catch |err| switch (err) { + pub fn genDebugFrameHeader(wip_nav: *WipNav) link.Error!void { + wip_nav.genDebugFrameHeaderInner() catch |err| switch (err) { error.WriteFailed => return wip_nav.reportWriteError(&wip_nav.fde_writer), else => |e| return e, }; } - fn genDebugFrameHeader(wip_nav: *WipNav) link.EmitError!void { + fn genDebugFrameHeaderInner(wip_nav: *WipNav) link.EmitError!void { assert(wip_nav.func != null); const dwarf = wip_nav.dwarf; const dfw = &wip_nav.fde_writer.interface; - switch (dwarf.format) { - .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian), - .@"64" => { - try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian); - try dfw.writeInt(u64, undefined, dwarf.endian); - }, - } - const unit = wip_nav.unit.get(dwarf); + try dwarf.genUnitLength(dfw); switch (wip_nav.frame_format) { .eh_frame => { try dfw.writeInt(u32, undefined, dwarf.endian); { const offset = dfw.end; try dfw.writeInt(u32, 0, dwarf.endian); - const elf = dwarf.linkFile().cast(.elf2).?; + const elf = dwarf.lf.cast(.elf2).?; try elf.addReloc( @bitCast(wip_nav.fde_writer.ni), offset, @@ -1035,14 +1088,14 @@ pub const WipNav = struct { .rel32(elf), ); } - wip_nav.frame_func_length_offset = dfw.end; + wip_nav.frame_func_length = .{ .offset = dfw.end, .size = .@"32" }; try dfw.writeInt(u32, undefined, dwarf.endian); try dfw.writeUleb128(0); }, .debug_frame => { - try wip_nav.frameSectionOffset(unit.cie_ni.unwrap().?, 0); + try wip_nav.frameSectionOffset(wip_nav.unit.get(dwarf).cie_ni.unwrap().?, 0); try wip_nav.frameAddrSym(wip_nav.func_si, 0); - wip_nav.frame_func_length_offset = dfw.end; + wip_nav.frame_func_length = .{ .offset = dfw.end, .size = dwarf.address_size }; try dfw.splatByteAll(undefined, @backingInt(dwarf.address_size)); }, } @@ -1063,30 +1116,23 @@ pub const WipNav = struct { pub fn finishDebugFrameFde(wip_nav: *WipNav, func_length: u64) void { const dwarf = wip_nav.dwarf; - const fde = wip_nav.fde_writer.interface.buffer; - switch (wip_nav.frame_format) { - .eh_frame => std.mem.writeInt( + const dfw = &wip_nav.fde_writer.interface; + switch (wip_nav.frame_func_length.size) { + _ => unreachable, + .@"32" => std.mem.writeInt( u32, - fde[wip_nav.frame_func_length_offset..][0..4], + dfw.buffered()[wip_nav.frame_func_length.offset..][0..4], @intCast(func_length), dwarf.endian, ), - .debug_frame => switch (dwarf.address_size) { - _ => unreachable, - .@"32" => std.mem.writeInt( - u32, - fde[wip_nav.frame_func_length_offset..][0..4], - @intCast(func_length), - dwarf.endian, - ), - .@"64" => std.mem.writeInt( - u64, - fde[wip_nav.frame_func_length_offset..][0..8], - func_length, - dwarf.endian, - ), - }, + .@"64" => std.mem.writeInt( + u64, + dfw.buffered()[wip_nav.frame_func_length.offset..][0..8], + func_length, + dwarf.endian, + ), } + @memset(dfw.unusedCapacitySlice(), DW.CFA.nop); } const ExprLocCounter = struct { @@ -1119,26 +1165,10 @@ pub const WipNav = struct { fn frameSectionOffset( wip_nav: *WipNav, - target: MappedFile.Node.Index, - addend: i64, + target_ni: MappedFile.Node.Index, + addend: usize, ) link.EmitError!void { - const dwarf = wip_nav.dwarf; - const dfw = &wip_nav.fde_writer.interface; - const offset = dfw.end; - switch (dwarf.format) { - .@"32" => try dfw.writeInt(u32, 0, dwarf.endian), - .@"64" => try dfw.writeInt(u64, 0, dwarf.endian), - } - try dwarf.linkFile().cast(.elf2).?.addNodeReloc( - wip_nav.fde_writer.ni, - offset, - target, - addend, - switch (dwarf.format) { - .@"32" => .abs32, - .@"64" => .abs64, - }, - ); + try wip_nav.dwarf.sectionOffset(&wip_nav.fde_writer, target_ni, addend); } fn frameExprLoc(wip_nav: *WipNav, loc: Loc) link.EmitError!void { @@ -1174,7 +1204,7 @@ pub const WipNav = struct { const dfw = &wip_nav.fde_writer.interface; const offset = dfw.end; try dfw.splatByteAll(0, @backingInt(dwarf.address_size)); - const elf = dwarf.linkFile().cast(.elf2).?; + const elf = dwarf.lf.cast(.elf2).?; try elf.addReloc( @bitCast(wip_nav.fde_writer.ni), offset, @@ -1190,7 +1220,7 @@ pub const WipNav = struct { fn reportWriteError(wip_nav: *WipNav, mfnw: *const MappedFile.Node.Writer) link.Error { switch (mfnw.err.?) { else => |e| return e, - error.MappedFileIo => return wip_nav.dwarf.linkFile().comp.link_diags.fail( + error.MappedFileIo => return wip_nav.dwarf.lf.comp.link_diags.fail( "failed to write output file: {t}", .{mfnw.mf.io_err.?}, ), @@ -1199,10 +1229,9 @@ pub const WipNav = struct { }; pub fn init(lf: *link.File, format: DW.Format) Dwarf { - const comp = lf.comp; - const target = &comp.root_mod.resolved_target.result; + const target = &lf.comp.root_mod.resolved_target.result; return .{ - .tag = lf.tag, + .lf = lf, .format = format, .address_size = switch (target.ptrBitWidth()) { 0...32 => .@"32", @@ -1216,29 +1245,10 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf { .globals = .empty, .funcs = .empty, - .debug_info = .{ - .section_index = .none, - }, - .debug_line = .{ - .header = switch (target.cpu.arch) { - .x86_64, .aarch64 => .{ - .minimum_instruction_length = 1, - .maximum_operations_per_instruction = 1, - .default_is_stmt = true, - .line_base = -5, - .line_range = 14, - .opcode_base = DW.LNS.set_isa + 1, - }, - else => .{ - .minimum_instruction_length = 1, - .maximum_operations_per_instruction = 1, - .default_is_stmt = true, - .line_base = 0, - .line_range = 1, - .opcode_base = DW.LNS.set_isa + 1, - }, - }, - .section_index = .none, + .debug_abbrev = .{ + .ni = .none, + .offset = 0, + .set = .empty, }, .frame = .{ .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: { @@ -1259,34 +1269,67 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf { .return_address_register = undefined, .initial_instructions = &.{}, }, - .section_index = .none, + }, + .debug_info = .{}, + .debug_line = .{ + .header = switch (target.cpu.arch) { + .x86_64, .aarch64 => .{ + .minimum_instruction_length = 1, + .maximum_operations_per_instruction = 1, + .default_is_stmt = true, + .line_base = -5, + .line_range = 14, + .opcode_base = DW.LNS.set_isa + 1, + }, + else => .{ + .minimum_instruction_length = 1, + .maximum_operations_per_instruction = 1, + .default_is_stmt = true, + .line_base = 0, + .line_range = 1, + .opcode_base = DW.LNS.set_isa + 1, + }, + }, + }, + .debug_line_str = .{ + .ni = .none, + .offset = 0, + .map = .empty, + }, + .debug_str = .{ + .ni = .none, + .offset = 0, + .map = .empty, + }, + .debug_str_offsets = .{ + .ni = .none, + .offset = 0, }, }; } -pub fn deinit(dwarf: *Dwarf, gpa: Allocator) void { +pub fn deinit(dwarf: *Dwarf) void { + const gpa = dwarf.lf.comp.gpa; dwarf.const_pool.deinit(gpa); dwarf.units.deinit(gpa); dwarf.values.deinit(gpa); dwarf.globals.deinit(gpa); dwarf.funcs.deinit(gpa); + dwarf.debug_str.map.deinit(gpa); dwarf.* = undefined; } -fn linkFile(dwarf: *Dwarf) *link.File { - return switch (dwarf.tag) { - else => unreachable, - .elf2 => |tag| &@as(*tag.Type(), @alignCast(@fieldParentPtr("dwarf", dwarf))).base, - }; -} - -pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) Allocator.Error!void { +pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!void { try dwarf.units.ensureTotalCapacity(zcu.gpa, zcu.module_roots.count()); for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, root| switch (root) { .none => {}, else => dwarf.units.putAssumeCapacityNoClobber(mod, .{ .frame_ni = .none, .cie_ni = .none, + .debug_info_ni = .none, + .debug_info_header_ni = .none, + .debug_line_ni = .none, + .debug_line_header_ni = .none, }), }; } @@ -1308,8 +1351,8 @@ pub fn getUnit(dwarf: *Dwarf, mod: *Module) Unit.Index { return @fromBackingInt(@intCast(dwarf.units.getIndex(mod).?)); } -pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) Allocator.Error!Func.Index { - const func_gop = try dwarf.funcs.getOrPut(dwarf.linkFile().comp.gpa, owner_nav); +pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) std.mem.Allocator.Error!Func.Index { + const func_gop = try dwarf.funcs.getOrPut(dwarf.lf.comp.gpa, owner_nav); if (!func_gop.found_existing) func_gop.value_ptr.* = .{ .fde_ni = .none, .debug_info_ni = .none, @@ -1318,6 +1361,21 @@ pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) Allocator.Error!F return @fromBackingInt(@intCast(func_gop.index)); } +pub fn unitLengthSize(dwarf: *Dwarf) usize { + return switch (dwarf.format) { + .@"32" => 4, + .@"64" => 12, + }; +} +pub fn genUnitLength(dwarf: *Dwarf, w: *Writer) Writer.Error!void { + switch (dwarf.format) { + .@"32" => try w.writeInt(u32, undefined, dwarf.endian), + .@"64" => { + try w.writeInt(u32, std.math.maxInt(u32), dwarf.endian); + try w.writeInt(u64, undefined, dwarf.endian); + }, + } +} pub fn updateUnitLength(dwarf: *Dwarf, header: []u8, unit_length: u64) void { switch (dwarf.format) { .@"32" => std.mem.writeInt(u32, header[0..4], @intCast(unit_length - 4), dwarf.endian), @@ -1325,6 +1383,11 @@ pub fn updateUnitLength(dwarf: *Dwarf, header: []u8, unit_length: u64) void { } } +pub fn genUnitPadding(dwarf: *Dwarf, w: *Writer) Writer.Error!void { + try dwarf.genUnitLength(w); + try w.writeInt(u16, 0, dwarf.endian); +} + pub const EhFrameHdr = extern struct { version: u8, eh_frame_ptr_enc: std.dwarf.EH.PE, @@ -1345,7 +1408,7 @@ pub fn genEhFrameHdr( .table_enc = .omit, .eh_frame_ptr = undefined, }; - const elf = dwarf.linkFile().cast(.elf2).?; + const elf = dwarf.lf.cast(.elf2).?; try elf.addReloc( eh_frame_hdr_ai, @offsetOf(EhFrameHdr, "eh_frame_ptr"), @@ -1357,26 +1420,20 @@ pub fn genEhFrameHdr( pub fn genDebugFrameCie( dwarf: *Dwarf, - w: *Writer, + dfw: *Writer, /// `null` means to generate an architecture-agnostic padding cie arch: ?std.Target.Cpu.Arch, format: Frame.Format, ) Writer.Error!void { - switch (dwarf.format) { - .@"32" => try w.writeInt(u32, undefined, dwarf.endian), - .@"64" => { - try w.writeInt(u32, std.math.maxInt(u32), dwarf.endian); - try w.writeInt(u64, undefined, dwarf.endian); - }, - } + try dwarf.genUnitLength(dfw); switch (format) { - .eh_frame => try w.writeInt(u32, 0, dwarf.endian), + .eh_frame => try dfw.writeInt(u32, 0, dwarf.endian), .debug_frame => switch (dwarf.format) { - .@"32" => try w.writeInt(u32, std.math.maxInt(u32), dwarf.endian), - .@"64" => try w.writeInt(u64, std.math.maxInt(u64), dwarf.endian), + .@"32" => try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian), + .@"64" => try dfw.writeInt(u64, std.math.maxInt(u64), dwarf.endian), }, } - try w.writeByte(if (arch) |_| switch (format) { + try dfw.writeByte(if (arch) |_| switch (format) { .eh_frame => 1, .debug_frame => 4, } else 0); @@ -1386,40 +1443,38 @@ pub fn genDebugFrameCie( dev.check(.x86_64_backend); const Register = @import("../codegen/x86_64/bits.zig").Register; switch (format) { - .eh_frame => try w.writeAll("zR\x00"), + .eh_frame => try dfw.writeAll("zR\x00"), .debug_frame => { - try w.writeAll("\x00"); - try w.writeByte(@backingInt(dwarf.address_size)); - try w.writeByte(0); + try dfw.writeAll("\x00"); + try dfw.writeByte(@backingInt(dwarf.address_size)); + try dfw.writeByte(0); }, } - try w.writeUleb128(dwarf.frame.header.code_alignment_factor); - try w.writeSleb128(dwarf.frame.header.data_alignment_factor); + try dfw.writeUleb128(dwarf.frame.header.code_alignment_factor); + try dfw.writeSleb128(dwarf.frame.header.data_alignment_factor); switch (format) { - .eh_frame => try w.writeByte(@intCast(dwarf.frame.header.return_address_register)), - .debug_frame => try w.writeUleb128(dwarf.frame.header.return_address_register), + .eh_frame => try dfw.writeByte(@intCast(dwarf.frame.header.return_address_register)), + .debug_frame => try dfw.writeUleb128(dwarf.frame.header.return_address_register), } switch (format) { .eh_frame => { - try w.writeUleb128(1); - try w.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel }))); + try dfw.writeUleb128(1); + try dfw.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel }))); }, .debug_frame => {}, } - try w.writeByte(DW.CFA.def_cfa_sf); - try w.writeUleb128(Register.rsp.dwarfNum()); - try w.writeSleb128(-1); - try w.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()); - try w.writeUleb128(1); + try dfw.writeByte(DW.CFA.def_cfa_sf); + try dfw.writeUleb128(Register.rsp.dwarfNum()); + try dfw.writeSleb128(-1); + try dfw.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()); + try dfw.writeUleb128(1); }, } + @memset(dfw.unusedCapacitySlice(), DW.CFA.nop); } pub fn updateEhFrameFde(dwarf: *Dwarf, fde: []u8, fde_offset: u64) void { - const cie_pointer_offset: usize = switch (dwarf.format) { - .@"32" => 4, - .@"64" => 12, - }; + const cie_pointer_offset = dwarf.unitLengthSize(); std.mem.writeInt( u32, fde[cie_pointer_offset..][0..4], @@ -1428,27 +1483,182 @@ pub fn updateEhFrameFde(dwarf: *Dwarf, fde: []u8, fde_offset: u64) void { ); } +pub fn genDebugInfoHeader( + dwarf: *Dwarf, + nw: *MappedFile.Node.Writer, + unit: Unit.Index, + zcu: *Zcu, +) link.EmitError!void { + const comp = zcu.comp; + const mod = unit.mod(dwarf); + const diw = &nw.interface; + try dwarf.genUnitLength(diw); + try diw.writeInt(u16, 5, dwarf.endian); + try diw.writeByte(DW.UT.compile); + try diw.writeByte(@backingInt(dwarf.address_size)); + try dwarf.sectionOffset(nw, dwarf.debug_abbrev.ni.unwrap().?, 0); + const compile_unit_offset = diw.end; + try diw.writeUleb128(try dwarf.refAbbrevCode(.compile_unit)); + try dwarf.strp(&dwarf.debug_str, nw, "zig " ++ @import("build_options").version); + try diw.writeByte(DW.LANG.Zig); + const root_dir_path = try mod.root.toAbsolute(&comp.dirs, comp.gpa); + defer comp.gpa.free(root_dir_path); + try dwarf.strp(&dwarf.debug_line_str, nw, root_dir_path); + try dwarf.strp(&dwarf.debug_line_str, nw, mod.root_src_path); + try dwarf.sectionOffset( + nw, + dwarf.getUnit(comp.root_mod).get(dwarf).debug_info_header_ni.unwrap().?, + compile_unit_offset, + ); + try dwarf.sectionOffset(nw, unit.get(dwarf).debug_line_header_ni.unwrap().?, 0); + const module_offset = diw.end; + try diw.writeUleb128(try dwarf.refAbbrevCode(.module)); + try dwarf.strp(&dwarf.debug_str, nw, mod.fully_qualified_name); + for ([_][]const u8{ "builtin", "root", "std" }, [_]*Module{ + zcu.builtin_modules.get(mod.getBuiltinOptions(comp.config).hash()).?, + zcu.root_mod, + zcu.std_mod, + }) |name, dep| try dwarf.genModuleDependency(nw, name, dep, module_offset); + for (mod.deps.keys(), mod.deps.values()) |name, dep| + try dwarf.genModuleDependency(nw, name, dep, module_offset); + for ([2]AbbrevCode{ .pad_1, .pad_n }) |pad| _ = try dwarf.refAbbrevCode(pad); + try dwarf.genDebugInfoPadding(diw, diw.unusedCapacityLen()); +} + +fn genModuleDependency( + dwarf: *Dwarf, + nw: *MappedFile.Node.Writer, + name: []const u8, + dep: *Module, + module_offset: usize, +) link.EmitError!void { + const diw = &nw.interface; + try diw.writeUleb128(try dwarf.refAbbrevCode(.module_dependency)); + try diw.writeAll(name); + try diw.writeByte(0); + try dwarf.sectionOffset( + nw, + dwarf.getUnit(dep).get(dwarf).debug_info_header_ni.unwrap().?, + module_offset, + ); +} + +pub fn genDebugInfoPadding(dwarf: *Dwarf, diw: *Writer, size: u64) Writer.Error!void { + switch (size) { + 0 => {}, + 1 => try diw.writeUleb128(dwarf.refAbbrevCodeIfExists(.pad_1).?), + else => { + const abbrev_code_offset = diw.end; + try diw.writeUleb128(dwarf.refAbbrevCodeIfExists(.pad_n).?); + const abbrev_code_size = diw.end - abbrev_code_offset; + var block_len_size: u5 = 1; + while (true) switch (std.math.order(size - abbrev_code_size - block_len_size, @as(u64, 1) << 7 * block_len_size)) { + .lt => break try diw.writeUleb128(size - abbrev_code_size - block_len_size), + .eq => { + // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte + block_len_size += 1; + std.leb.writeUnsignedExtended(try diw.writableSlice(block_len_size), size - abbrev_code_size - block_len_size); + break; + }, + .gt => block_len_size += 1, + }; + }, + } +} + +pub fn genDebugLineHeader(dwarf: *Dwarf, dlw: *Writer) Writer.Error!void { + try dwarf.genUnitLength(dlw); + @memset(dlw.unusedCapacitySlice(), 0xaa); +} + +pub fn genDebugLinePadding(dlw: *Writer, size: u64) Writer.Error!void { + switch (size) { + 0 => {}, + 1 => try dlw.writeByte(DW.LNS.const_add_pc), + else => { + const extended_op_offset = dlw.end; + try dlw.writeByte(DW.LNS.extended_op); + const extended_op_size = dlw.end - extended_op_offset; + var op_len_size: u5 = 1; + while (true) switch (std.math.order(size - extended_op_size - op_len_size, @as(u64, 1) << 7 * op_len_size)) { + .lt => break try dlw.writeUleb128(size - extended_op_size - op_len_size), + .eq => { + // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte + op_len_size += 1; + std.leb.writeUnsignedExtended(try dlw.writableSlice(op_len_size), size - extended_op_size - op_len_size); + break; + }, + .gt => op_len_size += 1, + }; + }, + } +} + +fn refAbbrevCodeIfExists( + dwarf: *Dwarf, + abbrev_code: AbbrevCode, +) ?@typeInfo(AbbrevCode).@"enum".tag_type { + assert(abbrev_code != .null); + return if (dwarf.debug_abbrev.set.contains(abbrev_code)) @backingInt(abbrev_code) else null; +} + fn refAbbrevCode( dwarf: *Dwarf, abbrev_code: AbbrevCode, ) link.EmitError!@typeInfo(AbbrevCode).@"enum".tag_type { - if (true) @panic("TODO"); - const Entry = {}; - const DebugAbbrev = {}; - assert(abbrev_code != .null); - const entry: Entry.Index = @fromBackingInt(@intCast(@backingInt(abbrev_code))); - if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @backingInt(abbrev_code); - var debug_abbrev_aw: Writer.Allocating = .init(dwarf.gpa); - defer debug_abbrev_aw.deinit(); - const daw = &debug_abbrev_aw.writer; + if (dwarf.refAbbrevCodeIfExists(abbrev_code)) |backing_int| { + @branchHint(.likely); + return backing_int; + } + const elf = dwarf.lf.cast(.elf2).?; + var nw: MappedFile.Node.Writer = undefined; + dwarf.debug_abbrev.ni.unwrap().?.writer(&elf.mf, elf.base.comp.gpa, &nw); + defer nw.deinit(); const abbrev = AbbrevCode.abbrevs.get(abbrev_code); + const daw = &nw.interface; + daw.end = dwarf.debug_abbrev.offset; try daw.writeUleb128(@backingInt(abbrev_code)); try daw.writeUleb128(@backingInt(abbrev.tag)); try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no); for (abbrev.attrs) |*attr| inline for (attr) |info| try daw.writeUleb128(@backingInt(info)); for (0..2) |_| try daw.writeUleb128(0); - try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev_aw.written()); - return @backingInt(abbrev_code); + dwarf.debug_abbrev.offset = daw.end; + dwarf.debug_abbrev.set.insert(abbrev_code); + return dwarf.refAbbrevCodeIfExists(abbrev_code).?; +} + +fn sectionOffset( + dwarf: *Dwarf, + nw: *MappedFile.Node.Writer, + target_ni: MappedFile.Node.Index, + addend: usize, +) link.EmitError!void { + const offset = nw.interface.end; + switch (dwarf.format) { + .@"32" => try nw.interface.writeInt(u32, 0, dwarf.endian), + .@"64" => try nw.interface.writeInt(u64, 0, dwarf.endian), + } + try dwarf.lf.cast(.elf2).?.addNodeReloc( + nw.ni, + offset, + target_ni, + @bitCast(@as(u64, addend)), + switch (dwarf.format) { + .@"32" => .abs32, + .@"64" => .abs64, + }, + ); +} + +fn strp(dwarf: *Dwarf, s: *String, nw: *MappedFile.Node.Writer, str: []const u8) link.EmitError!void { + const comp = dwarf.lf.comp; + const mf = &dwarf.lf.cast(.elf2).?.mf; + try dwarf.sectionOffset(nw, s.ni.unwrap().?, s.get(comp.gpa, mf, str) catch |err| switch (err) { + error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{ + mf.io_err.?, + }), + else => |e| return e, + }); } fn DeclValEnum(comptime T: type) type { @@ -1473,7 +1683,7 @@ fn DeclValEnum(comptime T: type) type { return @Enum(TagInt, .exhaustive, field_names[0..fields_len], &field_vals); } -const AbbrevCode = enum { +pub const AbbrevCode = enum { null, // padding codes must be one byte uleb128 values to function pad_1, @@ -1524,6 +1734,7 @@ const AbbrevCode = enum { // than the non-empty variant, and so should appear first compile_unit, module, + module_dependency, empty_file, file, access, @@ -1765,14 +1976,14 @@ const AbbrevCode = enum { .decl_func = .{ .tag = .subprogram, .children = true, - .attrs = decl_abbrev_common_attrs ++ .{ + .attrs = decl_abbrev_common_attrs[4..] ++ .{ .{ .linkage_name, .strp }, - .{ .type, .ref_addr }, - .{ .low_pc, .addr }, - .{ .high_pc, .data4 }, - .{ .alignment, .udata }, - .{ .external, .flag }, - .{ .noreturn, .flag }, + //.{ .type, .ref_addr }, + //.{ .low_pc, .addr }, + //.{ .high_pc, .data4 }, + //.{ .alignment, .udata }, + //.{ .external, .flag }, + //.{ .noreturn, .flag }, }, }, .decl_nullary_func_generic = .{ @@ -1989,14 +2200,15 @@ const AbbrevCode = enum { .tag = .compile_unit, .children = true, .attrs = &.{ + .{ .producer, .strp }, .{ .language, .data1 }, - .{ .producer, .line_strp }, .{ .comp_dir, .line_strp }, .{ .name, .line_strp }, .{ .base_types, .ref_addr }, .{ .stmt_list, .sec_offset }, - .{ .rnglists_base, .sec_offset }, - .{ .ranges, .rnglistx }, + //.{ .rnglists_base, .sec_offset }, + //.{ .ranges, .rnglistx }, + .{ .use_UTF8, .flag_present }, }, }, .module = .{ @@ -2004,7 +2216,14 @@ const AbbrevCode = enum { .children = true, .attrs = &.{ .{ .name, .strp }, - .{ .ranges, .rnglistx }, + //.{ .ranges, .rnglistx }, + }, + }, + .module_dependency = .{ + .tag = .imported_module, + .attrs = &.{ + .{ .name, .string }, + .{ .import, .ref_addr }, }, }, .empty_file = .{ @@ -2662,23 +2881,23 @@ const AbbrevCode = enum { }); }; -fn uleb128Bytes(value: anytype) u32 { +pub fn uleb128Bytes(value: anytype) u32 { var buf: [64]u8 = undefined; var dw: Writer.Discarding = .init(&buf); dw.writer.writeUleb128(value) catch unreachable; return @intCast(dw.fullCount()); } -fn sleb128Bytes(value: anytype) u32 { +pub fn sleb128Bytes(value: anytype) u32 { var buf: [64]u8 = undefined; var dw: Writer.Discarding = .init(&buf); dw.writer.writeSleb128(value) catch unreachable; return @intCast(dw.fullCount()); } -const Allocator = std.mem.Allocator; const assert = std.debug.assert; const codegen = @import("../codegen.zig"); +const Compilation = @import("../Compilation.zig"); const dev = @import("../dev.zig"); const DW = std.dwarf; const Dwarf = @This(); diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 1e2b6560526a77cd7d93c0b3b247737f2a590eca..4c5071fad3768f6123121295d5eeacd2c5b5443a 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -42,11 +42,15 @@ shndx: struct { tdata: Section.Index, rela_dyn: Section.Index, rela_plt: Section.Index, + debug_abbrev: Section.Index, eh_frame_hdr: Section.Index, eh_frame: Section.Index, debug_frame: Section.Index, debug_info: Section.Index, debug_line: Section.Index, + debug_line_str: Section.Index, + debug_str: Section.Index, + debug_str_offsets: Section.Index, // These sections are created only as needed, and are initially `.UNDEF`. init_array: Section.Index, fini_array: Section.Index, @@ -199,14 +203,34 @@ changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void), textrel_count: u32, dwarf: Dwarf, +dwarf_shared: std.enums.EnumArray(Dwarf.SharedSection, struct { + first_target_reloc: NodeReloc.Index, +}), dwarf_units: std.ArrayList(struct { - unit_frame_cie_first_target_reloc: NodeReloc.Index, + frame_cie_first_target_reloc: NodeReloc.Index, + debug_info_header_first_target_reloc: NodeReloc.Index, + debug_info_header_first_node_reloc: NodeReloc.Index, + debug_line_header_first_target_reloc: NodeReloc.Index, + debug_line_header_first_node_reloc: NodeReloc.Index, +}), +dwarf_values: std.ArrayList(struct { + debug_info_first_target_reloc: NodeReloc.Index, + debug_info_first_symbol_reloc: SymbolReloc.Index, + debug_info_first_node_reloc: NodeReloc.Index, +}), +dwarf_globals: std.ArrayList(struct { + debug_info_first_target_reloc: NodeReloc.Index, + debug_info_first_symbol_reloc: SymbolReloc.Index, + debug_info_first_node_reloc: NodeReloc.Index, }), -dwarf_values: std.ArrayList(struct {}), -dwarf_globals: std.ArrayList(struct {}), dwarf_funcs: std.ArrayList(struct { - func_frame_fde_first_symbol_reloc: SymbolReloc.Index, - func_frame_fde_first_node_reloc: NodeReloc.Index, + frame_fde_first_symbol_reloc: SymbolReloc.Index, + frame_fde_first_node_reloc: NodeReloc.Index, + debug_info_first_target_reloc: NodeReloc.Index, + debug_info_first_symbol_reloc: SymbolReloc.Index, + debug_info_first_node_reloc: NodeReloc.Index, + debug_line_first_symbol_reloc: SymbolReloc.Index, + debug_line_first_node_reloc: NodeReloc.Index, }), overflowed_reloc_count: u32, @@ -272,11 +296,17 @@ const Node = union(enum) { /// May contain relocations. lazy_const_data: LazyMapRef.Index(.const_data), - value_debug_info: link.ConstPool.Index, - global_debug_info: Dwarf.Global.Index, - frame_padding, + debug_shared: Dwarf.SharedSection, + unit_padding, unit_frame: Dwarf.Unit.Index, unit_frame_cie: Dwarf.Unit.Index, + unit_debug_info: Dwarf.Unit.Index, + unit_debug_info_header: Dwarf.Unit.Index, + unit_debug_line: Dwarf.Unit.Index, + unit_debug_line_header: Dwarf.Unit.Index, + + value_debug_info: link.ConstPool.Index, + global_debug_info: Dwarf.Global.Index, func_frame_fde: Dwarf.Func.Index, func_debug_info: Dwarf.Func.Index, func_debug_line: Dwarf.Func.Index, @@ -1778,7 +1808,9 @@ const NodeReloc = struct { .none => { const first_target_reloc = switch (elf.getNode(reloc.target)) { else => unreachable, - .unit_frame_cie => |ui| &elf.dwarf_units.items[@backingInt(ui)].unit_frame_cie_first_target_reloc, + .unit_frame_cie => |ui| &elf.dwarf_units.items[@backingInt(ui)].frame_cie_first_target_reloc, + .unit_debug_info_header => |ui| &elf.dwarf_units.items[@backingInt(ui)].debug_info_header_first_target_reloc, + .unit_debug_line_header => |ui| &elf.dwarf_units.items[@backingInt(ui)].debug_line_header_first_target_reloc, }; first_target_reloc.* = reloc.next; }, @@ -3218,11 +3250,16 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { .section_manual_size, .input_section, .copied_global, - .value_debug_info, - .global_debug_info, - .frame_padding, + .debug_shared, + .unit_padding, .unit_frame, .unit_frame_cie, + .unit_debug_info, + .unit_debug_info_header, + .unit_debug_line, + .unit_debug_line_header, + .value_debug_info, + .global_debug_info, .func_frame_fde, .func_debug_info, .func_debug_line, @@ -3661,11 +3698,15 @@ fn create( .tdata = .UNDEF, .rela_dyn = .UNDEF, .rela_plt = .UNDEF, + .debug_abbrev = .UNDEF, .eh_frame_hdr = .UNDEF, .eh_frame = .UNDEF, .debug_frame = .UNDEF, .debug_info = .UNDEF, .debug_line = .UNDEF, + .debug_line_str = .UNDEF, + .debug_str = .UNDEF, + .debug_str_offsets = .UNDEF, .init_array = .UNDEF, .fini_array = .UNDEF, .preinit_array = .UNDEF, @@ -3720,6 +3761,9 @@ fn create( .dwarf => |v| v, .code_view => unreachable, }), + .dwarf_shared = .initFill(.{ + .first_target_reloc = .none, + }), .dwarf_units = .empty, .dwarf_values = .empty, .dwarf_globals = .empty, @@ -3774,7 +3818,7 @@ pub fn deinit(elf: *Elf) void { elf.section_by_name.deinit(gpa); elf.changed_symtab_index.deinit(gpa); - elf.dwarf.deinit(gpa); + elf.dwarf.deinit(); elf.dwarf_units.deinit(gpa); elf.dwarf_values.deinit(gpa); elf.dwarf_globals.deinit(gpa); @@ -3851,9 +3895,13 @@ fn initHeaders( switch (comp.config.debug_format) { .strip => {}, .dwarf => { + shnum += 1; // .debug_abbrev shnum += @intFromBool(have_debug_frame); // .debug_frame shnum += 1; // .debug_info shnum += 1; // .debug_line + shnum += 1; // .debug_line_str + shnum += 1; // .debug_str + shnum += 1; // .debug_str_offsets }, .code_view => unreachable, } @@ -4942,6 +4990,7 @@ fn initHeaders( switch (comp.config.debug_format) { .strip => {}, .dwarf => { + elf.shndx.debug_abbrev = try elf.addSection(elf.ni.elf, .{ .name = ".debug_abbrev" }); if (have_debug_frame) elf.shndx.debug_frame = try elf.addSection(elf.ni.elf, .{ .name = ".debug_frame", .addralign = addr_align, @@ -4955,6 +5004,17 @@ fn initHeaders( .name = ".debug_line", .node_align = elf.mf.flags.block_size, }); + elf.shndx.debug_line_str = try elf.addSection(elf.ni.elf, .{ + .name = ".debug_line_str", + .flags = .{ .MERGE = true, .STRINGS = true }, + }); + elf.shndx.debug_str = try elf.addSection(elf.ni.elf, .{ + .name = ".debug_str", + .flags = .{ .MERGE = true, .STRINGS = true }, + }); + elf.shndx.debug_str_offsets = try elf.addSection(elf.ni.elf, .{ + .name = ".debug_str_offsets", + }); }, .code_view => unreachable, } @@ -5045,11 +5105,6 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { .ehdr, .shdr, .segment, - .value_debug_info, - .global_debug_info, - .frame_padding, - .func_debug_info, - .func_debug_line, => unreachable, .section, .section_manual_size => |shndx| shndx, .input_section, @@ -5058,13 +5113,21 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { .uav, .lazy_code, .lazy_const_data, + .debug_shared, + .unit_padding, .unit_frame, + .unit_debug_info, + .unit_debug_line, => elf.getNode(ni.parent(&elf.mf).unwrap().?).section, - .unit_frame_cie, .func_frame_fde => { - const unit_frame_ni = ni.parent(&elf.mf).unwrap().?; - assert(elf.getNode(unit_frame_ni) == .unit_frame); - return elf.getNode(unit_frame_ni.parent(&elf.mf).unwrap().?).section; - }, + .unit_frame_cie, + .unit_debug_info_header, + .unit_debug_line_header, + .value_debug_info, + .global_debug_info, + .func_frame_fde, + .func_debug_info, + .func_debug_line, + => elf.getNode(ni.parent(&elf.mf).unwrap().?.parent(&elf.mf).unwrap().?).section, }; } fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { @@ -5078,11 +5141,6 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { .shdr, .segment, .copied_global, - .value_debug_info, - .global_debug_info, - .frame_padding, - .func_debug_info, - .func_debug_line, => unreachable, .section, .section_manual_size => |shndx| shndx.vaddr(elf), .input_section => |isi| isi.ptrConst(elf).vaddr, @@ -5091,7 +5149,20 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { .lazy_code, .lazy_const_data, => |i| Symbol.Id.local(i.symbol(elf)).value(elf), - .unit_frame, .unit_frame_cie, .func_frame_fde => elf.computeNodeVAddr(ni), + .debug_shared, + .unit_padding, + .unit_frame, + .unit_frame_cie, + .unit_debug_info, + .unit_debug_info_header, + .unit_debug_line, + .unit_debug_line_header, + .value_debug_info, + .global_debug_info, + .func_frame_fde, + .func_debug_info, + .func_debug_line, + => elf.computeNodeVAddr(ni), }; } fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { @@ -5110,16 +5181,17 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { .lazy_code, .lazy_const_data, => |i| Symbol.Id.local(i.symbol(elf)).value(elf), - .value_debug_info, - .global_debug_info, - .frame_padding, - => unreachable, - .unit_frame => { + .debug_shared, .unit_padding => unreachable, + .unit_frame, .unit_debug_info, .unit_debug_line => { const section_ni = parent_ni.parent(&elf.mf).unwrap().?; const section_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); break :parent_vaddr elf.getNode(section_ni).section.vaddr(elf) + section_offset; }, .unit_frame_cie, + .unit_debug_info_header, + .unit_debug_line_header, + .value_debug_info, + .global_debug_info, .func_frame_fde, .func_debug_info, .func_debug_line, @@ -5138,7 +5210,7 @@ fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 { /// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support /// the special-case sections '.plt', '.dynamic', and '.eh_frame_hdr'. fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { - const symbol_relocs: *SymbolReloc.Index, const node_relocs: ?*NodeReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) { + const symbol_relocs: ?*SymbolReloc.Index, const node_relocs: ?*NodeReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) { .archive, .archive_header, .archive_input_member, @@ -5148,13 +5220,12 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { .shdr, .segment, .copied_global, - .value_debug_info, - .global_debug_info, - .frame_padding, + .debug_shared, + .unit_padding, .unit_frame, .unit_frame_cie, - .func_debug_info, - .func_debug_line, + .unit_debug_info, + .unit_debug_line, => unreachable, // cannot contain relocs .section, .section_manual_size, @@ -5179,23 +5250,52 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { null, &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_got_reloc, }, + .unit_debug_info_header => |ui| .{ + null, + &elf.dwarf_units.items[@backingInt(ui)].debug_info_header_first_node_reloc, + null, + }, + .unit_debug_line_header => |ui| .{ + null, + &elf.dwarf_units.items[@backingInt(ui)].debug_line_header_first_node_reloc, + null, + }, + .value_debug_info => |vi| .{ + &elf.dwarf_values.items[@backingInt(vi)].debug_info_first_symbol_reloc, + &elf.dwarf_values.items[@backingInt(vi)].debug_info_first_node_reloc, + null, + }, + .global_debug_info => |gi| .{ + &elf.dwarf_globals.items[@backingInt(gi)].debug_info_first_symbol_reloc, + &elf.dwarf_globals.items[@backingInt(gi)].debug_info_first_node_reloc, + null, + }, .func_frame_fde => |fi| .{ - &elf.dwarf_funcs.items[@backingInt(fi)].func_frame_fde_first_symbol_reloc, - &elf.dwarf_funcs.items[@backingInt(fi)].func_frame_fde_first_node_reloc, + &elf.dwarf_funcs.items[@backingInt(fi)].frame_fde_first_symbol_reloc, + &elf.dwarf_funcs.items[@backingInt(fi)].frame_fde_first_node_reloc, + null, + }, + .func_debug_info => |fi| .{ + &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_symbol_reloc, + &elf.dwarf_funcs.items[@backingInt(fi)].debug_info_first_node_reloc, + null, + }, + .func_debug_line => |fi| .{ + &elf.dwarf_funcs.items[@backingInt(fi)].debug_line_first_symbol_reloc, + &elf.dwarf_funcs.items[@backingInt(fi)].debug_line_first_node_reloc, null, }, }; - if (symbol_relocs.* != .none) { - for ( - elf.symbol_relocs.items[@backingInt(symbol_relocs.*)..], - @backingInt(symbol_relocs.*).., - ) |*reloc, index| { - if (reloc.node != ni) break; - reloc.delete(elf, @fromBackingInt(@intCast(index))); + if (symbol_relocs) |ptr| { + if (ptr.* != .none) { + for (elf.symbol_relocs.items[@backingInt(ptr.*)..], @backingInt(ptr.*)..) |*reloc, index| { + if (reloc.node != ni) break; + reloc.delete(elf, @fromBackingInt(@intCast(index))); + } } + ptr.* = @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); } - symbol_relocs.* = @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); if (node_relocs) |ptr| { if (ptr.* != .none) { @@ -5962,7 +6062,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load return error.BadMagic; } } - var strtab: std.Io.Writer.Allocating = .init(gpa); + var strtab: Io.Writer.Allocating = .init(gpa); defer strtab.deinit(); while (r.takeStruct(std.elf.ar_hdr, .native)) |header| { if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG)) @@ -6013,7 +6113,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEscape) { return .{ .data = member }; } -fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { +fn memberStringEscape(member: ?[]const u8, w: *Io.Writer) Io.Writer.Error!void { try w.print("({f})", .{std.zig.fmtString(member orelse return)}); } fn loadObject( @@ -6897,7 +6997,6 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) link.Error!void { fn prelinkInner(elf: *Elf) Error!void { const comp = elf.base.comp; const gpa = comp.gpa; - if (comp.zcu) |zcu| self_hosted_codegen: { if (comp.config.use_llvm) break :self_hosted_codegen; @@ -6922,35 +7021,130 @@ fn prelinkInner(elf: *Elf) Error!void { elf.input_pending_index += 1; try elf.dwarf.initUnits(zcu); + try elf.nodes.ensureUnusedCapacity(gpa, 4 + 4 + (4 + 4) * elf.dwarf.units.count()); try elf.dwarf_units.appendNTimes(gpa, .{ - .unit_frame_cie_first_target_reloc = .none, + .frame_cie_first_target_reloc = .none, + .debug_info_header_first_target_reloc = .none, + .debug_info_header_first_node_reloc = .none, + .debug_line_header_first_target_reloc = .none, + .debug_line_header_first_node_reloc = .none, }, elf.dwarf.units.count()); - try elf.nodes.ensureUnusedCapacity(gpa, 2); - for ( - [2]Dwarf.Frame.Format{ .eh_frame, .debug_frame }, - [2]Section.Index{ elf.shndx.eh_frame, elf.shndx.debug_frame }, - ) |format, frame_shndx| { - if (frame_shndx == .UNDEF) continue; - const frame_ni = frame_shndx.get(elf).ni; - _ = frame_ni.last(&elf.mf).unwrap() orelse continue; - const frame_padding_ni = try frame_ni.addFloatingChild(&elf.mf, gpa, .{ - .alignment = switch (elf.identClass()) { + elf.dwarf.debug_abbrev.ni = + .wrap(try elf.shndx.debug_abbrev.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{})); + elf.nodes.appendAssumeCapacity(.{ .debug_shared = .debug_abbrev }); + + elf.dwarf.debug_line_str.ni = + .wrap(try elf.shndx.debug_line_str.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{})); + elf.nodes.appendAssumeCapacity(.{ .debug_shared = .debug_line_str }); + + elf.dwarf.debug_str.ni = + .wrap(try elf.shndx.debug_str.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{})); + elf.nodes.appendAssumeCapacity(.{ .debug_shared = .debug_str }); + + elf.dwarf.debug_str_offsets.ni = + .wrap(try elf.shndx.debug_str_offsets.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{})); + elf.nodes.appendAssumeCapacity(.{ .debug_shared = .debug_str_offsets }); + + for ([4]Section.Index{ + elf.shndx.eh_frame, + elf.shndx.debug_frame, + elf.shndx.debug_info, + elf.shndx.debug_line, + }) |debug_shndx| { + if (debug_shndx == .UNDEF) continue; + const debug_ni = debug_shndx.get(elf).ni; + _ = debug_ni.last(&elf.mf).unwrap() orelse continue; + const frame_format = debug_shndx.debugFrameFormat(elf); + const unit_padding_ni = try debug_ni.addFloatingChild(&elf.mf, gpa, .{ + .alignment = if (frame_format) |_| switch (elf.identClass()) { .NONE, _ => unreachable, .@"32" => .@"4", .@"64" => .@"8", - }, + } else .@"1", .next_moved = true, .enable_next_moved = true, }); - elf.nodes.appendAssumeCapacity(.frame_padding); - var cie_writer: MappedFile.Node.Writer = undefined; - frame_padding_ni.writer(&elf.mf, gpa, &cie_writer); - defer cie_writer.deinit(); - elf.dwarf.genDebugFrameCie(&cie_writer.interface, null, format) catch |err| switch (err) { - error.WriteFailed => return cie_writer.err.?, + elf.nodes.appendAssumeCapacity(.unit_padding); + var debug_nw: MappedFile.Node.Writer = undefined; + unit_padding_ni.writer(&elf.mf, gpa, &debug_nw); + defer debug_nw.deinit(); + (if (frame_format) |format| + elf.dwarf.genDebugFrameCie(&debug_nw.interface, null, format) + else + elf.dwarf.genUnitPadding(&debug_nw.interface)) catch |err| switch (err) { + error.WriteFailed => return debug_nw.err.?, }; } + + for (0.., elf.dwarf.units.values()) |unit_index, *unit| { + const ui: Dwarf.Unit.Index = @fromBackingInt(@intCast(unit_index)); + switch (elf.shndx.debug_info) { + .UNDEF => {}, + else => |debug_info_shndx| { + const debug_info_ni = + try debug_info_shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ + .alignment = elf.mf.flags.block_size, + .next_moved = true, + .enable_next_moved = true, + }); + unit.debug_info_ni = .wrap(debug_info_ni); + elf.nodes.appendAssumeCapacity(.{ .unit_debug_info = ui }); + + unit.debug_info_header_ni = + .wrap(try debug_info_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ + .next_moved = true, + .enable_next_moved = true, + })); + elf.nodes.appendAssumeCapacity(.{ .unit_debug_info_header = ui }); + }, + } + switch (elf.shndx.debug_line) { + .UNDEF => {}, + else => |debug_line_shndx| { + const debug_line_ni = + try debug_line_shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ + .alignment = elf.mf.flags.block_size, + .next_moved = true, + .enable_next_moved = true, + }); + unit.debug_line_ni = .wrap(debug_line_ni); + elf.nodes.appendAssumeCapacity(.{ .unit_debug_line = ui }); + + unit.debug_line_header_ni = + .wrap(try debug_line_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ + .next_moved = true, + .enable_next_moved = true, + })); + elf.nodes.appendAssumeCapacity(.{ .unit_debug_line_header = ui }); + }, + } + } + + for (0.., elf.dwarf.units.values()) |unit_index, *unit| { + const ui: Dwarf.Unit.Index = @fromBackingInt(@intCast(unit_index)); + if (elf.shndx.debug_info != .UNDEF) { + var header_nw: MappedFile.Node.Writer = undefined; + const debug_info_header_ni = unit.debug_info_header_ni.unwrap().?; + debug_info_header_ni.writer(&elf.mf, gpa, &header_nw); + defer header_nw.deinit(); + elf.resetNodeRelocs(debug_info_header_ni); + elf.dwarf.genDebugInfoHeader(&header_nw, ui, zcu) catch |err| switch (err) { + error.WriteFailed => return header_nw.err.?, + else => |e| return e, + }; + } + if (elf.shndx.debug_line != .UNDEF) { + var header_nw: MappedFile.Node.Writer = undefined; + const debug_line_header_ni = unit.debug_line_header_ni.unwrap().?; + debug_line_header_ni.writer(&elf.mf, gpa, &header_nw); + defer header_nw.deinit(); + elf.resetNodeRelocs(debug_line_header_ni); + elf.dwarf.genDebugLineHeader(&header_nw.interface) catch |err| switch (err) { + error.WriteFailed => return header_nw.err.?, + }; + } + } } } @@ -7750,7 +7944,10 @@ fn addNodeRelocAssumeCapacity( assert(!shndx.flags(elf).ALLOC); // not yet needed so not implemented const first_target_reloc = switch (elf.getNode(target)) { else => unreachable, - .unit_frame_cie => |ui| &elf.dwarf_units.items[@backingInt(ui)].unit_frame_cie_first_target_reloc, + .debug_shared => |ss| &elf.dwarf_shared.getPtr(ss).first_target_reloc, + .unit_frame_cie => |ui| &elf.dwarf_units.items[@backingInt(ui)].frame_cie_first_target_reloc, + .unit_debug_info_header => |ui| &elf.dwarf_units.items[@backingInt(ui)].debug_info_header_first_target_reloc, + .unit_debug_line_header => |ui| &elf.dwarf_units.items[@backingInt(ui)].debug_line_header_first_target_reloc, }; const next = first_target_reloc.*; const ri: NodeReloc.Index = @fromBackingInt(@intCast(elf.node_relocs.items.len)); @@ -7843,11 +8040,16 @@ fn addGotRelocAssumeCapacity( .shdr, .segment, .copied_global, - .value_debug_info, - .global_debug_info, - .frame_padding, + .debug_shared, + .unit_padding, .unit_frame, .unit_frame_cie, + .unit_debug_info, + .unit_debug_info_header, + .unit_debug_line, + .unit_debug_line_header, + .value_debug_info, + .global_debug_info, .func_frame_fde, .func_debug_info, .func_debug_line, @@ -8207,21 +8409,27 @@ fn updateFuncInner( var nw: MappedFile.Node.Writer = undefined; ni.writer(&elf.mf, gpa, &nw); defer nw.deinit(); - var debug: Dwarf.WipNav.Debug = undefined; - const debug_output: link.File.DebugInfoOutput = debug_output: { - if (elf.ehdrMachine() != .X86_64) break :debug_output .none; + var debug_output_buf: Dwarf.WipNav.Debug = undefined; + const debug_output: link.File.DebugInfoOutput, const dwarf_func = debug_output: { + if (elf.ehdrMachine() != .X86_64) break :debug_output .{ .none, undefined }; const dwarf = &elf.dwarf; const mod = zcu.navFileScope(func.owner_nav).mod.?; - if (mod.strip and mod.unwind_tables == .none) break :debug_output .none; + if (mod.strip and mod.unwind_tables == .none) break :debug_output .{ .none, undefined }; try elf.nodes.ensureUnusedCapacity(gpa, 5); const dwarf_func_index = try dwarf.getFunc(func.owner_nav); try elf.dwarf_funcs.appendNTimes(gpa, .{ - .func_frame_fde_first_symbol_reloc = .none, - .func_frame_fde_first_node_reloc = .none, + .frame_fde_first_symbol_reloc = .none, + .frame_fde_first_node_reloc = .none, + .debug_info_first_target_reloc = .none, + .debug_info_first_symbol_reloc = .none, + .debug_info_first_node_reloc = .none, + .debug_line_first_symbol_reloc = .none, + .debug_line_first_node_reloc = .none, }, @backingInt(dwarf_func_index) + 1 -| elf.dwarf_funcs.items.len); - debug.wip_nav = .{ + const wip_nav = &debug_output_buf.wip_nav; + wip_nav.* = .{ .dwarf = dwarf, .unit = dwarf.getUnit(mod), .func = dwarf_func_index, @@ -8235,16 +8443,17 @@ fn updateFuncInner( .sync, .async => .eh_frame, }, .fde_writer = undefined, - .frame_func_length_offset = std.math.maxInt(usize), + .frame_func_length = undefined, }; - const unit = debug.wip_nav.unit.get(dwarf); + const unit = wip_nav.unit.get(dwarf); + const frame_align: Alignment = switch (elf.identClass()) { .NONE, _ => unreachable, .@"32" => .@"4", .@"64" => .@"8", }; const frame_ni = unit.frame_ni.unwrap() orelse frame_ni: { - const frame_ni = try switch (debug.wip_nav.frame_format) { + const frame_ni = try switch (wip_nav.frame_format) { .debug_frame => elf.shndx.debug_frame, .eh_frame => elf.shndx.eh_frame, }.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ @@ -8253,7 +8462,7 @@ fn updateFuncInner( .enable_next_moved = true, }); unit.frame_ni = .wrap(frame_ni); - elf.nodes.appendAssumeCapacity(.{ .unit_frame = debug.wip_nav.unit }); + elf.nodes.appendAssumeCapacity(.{ .unit_frame = wip_nav.unit }); break :frame_ni frame_ni; }; _ = unit.cie_ni.unwrap() orelse { @@ -8263,17 +8472,16 @@ fn updateFuncInner( .enable_next_moved = true, }); unit.cie_ni = .wrap(cie_ni); - elf.nodes.appendAssumeCapacity(.{ .unit_frame_cie = debug.wip_nav.unit }); - var cie_writer: MappedFile.Node.Writer = undefined; - cie_ni.writer(&elf.mf, gpa, &cie_writer); - defer cie_writer.deinit(); - dwarf.genDebugFrameCie(&cie_writer.interface, switch (elf.ehdrMachine()) { + elf.nodes.appendAssumeCapacity(.{ .unit_frame_cie = wip_nav.unit }); + var cie_nw: MappedFile.Node.Writer = undefined; + cie_ni.writer(&elf.mf, gpa, &cie_nw); + defer cie_nw.deinit(); + dwarf.genDebugFrameCie(&cie_nw.interface, switch (elf.ehdrMachine()) { else => unreachable, .X86_64 => .x86_64, - }, debug.wip_nav.frame_format) catch |err| switch (err) { - error.WriteFailed => return cie_writer.err.?, + }, wip_nav.frame_format) catch |err| switch (err) { + error.WriteFailed => return cie_nw.err.?, }; - @memset(cie_writer.interface.unusedCapacitySlice(), std.dwarf.CFA.nop); }; const dwarf_func = dwarf_func_index.get(dwarf); const fde_ni = if (dwarf_func.fde_ni.unwrap()) |fde_ni| fde_ni: { @@ -8290,15 +8498,17 @@ fn updateFuncInner( dwarf_func.fde_ni = .wrap(fde_ni); break :fde_ni fde_ni; }; - fde_ni.writer(&elf.mf, gpa, &debug.wip_nav.fde_writer); - if (mod.strip) break :debug_output .{ .eh_frame = &debug.wip_nav }; + fde_ni.writer(&elf.mf, gpa, &wip_nav.fde_writer); + if (mod.strip) break :debug_output .{ .{ .eh_frame = wip_nav }, dwarf_func }; + + const debug = &debug_output_buf; debug.pt = pt; debug.any_children = false; debug.blocks = .empty; const debug_info_ni = dwarf_func.debug_info_ni.unwrap() orelse debug_info_ni: { const debug_info_ni = - try elf.shndx.debug_info.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ + try unit.debug_info_ni.unwrap().?.addFloatingChild(&elf.mf, gpa, .{ .next_moved = true, .enable_next_moved = true, }); @@ -8309,7 +8519,7 @@ fn updateFuncInner( debug_info_ni.writer(&elf.mf, gpa, &debug.info_writer); const debug_line_ni = dwarf_func.debug_line_ni.unwrap() orelse debug_line_ni: { const debug_line_ni = - try elf.shndx.debug_line.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ + try unit.debug_line_ni.unwrap().?.addFloatingChild(&elf.mf, gpa, .{ .next_moved = true, .enable_next_moved = true, }); @@ -8317,18 +8527,25 @@ fn updateFuncInner( break :debug_line_ni debug_line_ni; }; debug_line_ni.writer(&elf.mf, gpa, &debug.line_writer); - break :debug_output .{ .dwarf2 = &debug }; + + break :debug_output .{ .{ .dwarf2 = debug }, dwarf_func }; }; defer switch (debug_output) { .dwarf => unreachable, - inline .eh_frame, .dwarf2 => |dwarf| dwarf.deinit(gpa), + inline .eh_frame, .dwarf2 => |dwarf| dwarf.deinit(), .none => {}, }; switch (debug_output) { .dwarf => unreachable, - inline .eh_frame, .dwarf2 => |dwarf| { - elf.resetNodeRelocs(debug.wip_nav.func.?.get(&elf.dwarf).fde_ni.unwrap().?); - try dwarf.genFuncHeaders(); + .eh_frame => |wip_nav| { + elf.resetNodeRelocs(dwarf_func.fde_ni.unwrap().?); + try wip_nav.genDebugFrameHeader(); + }, + .dwarf2 => |debug| { + elf.resetNodeRelocs(dwarf_func.fde_ni.unwrap().?); + try debug.wip_nav.genDebugFrameHeader(); + elf.resetNodeRelocs(dwarf_func.debug_info_ni.unwrap().?); + try debug.startDebugInfo(); }, .none => {}, } @@ -8348,30 +8565,45 @@ fn updateFuncInner( else => |e| return e, }; const func_length = nw.interface.end; - switch (debug_output) { + switch (elf.symPtr(nmi.symbol(elf).index())) { + inline else => |sym| elf.targetStore(&sym.size, @intCast(func_length)), + } + debug_output: switch (debug_output) { .dwarf => unreachable, - .eh_frame, .dwarf2 => { - debug.wip_nav.finishDebugFrameFde(func_length); - const frame_ni = switch (debug.wip_nav.frame_format) { + .eh_frame => |wip_nav| { + wip_nav.finishDebugFrameFde(func_length); + const frame_ni = switch (wip_nav.frame_format) { .debug_frame => elf.shndx.debug_frame, .eh_frame => elf.shndx.eh_frame, }.get(elf).ni; - try frame_ni.trimStart(&elf.mf, elf.base.comp.gpa); - switch (debug.wip_nav.frame_format) { + try frame_ni.trimStart(&elf.mf, gpa); + switch (wip_nav.frame_format) { .debug_frame => {}, .eh_frame => { const last_offset, const last_size = frame_ni.last(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf); - const last_end = last_offset + last_size; - try frame_ni.ensureMinimumSize(&elf.mf, elf.base.comp.gpa, last_end + 4); + try frame_ni.ensureMinimumSize(&elf.mf, gpa, last_offset + last_size + 4); }, } }, + .dwarf2 => |debug| { + try debug.finishFunc(); + for ([2]Section.Index{ + elf.shndx.debug_info, + elf.shndx.debug_line, + }) |debug_shndx| try debug_shndx.get(elf).ni.trimStart(&elf.mf, gpa); + { + const debug_info_ni = + debug.wip_nav.unit.get(debug.wip_nav.dwarf).debug_info_ni.unwrap().?; + const last_offset, const last_size = + debug_info_ni.last(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf); + try debug_info_ni.ensureMinimumSize(&elf.mf, gpa, last_offset + last_size + + comptime Dwarf.uleb128Bytes(@backingInt(Dwarf.AbbrevCode.null)) * 2); + } + continue :debug_output .{ .eh_frame = &debug.wip_nav }; + }, .none => {}, } - switch (elf.symPtr(nmi.symbol(elf).index())) { - inline else => |sym| elf.targetStore(&sym.size, @intCast(func_length)), - } } // The NAV's node is done---now generate any UAVs or lazy code/data which the NAV needs. @@ -8427,8 +8659,14 @@ fn flushInner( while (try elf.idle(tid)) {} + assert(elf.pending_uavs.items.len == 0); + var lazy_it = elf.lazy.iterator(); + while (lazy_it.next()) |lazy| assert(lazy.value.pending_index == lazy.value.map.count()); + // We've done the final `idle` loop, so everything is at its final place in the file. We have a // few more things to check and write now that addresses and offsets are finalized. + elf.mf.nodes_lock.lock(); + defer elf.mf.nodes_lock.unlock(); if (elf.overflowed_reloc_count > 0) { diags.addError("failed to apply {d} relocations: overflow", .{elf.overflowed_reloc_count}); @@ -8476,12 +8714,13 @@ fn flushInner( } pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { - const comp = elf.base.comp; - const diags = &comp.link_diags; - + // This function is called non-deterministically, and so must not affect the layout of any nodes. elf.mf.nodes_lock.lock(); defer elf.mf.nodes_lock.unlock(); + const comp = elf.base.comp; + const diags = &comp.link_diags; + assert(elf.pending_uavs.items.len == 0); for (&elf.lazy.values) |*lazy| { assert(lazy.pending_index == lazy.map.count()); @@ -8654,6 +8893,25 @@ fn idleProgNode( .uav => |umi| std.mem.print(&name, "{f}", .{ Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), }) catch &name, + .debug_shared => |ss| switch (ss) { + .debug_abbrev, .debug_str, .debug_str_offsets => "debug info", + .debug_line_str => "line info", + }, + .unit_frame, + .unit_frame_cie, + .unit_debug_info, + .unit_debug_info_header, + .unit_debug_line, + .unit_debug_line_header, + => |ui, tag| std.mem.print(&name, "{s} info for {s}", .{ + switch (tag) { + else => unreachable, + .unit_frame, .unit_frame_cie => "unwind", + .unit_debug_info, .unit_debug_info_header => "debug", + .unit_debug_line, .unit_debug_line_header => "line", + }, + ui.mod(&elf.dwarf).fully_qualified_name, + }) catch &name, .value_debug_info => |cpi| std.mem.print(&name, "debug info for {f}", .{ Value.fromInterned(cpi.val(&elf.dwarf.const_pool)) .fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), @@ -8664,9 +8922,6 @@ fn idleProgNode( ip.getNav(gi.nav(&elf.dwarf)).fqn.fmt(ip), }) catch &name; }, - .unit_frame, .unit_frame_cie => |ui| std.mem.print(&name, "unwind info for {s}", .{ - ui.mod(&elf.dwarf).fully_qualified_name, - }) catch &name, .func_frame_fde, .func_debug_info, .func_debug_line => |fi, tag| { const ip = &elf.base.comp.zcu.?.intern_pool; break :name std.mem.print(&name, "{s} info for {f}", .{ @@ -8684,38 +8939,35 @@ fn idleProgNode( fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void { const zcu = elf.base.comp.zcu.?; - pending: while (true) { - if (elf.pending_uavs.pop()) |umi| { - var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; - const prog_name = std.mem.print(&prog_name_buf, "{f}", .{ - Value.fromInterned(umi.uavValue(elf)).fmtValue(pt), - }) catch &prog_name_buf; - const prog_node = elf.const_prog_node.start(prog_name, 0); - defer prog_node.end(); - try elf.genUav(pt, umi); - continue :pending; - } - var lazy_it = elf.lazy.iterator(); - while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { - const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; - lazy.value.pending_index += 1; - const lazy_ty: Type = .fromInterned(lmr.lazySymbol(elf).ty); - var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; - const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(zcu)) { - .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, - .error_set => switch (lmr.kind) { - .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, - .const_data => "@errorName", - }, - else => unreachable, - }; - const prog_node = elf.synth_prog_node.start(prog_name, 0); - defer prog_node.end(); - try elf.genLazy(pt, lmr); - continue :pending; - }; - break; + + while (elf.pending_uavs.pop()) |umi| { + var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; + const prog_name = std.mem.print(&prog_name_buf, "{f}", .{ + Value.fromInterned(umi.uavValue(elf)).fmtValue(pt), + }) catch &prog_name_buf; + const prog_node = elf.const_prog_node.start(prog_name, 0); + defer prog_node.end(); + try elf.genUav(pt, umi); } + + var lazy_it = elf.lazy.iterator(); + while (lazy_it.next()) |lazy| while (lazy.value.pending_index < lazy.value.map.count()) { + const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; + lazy.value.pending_index += 1; + const lazy_ty: Type = .fromInterned(lmr.lazySymbol(elf).ty); + var prog_name_buf: [std.Progress.Node.max_name_len]u8 = undefined; + const prog_name: []const u8 = switch (lazy_ty.zigTypeTag(zcu)) { + .@"enum" => std.mem.print(&prog_name_buf, "@tagName({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, + .error_set => switch (lmr.kind) { + .code => std.mem.print(&prog_name_buf, "@errorCast({f})", .{lazy_ty.fmt(pt)}) catch &prog_name_buf, + .const_data => "@errorName", + }, + else => unreachable, + }; + const prog_node = elf.synth_prog_node.start(prog_name, 0); + defer prog_node.end(); + try elf.genLazy(pt, lmr); + }; } fn genUav( @@ -9071,16 +9323,27 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void name = elf.globalByName(name).?.next_in_node; } } - elf.flushMovedNodeRelocs(ni, new_addr, mi.firstSymbolReloc(elf), .none, mi.firstGotReloc(elf)); + elf.flushMovedNodeRelocs( + ni, + new_addr, + mi.firstSymbolReloc(elf), + .none, + mi.firstGotReloc(elf), + ); }, - .value_debug_info, - .global_debug_info, - .frame_padding, - .unit_frame, - => {}, + .debug_shared => |ss| { + var target_ri = elf.dwarf_shared.getPtr(ss).first_target_reloc; + while (target_ri != .none) { + const target_reloc = target_ri.get(elf); + assert(target_reloc.target == ni); + target_reloc.apply(elf); + target_ri = target_reloc.next; + } + }, + .unit_padding, .unit_frame, .unit_debug_info, .unit_debug_line => {}, .unit_frame_cie => |ui| { const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)]; - var target_ri = dwarf_unit.unit_frame_cie_first_target_reloc; + var target_ri = dwarf_unit.frame_cie_first_target_reloc; while (target_ri != .none) { const target_reloc = target_ri.get(elf); assert(target_reloc.target == ni); @@ -9088,8 +9351,75 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void target_ri = target_reloc.next; } }, + .unit_debug_info_header => |ui| { + const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)]; + var target_ri = dwarf_unit.debug_info_header_first_target_reloc; + while (target_ri != .none) { + const target_reloc = target_ri.get(elf); + assert(target_reloc.target == ni); + target_reloc.apply(elf); + target_ri = target_reloc.next; + } + elf.flushMovedNodeRelocs( + ni, + elf.computeNodeVAddr(ni), + .none, + dwarf_unit.debug_info_header_first_node_reloc, + .none, + ); + }, + .unit_debug_line_header => |ui| { + const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)]; + var target_ri = dwarf_unit.debug_line_header_first_target_reloc; + while (target_ri != .none) { + const target_reloc = target_ri.get(elf); + assert(target_reloc.target == ni); + target_reloc.apply(elf); + target_ri = target_reloc.next; + } + elf.flushMovedNodeRelocs( + ni, + elf.computeNodeVAddr(ni), + .none, + dwarf_unit.debug_line_header_first_node_reloc, + .none, + ); + }, + .value_debug_info => |vi| { + const dwarf_value = &elf.dwarf_values.items[@backingInt(vi)]; + var target_ri = dwarf_value.debug_info_first_target_reloc; + while (target_ri != .none) { + const target_reloc = target_ri.get(elf); + assert(target_reloc.target == ni); + target_reloc.apply(elf); + target_ri = target_reloc.next; + } + elf.flushMovedNodeRelocs( + ni, + elf.computeNodeVAddr(ni), + dwarf_value.debug_info_first_symbol_reloc, + dwarf_value.debug_info_first_node_reloc, + .none, + ); + }, + .global_debug_info => |vi| { + const dwarf_global = &elf.dwarf_globals.items[@backingInt(vi)]; + var target_ri = dwarf_global.debug_info_first_target_reloc; + while (target_ri != .none) { + const target_reloc = target_ri.get(elf); + assert(target_reloc.target == ni); + target_reloc.apply(elf); + target_ri = target_reloc.next; + } + elf.flushMovedNodeRelocs( + ni, + elf.computeNodeVAddr(ni), + dwarf_global.debug_info_first_symbol_reloc, + dwarf_global.debug_info_first_node_reloc, + .none, + ); + }, .func_frame_fde => |fi| { - const new_addr = elf.computeNodeVAddr(ni); const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)]; const mod = elf.base.comp.zcu.?.navFileScope(fi.nav(&elf.dwarf)).mod.?; switch (mod.unwind_tables) { @@ -9101,15 +9431,39 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void } elf.flushMovedNodeRelocs( ni, - new_addr, - dwarf_func.func_frame_fde_first_symbol_reloc, - dwarf_func.func_frame_fde_first_node_reloc, + elf.computeNodeVAddr(ni), + dwarf_func.frame_fde_first_symbol_reloc, + dwarf_func.frame_fde_first_node_reloc, + .none, + ); + }, + .func_debug_info => |fi| { + const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)]; + var target_ri = dwarf_func.debug_info_first_target_reloc; + while (target_ri != .none) { + const target_reloc = target_ri.get(elf); + assert(target_reloc.target == ni); + target_reloc.apply(elf); + target_ri = target_reloc.next; + } + elf.flushMovedNodeRelocs( + ni, + elf.computeNodeVAddr(ni), + dwarf_func.debug_info_first_symbol_reloc, + dwarf_func.debug_info_first_node_reloc, + .none, + ); + }, + .func_debug_line => |fi| { + const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)]; + elf.flushMovedNodeRelocs( + ni, + elf.computeNodeVAddr(ni), + dwarf_func.debug_line_first_symbol_reloc, + dwarf_func.debug_line_first_node_reloc, .none, ); }, - .func_debug_info, - .func_debug_line, - => {}, } try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); } @@ -9346,11 +9700,16 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo .uav, .lazy_code, .lazy_const_data, - .value_debug_info, - .global_debug_info, - .frame_padding, + .debug_shared, + .unit_padding, .unit_frame, .unit_frame_cie, + .unit_debug_info, + .unit_debug_info_header, + .unit_debug_line, + .unit_debug_line_header, + .value_debug_info, + .global_debug_info, .func_frame_fde, .func_debug_info, .func_debug_line, @@ -9378,6 +9737,7 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! .uav, .lazy_code, .lazy_const_data, + .debug_shared, => unreachable, .archive_header => { @@ -9406,66 +9766,111 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! error.NoSpaceLeft => archive.strtab_member_too_big = true, } }, + .unit_padding, + .unit_frame_cie, + .unit_debug_info_header, + .unit_debug_line_header, .value_debug_info, .global_debug_info, - => {}, - .frame_padding, .unit_frame_cie, .func_frame_fde => |_, tag| { + .func_frame_fde, + .func_debug_info, + .func_debug_line, + => |_, tag| { const offset, const size = ni.location(&elf.mf).resolve(&elf.mf); - const slice = slice: { - const parent_ni = ni.parent(&elf.mf).unwrap().?; - if (ni.next(&elf.mf).unwrap()) |next_ni| { - const parent_slice = parent_ni.slicePadding(&elf.mf); - const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf); - break :slice parent_slice[@intCast(offset)..@intCast(next_offset)]; - } else switch (tag) { - else => unreachable, - .frame_padding => { - const frame_slice = parent_ni.slicePadding(&elf.mf); - switch (elf.getNode(parent_ni).section.debugFrameFormat(elf).?) { - .eh_frame => { - const end = frame_slice.len - 4; - std.mem.writeInt(u32, frame_slice[end..][0..4], 0, elf.dwarf.endian); - break :slice frame_slice[@intCast(offset)..end]; - }, - .debug_frame => break :slice frame_slice[@intCast(offset)..], - } - }, - .unit_frame_cie, .func_frame_fde => { - const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); - const frame_ni = parent_ni.parent(&elf.mf).unwrap().?; - const frame_slice = frame_ni.slicePadding(&elf.mf); - const format = elf.getNode(frame_ni).section.debugFrameFormat(elf).?; - const slice = frame_slice[@intCast(parent_offset + offset)..if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| frame_end: { - const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf); - break :frame_end @intCast(parent_next_offset); - } else frame_end: switch (format) { - .eh_frame => { - const frame_end = frame_slice.len - 4; - std.mem.writeInt(u32, frame_slice[frame_end..][0..4], 0, elf.dwarf.endian); - break :frame_end frame_end; - }, - .debug_frame => frame_slice.len, - }]; - var fw: std.Io.Writer = .fixed(slice[@intCast(size)..]); - elf.dwarf.genDebugFrameCie(&fw, null, format) catch |err| switch (err) { - error.WriteFailed => break :slice slice, - }; - elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len); - break :slice slice[0..@intCast(size)]; - }, - } + const parent_ni = ni.parent(&elf.mf).unwrap().?; + const slice = if (ni.next(&elf.mf).unwrap()) |next_ni| slice: { + const parent_slice = parent_ni.slicePadding(&elf.mf); + const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf); + break :slice parent_slice[@intCast(offset)..@intCast(next_offset)]; + } else slice: switch (tag) { + else => unreachable, + .unit_padding => { + const frame_slice = parent_ni.slicePadding(&elf.mf); + switch (elf.getNode(parent_ni).section.debugFrameFormat(elf) orelse .debug_frame) { + .eh_frame => { + const end = frame_slice.len - 4; + std.mem.writeInt(u32, frame_slice[end..][0..4], 0, elf.dwarf.endian); + break :slice frame_slice[@intCast(offset)..end]; + }, + .debug_frame => break :slice frame_slice[@intCast(offset)..], + } + }, + .unit_frame_cie, .func_frame_fde => { + const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); + const frame_ni = parent_ni.parent(&elf.mf).unwrap().?; + const frame_slice = frame_ni.slicePadding(&elf.mf); + const frame_format = elf.getNode(frame_ni).section.debugFrameFormat(elf); + const slice = frame_slice[@intCast(parent_offset + offset)..if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| frame_end: { + const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf); + break :frame_end @intCast(parent_next_offset); + } else frame_end: switch (frame_format orelse .debug_frame) { + .eh_frame => { + const frame_end = frame_slice.len - 4; + std.mem.writeInt(u32, frame_slice[frame_end..][0..4], 0, elf.dwarf.endian); + break :frame_end frame_end; + }, + .debug_frame => frame_slice.len, + }]; + var fw: Io.Writer = .fixed(slice[@intCast(size)..]); + (if (frame_format) |format| + elf.dwarf.genDebugFrameCie(&fw, null, format) + else + elf.dwarf.genUnitPadding(&fw)) catch |err| switch (err) { + error.WriteFailed => break :slice slice, + }; + elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len); + break :slice slice[0..@intCast(size)]; + }, + .unit_debug_info_header, + .unit_debug_line_header, + .value_debug_info, + .global_debug_info, + .func_debug_info, + .func_debug_line, + => { + const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); + const debug_ni = parent_ni.parent(&elf.mf).unwrap().?; + const debug_slice = debug_ni.slicePadding(&elf.mf); + var fw: Io.Writer = .fixed(debug_slice[@intCast(parent_offset)..if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| debug_end: { + const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf); + break :debug_end @intCast(parent_next_offset); + } else debug_slice.len]); + fw.end = @intCast(offset + size); + for (0..2) |_| fw.writeUleb128(@backingInt(Dwarf.AbbrevCode.null)) catch + unreachable; // ensured by `updateFunc` + elf.dwarf.updateUnitLength(fw.buffer, fw.end); + const unit_padding = fw.unusedCapacitySlice(); + elf.dwarf.genUnitPadding(&fw) catch |err| switch (err) { + error.WriteFailed => { + comptime assert(Dwarf.uleb128Bytes(@backingInt(Dwarf.AbbrevCode.null)) == 1); + @memset(fw.buffer, @backingInt(Dwarf.AbbrevCode.null)); + }, + }; + elf.dwarf.updateUnitLength(unit_padding, unit_padding.len); + return; + }, }; - elf.dwarf.updateUnitLength(slice, slice.len); switch (tag) { else => unreachable, - .frame_padding => {}, - .unit_frame_cie, .func_frame_fde => @memset(slice[@intCast(size)..], std.dwarf.CFA.nop), + .unit_padding => elf.dwarf.updateUnitLength(slice, slice.len), + .unit_frame_cie, .func_frame_fde => { + elf.dwarf.updateUnitLength(slice, slice.len); + @memset(slice[@intCast(size)..], std.dwarf.CFA.nop); + }, + .unit_debug_info_header, + .unit_debug_line_header, + .value_debug_info, + .global_debug_info, + .func_debug_info, + .func_debug_line, + => { + var fw: Io.Writer = .fixed(slice[@intCast(size)..]); + elf.dwarf.genDebugInfoPadding(&fw, fw.unusedCapacityLen()) catch unreachable; + }, } }, - .unit_frame, - .func_debug_info, - .func_debug_line, - => {}, + .unit_frame, .unit_debug_info, .unit_debug_line => if (ni.last(&elf.mf).unwrap()) |last_ni| + try last_ni.nextMoved(elf.base.comp.gpa, &elf.mf), } } @@ -9986,6 +10391,16 @@ pub fn printNode( .tid = tid, }), }), + .debug_shared => |ss| try w.print("({})", .{ss}), + .unit_frame, + .unit_frame_cie, + .unit_debug_info, + .unit_debug_info_header, + .unit_debug_line, + .unit_debug_line_header, + => |ui| try w.print("({s})", .{ + ui.mod(&elf.dwarf).fully_qualified_name, + }), .value_debug_info => |cpi| try w.print("({f})", .{ Value.fromInterned(cpi.val(&elf.dwarf.const_pool)) .fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), @@ -9999,9 +10414,6 @@ pub fn printNode( nav.fqn.fmt(ip), }); }, - .unit_frame, .unit_frame_cie => |ui| try w.print("({s})", .{ - ui.mod(&elf.dwarf).fully_qualified_name, - }), .func_frame_fde, .func_debug_info, .func_debug_line => |fi| { const zcu = elf.base.comp.zcu.?; const ip = &zcu.intern_pool; -- 2.54.0