Elf2: implement dwarf unwind info

Other debug info is still in progress.

Closes #25421
This commit is contained in:
Jacob Young committed 2026-09-03 11:00:53 -04:00
1 parent e78ea8f2cb
commit 79bb28aa57
21 files changed
+4338 -762

No files matched your search

+1
View File
@@ -383,6 +383,7 @@ set(ZIG_STAGE2_SOURCES
src/link/ConstPool.zig
src/link/Coff.zig
src/link/Dwarf.zig
src/link/Dwarf2.zig
src/link/Elf.zig
src/link/Elf/Archive.zig
src/link/Elf/Atom.zig
+16 -7
View File
@@ -362,8 +362,7 @@ pub const CommonInformationEntry = struct {
if (aug_str.len == 0) break :aug .none;
if (aug_str[0] == 'z') break :aug .lsb_z;
if (std.mem.eql(u8, aug_str, "eh")) break :aug .gcc_eh;
// We can't finish parsing the CIE if we don't know what its augmentation means.
return bad();
return error.UnsupportedAugmentation;
};
switch (aug_kind) {
@@ -396,7 +395,7 @@ pub const CommonInformationEntry = struct {
'R' => fde_pointer_enc = @bitCast(try aug_data.takeByte()),
'S' => is_signal_frame = true,
'B', 'G' => {},
else => return bad(),
else => return error.UnsupportedAugmentation,
};
break :aug .{ fde_pointer_enc, is_signal_frame };
};
@@ -502,7 +501,15 @@ pub fn prepare(
const idx = unwind.cie_list.len;
try unwind.cie_list.append(gpa, .{
.offset = entry_offset,
.cie = try .parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes),
.cie = CommonInformationEntry.parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes) catch |err| switch (err) {
error.UnsupportedDwarfVersion,
error.UnsupportedAugmentation,
=> {
// These are recoverable by just skipping the CIE.
continue;
},
else => |e| return e,
},
});
errdefer _ = unwind.cie_list.pop().?;
try VirtualMachine.populateCieLastRow(gpa, &unwind.cie_list.items(.cie)[idx], addr_size_bytes, endian);
@@ -514,8 +521,10 @@ pub fn prepare(
try r.discardAll(bytes_len);
continue;
}
const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo;
const fde: FrameDescriptionEntry = try .parse(section.vaddr + r.seek, try r.take(bytes_len), cie, endian);
const fde_vaddr = section.vaddr + r.seek;
const fde_bytes = try r.take(bytes_len);
const cie = unwind.findCie(fde_info.cie_offset) orelse continue;
const fde: FrameDescriptionEntry = try .parse(fde_vaddr, fde_bytes, cie, endian);
try fde_list.append(gpa, .{
.pc_begin = fde.pc_begin,
.fde_offset = entry_offset,
@@ -612,7 +621,7 @@ pub fn getFde(unwind: *const Unwind, fde_offset: u64, endian: Endian) !struct {
.cie, .terminator => return bad(), // This is meant to be an FDE
};
const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo;
const cie = unwind.findCie(fde_info.cie_offset) orelse return bad();
const fde: FrameDescriptionEntry = try .parse(
section.vaddr + fde_offset + fde_reader.seek,
try fde_reader.take(cast(usize, fde_info.bytes_len) orelse return error.EndOfStream),
-1
View File
@@ -340,7 +340,6 @@ const Module = struct {
error.InvalidOperation,
=> return error.InvalidDebugInfo,
error.UnsupportedAddrSize,
error.UnsupportedDwarfVersion,
error.UnimplementedUserOpcode,
=> return error.UnsupportedDebugInfo,
};
-1
View File
@@ -578,7 +578,6 @@ const Module = struct {
error.InvalidOperation,
=> return error.InvalidDebugInfo,
error.UnsupportedAddrSize,
error.UnsupportedDwarfVersion,
error.UnimplementedUserOpcode,
=> return error.UnsupportedDebugInfo,
};
+4 -3
View File
@@ -26,6 +26,7 @@ pub const aarch64 = @import("codegen/aarch64.zig");
pub const loongarch = @import("codegen/loongarch.zig");
pub const Error = link.Error;
pub const EmitError = Error || std.Io.Writer.Error || error{MappedFileIo};
fn devFeatureForBackend(backend: std.lang.CompilerBackend) dev.Feature {
return switch (backend) {
@@ -196,7 +197,7 @@ pub fn emitFunction(
any_mir: *const AnyMir,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) (Error || std.Io.Writer.Error)!void {
) EmitError!void {
const zcu = pt.zcu;
const func = zcu.funcInfo(func_index);
const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
@@ -228,7 +229,7 @@ pub fn generateLazyFunction(
atom_id: link.File.AtomId,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) (Error || std.Io.Writer.Error)!void {
) EmitError!void {
const zcu = pt.zcu;
const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|
&zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result
@@ -252,7 +253,7 @@ pub fn generateLazySymbol(
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
reloc_parent: link.File.RelocInfo.Parent,
) (Error || std.Io.Writer.Error)!void {
) EmitError!void {
const tracy = trace(@src());
defer tracy.end();
tracy.addTextFmt("{t}, {f}", .{ lazy_sym.kind, Type.fromInterned(lazy_sym.ty).fmt(pt) });
+1 -1
View File
@@ -856,7 +856,7 @@ pub fn generateLazy(
atom_index: link.File.AtomId,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) (codegen.Error || std.Io.Writer.Error)!void {
) codegen.EmitError!void {
_ = atom_index;
const comp = bin_file.comp;
const gpa = comp.gpa;
+9 -8
View File
@@ -13,7 +13,7 @@ prev_di_pc: usize,
code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
relocs: std.ArrayList(Reloc) = .empty,
pub const Error = Lower.Error || std.Io.Writer.Error || error{
pub const Error = Lower.Error || codegen.EmitError || error{
EmitFail,
};
@@ -118,14 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void {
else => unreachable,
.pseudo_dbg_prologue_end => {
switch (emit.debug_output) {
.dwarf => |dw| {
inline .dwarf, .dwarf2 => |dw| {
try dw.setPrologueEnd();
log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
emit.prev_di_line, emit.prev_di_column,
});
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
},
.none => {},
.eh_frame, .none => {},
}
},
.pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(
@@ -134,14 +134,14 @@ pub fn emitMir(emit: *Emit) Error!void {
),
.pseudo_dbg_epilogue_begin => {
switch (emit.debug_output) {
.dwarf => |dw| {
inline .dwarf, .dwarf2 => |dw| {
try dw.setEpilogueBegin();
log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
emit.prev_di_line, emit.prev_di_column,
});
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
},
.none => {},
.eh_frame, .none => {},
}
},
.pseudo_dead => {},
@@ -190,15 +190,15 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
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) {
.dwarf => |dw| {
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.advancePcAndLine(delta_line, delta_pc);
emit.prev_di_line = line;
emit.prev_di_column = column;
emit.prev_di_pc = emit.w.end;
},
.none => {},
.eh_frame, .none => {},
}
}
@@ -209,6 +209,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
};
}
const codegen = @import("../../codegen.zig");
const link = @import("../../link.zig");
const log = std.log.scoped(.emit);
const mem = std.mem;
+1 -1
View File
@@ -111,7 +111,7 @@ pub fn emit(
atom_index: link.File.AtomId,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) (codegen.Error || std.Io.Writer.Error)!void {
) codegen.EmitError!void {
_ = atom_index;
const zcu = pt.zcu;
const comp = zcu.comp;
+9 -9
View File
@@ -4,6 +4,7 @@
const std = @import("std");
const Endian = std.lang.Endian;
const assert = std.debug.assert;
const codegen = @import("../../codegen.zig");
const link = @import("../../link.zig");
const Zcu = @import("../../Zcu.zig");
const ErrorMsg = Zcu.ErrorMsg;
@@ -40,8 +41,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayList(M
/// instruction
code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
const InnerError = std.Io.Writer.Error || error{
OutOfMemory,
const InnerError = codegen.EmitError || error{
EmitFail,
};
@@ -175,21 +175,21 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
fn mirDebugPrologueEnd(emit: *Emit) !void {
switch (emit.debug_output) {
.dwarf => |dbg_out| {
inline .dwarf, .dwarf2 => |dbg_out| {
try dbg_out.setPrologueEnd();
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
},
.none => {},
.eh_frame, .none => {},
}
}
fn mirDebugEpilogueBegin(emit: *Emit) !void {
switch (emit.debug_output) {
.dwarf => |dbg_out| {
inline .dwarf, .dwarf2 => |dbg_out| {
try dbg_out.setEpilogueBegin();
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
},
.none => {},
.eh_frame, .none => {},
}
}
@@ -496,13 +496,13 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
const delta_pc: usize = emit.w.end - emit.prev_di_pc;
switch (emit.debug_output) {
.dwarf => |dbg_out| {
try dbg_out.advancePCAndLine(delta_line, delta_pc);
inline .dwarf, .dwarf2 => |dbg_out| {
try dbg_out.advancePcAndLine(delta_line, delta_pc);
emit.prev_di_line = line;
emit.prev_di_column = column;
emit.prev_di_pc = emit.w.end;
},
else => {},
.eh_frame, .none => {},
}
}
+1 -1
View File
@@ -382,7 +382,7 @@ pub fn emit(
atom_index: link.File.AtomId,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) (codegen.Error || std.Io.Writer.Error)!void {
) codegen.EmitError!void {
_ = atom_index;
const zcu = pt.zcu;
const func = zcu.funcInfo(func_index);
+1 -1
View File
@@ -1120,7 +1120,7 @@ pub fn generateLazy(
atom_id: link.File.AtomId,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) codegen.Error!void {
) codegen.EmitError!void {
const gpa = pt.zcu.gpa;
// This function is for generating global code, so we use the root module.
const mod = pt.zcu.comp.root_mod;
+194 -193
View File
@@ -16,10 +16,8 @@ code_offset_mapping: std.ArrayList(u32),
relocs: std.ArrayList(Reloc),
table_relocs: std.ArrayList(TableReloc),
pub const Error = Lower.Error || error{
AlreadyReported,
pub const Error = Lower.Error || codegen.EmitError || error{
EmitFail,
NotFile,
} || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError;
pub fn emitMir(emit: *Emit) Error!void {
@@ -38,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) {
.dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {
inline .dwarf, .eh_frame, .dwarf2 => |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,
@@ -460,204 +458,207 @@ pub fn emitMir(emit: *Emit) Error!void {
if (lowered.insts.len == 0) {
const mir_inst = emit.lower.mir.instructions.get(mir_index);
switch (mir_inst.tag) {
assert(mir_inst.tag == .pseudo);
switch (mir_inst.ops) {
else => unreachable,
.pseudo => switch (mir_inst.ops) {
else => unreachable,
.pseudo_dbg_prologue_end_none => switch (emit.debug_output) {
.dwarf => |dwarf| try dwarf.setPrologueEnd(),
.none => {},
.pseudo_dbg_prologue_end_none => switch (emit.debug_output) {
inline .dwarf, .dwarf2 => |dwarf| try dwarf.setPrologueEnd(),
.eh_frame, .none => {},
},
.pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePcAndLine(.{
.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(.{
.line = mir_inst.data.line_column.line,
.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);
},
.pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePCAndLine(.{
.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(.{
.line = mir_inst.data.line_column.line,
.column = mir_inst.data.line_column.column,
.is_stmt = false,
}),
.pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) {
.dwarf => |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);
},
.none => {},
.eh_frame, .none => {},
},
.pseudo_dbg_enter_block_none => switch (emit.debug_output) {
inline .dwarf, .dwarf2 => |dwarf| {
log.debug("mirDbgEnterBlock (line={d}, col={d})", .{
emit.prev_di_loc.line, emit.prev_di_loc.column,
});
try dwarf.enterBlock(emit.w.end);
},
.pseudo_dbg_enter_block_none => switch (emit.debug_output) {
.dwarf => |dwarf| {
log.debug("mirDbgEnterBlock (line={d}, col={d})", .{
emit.prev_di_loc.line, emit.prev_di_loc.column,
});
try dwarf.enterBlock(emit.w.end);
},
.none => {},
.eh_frame, .none => {},
},
.pseudo_dbg_leave_block_none => switch (emit.debug_output) {
inline .dwarf, .dwarf2 => |dwarf| {
log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{
emit.prev_di_loc.line, emit.prev_di_loc.column,
});
try dwarf.leaveBlock(emit.w.end);
},
.pseudo_dbg_leave_block_none => switch (emit.debug_output) {
.dwarf => |dwarf| {
log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{
emit.prev_di_loc.line, emit.prev_di_loc.column,
});
try dwarf.leaveBlock(emit.w.end);
},
.none => {},
.eh_frame, .none => {},
},
.pseudo_dbg_enter_inline_func => switch (emit.debug_output) {
inline .dwarf, .dwarf2 => |dwarf| {
log.debug("mirDbgEnterInline (line={d}, col={d})", .{
emit.prev_di_loc.line, emit.prev_di_loc.column,
});
try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);
},
.pseudo_dbg_enter_inline_func => switch (emit.debug_output) {
.dwarf => |dwarf| {
log.debug("mirDbgEnterInline (line={d}, col={d})", .{
emit.prev_di_loc.line, emit.prev_di_loc.column,
});
try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);
},
.none => {},
.eh_frame, .none => {},
},
.pseudo_dbg_leave_inline_func => switch (emit.debug_output) {
inline .dwarf, .dwarf2 => |dwarf| {
log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
emit.prev_di_loc.line, emit.prev_di_loc.column,
});
try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);
},
.pseudo_dbg_leave_inline_func => switch (emit.debug_output) {
.dwarf => |dwarf| {
log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
emit.prev_di_loc.line, emit.prev_di_loc.column,
});
try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);
},
.none => {},
},
.pseudo_dbg_arg_none,
.pseudo_dbg_arg_i_s,
.pseudo_dbg_arg_i_u,
.pseudo_dbg_arg_i_64,
.pseudo_dbg_arg_ro,
.pseudo_dbg_arg_fa,
.pseudo_dbg_arg_m,
.pseudo_dbg_var_none,
.pseudo_dbg_var_i_s,
.pseudo_dbg_var_i_u,
.pseudo_dbg_var_i_64,
.pseudo_dbg_var_ro,
.pseudo_dbg_var_fa,
.pseudo_dbg_var_m,
=> switch (emit.debug_output) {
.dwarf => |dwarf| {
var loc_buf: [2]link.File.Dwarf.Loc = undefined;
const loc: link.File.Dwarf.Loc = loc: switch (mir_inst.ops) {
.eh_frame, .none => {},
},
.pseudo_dbg_arg_none,
.pseudo_dbg_arg_i_s,
.pseudo_dbg_arg_i_u,
.pseudo_dbg_arg_i_64,
.pseudo_dbg_arg_ro,
.pseudo_dbg_arg_fa,
.pseudo_dbg_arg_m,
.pseudo_dbg_var_none,
.pseudo_dbg_var_i_s,
.pseudo_dbg_var_i_u,
.pseudo_dbg_var_i_64,
.pseudo_dbg_var_ro,
.pseudo_dbg_var_fa,
.pseudo_dbg_var_m,
=> switch (emit.debug_output) {
inline .dwarf, .dwarf2 => |dwarf, tag| {
const DwarfLoc = switch (tag) {
.dwarf => link.File.Dwarf.Loc,
.dwarf2 => link.File.Dwarf2.Loc,
.eh_frame, .none => comptime unreachable,
};
var loc_buf: [2]DwarfLoc = undefined;
const loc: DwarfLoc = loc: switch (mir_inst.ops) {
else => unreachable,
.pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty,
.pseudo_dbg_arg_i_s,
.pseudo_dbg_arg_i_u,
.pseudo_dbg_var_i_s,
.pseudo_dbg_var_i_u,
=> .{ .stack_value = stack_value: {
loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) {
.signed => |s| .{ .consts = s },
.unsigned => |u| .{ .constu = u },
};
break :stack_value &loc_buf[0];
} },
.pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: {
loc_buf[0] = .{ .constu = mir_inst.data.i64 };
break :stack_value &loc_buf[0];
} },
.pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => {
const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa);
break :loc .{ .plus = .{
reg: {
loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() };
break :reg &loc_buf[0];
},
off: {
loc_buf[1] = .{ .consts = reg_off.off };
break :off &loc_buf[1];
},
} };
},
.pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode();
break :loc .{ .plus = .{
base: {
loc_buf[0] = switch (mem.base()) {
.none => .{ .constu = 0 },
.reg => |reg| .{ .breg = reg.dwarfNum() },
.frame, .table, .rip_inst => unreachable,
.nav => |nav| .{ .addr_reloc = try codegen.genNavRef(
emit.bin_file,
emit.pt,
nav,
) },
.uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav(
emit.pt,
uav.val,
Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),
) },
.lazy_sym, .extern_func => unreachable,
};
break :base &loc_buf[0];
},
disp: {
loc_buf[1] = switch (mem.disp()) {
.signed => |s| .{ .consts = s },
.unsigned => |u| .{ .constu = u },
};
break :disp &loc_buf[1];
},
} };
},
};
const local = &emit.lower.mir.locals[local_index];
local_index += 1;
try dwarf.genLocalVarDebugInfo(
switch (mir_inst.ops) {
else => unreachable,
.pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty,
.pseudo_dbg_arg_none,
.pseudo_dbg_arg_i_s,
.pseudo_dbg_arg_i_u,
.pseudo_dbg_arg_i_64,
.pseudo_dbg_arg_ro,
.pseudo_dbg_arg_fa,
.pseudo_dbg_arg_m,
.pseudo_dbg_arg_val,
=> .arg,
.pseudo_dbg_var_none,
.pseudo_dbg_var_i_s,
.pseudo_dbg_var_i_u,
=> .{ .stack_value = stack_value: {
loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) {
.signed => |s| .{ .consts = s },
.unsigned => |u| .{ .constu = u },
};
break :stack_value &loc_buf[0];
} },
.pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: {
loc_buf[0] = .{ .constu = mir_inst.data.i64 };
break :stack_value &loc_buf[0];
} },
.pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => {
const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa);
break :loc .{ .plus = .{
reg: {
loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() };
break :reg &loc_buf[0];
},
off: {
loc_buf[1] = .{ .consts = reg_off.off };
break :off &loc_buf[1];
},
} };
},
.pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode();
break :loc .{ .plus = .{
base: {
loc_buf[0] = switch (mem.base()) {
.none => .{ .constu = 0 },
.reg => |reg| .{ .breg = reg.dwarfNum() },
.frame, .table, .rip_inst => unreachable,
.nav => |nav| .{ .addr_reloc = try codegen.genNavRef(
emit.bin_file,
emit.pt,
nav,
) },
.uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav(
emit.pt,
uav.val,
Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),
) },
.lazy_sym, .extern_func => unreachable,
};
break :base &loc_buf[0];
},
disp: {
loc_buf[1] = switch (mem.disp()) {
.signed => |s| .{ .consts = s },
.unsigned => |u| .{ .constu = u },
};
break :disp &loc_buf[1];
},
} };
},
};
const local = &emit.lower.mir.locals[local_index];
local_index += 1;
try dwarf.genLocalVarDebugInfo(
switch (mir_inst.ops) {
else => unreachable,
.pseudo_dbg_arg_none,
.pseudo_dbg_arg_i_s,
.pseudo_dbg_arg_i_u,
.pseudo_dbg_arg_i_64,
.pseudo_dbg_arg_ro,
.pseudo_dbg_arg_fa,
.pseudo_dbg_arg_m,
.pseudo_dbg_arg_val,
=> .arg,
.pseudo_dbg_var_none,
.pseudo_dbg_var_i_s,
.pseudo_dbg_var_i_u,
.pseudo_dbg_var_i_64,
.pseudo_dbg_var_ro,
.pseudo_dbg_var_fa,
.pseudo_dbg_var_m,
.pseudo_dbg_var_val,
=> .local_var,
},
local.name.toSlice(&emit.lower.mir),
.fromInterned(local.type),
loc,
);
},
.none => local_index += 1,
.pseudo_dbg_var_i_64,
.pseudo_dbg_var_ro,
.pseudo_dbg_var_fa,
.pseudo_dbg_var_m,
.pseudo_dbg_var_val,
=> .local_var,
},
local.name.toSlice(&emit.lower.mir),
.fromInterned(local.type),
loc,
);
},
.pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) {
.dwarf => |dwarf| {
const local = &emit.lower.mir.locals[local_index];
local_index += 1;
try dwarf.genLocalConstDebugInfo(
switch (mir_inst.ops) {
else => unreachable,
.pseudo_dbg_arg_val => .comptime_arg,
.pseudo_dbg_var_val => .local_const,
},
local.name.toSlice(&emit.lower.mir),
.fromInterned(mir_inst.data.ip_index),
);
},
.none => local_index += 1,
},
.pseudo_dbg_var_args_none => switch (emit.debug_output) {
.dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(),
.none => {},
},
.pseudo_dead_none => {},
.eh_frame, .none => local_index += 1,
},
.pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) {
inline .dwarf, .dwarf2 => |dwarf| {
const local = &emit.lower.mir.locals[local_index];
local_index += 1;
try dwarf.genLocalConstDebugInfo(
switch (mir_inst.ops) {
else => unreachable,
.pseudo_dbg_arg_val => .comptime_arg,
.pseudo_dbg_var_val => .local_const,
},
local.name.toSlice(&emit.lower.mir),
.fromInterned(mir_inst.data.ip_index),
);
},
.eh_frame, .none => local_index += 1,
},
.pseudo_dbg_var_args_none => switch (emit.debug_output) {
inline .dwarf, .dwarf2 => |dwarf| try dwarf.genVarArgsDebugInfo(),
.eh_frame, .none => {},
},
.pseudo_dead_none => {},
}
}
}
@@ -974,19 +975,19 @@ const Loc = struct {
is_stmt: bool,
};
fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void {
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) {
.dwarf => |dwarf| {
inline .dwarf, .dwarf2 => |dwarf| {
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);
try dwarf.advancePcAndLine(delta_line, delta_pc);
emit.prev_di_loc = loc;
emit.prev_di_pc = emit.w.end;
},
.none => {},
.eh_frame, .none => {},
}
}
+14 -11
View File
@@ -1978,7 +1978,7 @@ pub fn emit(
atom_id: link.File.AtomId,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) codegen.Error!void {
) codegen.EmitError!void {
const zcu = pt.zcu;
const comp = zcu.comp;
const gpa = comp.gpa;
@@ -1986,7 +1986,7 @@ pub fn emit(
const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
const nav = func.owner_nav;
const mod = zcu.navFileScope(nav).mod.?;
var e: Emit = .{
var em: Emit = .{
.lower = .{
.target = &mod.resolved_target.result,
.allocator = gpa,
@@ -2006,7 +2006,8 @@ pub fn emit(
.column = func.lbrace_column,
.is_stmt = switch (debug_output) {
.dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt,
.none => undefined,
.dwarf2 => |dwarf| dwarf.wip_nav.dwarf.debug_line.header.default_is_stmt,
.eh_frame, .none => undefined,
},
},
.prev_di_pc = 0,
@@ -2015,11 +2016,12 @@ pub fn emit(
.relocs = .empty,
.table_relocs = .empty,
};
defer e.deinit();
e.emitMir() catch |err| switch (err) {
error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?),
defer em.deinit();
em.emitMir() catch |err| switch (err) {
error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, em.lower.err_msg.?),
error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}),
error.AlreadyReported, error.Canceled, error.MappedFileIo, error.WriteFailed => |e| return e,
};
}
@@ -2031,12 +2033,12 @@ pub fn emitLazy(
atom_id: link.File.AtomId,
w: *std.Io.Writer,
debug_output: link.File.DebugInfoOutput,
) codegen.Error!void {
) codegen.EmitError!void {
const zcu = pt.zcu;
const comp = zcu.comp;
const gpa = comp.gpa;
const mod = comp.root_mod;
var e: Emit = .{
var em: Emit = .{
.lower = .{
.target = &mod.resolved_target.result,
.allocator = gpa,
@@ -2058,11 +2060,12 @@ pub fn emitLazy(
.relocs = .empty,
.table_relocs = .empty,
};
defer e.deinit();
e.emitMir() catch |err| switch (err) {
error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, e.lower.err_msg.?),
defer em.deinit();
em.emitMir() catch |err| switch (err) {
error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, em.lower.err_msg.?),
error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}),
error.AlreadyReported, error.Canceled, error.MappedFileIo, error.WriteFailed => |e| return e,
};
}
+3
View File
@@ -757,6 +757,8 @@ pub const File = struct {
pub const DebugInfoOutput = union(enum) {
dwarf: *Dwarf.WipNav,
eh_frame: *Dwarf2.WipNav,
dwarf2: *Dwarf2.WipNav.Debug,
none,
};
pub const UpdateDebugInfoError = Dwarf.UpdateError;
@@ -1391,6 +1393,7 @@ pub const File = struct {
pub const SpirV = @import("link/SpirV.zig");
pub const Wasm = @import("link/Wasm.zig");
pub const Dwarf = @import("link/Dwarf.zig");
pub const Dwarf2 = @import("link/Dwarf2.zig");
};
pub const PrelinkTask = union(enum) {
+14 -15
View File
@@ -1626,12 +1626,12 @@ 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 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) {
error.WriteFailed => error.OutOfMemory,
};
}
fn advancePCAndLineWriterError(
fn advancePcAndLineWriterError(
wip_nav: *WipNav,
delta_line: i33,
delta_pc: u64,
@@ -1990,7 +1990,7 @@ pub const WipNav = struct {
try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
}
} = .{ .wip_nav = wip_nav };
try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);
try adapter.writer().writeUleb128(counter.dw.fullCount());
try loc.write(adapter);
}
@@ -2032,7 +2032,7 @@ pub const WipNav = struct {
try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);
}
} = .{ .wip_nav = wip_nav };
try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);
try adapter.writer().writeUleb128(counter.dw.fullCount());
try loc.write(adapter);
}
@@ -2105,20 +2105,20 @@ pub const WipNav = struct {
const size = ty.abiSize(wip_nav.pt.zcu);
try diw.writeUleb128(size);
if (size == 0) return;
const old_end = wip_nav.debug_info.writer.end;
const old_end = diw.end;
try codegen.generateSymbol(
wip_nav.dwarf.bin_file,
wip_nav.pt,
val,
&wip_nav.debug_info.writer,
diw,
.{ .debug_output = .{ .dwarf = wip_nav } },
);
if (old_end + size != wip_nav.debug_info.writer.end) {
if (old_end + size != diw.end) {
std.debug.print("{f} [{}]: {} != {}\n", .{
ty.fmt(wip_nav.pt),
ty.toIntern(),
size,
wip_nav.debug_info.writer.end - old_end,
diw.end - old_end,
});
unreachable;
}
@@ -2278,10 +2278,9 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
pub fn init(lf: *link.File, format: DW.Format) Dwarf {
const comp = lf.comp;
const gpa = comp.gpa;
const target = &comp.root_mod.resolved_target.result;
return .{
.gpa = gpa,
.gpa = comp.gpa,
.bin_file = lf,
.format = format,
.address_size = switch (target.ptrBitWidth()) {
@@ -2774,7 +2773,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.advancePcAndLine(func.lbrace_line, 0);
} else {
try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));
try dlw.writeByte(DW.LNE.set_address);
@@ -2791,7 +2790,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.advancePcAndLine(@intCast(decl.src_line + func.lbrace_line), 0);
}
},
else => {
@@ -6362,14 +6361,14 @@ 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.count + dw.writer.end);
return @intCast(dw.fullCount());
}
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.count + dw.writer.end);
return @intCast(dw.fullCount());
}
/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
+2685
View File
File diff suppressed because it is too large. Load diff
+11 -16
View File
@@ -946,14 +946,11 @@ pub fn getNavVAddr(
.r_addend = reloc_info.addend,
}, self);
},
.debug_output => |debug_output| switch (debug_output) {
.dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
.source_off = @intCast(reloc_info.offset),
.target_sym = @fromBackingInt(@intCast(this_sym_index)),
.target_off = reloc_info.addend,
}),
.none => unreachable,
},
.debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
.source_off = @intCast(reloc_info.offset),
.target_sym = @fromBackingInt(@intCast(this_sym_index)),
.target_off = reloc_info.addend,
}),
}
return @intCast(vaddr);
}
@@ -978,14 +975,11 @@ pub fn getUavVAddr(
.r_addend = reloc_info.addend,
}, self);
},
.debug_output => |debug_output| switch (debug_output) {
.dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
.source_off = @intCast(reloc_info.offset),
.target_sym = @fromBackingInt(@intCast(sym_index)),
.target_off = reloc_info.addend,
}),
.none => unreachable,
},
.debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
.source_off = @intCast(reloc_info.offset),
.target_sym = @fromBackingInt(@intCast(sym_index)),
.target_off = reloc_info.addend,
}),
}
return @intCast(vaddr);
}
@@ -1555,6 +1549,7 @@ pub fn updateFunc(
if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,
) catch |err| switch (err) {
error.WriteFailed => return error.OutOfMemory,
error.MappedFileIo => unreachable, // MappedFile is not being used
else => |e| return e,
};
const code = aw.written();
+1334 -478
View File
File diff suppressed because it is too large. Load diff
+11 -16
View File
@@ -647,14 +647,11 @@ pub fn getNavVAddr(
},
});
},
.debug_output => |debug_output| switch (debug_output) {
.dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
.source_off = @intCast(reloc_info.offset),
.target_sym = @fromBackingInt(@intCast(sym_index)),
.target_off = reloc_info.addend,
}),
.none => unreachable,
},
.debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
.source_off = @intCast(reloc_info.offset),
.target_sym = @fromBackingInt(@intCast(sym_index)),
.target_off = reloc_info.addend,
}),
}
return vaddr;
}
@@ -686,14 +683,11 @@ pub fn getUavVAddr(
},
});
},
.debug_output => |debug_output| switch (debug_output) {
.dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
.source_off = @intCast(reloc_info.offset),
.target_sym = @fromBackingInt(@intCast(sym_index)),
.target_off = reloc_info.addend,
}),
.none => unreachable,
},
.debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
.source_off = @intCast(reloc_info.offset),
.target_sym = @fromBackingInt(@intCast(sym_index)),
.target_off = reloc_info.addend,
}),
}
return vaddr;
}
@@ -796,6 +790,7 @@ pub fn updateFunc(
if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
) catch |err| switch (err) {
error.WriteFailed => return error.OutOfMemory,
error.MappedFileIo => unreachable, // MappedFile is not being used
else => |e| return e,
};
const code = aw.written();
+22
View File
@@ -636,11 +636,33 @@ pub const Node = extern struct {
return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
}
pub fn slicePadding(ni: Node.Index, mf: *const MappedFile) []u8 {
const file_loc = ni.fileLocation(mf, false);
return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
}
pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 {
const file_loc = ni.fileLocation(mf, false);
return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
}
pub fn trimStart(ni: Node.Index, mf: *MappedFile, gpa: Allocator) Allocator.Error!void {
mf.nodes_lock.assertUnlocked();
const node = ni.get(mf);
const first_ni = node.first.unwrap() orelse return;
const shift, _ = first_ni.location(mf).resolve(mf);
if (shift == 0) return;
const offset, const size = node.location().resolve(mf);
try ni.setLocation(mf, gpa, offset + shift, size - shift);
var child_oni = node.first;
while (child_oni.unwrap()) |child_ni| {
const child_node = child_ni.get(mf);
const child_offset, const child_size = child_node.location().resolve(mf);
try child_ni.setLocation(mf, gpa, child_offset - shift, child_size);
child_oni = child_node.next;
}
}
/// Ensures that the size of `ni` is at least `min_size`. Valid for any node.
///
/// Applies `growth_factor` if necessary (so the caller should *not* apply `growth_factor`).
+7
View File
@@ -17,6 +17,7 @@ const usage =
\\Debug Options:
\\ --preserve-tmp
\\ --debug-log foo
\\ --debug-link-snapshot
;
pub const std_options: std.Options = .{
@@ -60,6 +61,7 @@ pub fn main(init: std.process.Init) !void {
var quiet: bool = false;
var debug_log_args: std.ArrayList([]const u8) = .empty;
var debug_link_snapshot = false;
var arg_it = try init.minimal.args.iterateAllocator(arena);
_ = arg_it.skip();
@@ -77,6 +79,8 @@ pub fn main(init: std.process.Init) !void {
arena,
arg_it.next() orelse badUsage("expected arg after --debug-log", .{}),
);
} else if (std.mem.eql(u8, arg, "--debug-link-snapshot")) {
debug_link_snapshot = true;
} else if (std.mem.eql(u8, arg, "--preserve-tmp")) {
preserve_tmp = true;
} else if (std.mem.eql(u8, arg, "-fqemu")) {
@@ -173,6 +177,9 @@ pub fn main(init: std.process.Init) !void {
for (debug_log_args.items) |arg| {
try child_args.appendSlice(arena, &.{ "--debug-log", arg });
}
if (debug_link_snapshot) {
try child_args.append(arena, "--debug-link-snapshot");
}
for (case.modules) |mod| {
try child_args.appendSlice(arena, &.{ "--dep", mod.name });
}