From 0bf3e08c705ec460c71d3b2261acb0b87aacd066 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 11 Aug 2026 01:43:20 -0400 Subject: [PATCH] x86_64: change how epilogue line info is emitted This more closely matches the output of other compilers. --- src/codegen/riscv64/Emit.zig | 3 +- src/codegen/sparc64/Emit.zig | 2 +- src/codegen/x86_64/CodeGen.zig | 41 +++++++------- src/codegen/x86_64/Emit.zig | 32 +++++++---- src/codegen/x86_64/Lower.zig | 3 +- src/codegen/x86_64/Mir.zig | 23 ++++---- src/link/Dwarf.zig | 50 +++++++++++------- src/link/Dwarf2.zig | 97 ++++++++++++++++++++++++---------- src/link/Elf2.zig | 2 +- 9 files changed, 161 insertions(+), 92 deletions(-) diff --git a/src/codegen/riscv64/Emit.zig b/src/codegen/riscv64/Emit.zig index bd59e64ccb6a9c2f62aa5373d78711d78c5b6cac..29b57cd74427d1004b1dd179d19a6ffa50af8b73 100644 --- a/src/codegen/riscv64/Emit.zig +++ b/src/codegen/riscv64/Emit.zig @@ -192,8 +192,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { switch (emit.debug_output) { inline .dwarf, .dwarf2 => |dw| { if (column != emit.prev_di_column) try dw.setColumn(column); - if (delta_line == 0) return; // TODO: fix these edge cases. - try dw.advancePcAndLine(delta_line, delta_pc); + try dw.advanceLineAndPc(delta_line, delta_pc, false); emit.prev_di_line = line; emit.prev_di_column = column; emit.prev_di_pc = emit.w.end; diff --git a/src/codegen/sparc64/Emit.zig b/src/codegen/sparc64/Emit.zig index 1b03f31fd830c0b6d84bedbef9ad88663129a437..8545355fa30413de5db138a1da3f319ad488f48e 100644 --- a/src/codegen/sparc64/Emit.zig +++ b/src/codegen/sparc64/Emit.zig @@ -497,7 +497,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { const delta_pc: usize = emit.w.end - emit.prev_di_pc; switch (emit.debug_output) { inline .dwarf, .dwarf2 => |dbg_out| { - try dbg_out.advancePcAndLine(delta_line, delta_pc); + try dbg_out.advanceLineAndPc(delta_line, delta_pc, false); emit.prev_di_line = line; emit.prev_di_column = column; emit.prev_di_pc = emit.w.end; diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index e1cd83e45768e7a8726b2f48ba4dfce867de728e..eeee3888956a5a3a5c6ea405986f7a2a96211302 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -1072,20 +1072,12 @@ pub fn generate( ); } - function.gen(&file.zir.?, func_zir.inst, func.comptime_args, call_info.air_arg_count) catch |err| switch (err) { + function.gen(&file.zir.?, func_zir.inst, &func, call_info.air_arg_count) catch |err| switch (err) { error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}), else => |e| return e, }; - // Drop them off at the rbrace. - if (!mod.strip) _ = try function.addInst(.{ - .tag = .pseudo, - .ops = .pseudo_dbg_line_line_column, - .data = .{ .line_column = .{ - .line = func.rbrace_line, - .column = func.rbrace_column, - } }, - }); + if (!mod.strip) _ = try function.asmPseudo(.pseudo_dbg_end_none); try function.mir_extra.shrinkToLen(gpa); try function.mir_string_bytes.shrinkToLen(gpa); @@ -1228,18 +1220,18 @@ fn formatWipMir(data: FormatWipMirData, w: *Writer) Writer.Error!void { switch (mir_inst.ops) { else => unreachable, .pseudo_dbg_prologue_end_none, - .pseudo_dbg_epilogue_begin_none, .pseudo_dbg_enter_block_none, .pseudo_dbg_leave_block_none, + .pseudo_dbg_end_none, .pseudo_dbg_arg_none, .pseudo_dbg_var_args_none, .pseudo_dbg_var_none, .pseudo_dead_none, => {}, - .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try w.print( - " {[line]d}, {[column]d}", - mir_inst.data.line_column, - ), + .pseudo_dbg_line_stmt_line_column, + .pseudo_dbg_line_line_column, + .pseudo_dbg_epilogue_begin_line_column, + => try w.print(" {[line]d}, {[column]d}", mir_inst.data.line_column), .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try w.print(" {f}", .{ ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip), }), @@ -2069,7 +2061,7 @@ fn gen( self: *CodeGen, zir: *const std.zig.Zir, func_zir_inst: std.zig.Zir.Inst.Index, - comptime_args: InternPool.Index.Slice, + func: *const InternPool.Key.Func, air_arg_count: u32, ) InnerError!void { const pt = self.pt; @@ -2150,7 +2142,7 @@ fn gen( if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none); - try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count); + try self.genMainBody(zir, func_zir_inst, func.comptime_args, air_arg_count); const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: { var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1); @@ -2165,7 +2157,14 @@ fn gen( } for (self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc); - if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); + if (!self.mod.strip) _ = try self.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_dbg_epilogue_begin_line_column, + .data = .{ .line_column = .{ + .line = func.rbrace_line, + .column = func.rbrace_column, + } }, + }); const backpatch_stack_dealloc = try self.asmPlaceholder(); const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder(); try self.asmRegister(.{ ._, .pop }, .rbp); @@ -2283,11 +2282,7 @@ fn gen( .data = .{ .reg_list = frame_layout.save_reg_list }, }); } - } else { - if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none); - try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count); - if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); - } + } else try self.genMainBody(zir, func_zir_inst, func.comptime_args, air_arg_count); } fn genMainBody( diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig index a585df85fca110675427de36b51a160c01381424..7196aca6ef02eee3b07bcdf58d84822ee550877d 100644 --- a/src/codegen/x86_64/Emit.zig +++ b/src/codegen/x86_64/Emit.zig @@ -462,20 +462,25 @@ pub fn emitMir(emit: *Emit) Error!void { switch (mir_inst.ops) { else => unreachable, .pseudo_dbg_prologue_end_none => switch (emit.debug_output) { - inline .dwarf, .dwarf2 => |dwarf| try dwarf.setPrologueEnd(), + inline .dwarf, .dwarf2 => |dwarf| { + try dwarf.setPrologueEnd(); + log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ + emit.prev_di_loc.line, emit.prev_di_loc.column, + }); + }, .eh_frame, .none => {}, }, - .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePcAndLine(.{ + .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvanceLineAndPc(.{ .line = mir_inst.data.line_column.line, .column = mir_inst.data.line_column.column, .is_stmt = true, }), - .pseudo_dbg_line_line_column => try emit.dbgAdvancePcAndLine(.{ + .pseudo_dbg_line_line_column => try emit.dbgAdvanceLineAndPc(.{ .line = mir_inst.data.line_column.line, .column = mir_inst.data.line_column.column, .is_stmt = false, }), - .pseudo_dbg_epilogue_begin_none => { + .pseudo_dbg_epilogue_begin_line_column => { switch (emit.debug_output) { inline .dwarf, .dwarf2 => |dwarf| { try dwarf.setEpilogueBegin(); @@ -485,7 +490,10 @@ pub fn emitMir(emit: *Emit) Error!void { }, .eh_frame, .none => {}, } - try emit.dbgAdvancePcAndLine(emit.prev_di_loc); + try emit.dbgAdvanceLineAndPc(.{ + .line = mir_inst.data.line_column.line, + .column = mir_inst.data.line_column.column, + }); }, .pseudo_dbg_enter_block_none => switch (emit.debug_output) { inline .dwarf, .dwarf2 => |dwarf| { @@ -523,6 +531,11 @@ pub fn emitMir(emit: *Emit) Error!void { }, .eh_frame, .none => {}, }, + .pseudo_dbg_end_none => try emit.dbgAdvanceLineAndPc(.{ + .line = emit.prev_di_loc.line, + .column = emit.prev_di_loc.column, + .end = true, + }), .pseudo_dbg_arg_none, .pseudo_dbg_arg_i_s, .pseudo_dbg_arg_i_u, @@ -974,18 +987,19 @@ const TableReloc = struct { const Loc = struct { line: u32, column: u32, - is_stmt: bool, + is_stmt: ?bool = null, + end: bool = false, }; -fn dbgAdvancePcAndLine(emit: *Emit, loc: Loc) Error!void { +fn dbgAdvanceLineAndPc(emit: *Emit, loc: Loc) Error!void { 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.is_stmt) |is_stmt| if (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); + try dwarf.advanceLineAndPc(delta_line, delta_pc, loc.end); emit.prev_di_loc = loc; emit.prev_di_pc = emit.w.end; }, diff --git a/src/codegen/x86_64/Lower.zig b/src/codegen/x86_64/Lower.zig index 389d57f62d6540f7f5dc096d65c59402f72ab06b..db93e40a1dd04cf6a2076b06fda4cd64fc2fe017 100644 --- a/src/codegen/x86_64/Lower.zig +++ b/src/codegen/x86_64/Lower.zig @@ -314,11 +314,12 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_dbg_prologue_end_none, .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column, - .pseudo_dbg_epilogue_begin_none, + .pseudo_dbg_epilogue_begin_line_column, .pseudo_dbg_enter_block_none, .pseudo_dbg_leave_block_none, .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func, + .pseudo_dbg_end_none, .pseudo_dbg_arg_none, .pseudo_dbg_arg_i_s, .pseudo_dbg_arg_i_u, diff --git a/src/codegen/x86_64/Mir.zig b/src/codegen/x86_64/Mir.zig index 01cbecc44936c987272acd482b037bfae160fd4a..763378dd4bb41acafb46c7302286f12aa8dde08b 100644 --- a/src/codegen/x86_64/Mir.zig +++ b/src/codegen/x86_64/Mir.zig @@ -1519,30 +1519,33 @@ pub const Inst = struct { /// Uses `bytes` payload. pseudo_cfi_escape_bytes, - /// End of prologue + /// End of prologue. /// Uses `none` payload. pseudo_dbg_prologue_end_none, - /// Update debug line with is_stmt register set + /// Update debug line with is_stmt register set. /// Uses `line_column` payload. pseudo_dbg_line_stmt_line_column, - /// Update debug line with is_stmt register clear + /// Update debug line with is_stmt register clear. /// Uses `line_column` payload. pseudo_dbg_line_line_column, - /// Start of epilogue - /// Uses `none` payload. - pseudo_dbg_epilogue_begin_none, - /// Start of lexical block + /// Start of epilogue. + /// Uses `line_column` payload. + pseudo_dbg_epilogue_begin_line_column, + /// Start of lexical block. /// Uses `none` payload. pseudo_dbg_enter_block_none, - /// End of lexical block + /// End of lexical block. /// Uses `none` payload. pseudo_dbg_leave_block_none, - /// Start of inline function + /// Start of inline function. /// Uses `ip_index` payload. pseudo_dbg_enter_inline_func, - /// End of inline function + /// End of inline function. /// Uses `ip_index` payload. pseudo_dbg_leave_inline_func, + /// End of function. + /// Uses `none` payload. + pseudo_dbg_end_none, /// Local argument. /// Uses `none` payload. pseudo_dbg_arg_none, diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 59c9952afba6642c665f529364fd0560af479c5c..8b937cb20d07ec3c654d95e1e44d74554f66d5f0 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1626,15 +1626,25 @@ pub const WipNav = struct { wip_nav.any_children = true; } - pub fn advancePcAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void { - return wip_nav.advancePcAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) { + pub fn advanceLineAndPc( + wip_nav: *WipNav, + delta_line: i33, + delta_pc: u64, + end: bool, + ) Allocator.Error!void { + return wip_nav.advanceLineAndPcWriterError( + delta_line, + delta_pc, + end, + ) catch |err| switch (err) { error.WriteFailed => error.OutOfMemory, }; } - fn advancePcAndLineWriterError( + fn advanceLineAndPcWriterError( wip_nav: *WipNav, delta_line: i33, delta_pc: u64, + end: bool, ) Writer.Error!void { const dlw = &wip_nav.debug_line.writer; @@ -1654,20 +1664,30 @@ pub const WipNav = struct { const op_advance = @divExact(delta_pc, header.minimum_instruction_length) * header.maximum_operations_per_instruction + delta_op; const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range; - const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: { - try dlw.writeByte(DW.LNS.advance_pc); - try dlw.writeUleb128(op_advance); + const remaining_op_advance: u8 = @intCast(if (end or + op_advance >= 2 * max_op_advance) + remaining: { + if (op_advance == max_op_advance) { + try dlw.writeByte(DW.LNS.const_add_pc); + } else if (op_advance != 0) { + try dlw.writeByte(DW.LNS.advance_pc); + try dlw.writeUleb128(op_advance); + } else assert(end); break :remaining 0; } else if (op_advance >= max_op_advance) remaining: { try dlw.writeByte(DW.LNS.const_add_pc); break :remaining op_advance - max_op_advance; } else op_advance); - if (remaining_delta_line == 0 and remaining_op_advance == 0) - try dlw.writeByte(DW.LNS.copy) - else + if (remaining_delta_line != 0 or remaining_op_advance != 0) { + assert(!end); try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) + (header.line_range * remaining_op_advance) + header.opcode_base)); + } else if (end) { + try dlw.writeByte(DW.LNS.extended_op); + try dlw.writeUleb128(1); + try dlw.writeByte(DW.LNE.end_sequence); + } else try dlw.writeByte(DW.LNS.copy); } pub fn setColumn(wip_nav: *WipNav, column: u32) Allocator.Error!void { @@ -2773,7 +2793,7 @@ fn initWipNavInner( try dlw.writeByte(DW.LNS.set_column); try dlw.writeUleb128(func.lbrace_column + 1); - try wip_nav.advancePcAndLine(func.lbrace_line, 0); + try wip_nav.advanceLineAndPc(func.lbrace_line, 0, false); } else { try dlw.writeUleb128(1 + @backingInt(dwarf.address_size)); try dlw.writeByte(DW.LNE.set_address); @@ -2790,7 +2810,7 @@ fn initWipNavInner( try dlw.writeByte(DW.LNS.set_column); try dlw.writeUleb128(func.lbrace_column + 1); - try wip_nav.advancePcAndLine(@intCast(decl.src_line + func.lbrace_line), 0); + try wip_nav.advanceLineAndPc(decl.src_line + func.lbrace_line, 0, false); } }, else => { @@ -2982,13 +3002,7 @@ fn finishWipNavWriterError( log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)}); try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written()); - const dlw = &wip_nav.debug_line.writer; - if (dlw.end > 0) { - try dlw.writeByte(DW.LNS.extended_op); - try dlw.writeUleb128(1); - try dlw.writeByte(DW.LNE.end_sequence); - try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written()); - } + try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.written()); try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written()); try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf }); diff --git a/src/link/Dwarf2.zig b/src/link/Dwarf2.zig index 0cf83ac340bd2c3d8a91c5ec80d57dd99c9e4906..97d2876cff2b62035a25f6220fd3cc861967ebd3 100644 --- a/src/link/Dwarf2.zig +++ b/src/link/Dwarf2.zig @@ -24,14 +24,15 @@ debug_str_offsets: StrOffsets, pub const AddressSize = enum(u8) { @"32" = 4, @"64" = 8, _ }; pub const Unit = struct { + dirs: std.array_hash_map.Auto(Unit.Index, void), files: std.array_hash_map.Auto(Zcu.File.Index, void), - files_changed: bool, 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, + debug_line_header_changed: bool, debug_rnglists_ni: MappedFile.Node.Index.Optional, debug_rnglists_offset: usize, @@ -47,6 +48,15 @@ pub const Unit = struct { } }; + pub const DirIndex = enum(u32) { + root = 0, + _, + + fn get(di: DirIndex, unit: *Unit) Unit.Index { + return unit.dirs.keys()[@backingInt(di)]; + } + }; + pub const FileIndex = enum(u32) { root = 0, _, @@ -56,19 +66,29 @@ pub const Unit = struct { } }; + fn deinit(unit: *Unit, gpa: std.mem.Allocator) void { + unit.dirs.deinit(gpa); + unit.files.deinit(gpa); + unit.* = undefined; + } + fn getFile( unit: *Unit, gpa: std.mem.Allocator, + ui: Unit.Index, zfi: Zcu.File.Index, - ) std.mem.Allocator.Error!FileIndex { - const file_gop = try unit.files.getOrPut(gpa, zfi); - if (!file_gop.found_existing) unit.files_changed = true; - return @fromBackingInt(@intCast(file_gop.index)); + ) std.mem.Allocator.Error!struct { DirIndex, FileIndex } { + try unit.dirs.ensureUnusedCapacity(gpa, 1); + try unit.files.ensureUnusedCapacity(gpa, 1); + const dir_gop = unit.dirs.getOrPutAssumeCapacity(ui); + const file_gop = unit.files.getOrPutAssumeCapacity(zfi); + if (!dir_gop.found_existing or !file_gop.found_existing) unit.debug_line_header_changed = true; + return .{ @fromBackingInt(@intCast(dir_gop.index)), @fromBackingInt(@intCast(file_gop.index)) }; } - pub fn cleanFilesChanged(unit: *Unit) bool { - defer unit.files_changed = false; - return unit.files_changed; + pub fn cleanDebugLineHeaderChanged(unit: *Unit) bool { + defer unit.debug_line_header_changed = false; + return unit.debug_line_header_changed; } }; @@ -623,7 +643,6 @@ pub const WipNav = struct { const zf = zcu.fileByIndex(zfi); const inst_info = ip.getNav(nav).srcInst(ip).resolveFull(ip).?; const decl = zf.zir.?.getDeclaration(inst_info.inst); - const mod = zf.mod.?; const dlw = &debug.line_writer.interface; try dlw.writeByte(DW.LNS.extended_op); if (zcu.comp.config.incremental) { @@ -637,20 +656,21 @@ pub const WipNav = struct { try dlw.writeByte(DW.LNS.set_column); try dlw.writeUleb128(func.lbrace_column + 1); - try debug.advancePcAndLine(func.lbrace_line, 0); + try debug.advanceLineAndPc(func.lbrace_line, 0, false); } else { try dlw.writeUleb128(1 + @backingInt(dwarf.address_size)); try dlw.writeByte(DW.LNE.set_address); try dwarf.symbolAddress(&debug.line_writer, debug.wip_nav.func_si, 0); - const fi = try dwarf.getUnit(mod).get(dwarf).getFile(zcu.gpa, zfi); + const unit = dwarf.getUnit(zf.mod.?); + _, const fi = try unit.get(dwarf).getFile(zcu.gpa, unit, zfi); try dlw.writeByte(DW.LNS.set_file); try dlw.writeUleb128(@backingInt(fi)); try dlw.writeByte(DW.LNS.set_column); try dlw.writeUleb128(func.lbrace_column + 1); - try debug.advancePcAndLine(@intCast(decl.src_line + func.lbrace_line), 0); + try debug.advanceLineAndPc(decl.src_line + func.lbrace_line, 0, false); } } @@ -678,9 +698,6 @@ pub const WipNav = struct { } fn finishDebugLine(debug: *Debug) link.EmitError!void { const dlw = &debug.line_writer.interface; - try dlw.writeByte(DW.LNS.extended_op); - try dlw.writeUleb128(1); - try dlw.writeByte(DW.LNE.end_sequence); try genDebugLinePadding(dlw, dlw.unusedCapacityLen()); } @@ -773,12 +790,22 @@ pub const WipNav = struct { debug.any_children = true; } - pub fn advancePcAndLine(debug: *Debug, delta_line: i33, delta_pc: u64) link.Error!void { - return debug.advancePcAndLineInner(delta_line, delta_pc) catch |err| switch (err) { + pub fn advanceLineAndPc( + debug: *Debug, + delta_line: i33, + delta_pc: u64, + end: bool, + ) link.Error!void { + return debug.advanceLineAndPcInner(delta_line, delta_pc, end) catch |err| switch (err) { error.WriteFailed => return debug.wip_nav.reportWriteError(&debug.line_writer), }; } - fn advancePcAndLineInner(debug: *Debug, delta_line: i33, delta_pc: u64) Writer.Error!void { + fn advanceLineAndPcInner( + debug: *Debug, + delta_line: i33, + delta_pc: u64, + end: bool, + ) Writer.Error!void { const dlw = &debug.line_writer.interface; const header = debug.wip_nav.dwarf.debug_line.header; @@ -797,20 +824,30 @@ pub const WipNav = struct { const op_advance = @divExact(delta_pc, header.minimum_instruction_length) * header.maximum_operations_per_instruction + delta_op; const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range; - const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: { - try dlw.writeByte(DW.LNS.advance_pc); - try dlw.writeUleb128(op_advance); + const remaining_op_advance: u8 = @intCast(if (end or + op_advance >= 2 * max_op_advance) + remaining: { + if (op_advance == max_op_advance) { + try dlw.writeByte(DW.LNS.const_add_pc); + } else if (op_advance != 0) { + try dlw.writeByte(DW.LNS.advance_pc); + try dlw.writeUleb128(op_advance); + } else assert(end); break :remaining 0; } else if (op_advance >= max_op_advance) remaining: { try dlw.writeByte(DW.LNS.const_add_pc); break :remaining op_advance - max_op_advance; } else op_advance); - if (remaining_delta_line == 0 and remaining_op_advance == 0) - try dlw.writeByte(DW.LNS.copy) - else + if (remaining_delta_line != 0 or remaining_op_advance != 0) { + assert(!end); try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) + (header.line_range * remaining_op_advance) + header.opcode_base)); + } else if (end) { + try dlw.writeByte(DW.LNS.extended_op); + try dlw.writeUleb128(1); + try dlw.writeByte(DW.LNE.end_sequence); + } else try dlw.writeByte(DW.LNS.copy); } pub fn setColumn(debug: *Debug, column: u32) link.Error!void { @@ -1398,7 +1435,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf { pub fn deinit(dwarf: *Dwarf) void { const gpa = dwarf.lf.comp.gpa; dwarf.const_pool.deinit(gpa); - for (dwarf.units.values()) |*unit| unit.files.deinit(gpa); + for (dwarf.units.values()) |*unit| unit.deinit(gpa); dwarf.units.deinit(gpa); dwarf.values.deinit(gpa); dwarf.globals.deinit(gpa); @@ -1414,18 +1451,24 @@ pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) std.mem.Allocator.Error!void { const unit_gop = dwarf.units.getOrPutAssumeCapacity(mod); assert(!unit_gop.found_existing); unit_gop.value_ptr.* = .{ + .dirs = .empty, .files = .empty, - .files_changed = true, .frame_ni = .none, .cie_ni = .none, .debug_info_ni = .none, .debug_info_header_ni = .none, .debug_line_ni = .none, .debug_line_header_ni = .none, + .debug_line_header_changed = true, .debug_rnglists_ni = .none, .debug_rnglists_offset = undefined, }; - assert(try unit_gop.value_ptr.getFile(zcu.gpa, root_zfi) == .root); + const root_di, const root_fi = try unit_gop.value_ptr.getFile( + zcu.gpa, + @fromBackingInt(@intCast(unit_gop.index)), + root_zfi, + ); + assert(root_di == .root and root_fi == .root); }; } diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 01c1265672b33514a89eb4030963d82636b51cdf..706099a25a94adaf03ff4b6ea2e414c02443b4f1 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -7205,7 +7205,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { fn flushFiles(elf: *Elf) Error!void { const gpa = elf.base.comp.gpa; if (elf.shndx.debug_line != .UNDEF) for (elf.dwarf.units.keys(), elf.dwarf.units.values()) |mod, *unit| { - if (!unit.cleanFilesChanged()) continue; + if (!unit.cleanDebugLineHeaderChanged()) continue; const debug_line_header_ni = unit.debug_line_header_ni.unwrap().?; try debug_line_header_ni.moved(gpa, &elf.mf); try debug_line_header_ni.nextMoved(gpa, &elf.mf); -- 2.54.0