link: decouple DI atoms from linker atoms, and manage them in Dwarf linker

This commit is contained in:
Jakub Konka 2023-02-01 15:03:55 +01:00
parent d98fc53b8f
commit 5de2aae63c
19 changed files with 655 additions and 657 deletions

View file

@ -3299,7 +3299,7 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
const gpa = comp.gpa; const gpa = comp.gpa;
const module = comp.bin_file.options.module.?; const module = comp.bin_file.options.module.?;
const decl = module.declPtr(decl_index); const decl = module.declPtr(decl_index);
comp.bin_file.updateDeclLineNumber(module, decl) catch |err| { comp.bin_file.updateDeclLineNumber(module, decl_index) catch |err| {
try module.failed_decls.ensureUnusedCapacity(gpa, 1); try module.failed_decls.ensureUnusedCapacity(gpa, 1);
module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
gpa, gpa,

View file

@ -5186,12 +5186,12 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
.coff => { .coff => {
// TODO Implement for COFF // TODO Implement for COFF
}, },
.elf => if (decl.fn_link.elf.len != 0) { .elf => {
// TODO Look into detecting when this would be unnecessary by storing enough state // TODO Look into detecting when this would be unnecessary by storing enough state
// in `Decl` to notice that the line number did not change. // in `Decl` to notice that the line number did not change.
comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
}, },
.macho => if (decl.fn_link.macho.len != 0) { .macho => {
// TODO Look into detecting when this would be unnecessary by storing enough state // TODO Look into detecting when this would be unnecessary by storing enough state
// in `Decl` to notice that the line number did not change. // in `Decl` to notice that the line number did not change.
comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
@ -5285,8 +5285,8 @@ pub fn clearDecl(
}; };
decl.fn_link = switch (mod.comp.bin_file.tag) { decl.fn_link = switch (mod.comp.bin_file.tag) {
.coff => .{ .coff = {} }, .coff => .{ .coff = {} },
.elf => .{ .elf = link.File.Dwarf.SrcFn.empty }, .elf => .{ .elf = {} },
.macho => .{ .macho = link.File.Dwarf.SrcFn.empty }, .macho => .{ .macho = {} },
.plan9 => .{ .plan9 = {} }, .plan9 => .{ .plan9 = {} },
.c => .{ .c = {} }, .c => .{ .c = {} },
.wasm => .{ .wasm = link.File.Wasm.FnData.empty }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
@ -5705,8 +5705,8 @@ pub fn allocateNewDecl(
}, },
.fn_link = switch (mod.comp.bin_file.tag) { .fn_link = switch (mod.comp.bin_file.tag) {
.coff => .{ .coff = {} }, .coff => .{ .coff = {} },
.elf => .{ .elf = link.File.Dwarf.SrcFn.empty }, .elf => .{ .elf = {} },
.macho => .{ .macho = link.File.Dwarf.SrcFn.empty }, .macho => .{ .macho = {} },
.plan9 => .{ .plan9 = {} }, .plan9 => .{ .plan9 = {} },
.c => .{ .c = {} }, .c => .{ .c = {} },
.wasm => .{ .wasm = link.File.Wasm.FnData.empty }, .wasm => .{ .wasm = link.File.Wasm.FnData.empty },

View file

@ -203,13 +203,7 @@ const DbgInfoReloc = struct {
else => unreachable, // not a possible argument else => unreachable, // not a possible argument
}; };
try dw.genArgDbgInfo( try dw.genArgDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, loc);
reloc.name,
reloc.ty,
function.bin_file.tag,
function.mod_fn.owner_decl,
loc,
);
}, },
.plan9 => {}, .plan9 => {},
.none => {}, .none => {},
@ -255,14 +249,7 @@ const DbgInfoReloc = struct {
break :blk .nop; break :blk .nop;
}, },
}; };
try dw.genVarDbgInfo( try dw.genVarDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, is_ptr, loc);
reloc.name,
reloc.ty,
function.bin_file.tag,
function.mod_fn.owner_decl,
is_ptr,
loc,
);
}, },
.plan9 => {}, .plan9 => {},
.none => {}, .none => {},

View file

@ -282,13 +282,7 @@ const DbgInfoReloc = struct {
else => unreachable, // not a possible argument else => unreachable, // not a possible argument
}; };
try dw.genArgDbgInfo( try dw.genArgDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, loc);
reloc.name,
reloc.ty,
function.bin_file.tag,
function.mod_fn.owner_decl,
loc,
);
}, },
.plan9 => {}, .plan9 => {},
.none => {}, .none => {},
@ -331,14 +325,7 @@ const DbgInfoReloc = struct {
break :blk .nop; break :blk .nop;
}, },
}; };
try dw.genVarDbgInfo( try dw.genVarDbgInfo(reloc.name, reloc.ty, function.mod_fn.owner_decl, is_ptr, loc);
reloc.name,
reloc.ty,
function.bin_file.tag,
function.mod_fn.owner_decl,
is_ptr,
loc,
);
}, },
.plan9 => {}, .plan9 => {},
.none => {}, .none => {},

View file

@ -1615,13 +1615,9 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
switch (self.debug_output) { switch (self.debug_output) {
.dwarf => |dw| switch (mcv) { .dwarf => |dw| switch (mcv) {
.register => |reg| try dw.genArgDbgInfo( .register => |reg| try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, .{
name, .register = reg.dwarfLocOp(),
ty, }),
self.bin_file.tag,
self.mod_fn.owner_decl,
.{ .register = reg.dwarfLocOp() },
),
.stack_offset => {}, .stack_offset => {},
else => {}, else => {},
}, },

View file

@ -3412,13 +3412,9 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
switch (self.debug_output) { switch (self.debug_output) {
.dwarf => |dw| switch (mcv) { .dwarf => |dw| switch (mcv) {
.register => |reg| try dw.genArgDbgInfo( .register => |reg| try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, .{
name, .register = reg.dwarfLocOp(),
ty, }),
self.bin_file.tag,
self.mod_fn.owner_decl,
.{ .register = reg.dwarfLocOp() },
),
else => {}, else => {},
}, },
else => {}, else => {},

View file

@ -2475,7 +2475,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.dwarf => |dwarf| { .dwarf => |dwarf| {
const src_index = func.air.instructions.items(.data)[inst].arg.src_index; const src_index = func.air.instructions.items(.data)[inst].arg.src_index;
const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, src_index); const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, src_index);
try dwarf.genArgDbgInfo(name, arg_ty, .wasm, func.mod_fn.owner_decl, .{ try dwarf.genArgDbgInfo(name, arg_ty, func.mod_fn.owner_decl, .{
.wasm_local = arg.local.value, .wasm_local = arg.local.value,
}); });
}, },
@ -5539,7 +5539,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void {
break :blk .nop; break :blk .nop;
}, },
}; };
try func.debug_output.dwarf.genVarDbgInfo(name, ty, .wasm, func.mod_fn.owner_decl, is_ptr, loc); try func.debug_output.dwarf.genVarDbgInfo(name, ty, func.mod_fn.owner_decl, is_ptr, loc);
func.finishAir(inst, .none, &.{}); func.finishAir(inst, .none, &.{});
} }

View file

@ -3836,7 +3836,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
}, },
else => unreachable, // not a valid function parameter else => unreachable, // not a valid function parameter
}; };
try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc); try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, loc);
}, },
.plan9 => {}, .plan9 => {},
.none => {}, .none => {},
@ -3876,7 +3876,7 @@ fn genVarDbgInfo(
break :blk .nop; break :blk .nop;
}, },
}; };
try dw.genVarDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, is_ptr, loc); try dw.genVarDbgInfo(name, ty, self.mod_fn.owner_decl, is_ptr, loc);
}, },
.plan9 => {}, .plan9 => {},
.none => {}, .none => {},

View file

@ -273,9 +273,9 @@ pub const File = struct {
}; };
pub const LinkFn = union { pub const LinkFn = union {
elf: Dwarf.SrcFn, elf: void,
coff: Coff.SrcFn, coff: void,
macho: Dwarf.SrcFn, macho: void,
plan9: void, plan9: void,
c: void, c: void,
wasm: Wasm.FnData, wasm: Wasm.FnData,
@ -580,22 +580,23 @@ pub const File = struct {
} }
} }
pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) UpdateDeclError!void { pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
const decl = module.declPtr(decl_index);
log.debug("updateDeclLineNumber {*} ({s}), line={}", .{ log.debug("updateDeclLineNumber {*} ({s}), line={}", .{
decl, decl.name, decl.src_line + 1, decl, decl.name, decl.src_line + 1,
}); });
assert(decl.has_tv); assert(decl.has_tv);
if (build_options.only_c) { if (build_options.only_c) {
assert(base.tag == .c); assert(base.tag == .c);
return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl); return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index);
} }
switch (base.tag) { switch (base.tag) {
.coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl), .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl_index),
.elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl_index),
.macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl), .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl_index),
.c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl), .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index),
.wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl), .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl_index),
.plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl), .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl_index),
.spirv, .nvptx => {}, .spirv, .nvptx => {},
} }
} }

View file

@ -219,12 +219,12 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
code.shrinkAndFree(module.gpa, code.items.len); code.shrinkAndFree(module.gpa, code.items.len);
} }
pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void { pub fn updateDeclLineNumber(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
// The C backend does not have the ability to fix line numbers without re-generating // The C backend does not have the ability to fix line numbers without re-generating
// the entire Decl. // the entire Decl.
_ = self; _ = self;
_ = module; _ = module;
_ = decl; _ = decl_index;
} }
pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void { pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void {

View file

@ -195,7 +195,6 @@ pub const PtrWidth = enum {
}; };
} }
}; };
pub const SrcFn = void;
pub const SymbolWithLoc = struct { pub const SymbolWithLoc = struct {
// Index into the respective symbol table. // Index into the respective symbol table.
@ -1545,10 +1544,10 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
return global_index; return global_index;
} }
pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !void { pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void {
_ = self; _ = self;
_ = module; _ = module;
_ = decl; _ = decl_index;
log.debug("TODO implement updateDeclLineNumber", .{}); log.debug("TODO implement updateDeclLineNumber", .{});
} }

View file

@ -27,17 +27,21 @@ bin_file: *File,
ptr_width: PtrWidth, ptr_width: PtrWidth,
target: std.Target, target: std.Target,
/// A list of `File.LinkFn` whose Line Number Programs have surplus capacity. /// A list of `Atom`s whose Line Number Programs have surplus capacity.
/// This is the same concept as `text_block_free_list`; see those doc comments. /// This is the same concept as `Section.free_list` in Elf; see those doc comments.
dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{}, src_fn_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},
dbg_line_fn_first: ?*SrcFn = null, src_fn_first_index: ?Atom.Index = null,
dbg_line_fn_last: ?*SrcFn = null, src_fn_last_index: ?Atom.Index = null,
src_fns: std.ArrayListUnmanaged(Atom) = .{},
src_fn_decls: AtomTable = .{},
/// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity. /// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity.
/// This is the same concept as `text_block_free_list`; see those doc comments. /// This is the same concept as `text_block_free_list`; see those doc comments.
atom_free_list: std.AutoHashMapUnmanaged(*Atom, void) = .{}, di_atom_free_list: std.AutoHashMapUnmanaged(Atom.Index, void) = .{},
atom_first: ?*Atom = null, di_atom_first_index: ?Atom.Index = null,
atom_last: ?*Atom = null, di_atom_last_index: ?Atom.Index = null,
di_atoms: std.ArrayListUnmanaged(Atom) = .{},
di_atom_decls: AtomTable = .{},
abbrev_table_offset: ?u64 = null, abbrev_table_offset: ?u64 = null,
@ -51,22 +55,23 @@ strtab: StringTable(.strtab) = .{},
/// * []file_names /// * []file_names
di_files: std.AutoArrayHashMapUnmanaged(*const Module.File, void) = .{}, di_files: std.AutoArrayHashMapUnmanaged(*const Module.File, void) = .{},
/// List of atoms that are owned directly by the DWARF module.
/// TODO convert links in DebugInfoAtom into indices and make
/// sure every atom is owned by this module.
managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
pub const Atom = struct { const AtomTable = std.AutoHashMapUnmanaged(Module.Decl.Index, Atom.Index);
/// Previous/next linked list pointers.
/// This is the linked list node for this Decl's corresponding .debug_info tag. const Atom = struct {
prev: ?*Atom, /// Offset into .debug_info pointing to the tag for this Decl, or
next: ?*Atom, /// offset from the beginning of the Debug Line Program header that contains this function.
/// Offset into .debug_info pointing to the tag for this Decl.
off: u32, off: u32,
/// Size of the .debug_info tag for this Decl, not including padding. /// Size of the .debug_info tag for this Decl, not including padding, or
/// size of the line number program component belonging to this function, not
/// including padding.
len: u32, len: u32,
prev_index: ?Index,
next_index: ?Index,
pub const Index = u32;
}; };
/// Represents state of the analysed Decl. /// Represents state of the analysed Decl.
@ -76,6 +81,7 @@ pub const Atom = struct {
pub const DeclState = struct { pub const DeclState = struct {
gpa: Allocator, gpa: Allocator,
mod: *Module, mod: *Module,
di_atom_decls: *const AtomTable,
dbg_line: std.ArrayList(u8), dbg_line: std.ArrayList(u8),
dbg_info: std.ArrayList(u8), dbg_info: std.ArrayList(u8),
abbrev_type_arena: std.heap.ArenaAllocator, abbrev_type_arena: std.heap.ArenaAllocator,
@ -89,10 +95,11 @@ pub const DeclState = struct {
abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{}, exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{},
fn init(gpa: Allocator, mod: *Module) DeclState { fn init(gpa: Allocator, mod: *Module, di_atom_decls: *const AtomTable) DeclState {
return .{ return .{
.gpa = gpa, .gpa = gpa,
.mod = mod, .mod = mod,
.di_atom_decls = di_atom_decls,
.dbg_line = std.ArrayList(u8).init(gpa), .dbg_line = std.ArrayList(u8).init(gpa),
.dbg_info = std.ArrayList(u8).init(gpa), .dbg_info = std.ArrayList(u8).init(gpa),
.abbrev_type_arena = std.heap.ArenaAllocator.init(gpa), .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),
@ -120,11 +127,11 @@ pub const DeclState = struct {
/// Adds local type relocation of the form: @offset => @this + addend /// Adds local type relocation of the form: @offset => @this + addend
/// @this signifies the offset within the .debug_abbrev section of the containing atom. /// @this signifies the offset within the .debug_abbrev section of the containing atom.
fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void { fn addTypeRelocLocal(self: *DeclState, atom_index: Atom.Index, offset: u32, addend: u32) !void {
log.debug("{x}: @this + {x}", .{ offset, addend }); log.debug("{x}: @this + {x}", .{ offset, addend });
try self.abbrev_relocs.append(self.gpa, .{ try self.abbrev_relocs.append(self.gpa, .{
.target = null, .target = null,
.atom = atom, .atom_index = atom_index,
.offset = offset, .offset = offset,
.addend = addend, .addend = addend,
}); });
@ -133,13 +140,13 @@ pub const DeclState = struct {
/// Adds global type relocation of the form: @offset => @symbol + 0 /// Adds global type relocation of the form: @offset => @symbol + 0
/// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section
/// which we use as our target of the relocation. /// which we use as our target of the relocation.
fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void { fn addTypeRelocGlobal(self: *DeclState, atom_index: Atom.Index, ty: Type, offset: u32) !void {
const resolv = self.abbrev_resolver.getContext(ty, .{ const resolv = self.abbrev_resolver.getContext(ty, .{
.mod = self.mod, .mod = self.mod,
}) orelse blk: { }) orelse blk: {
const sym_index = @intCast(u32, self.abbrev_table.items.len); const sym_index = @intCast(u32, self.abbrev_table.items.len);
try self.abbrev_table.append(self.gpa, .{ try self.abbrev_table.append(self.gpa, .{
.atom = atom, .atom_index = atom_index,
.type = ty, .type = ty,
.offset = undefined, .offset = undefined,
}); });
@ -154,7 +161,7 @@ pub const DeclState = struct {
log.debug("{x}: %{d} + 0", .{ offset, resolv }); log.debug("{x}: %{d} + 0", .{ offset, resolv });
try self.abbrev_relocs.append(self.gpa, .{ try self.abbrev_relocs.append(self.gpa, .{
.target = resolv, .target = resolv,
.atom = atom, .atom_index = atom_index,
.offset = offset, .offset = offset,
.addend = 0, .addend = 0,
}); });
@ -163,7 +170,7 @@ pub const DeclState = struct {
fn addDbgInfoType( fn addDbgInfoType(
self: *DeclState, self: *DeclState,
module: *Module, module: *Module,
atom: *Atom, atom_index: Atom.Index,
ty: Type, ty: Type,
) error{OutOfMemory}!void { ) error{OutOfMemory}!void {
const arena = self.abbrev_type_arena.allocator(); const arena = self.abbrev_type_arena.allocator();
@ -228,7 +235,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
var index = dbg_info_buffer.items.len; var index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, Type.bool, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, Type.bool, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
try dbg_info_buffer.ensureUnusedCapacity(6); try dbg_info_buffer.ensureUnusedCapacity(6);
dbg_info_buffer.appendAssumeCapacity(0); dbg_info_buffer.appendAssumeCapacity(0);
@ -240,7 +247,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
index = dbg_info_buffer.items.len; index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
const offset = abi_size - payload_ty.abiSize(target); const offset = abi_size - payload_ty.abiSize(target);
try leb128.writeULEB128(dbg_info_buffer.writer(), offset); try leb128.writeULEB128(dbg_info_buffer.writer(), offset);
@ -271,7 +278,7 @@ pub const DeclState = struct {
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
const ptr_ty = ty.slicePtrFieldType(buf); const ptr_ty = ty.slicePtrFieldType(buf);
try self.addTypeRelocGlobal(atom, ptr_ty, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
try dbg_info_buffer.ensureUnusedCapacity(6); try dbg_info_buffer.ensureUnusedCapacity(6);
dbg_info_buffer.appendAssumeCapacity(0); dbg_info_buffer.appendAssumeCapacity(0);
@ -283,7 +290,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
index = dbg_info_buffer.items.len; index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
try dbg_info_buffer.ensureUnusedCapacity(2); try dbg_info_buffer.ensureUnusedCapacity(2);
dbg_info_buffer.appendAssumeCapacity(ptr_bytes); dbg_info_buffer.appendAssumeCapacity(ptr_bytes);
@ -295,7 +302,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len; const index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, ty.childType(), @intCast(u32, index));
} }
}, },
.Array => { .Array => {
@ -306,13 +313,13 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
var index = dbg_info_buffer.items.len; var index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, ty.childType(), @intCast(u32, index));
// DW.AT.subrange_type // DW.AT.subrange_type
try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim)); try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim));
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
index = dbg_info_buffer.items.len; index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index));
// DW.AT.count, DW.FORM.udata // DW.AT.count, DW.FORM.udata
const len = ty.arrayLenIncludingSentinel(); const len = ty.arrayLenIncludingSentinel();
try leb128.writeULEB128(dbg_info_buffer.writer(), len); try leb128.writeULEB128(dbg_info_buffer.writer(), len);
@ -340,7 +347,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
var index = dbg_info_buffer.items.len; var index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, field, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, field, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
const field_off = ty.structFieldOffset(field_index, target); const field_off = ty.structFieldOffset(field_index, target);
try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
@ -372,7 +379,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
var index = dbg_info_buffer.items.len; var index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
const field_off = ty.structFieldOffset(field_index, target); const field_off = ty.structFieldOffset(field_index, target);
try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
@ -455,7 +462,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
const inner_union_index = dbg_info_buffer.items.len; const inner_union_index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(inner_union_index + 4); try dbg_info_buffer.resize(inner_union_index + 4);
try self.addTypeRelocLocal(atom, @intCast(u32, inner_union_index), 5); try self.addTypeRelocLocal(atom_index, @intCast(u32, inner_union_index), 5);
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset); try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
} }
@ -482,7 +489,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len; const index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
try dbg_info_buffer.append(0); try dbg_info_buffer.append(0);
} }
@ -499,7 +506,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
const index = dbg_info_buffer.items.len; const index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, union_obj.tag_ty, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, union_obj.tag_ty, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset); try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
@ -542,7 +549,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
var index = dbg_info_buffer.items.len; var index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off); try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
@ -555,7 +562,7 @@ pub const DeclState = struct {
// DW.AT.type, DW.FORM.ref4 // DW.AT.type, DW.FORM.ref4
index = dbg_info_buffer.items.len; index = dbg_info_buffer.items.len;
try dbg_info_buffer.resize(index + 4); try dbg_info_buffer.resize(index + 4);
try self.addTypeRelocGlobal(atom, error_ty, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(u32, index));
// DW.AT.data_member_location, DW.FORM.sdata // DW.AT.data_member_location, DW.FORM.sdata
try leb128.writeULEB128(dbg_info_buffer.writer(), error_off); try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
@ -588,12 +595,11 @@ pub const DeclState = struct {
self: *DeclState, self: *DeclState,
name: [:0]const u8, name: [:0]const u8,
ty: Type, ty: Type,
tag: File.Tag,
owner_decl: Module.Decl.Index, owner_decl: Module.Decl.Index,
loc: DbgInfoLoc, loc: DbgInfoLoc,
) error{OutOfMemory}!void { ) error{OutOfMemory}!void {
const dbg_info = &self.dbg_info; const dbg_info = &self.dbg_info;
const atom = getDbgInfoAtom(tag, self.mod, owner_decl); const atom_index = self.di_atom_decls.get(owner_decl).?;
const name_with_null = name.ptr[0 .. name.len + 1]; const name_with_null = name.ptr[0 .. name.len + 1];
switch (loc) { switch (loc) {
@ -638,7 +644,7 @@ pub const DeclState = struct {
try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
const index = dbg_info.items.len; const index = dbg_info.items.len;
try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4 try self.addTypeRelocGlobal(atom_index, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4
dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
} }
@ -646,13 +652,12 @@ pub const DeclState = struct {
self: *DeclState, self: *DeclState,
name: [:0]const u8, name: [:0]const u8,
ty: Type, ty: Type,
tag: File.Tag,
owner_decl: Module.Decl.Index, owner_decl: Module.Decl.Index,
is_ptr: bool, is_ptr: bool,
loc: DbgInfoLoc, loc: DbgInfoLoc,
) error{OutOfMemory}!void { ) error{OutOfMemory}!void {
const dbg_info = &self.dbg_info; const dbg_info = &self.dbg_info;
const atom = getDbgInfoAtom(tag, self.mod, owner_decl); const atom_index = self.di_atom_decls.get(owner_decl).?;
const name_with_null = name.ptr[0 .. name.len + 1]; const name_with_null = name.ptr[0 .. name.len + 1];
try dbg_info.append(@enumToInt(AbbrevKind.variable)); try dbg_info.append(@enumToInt(AbbrevKind.variable));
const target = self.mod.getTarget(); const target = self.mod.getTarget();
@ -782,7 +787,7 @@ pub const DeclState = struct {
try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
const index = dbg_info.items.len; const index = dbg_info.items.len;
try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
try self.addTypeRelocGlobal(atom, child_ty, @intCast(u32, index)); try self.addTypeRelocGlobal(atom_index, child_ty, @intCast(u32, index));
dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
} }
@ -815,7 +820,7 @@ pub const DeclState = struct {
}; };
pub const AbbrevEntry = struct { pub const AbbrevEntry = struct {
atom: *const Atom, atom_index: Atom.Index,
type: Type, type: Type,
offset: u32, offset: u32,
}; };
@ -824,7 +829,7 @@ pub const AbbrevRelocation = struct {
/// If target is null, we deal with a local relocation that is based on simple offset + addend /// If target is null, we deal with a local relocation that is based on simple offset + addend
/// only. /// only.
target: ?u32, target: ?u32,
atom: *const Atom, atom_index: Atom.Index,
offset: u32, offset: u32,
addend: u32, addend: u32,
}; };
@ -841,26 +846,6 @@ pub const ExprlocRelocation = struct {
offset: u32, offset: u32,
}; };
pub const SrcFn = struct {
/// Offset from the beginning of the Debug Line Program header that contains this function.
off: u32,
/// Size of the line number program component belonging to this function, not
/// including padding.
len: u32,
/// Points to the previous and next neighbors, based on the offset from .debug_line.
/// This can be used to find, for example, the capacity of this `SrcFn`.
prev: ?*SrcFn,
next: ?*SrcFn,
pub const empty: SrcFn = .{
.off = 0,
.len = 0,
.prev = null,
.next = null,
};
};
pub const PtrWidth = enum { p32, p64 }; pub const PtrWidth = enum { p32, p64 };
pub const AbbrevKind = enum(u8) { pub const AbbrevKind = enum(u8) {
@ -910,16 +895,18 @@ pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf {
pub fn deinit(self: *Dwarf) void { pub fn deinit(self: *Dwarf) void {
const gpa = self.allocator; const gpa = self.allocator;
self.dbg_line_fn_free_list.deinit(gpa);
self.atom_free_list.deinit(gpa); self.src_fn_free_list.deinit(gpa);
self.src_fns.deinit(gpa);
self.src_fn_decls.deinit(gpa);
self.di_atom_free_list.deinit(gpa);
self.di_atoms.deinit(gpa);
self.di_atom_decls.deinit(gpa);
self.strtab.deinit(gpa); self.strtab.deinit(gpa);
self.di_files.deinit(gpa); self.di_files.deinit(gpa);
self.global_abbrev_relocs.deinit(gpa); self.global_abbrev_relocs.deinit(gpa);
for (self.managed_atoms.items) |atom| {
gpa.destroy(atom);
}
self.managed_atoms.deinit(gpa);
} }
/// Initializes Decl's state and its matching output buffers. /// Initializes Decl's state and its matching output buffers.
@ -935,15 +922,19 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
log.debug("initDeclState {s}{*}", .{ decl_name, decl }); log.debug("initDeclState {s}{*}", .{ decl_name, decl });
const gpa = self.allocator; const gpa = self.allocator;
var decl_state = DeclState.init(gpa, mod); var decl_state = DeclState.init(gpa, mod, &self.di_atom_decls);
errdefer decl_state.deinit(); errdefer decl_state.deinit();
const dbg_line_buffer = &decl_state.dbg_line; const dbg_line_buffer = &decl_state.dbg_line;
const dbg_info_buffer = &decl_state.dbg_info; const dbg_info_buffer = &decl_state.dbg_info;
const di_atom_index = try self.getOrCreateAtomForDecl(.di_atom, decl_index);
assert(decl.has_tv); assert(decl.has_tv);
switch (decl.ty.zigTypeTag()) { switch (decl.ty.zigTypeTag()) {
.Fn => { .Fn => {
_ = try self.getOrCreateAtomForDecl(.src_fn, decl_index);
// For functions we need to add a prologue to the debug line program. // For functions we need to add a prologue to the debug line program.
try dbg_line_buffer.ensureTotalCapacity(26); try dbg_line_buffer.ensureTotalCapacity(26);
@ -1003,8 +994,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
// //
if (fn_ret_has_bits) { if (fn_ret_has_bits) {
const atom = getDbgInfoAtom(self.bin_file.tag, mod, decl_index); try decl_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
} }
@ -1076,26 +1066,23 @@ pub fn commitDeclState(
// This logic is nearly identical to the logic below in `updateDeclDebugInfo` for // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
// `TextBlock` and the .debug_info. If you are editing this logic, you // `TextBlock` and the .debug_info. If you are editing this logic, you
// probably need to edit that logic too. // probably need to edit that logic too.
const src_fn = switch (self.bin_file.tag) { const src_fn_index = self.src_fn_decls.get(decl_index).?;
.elf => &decl.fn_link.elf, const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
.macho => &decl.fn_link.macho,
.wasm => &decl.fn_link.wasm.src_fn,
else => unreachable, // TODO
};
src_fn.len = @intCast(u32, dbg_line_buffer.items.len); src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
if (self.dbg_line_fn_last) |last| blk: { if (self.src_fn_last_index) |last_index| blk: {
if (src_fn == last) break :blk; if (src_fn_index == last_index) break :blk;
if (src_fn.next) |next| { if (src_fn.next_index) |next_index| {
const next = self.getAtomPtr(.src_fn, next_index);
// Update existing function - non-last item. // Update existing function - non-last item.
if (src_fn.off + src_fn.len + min_nop_size > next.off) { if (src_fn.off + src_fn.len + min_nop_size > next.off) {
// It grew too big, so we move it to a new location. // It grew too big, so we move it to a new location.
if (src_fn.prev) |prev| { if (src_fn.prev_index) |prev_index| {
self.dbg_line_fn_free_list.put(gpa, prev, {}) catch {}; self.src_fn_free_list.put(gpa, prev_index, {}) catch {};
prev.next = src_fn.next; self.getAtomPtr(.src_fn, prev_index).next_index = src_fn.next_index;
} }
next.prev = src_fn.prev; next.prev_index = src_fn.prev_index;
src_fn.next = null; src_fn.next_index = null;
// Populate where it used to be with NOPs. // Populate where it used to be with NOPs.
switch (self.bin_file.tag) { switch (self.bin_file.tag) {
.elf => { .elf => {
@ -1118,33 +1105,42 @@ pub fn commitDeclState(
else => unreachable, else => unreachable,
} }
// TODO Look at the free list before appending at the end. // TODO Look at the free list before appending at the end.
src_fn.prev = last; src_fn.prev_index = last_index;
last.next = src_fn; const last = self.getAtomPtr(.src_fn, last_index);
self.dbg_line_fn_last = src_fn; last.next_index = src_fn_index;
self.src_fn_last_index = src_fn_index;
src_fn.off = last.off + padToIdeal(last.len); src_fn.off = last.off + padToIdeal(last.len);
} }
} else if (src_fn.prev == null) { } else if (src_fn.prev_index == null) {
// Append new function. // Append new function.
// TODO Look at the free list before appending at the end. // TODO Look at the free list before appending at the end.
src_fn.prev = last; src_fn.prev_index = last_index;
last.next = src_fn; const last = self.getAtomPtr(.src_fn, last_index);
self.dbg_line_fn_last = src_fn; last.next_index = src_fn_index;
self.src_fn_last_index = src_fn_index;
src_fn.off = last.off + padToIdeal(last.len); src_fn.off = last.off + padToIdeal(last.len);
} }
} else { } else {
// This is the first function of the Line Number Program. // This is the first function of the Line Number Program.
self.dbg_line_fn_first = src_fn; self.src_fn_first_index = src_fn_index;
self.dbg_line_fn_last = src_fn; self.src_fn_last_index = src_fn_index;
src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{})); src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes(&[0][]u8{}, &[0][]u8{}));
} }
const last_src_fn = self.dbg_line_fn_last.?; const last_src_fn_index = self.src_fn_last_index.?;
const last_src_fn = self.getAtom(.src_fn, last_src_fn_index);
const needed_size = last_src_fn.off + last_src_fn.len; const needed_size = last_src_fn.off + last_src_fn.len;
const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0; const prev_padding_size: u32 = if (src_fn.prev_index) |prev_index| blk: {
const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; const prev = self.getAtom(.src_fn, prev_index);
break :blk src_fn.off - (prev.off + prev.len);
} else 0;
const next_padding_size: u32 = if (src_fn.next_index) |next_index| blk: {
const next = self.getAtom(.src_fn, next_index);
break :blk next.off - (src_fn.off + src_fn.len);
} else 0;
// We only have support for one compilation unit so far, so the offsets are directly // We only have support for one compilation unit so far, so the offsets are directly
// from the .debug_line section. // from the .debug_line section.
@ -1213,7 +1209,7 @@ pub fn commitDeclState(
if (dbg_info_buffer.items.len == 0) if (dbg_info_buffer.items.len == 0)
return; return;
const atom = getDbgInfoAtom(self.bin_file.tag, module, decl_index); const di_atom_index = self.di_atom_decls.get(decl_index).?;
if (decl_state.abbrev_table.items.len > 0) { if (decl_state.abbrev_table.items.len > 0) {
// Now we emit the .debug_info types of the Decl. These will count towards the size of // Now we emit the .debug_info types of the Decl. These will count towards the size of
// the buffer, so we have to do it before computing the offset, and we can't perform the actual // the buffer, so we have to do it before computing the offset, and we can't perform the actual
@ -1235,12 +1231,12 @@ pub fn commitDeclState(
if (deferred) continue; if (deferred) continue;
symbol.offset = @intCast(u32, dbg_info_buffer.items.len); symbol.offset = @intCast(u32, dbg_info_buffer.items.len);
try decl_state.addDbgInfoType(module, atom, ty); try decl_state.addDbgInfoType(module, di_atom_index, ty);
} }
} }
log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name}); log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name});
try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len)); try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len));
while (decl_state.abbrev_relocs.popOrNull()) |reloc| { while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
if (reloc.target) |target| { if (reloc.target) |target| {
@ -1261,11 +1257,12 @@ pub fn commitDeclState(
try self.global_abbrev_relocs.append(gpa, .{ try self.global_abbrev_relocs.append(gpa, .{
.target = null, .target = null,
.offset = reloc.offset, .offset = reloc.offset,
.atom = reloc.atom, .atom_index = reloc.atom_index,
.addend = reloc.addend, .addend = reloc.addend,
}); });
} else { } else {
const value = symbol.atom.off + symbol.offset + reloc.addend; const atom = self.getAtom(.di_atom, symbol.atom_index);
const value = atom.off + symbol.offset + reloc.addend;
log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() }); log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() });
mem.writeInt( mem.writeInt(
u32, u32,
@ -1275,10 +1272,11 @@ pub fn commitDeclState(
); );
} }
} else { } else {
const atom = self.getAtom(.di_atom, reloc.atom_index);
mem.writeInt( mem.writeInt(
u32, u32,
dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
reloc.atom.off + reloc.offset + reloc.addend, atom.off + reloc.offset + reloc.addend,
target_endian, target_endian,
); );
} }
@ -1294,7 +1292,7 @@ pub fn commitDeclState(
.got_load => .got_load, .got_load => .got_load,
}, },
.target = reloc.target, .target = reloc.target,
.offset = reloc.offset + atom.off, .offset = reloc.offset + self.getAtom(.di_atom, di_atom_index).off,
.addend = 0, .addend = 0,
.prev_vaddr = 0, .prev_vaddr = 0,
}); });
@ -1304,10 +1302,10 @@ pub fn commitDeclState(
} }
log.debug("writeDeclDebugInfo for '{s}", .{decl.name}); log.debug("writeDeclDebugInfo for '{s}", .{decl.name});
try self.writeDeclDebugInfo(atom, dbg_info_buffer.items); try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items);
} }
fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void { fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32) !void {
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -1316,19 +1314,21 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
// probably need to edit that logic too. // probably need to edit that logic too.
const gpa = self.allocator; const gpa = self.allocator;
const atom = self.getAtomPtr(.di_atom, atom_index);
atom.len = len; atom.len = len;
if (self.atom_last) |last| blk: { if (self.di_atom_last_index) |last_index| blk: {
if (atom == last) break :blk; if (atom_index == last_index) break :blk;
if (atom.next) |next| { if (atom.next_index) |next_index| {
const next = self.getAtomPtr(.di_atom, next_index);
// Update existing Decl - non-last item. // Update existing Decl - non-last item.
if (atom.off + atom.len + min_nop_size > next.off) { if (atom.off + atom.len + min_nop_size > next.off) {
// It grew too big, so we move it to a new location. // It grew too big, so we move it to a new location.
if (atom.prev) |prev| { if (atom.prev_index) |prev_index| {
self.atom_free_list.put(gpa, prev, {}) catch {}; self.di_atom_free_list.put(gpa, prev_index, {}) catch {};
prev.next = atom.next; self.getAtomPtr(.di_atom, prev_index).next_index = atom.next_index;
} }
next.prev = atom.prev; next.prev_index = atom.prev_index;
atom.next = null; atom.next_index = null;
// Populate where it used to be with NOPs. // Populate where it used to be with NOPs.
switch (self.bin_file.tag) { switch (self.bin_file.tag) {
.elf => { .elf => {
@ -1351,31 +1351,33 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
else => unreachable, else => unreachable,
} }
// TODO Look at the free list before appending at the end. // TODO Look at the free list before appending at the end.
atom.prev = last; atom.prev_index = last_index;
last.next = atom; const last = self.getAtomPtr(.di_atom, last_index);
self.atom_last = atom; last.next_index = atom_index;
self.di_atom_last_index = atom_index;
atom.off = last.off + padToIdeal(last.len); atom.off = last.off + padToIdeal(last.len);
} }
} else if (atom.prev == null) { } else if (atom.prev_index == null) {
// Append new Decl. // Append new Decl.
// TODO Look at the free list before appending at the end. // TODO Look at the free list before appending at the end.
atom.prev = last; atom.prev_index = last_index;
last.next = atom; const last = self.getAtomPtr(.di_atom, last_index);
self.atom_last = atom; last.next_index = atom_index;
self.di_atom_last_index = atom_index;
atom.off = last.off + padToIdeal(last.len); atom.off = last.off + padToIdeal(last.len);
} }
} else { } else {
// This is the first Decl of the .debug_info // This is the first Decl of the .debug_info
self.atom_first = atom; self.di_atom_first_index = atom_index;
self.atom_last = atom; self.di_atom_last_index = atom_index;
atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes())); atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes()));
} }
} }
fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void { fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []const u8) !void {
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -1384,14 +1386,22 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
// probably need to edit that logic too. // probably need to edit that logic too.
const gpa = self.allocator; const gpa = self.allocator;
const last_decl = self.atom_last.?; const atom = self.getAtom(.di_atom, atom_index);
const last_decl_index = self.di_atom_last_index.?;
const last_decl = self.getAtom(.di_atom, last_decl_index);
// +1 for a trailing zero to end the children of the decl tag. // +1 for a trailing zero to end the children of the decl tag.
const needed_size = last_decl.off + last_decl.len + 1; const needed_size = last_decl.off + last_decl.len + 1;
const prev_padding_size: u32 = if (atom.prev) |prev| atom.off - (prev.off + prev.len) else 0; const prev_padding_size: u32 = if (atom.prev_index) |prev_index| blk: {
const next_padding_size: u32 = if (atom.next) |next| next.off - (atom.off + atom.len) else 0; const prev = self.getAtom(.di_atom, prev_index);
break :blk atom.off - (prev.off + prev.len);
} else 0;
const next_padding_size: u32 = if (atom.next_index) |next_index| blk: {
const next = self.getAtom(.di_atom, next_index);
break :blk next.off - (atom.off + atom.len);
} else 0;
// To end the children of the decl tag. // To end the children of the decl tag.
const trailing_zero = atom.next == null; const trailing_zero = atom.next_index == null;
// We only have support for one compilation unit so far, so the offsets are directly // We only have support for one compilation unit so far, so the offsets are directly
// from the .debug_info section. // from the .debug_info section.
@ -1459,10 +1469,15 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
} }
} }
pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void { pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.Decl.Index) !void {
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
const atom_index = try self.getOrCreateAtomForDecl(.src_fn, decl_index);
const atom = self.getAtom(.src_fn, atom_index);
if (atom.len == 0) return;
const decl = module.declPtr(decl_index);
const func = decl.val.castTag(.function).?.data; const func = decl.val.castTag(.function).?.data;
log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{
decl.src_line, decl.src_line,
@ -1477,78 +1492,80 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {
.elf => { .elf => {
const elf_file = self.bin_file.cast(File.Elf).?; const elf_file = self.bin_file.cast(File.Elf).?;
const shdr = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?]; const shdr = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff(); const file_pos = shdr.sh_offset + atom.off + self.getRelocDbgLineOff();
try elf_file.base.file.?.pwriteAll(&data, file_pos); try elf_file.base.file.?.pwriteAll(&data, file_pos);
}, },
.macho => { .macho => {
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
const sect = d_sym.getSection(d_sym.debug_line_section_index.?); const sect = d_sym.getSection(d_sym.debug_line_section_index.?);
const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff(); const file_pos = sect.offset + atom.off + self.getRelocDbgLineOff();
try d_sym.file.pwriteAll(&data, file_pos); try d_sym.file.pwriteAll(&data, file_pos);
}, },
.wasm => { .wasm => {
const wasm_file = self.bin_file.cast(File.Wasm).?; const wasm_file = self.bin_file.cast(File.Wasm).?;
const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff(); const offset = atom.off + self.getRelocDbgLineOff();
const atom = wasm_file.debug_line_atom.?; const atom_ = wasm_file.debug_line_atom.?;
mem.copy(u8, atom.code.items[offset..], &data); mem.copy(u8, atom_.code.items[offset..], &data);
}, },
else => unreachable, else => unreachable,
} }
} }
pub fn freeAtom(self: *Dwarf, atom: *Atom) void { pub fn freeDecl(self: *Dwarf, decl_index: Module.Decl.Index) void {
if (self.atom_first == atom) {
self.atom_first = atom.next;
}
if (self.atom_last == atom) {
// TODO shrink the .debug_info section size here
self.atom_last = atom.prev;
}
if (atom.prev) |prev| {
prev.next = atom.next;
// TODO the free list logic like we do for text blocks above
} else {
atom.prev = null;
}
if (atom.next) |next| {
next.prev = atom.prev;
} else {
atom.next = null;
}
}
pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {
// TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
// is desired for both.
const gpa = self.allocator; const gpa = self.allocator;
const fn_link = switch (self.bin_file.tag) {
.elf => &decl.fn_link.elf,
.macho => &decl.fn_link.macho,
.wasm => &decl.fn_link.wasm.src_fn,
else => unreachable,
};
_ = self.dbg_line_fn_free_list.remove(fn_link);
if (fn_link.prev) |prev| { // Free SrcFn atom
self.dbg_line_fn_free_list.put(gpa, prev, {}) catch {}; if (self.src_fn_decls.fetchRemove(decl_index)) |kv| {
prev.next = fn_link.next; const src_fn_index = kv.value;
if (fn_link.next) |next| { const src_fn = self.getAtom(.src_fn, src_fn_index);
next.prev = prev; _ = self.src_fn_free_list.remove(src_fn_index);
if (src_fn.prev_index) |prev_index| {
self.src_fn_free_list.put(gpa, prev_index, {}) catch {};
const prev = self.getAtomPtr(.src_fn, prev_index);
prev.next_index = src_fn.next_index;
if (src_fn.next_index) |next_index| {
self.getAtomPtr(.src_fn, next_index).prev_index = prev_index;
} else { } else {
self.dbg_line_fn_last = prev; self.src_fn_last_index = prev_index;
} }
} else if (fn_link.next) |next| { } else if (src_fn.next_index) |next_index| {
self.dbg_line_fn_first = next; self.src_fn_first_index = next_index;
next.prev = null; self.getAtomPtr(.src_fn, next_index).prev_index = null;
} }
if (self.dbg_line_fn_first == fn_link) { if (self.src_fn_first_index == src_fn_index) {
self.dbg_line_fn_first = fn_link.next; self.src_fn_first_index = src_fn.next_index;
}
if (self.src_fn_last_index == src_fn_index) {
self.src_fn_last_index = src_fn.prev_index;
}
}
// Free DI atom
if (self.di_atom_decls.fetchRemove(decl_index)) |kv| {
const di_atom_index = kv.value;
const di_atom = self.getAtomPtr(.di_atom, di_atom_index);
if (self.di_atom_first_index == di_atom_index) {
self.di_atom_first_index = di_atom.next_index;
}
if (self.di_atom_last_index == di_atom_index) {
// TODO shrink the .debug_info section size here
self.di_atom_last_index = di_atom.prev_index;
}
if (di_atom.prev_index) |prev_index| {
self.getAtomPtr(.di_atom, prev_index).next_index = di_atom.next_index;
// TODO the free list logic like we do for SrcFn above
} else {
di_atom.prev_index = null;
}
if (di_atom.next_index) |next_index| {
self.getAtomPtr(.di_atom, next_index).prev_index = di_atom.prev_index;
} else {
di_atom.next_index = null;
} }
if (self.dbg_line_fn_last == fn_link) {
self.dbg_line_fn_last = fn_link.prev;
} }
} }
@ -2276,10 +2293,14 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
const needed_with_padding = padToIdeal(needed_bytes); const needed_with_padding = padToIdeal(needed_bytes);
const delta = needed_with_padding - dbg_line_prg_off; const delta = needed_with_padding - dbg_line_prg_off;
var src_fn = self.dbg_line_fn_first.?; const first_fn_index = self.src_fn_first_index.?;
const last_fn = self.dbg_line_fn_last.?; const first_fn = self.getAtom(.src_fn, first_fn_index);
const last_fn_index = self.src_fn_last_index.?;
const last_fn = self.getAtom(.src_fn, last_fn_index);
var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - src_fn.off); var src_fn_index = first_fn_index;
var buffer = try gpa.alloc(u8, last_fn.off + last_fn.len - first_fn.off);
defer gpa.free(buffer); defer gpa.free(buffer);
switch (self.bin_file.tag) { switch (self.bin_file.tag) {
@ -2288,7 +2309,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
const shdr_index = elf_file.debug_line_section_index.?; const shdr_index = elf_file.debug_line_section_index.?;
const needed_size = elf_file.sections.items(.shdr)[shdr_index].sh_size + delta; const needed_size = elf_file.sections.items(.shdr)[shdr_index].sh_size + delta;
try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true); try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
const file_pos = elf_file.sections.items(.shdr)[shdr_index].sh_offset + src_fn.off; const file_pos = elf_file.sections.items(.shdr)[shdr_index].sh_offset + first_fn.off;
const amt = try elf_file.base.file.?.preadAll(buffer, file_pos); const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
if (amt != buffer.len) return error.InputOutput; if (amt != buffer.len) return error.InputOutput;
@ -2300,7 +2321,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
const sect_index = d_sym.debug_line_section_index.?; const sect_index = d_sym.debug_line_section_index.?;
const needed_size = @intCast(u32, d_sym.getSection(sect_index).size + delta); const needed_size = @intCast(u32, d_sym.getSection(sect_index).size + delta);
try d_sym.growSection(sect_index, needed_size, true); try d_sym.growSection(sect_index, needed_size, true);
const file_pos = d_sym.getSection(sect_index).offset + src_fn.off; const file_pos = d_sym.getSection(sect_index).offset + first_fn.off;
const amt = try d_sym.file.preadAll(buffer, file_pos); const amt = try d_sym.file.preadAll(buffer, file_pos);
if (amt != buffer.len) return error.InputOutput; if (amt != buffer.len) return error.InputOutput;
@ -2310,18 +2331,19 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
.wasm => { .wasm => {
const wasm_file = self.bin_file.cast(File.Wasm).?; const wasm_file = self.bin_file.cast(File.Wasm).?;
const debug_line = &wasm_file.debug_line_atom.?.code; const debug_line = &wasm_file.debug_line_atom.?.code;
mem.copy(u8, buffer, debug_line.items[src_fn.off..]); mem.copy(u8, buffer, debug_line.items[first_fn.off..]);
try debug_line.resize(self.allocator, debug_line.items.len + delta); try debug_line.resize(self.allocator, debug_line.items.len + delta);
mem.copy(u8, debug_line.items[src_fn.off + delta ..], buffer); mem.copy(u8, debug_line.items[first_fn.off + delta ..], buffer);
}, },
else => unreachable, else => unreachable,
} }
while (true) { while (true) {
const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
src_fn.off += delta; src_fn.off += delta;
if (src_fn.next) |next| { if (src_fn.next_index) |next_index| {
src_fn = next; src_fn_index = next_index;
} else break; } else break;
} }
} }
@ -2367,22 +2389,26 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
} }
fn getDebugInfoOff(self: Dwarf) ?u32 { fn getDebugInfoOff(self: Dwarf) ?u32 {
const first = self.atom_first orelse return null; const first_index = self.di_atom_first_index orelse return null;
const first = self.getAtom(.di_atom, first_index);
return first.off; return first.off;
} }
fn getDebugInfoEnd(self: Dwarf) ?u32 { fn getDebugInfoEnd(self: Dwarf) ?u32 {
const last = self.atom_last orelse return null; const last_index = self.di_atom_last_index orelse return null;
const last = self.getAtom(.di_atom, last_index);
return last.off + last.len; return last.off + last.len;
} }
fn getDebugLineProgramOff(self: Dwarf) ?u32 { fn getDebugLineProgramOff(self: Dwarf) ?u32 {
const first = self.dbg_line_fn_first orelse return null; const first_index = self.src_fn_first_index orelse return null;
const first = self.getAtom(.src_fn, first_index);
return first.off; return first.off;
} }
fn getDebugLineProgramEnd(self: Dwarf) ?u32 { fn getDebugLineProgramEnd(self: Dwarf) ?u32 {
const last = self.dbg_line_fn_last orelse return null; const last_index = self.src_fn_last_index orelse return null;
const last = self.getAtom(.src_fn, last_index);
return last.off + last.len; return last.off + last.len;
} }
@ -2457,23 +2483,14 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
} }
error_set.names = names; error_set.names = names;
const atom = try gpa.create(Atom);
errdefer gpa.destroy(atom);
atom.* = .{
.prev = null,
.next = null,
.off = 0,
.len = 0,
};
var dbg_info_buffer = std.ArrayList(u8).init(arena); var dbg_info_buffer = std.ArrayList(u8).init(arena);
try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer); try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer);
try self.managed_atoms.append(gpa, atom); const di_atom_index = try self.createAtom(.di_atom);
log.debug("updateDeclDebugInfoAllocation in flushModule", .{}); log.debug("updateDeclDebugInfoAllocation in flushModule", .{});
try self.updateDeclDebugInfoAllocation(atom, @intCast(u32, dbg_info_buffer.items.len)); try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len));
log.debug("writeDeclDebugInfo in flushModule", .{}); log.debug("writeDeclDebugInfo in flushModule", .{});
try self.writeDeclDebugInfo(atom, dbg_info_buffer.items); try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items);
const file_pos = blk: { const file_pos = blk: {
switch (self.bin_file.tag) { switch (self.bin_file.tag) {
@ -2494,22 +2511,23 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
}; };
var buf: [@sizeOf(u32)]u8 = undefined; var buf: [@sizeOf(u32)]u8 = undefined;
mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian()); mem.writeInt(u32, &buf, self.getAtom(.di_atom, di_atom_index).off, self.target.cpu.arch.endian());
while (self.global_abbrev_relocs.popOrNull()) |reloc| { while (self.global_abbrev_relocs.popOrNull()) |reloc| {
const atom = self.getAtom(.di_atom, reloc.atom_index);
switch (self.bin_file.tag) { switch (self.bin_file.tag) {
.elf => { .elf => {
const elf_file = self.bin_file.cast(File.Elf).?; const elf_file = self.bin_file.cast(File.Elf).?;
try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset); try elf_file.base.file.?.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
}, },
.macho => { .macho => {
const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?; const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset); try d_sym.file.pwriteAll(&buf, file_pos + atom.off + reloc.offset);
}, },
.wasm => { .wasm => {
const wasm_file = self.bin_file.cast(File.Wasm).?; const wasm_file = self.bin_file.cast(File.Wasm).?;
const debug_info = wasm_file.debug_info_atom.?.code; const debug_info = wasm_file.debug_info_atom.?.code;
mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf); mem.copy(u8, debug_info.items[atom.off + reloc.offset ..], &buf);
}, },
else => unreachable, else => unreachable,
} }
@ -2627,12 +2645,62 @@ fn addDbgInfoErrorSet(
try dbg_info_buffer.append(0); try dbg_info_buffer.append(0);
} }
fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *Atom { const Kind = enum { src_fn, di_atom };
const decl = mod.declPtr(decl_index);
return switch (tag) { fn createAtom(self: *Dwarf, comptime kind: Kind) !Atom.Index {
.elf => unreachable, const index = blk: {
.macho => unreachable, switch (kind) {
.wasm => &decl.link.wasm.dbg_info_atom, .src_fn => {
else => unreachable, const index = @intCast(Atom.Index, self.src_fns.items.len);
_ = try self.src_fns.addOne(self.allocator);
break :blk index;
},
.di_atom => {
const index = @intCast(Atom.Index, self.di_atoms.items.len);
_ = try self.di_atoms.addOne(self.allocator);
break :blk index;
},
}
};
const atom = self.getAtomPtr(kind, index);
atom.* = .{
.off = 0,
.len = 0,
.prev_index = null,
.next_index = null,
};
return index;
}
fn getOrCreateAtomForDecl(self: *Dwarf, comptime kind: Kind, decl_index: Module.Decl.Index) !Atom.Index {
switch (kind) {
.src_fn => {
const gop = try self.src_fn_decls.getOrPut(self.allocator, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = try self.createAtom(kind);
}
return gop.value_ptr.*;
},
.di_atom => {
const gop = try self.di_atom_decls.getOrPut(self.allocator, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = try self.createAtom(kind);
}
return gop.value_ptr.*;
},
}
}
fn getAtom(self: *const Dwarf, comptime kind: Kind, index: Atom.Index) Atom {
return switch (kind) {
.src_fn => self.src_fns.items[index],
.di_atom => self.di_atoms.items[index],
};
}
fn getAtomPtr(self: *Dwarf, comptime kind: Kind, index: Atom.Index) *Atom {
return switch (kind) {
.src_fn => &self.src_fns.items[index],
.di_atom => &self.di_atoms.items[index],
}; };
} }

View file

@ -344,9 +344,9 @@ pub fn deinit(self: *Elf) void {
self.relocs.deinit(gpa); self.relocs.deinit(gpa);
} }
// if (self.dwarf) |*dw| { if (self.dwarf) |*dw| {
// dw.deinit(); dw.deinit();
// } }
} }
pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 { pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 {
@ -685,146 +685,146 @@ pub fn populateMissingMetadata(self: *Elf) !void {
try self.writeSymbol(0); try self.writeSymbol(0);
} }
// if (self.dwarf) |*dw| { if (self.dwarf) |*dw| {
// if (self.debug_str_section_index == null) { if (self.debug_str_section_index == null) {
// self.debug_str_section_index = @intCast(u16, self.sections.slice().len); self.debug_str_section_index = @intCast(u16, self.sections.slice().len);
// assert(dw.strtab.buffer.items.len == 0); assert(dw.strtab.buffer.items.len == 0);
// try dw.strtab.buffer.append(gpa, 0); try dw.strtab.buffer.append(gpa, 0);
// try self.sections.append(gpa, .{ try self.sections.append(gpa, .{
// .shdr = .{ .shdr = .{
// .sh_name = try self.shstrtab.insert(gpa, ".debug_str"), .sh_name = try self.shstrtab.insert(gpa, ".debug_str"),
// .sh_type = elf.SHT_PROGBITS, .sh_type = elf.SHT_PROGBITS,
// .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
// .sh_addr = 0, .sh_addr = 0,
// .sh_offset = 0, .sh_offset = 0,
// .sh_size = 0, .sh_size = 0,
// .sh_link = 0, .sh_link = 0,
// .sh_info = 0, .sh_info = 0,
// .sh_addralign = 1, .sh_addralign = 1,
// .sh_entsize = 1, .sh_entsize = 1,
// }, },
// .phdr_index = undefined, .phdr_index = undefined,
// }); });
// self.debug_strtab_dirty = true; self.debug_strtab_dirty = true;
// self.shdr_table_dirty = true; self.shdr_table_dirty = true;
// } }
// if (self.debug_info_section_index == null) { if (self.debug_info_section_index == null) {
// self.debug_info_section_index = @intCast(u16, self.sections.slice().len); self.debug_info_section_index = @intCast(u16, self.sections.slice().len);
// const file_size_hint = 200; const file_size_hint = 200;
// const p_align = 1; const p_align = 1;
// const off = self.findFreeSpace(file_size_hint, p_align); const off = self.findFreeSpace(file_size_hint, p_align);
// log.debug("found .debug_info free space 0x{x} to 0x{x}", .{ log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
// off, off,
// off + file_size_hint, off + file_size_hint,
// }); });
// try self.sections.append(gpa, .{ try self.sections.append(gpa, .{
// .shdr = .{ .shdr = .{
// .sh_name = try self.shstrtab.insert(gpa, ".debug_info"), .sh_name = try self.shstrtab.insert(gpa, ".debug_info"),
// .sh_type = elf.SHT_PROGBITS, .sh_type = elf.SHT_PROGBITS,
// .sh_flags = 0, .sh_flags = 0,
// .sh_addr = 0, .sh_addr = 0,
// .sh_offset = off, .sh_offset = off,
// .sh_size = file_size_hint, .sh_size = file_size_hint,
// .sh_link = 0, .sh_link = 0,
// .sh_info = 0, .sh_info = 0,
// .sh_addralign = p_align, .sh_addralign = p_align,
// .sh_entsize = 0, .sh_entsize = 0,
// }, },
// .phdr_index = undefined, .phdr_index = undefined,
// }); });
// self.shdr_table_dirty = true; self.shdr_table_dirty = true;
// self.debug_info_header_dirty = true; self.debug_info_header_dirty = true;
// } }
// if (self.debug_abbrev_section_index == null) { if (self.debug_abbrev_section_index == null) {
// self.debug_abbrev_section_index = @intCast(u16, self.sections.slice().len); self.debug_abbrev_section_index = @intCast(u16, self.sections.slice().len);
// const file_size_hint = 128; const file_size_hint = 128;
// const p_align = 1; const p_align = 1;
// const off = self.findFreeSpace(file_size_hint, p_align); const off = self.findFreeSpace(file_size_hint, p_align);
// log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{ log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
// off, off,
// off + file_size_hint, off + file_size_hint,
// }); });
// try self.sections.append(gpa, .{ try self.sections.append(gpa, .{
// .shdr = .{ .shdr = .{
// .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"), .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"),
// .sh_type = elf.SHT_PROGBITS, .sh_type = elf.SHT_PROGBITS,
// .sh_flags = 0, .sh_flags = 0,
// .sh_addr = 0, .sh_addr = 0,
// .sh_offset = off, .sh_offset = off,
// .sh_size = file_size_hint, .sh_size = file_size_hint,
// .sh_link = 0, .sh_link = 0,
// .sh_info = 0, .sh_info = 0,
// .sh_addralign = p_align, .sh_addralign = p_align,
// .sh_entsize = 0, .sh_entsize = 0,
// }, },
// .phdr_index = undefined, .phdr_index = undefined,
// }); });
// self.shdr_table_dirty = true; self.shdr_table_dirty = true;
// self.debug_abbrev_section_dirty = true; self.debug_abbrev_section_dirty = true;
// } }
// if (self.debug_aranges_section_index == null) { if (self.debug_aranges_section_index == null) {
// self.debug_aranges_section_index = @intCast(u16, self.sections.slice().len); self.debug_aranges_section_index = @intCast(u16, self.sections.slice().len);
// const file_size_hint = 160; const file_size_hint = 160;
// const p_align = 16; const p_align = 16;
// const off = self.findFreeSpace(file_size_hint, p_align); const off = self.findFreeSpace(file_size_hint, p_align);
// log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{ log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
// off, off,
// off + file_size_hint, off + file_size_hint,
// }); });
// try self.sections.append(gpa, .{ try self.sections.append(gpa, .{
// .shdr = .{ .shdr = .{
// .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"), .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"),
// .sh_type = elf.SHT_PROGBITS, .sh_type = elf.SHT_PROGBITS,
// .sh_flags = 0, .sh_flags = 0,
// .sh_addr = 0, .sh_addr = 0,
// .sh_offset = off, .sh_offset = off,
// .sh_size = file_size_hint, .sh_size = file_size_hint,
// .sh_link = 0, .sh_link = 0,
// .sh_info = 0, .sh_info = 0,
// .sh_addralign = p_align, .sh_addralign = p_align,
// .sh_entsize = 0, .sh_entsize = 0,
// }, },
// .phdr_index = undefined, .phdr_index = undefined,
// }); });
// self.shdr_table_dirty = true; self.shdr_table_dirty = true;
// self.debug_aranges_section_dirty = true; self.debug_aranges_section_dirty = true;
// } }
// if (self.debug_line_section_index == null) { if (self.debug_line_section_index == null) {
// self.debug_line_section_index = @intCast(u16, self.sections.slice().len); self.debug_line_section_index = @intCast(u16, self.sections.slice().len);
// const file_size_hint = 250; const file_size_hint = 250;
// const p_align = 1; const p_align = 1;
// const off = self.findFreeSpace(file_size_hint, p_align); const off = self.findFreeSpace(file_size_hint, p_align);
// log.debug("found .debug_line free space 0x{x} to 0x{x}", .{ log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
// off, off,
// off + file_size_hint, off + file_size_hint,
// }); });
// try self.sections.append(gpa, .{ try self.sections.append(gpa, .{
// .shdr = .{ .shdr = .{
// .sh_name = try self.shstrtab.insert(gpa, ".debug_line"), .sh_name = try self.shstrtab.insert(gpa, ".debug_line"),
// .sh_type = elf.SHT_PROGBITS, .sh_type = elf.SHT_PROGBITS,
// .sh_flags = 0, .sh_flags = 0,
// .sh_addr = 0, .sh_addr = 0,
// .sh_offset = off, .sh_offset = off,
// .sh_size = file_size_hint, .sh_size = file_size_hint,
// .sh_link = 0, .sh_link = 0,
// .sh_info = 0, .sh_info = 0,
// .sh_addralign = p_align, .sh_addralign = p_align,
// .sh_entsize = 0, .sh_entsize = 0,
// }, },
// .phdr_index = undefined, .phdr_index = undefined,
// }); });
// self.shdr_table_dirty = true; self.shdr_table_dirty = true;
// self.debug_line_header_dirty = true; self.debug_line_header_dirty = true;
// } }
// } }
const shsize: u64 = switch (self.ptr_width) { const shsize: u64 = switch (self.ptr_width) {
.p32 => @sizeOf(elf.Elf32_Shdr), .p32 => @sizeOf(elf.Elf32_Shdr),
@ -956,26 +956,25 @@ pub fn growNonAllocSection(
} }
pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void { pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void {
_ = shdr_index;
self.shdr_table_dirty = true; // TODO look into only writing one section self.shdr_table_dirty = true; // TODO look into only writing one section
if (phdr_index) |_| { if (phdr_index) |_| {
self.phdr_table_dirty = true; // TODO look into making only the one program header dirty self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
} }
// if (self.dwarf) |_| { if (self.dwarf) |_| {
// if (self.debug_info_section_index.? == shdr_index) { if (self.debug_info_section_index.? == shdr_index) {
// self.debug_info_header_dirty = true; self.debug_info_header_dirty = true;
// } else if (self.debug_line_section_index.? == shdr_index) { } else if (self.debug_line_section_index.? == shdr_index) {
// self.debug_line_header_dirty = true; self.debug_line_header_dirty = true;
// } else if (self.debug_abbrev_section_index.? == shdr_index) { } else if (self.debug_abbrev_section_index.? == shdr_index) {
// self.debug_abbrev_section_dirty = true; self.debug_abbrev_section_dirty = true;
// } else if (self.debug_str_section_index.? == shdr_index) { } else if (self.debug_str_section_index.? == shdr_index) {
// self.debug_strtab_dirty = true; self.debug_strtab_dirty = true;
// } else if (self.debug_aranges_section_index.? == shdr_index) { } else if (self.debug_aranges_section_index.? == shdr_index) {
// self.debug_aranges_section_dirty = true; self.debug_aranges_section_dirty = true;
// } }
// } }
} }
pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
@ -1015,14 +1014,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
// TODO This linker code currently assumes there is only 1 compilation unit and it // TODO This linker code currently assumes there is only 1 compilation unit and it
// corresponds to the Zig source code. // corresponds to the Zig source code.
const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
_ = module;
const target_endian = self.base.options.target.cpu.arch.endian(); const target_endian = self.base.options.target.cpu.arch.endian();
const foreign_endian = target_endian != builtin.cpu.arch.endian(); const foreign_endian = target_endian != builtin.cpu.arch.endian();
// if (self.dwarf) |*dw| { if (self.dwarf) |*dw| {
// try dw.flushModule(module); try dw.flushModule(module);
// } }
{ {
var it = self.relocs.iterator(); var it = self.relocs.iterator();
@ -1068,43 +1066,43 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
self.logSymtab(); self.logSymtab();
} }
// if (self.dwarf) |*dw| { if (self.dwarf) |*dw| {
// if (self.debug_abbrev_section_dirty) { if (self.debug_abbrev_section_dirty) {
// try dw.writeDbgAbbrev(); try dw.writeDbgAbbrev();
// if (!self.shdr_table_dirty) { if (!self.shdr_table_dirty) {
// // Then it won't get written with the others and we need to do it. // Then it won't get written with the others and we need to do it.
// try self.writeSectHeader(self.debug_abbrev_section_index.?); try self.writeSectHeader(self.debug_abbrev_section_index.?);
// } }
// self.debug_abbrev_section_dirty = false; self.debug_abbrev_section_dirty = false;
// } }
// if (self.debug_info_header_dirty) { if (self.debug_info_header_dirty) {
// // Currently only one compilation unit is supported, so the address range is simply // Currently only one compilation unit is supported, so the address range is simply
// // identical to the main program header virtual address and memory size. // identical to the main program header virtual address and memory size.
// const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
// const low_pc = text_phdr.p_vaddr; const low_pc = text_phdr.p_vaddr;
// const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
// try dw.writeDbgInfoHeader(module, low_pc, high_pc); try dw.writeDbgInfoHeader(module, low_pc, high_pc);
// self.debug_info_header_dirty = false; self.debug_info_header_dirty = false;
// } }
// if (self.debug_aranges_section_dirty) { if (self.debug_aranges_section_dirty) {
// // Currently only one compilation unit is supported, so the address range is simply // Currently only one compilation unit is supported, so the address range is simply
// // identical to the main program header virtual address and memory size. // identical to the main program header virtual address and memory size.
// const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
// try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
// if (!self.shdr_table_dirty) { if (!self.shdr_table_dirty) {
// // Then it won't get written with the others and we need to do it. // Then it won't get written with the others and we need to do it.
// try self.writeSectHeader(self.debug_aranges_section_index.?); try self.writeSectHeader(self.debug_aranges_section_index.?);
// } }
// self.debug_aranges_section_dirty = false; self.debug_aranges_section_dirty = false;
// } }
// if (self.debug_line_header_dirty) { if (self.debug_line_header_dirty) {
// try dw.writeDbgLineHeader(); try dw.writeDbgLineHeader();
// self.debug_line_header_dirty = false; self.debug_line_header_dirty = false;
// } }
// } }
if (self.phdr_table_dirty) { if (self.phdr_table_dirty) {
const phsize: u64 = switch (self.ptr_width) { const phsize: u64 = switch (self.ptr_width) {
@ -1162,15 +1160,15 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
} }
} }
// if (self.dwarf) |dwarf| { if (self.dwarf) |dwarf| {
// const shdr_index = self.debug_str_section_index.?; const shdr_index = self.debug_str_section_index.?;
// if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) { if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
// try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false); try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false);
// const debug_strtab_sect = self.sections.items(.shdr)[shdr_index]; const debug_strtab_sect = self.sections.items(.shdr)[shdr_index];
// try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset); try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset);
// self.debug_strtab_dirty = false; self.debug_strtab_dirty = false;
// } }
// } }
if (self.shdr_table_dirty) { if (self.shdr_table_dirty) {
const shsize: u64 = switch (self.ptr_width) { const shsize: u64 = switch (self.ptr_width) {
@ -2100,10 +2098,6 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void {
self.getAtomPtr(atom_index).local_sym_index = 0; self.getAtomPtr(atom_index).local_sym_index = 0;
self.offset_table_free_list.append(self.base.allocator, atom.offset_table_index) catch {}; self.offset_table_free_list.append(self.base.allocator, atom.offset_table_index) catch {};
// if (self.dwarf) |*dw| {
// dw.freeAtom(&atom.dbg_info_atom);
// }
} }
fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void { fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void {
@ -2133,7 +2127,6 @@ pub fn createAtom(self: *Elf) !Atom.Index {
.offset_table_index = offset_table_index, .offset_table_index = offset_table_index,
.prev_index = null, .prev_index = null,
.next_index = null, .next_index = null,
.dbg_info_atom = undefined,
}; };
log.debug("creating ATOM(%{d}) at index {d}", .{ local_sym_index, atom_index }); log.debug("creating ATOM(%{d}) at index {d}", .{ local_sym_index, atom_index });
return atom_index; return atom_index;
@ -2219,16 +2212,16 @@ fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignme
try self.growAllocSection(sym.st_shndx, needed_size); try self.growAllocSection(sym.st_shndx, needed_size);
maybe_last_atom_index.* = atom_index; maybe_last_atom_index.* = atom_index;
// if (self.dwarf) |_| { if (self.dwarf) |_| {
// // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
// // range of the compilation unit. When we expand the text section, this range changes, // range of the compilation unit. When we expand the text section, this range changes,
// // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty. // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
// self.debug_info_header_dirty = true; self.debug_info_header_dirty = true;
// // This becomes dirty for the same reason. We could potentially make this more // This becomes dirty for the same reason. We could potentially make this more
// // fine-grained with the addition of support for more compilation units. It is planned to // fine-grained with the addition of support for more compilation units. It is planned to
// // model each package as a different compilation unit. // model each package as a different compilation unit.
// self.debug_aranges_section_dirty = true; self.debug_aranges_section_dirty = true;
// } }
} }
shdr.sh_addralign = math.max(shdr.sh_addralign, alignment); shdr.sh_addralign = math.max(shdr.sh_addralign, alignment);
@ -2333,9 +2326,9 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
kv.value.exports.deinit(self.base.allocator); kv.value.exports.deinit(self.base.allocator);
} }
// if (self.dwarf) |*dw| { if (self.dwarf) |*dw| {
// dw.freeDecl(decl); dw.freeDecl(decl_index);
// } }
} }
pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {
@ -2471,15 +2464,15 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
var code_buffer = std.ArrayList(u8).init(self.base.allocator); var code_buffer = std.ArrayList(u8).init(self.base.allocator);
defer code_buffer.deinit(); defer code_buffer.deinit();
// var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
// defer if (decl_state) |*ds| ds.deinit(); defer if (decl_state) |*ds| ds.deinit();
// const res = if (decl_state) |*ds| const res = if (decl_state) |*ds|
// try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
// .dwarf = ds, .dwarf = ds,
// }) })
// else else
const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
const code = switch (res) { const code = switch (res) {
.ok => code_buffer.items, .ok => code_buffer.items,
@ -2490,16 +2483,15 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
}, },
}; };
const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC); const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC);
_ = local_sym; if (decl_state) |*ds| {
// if (decl_state) |*ds| { try self.dwarf.?.commitDeclState(
// try self.dwarf.?.commitDeclState( module,
// module, decl_index,
// decl_index, local_sym.st_value,
// local_sym.st_value, local_sym.st_size,
// local_sym.st_size, ds,
// ds, );
// ); }
// }
// Since we updated the vaddr and the size, each corresponding export // Since we updated the vaddr and the size, each corresponding export
// symbol also needs to be updated. // symbol also needs to be updated.
@ -2536,22 +2528,22 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
var code_buffer = std.ArrayList(u8).init(self.base.allocator); var code_buffer = std.ArrayList(u8).init(self.base.allocator);
defer code_buffer.deinit(); defer code_buffer.deinit();
// var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
// defer if (decl_state) |*ds| ds.deinit(); defer if (decl_state) |*ds| ds.deinit();
// TODO implement .debug_info for global variables // TODO implement .debug_info for global variables
const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
// const res = if (decl_state) |*ds| const res = if (decl_state) |*ds|
// try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
// .ty = decl.ty, .ty = decl.ty,
// .val = decl_val, .val = decl_val,
// }, &code_buffer, .{ }, &code_buffer, .{
// .dwarf = ds, .dwarf = ds,
// }, .{ }, .{
// .parent_atom_index = atom.getSymbolIndex().?, .parent_atom_index = atom.getSymbolIndex().?,
// }) })
// else else
const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
.ty = decl.ty, .ty = decl.ty,
.val = decl_val, .val = decl_val,
}, &code_buffer, .none, .{ }, &code_buffer, .none, .{
@ -2568,16 +2560,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
}; };
const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT); const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT);
_ = local_sym; if (decl_state) |*ds| {
// if (decl_state) |*ds| { try self.dwarf.?.commitDeclState(
// try self.dwarf.?.commitDeclState( module,
// module, decl_index,
// decl_index, local_sym.st_value,
// local_sym.st_value, local_sym.st_size,
// local_sym.st_size, ds,
// ds, );
// ); }
// }
// Since we updated the vaddr and the size, each corresponding export // Since we updated the vaddr and the size, each corresponding export
// symbol also needs to be updated. // symbol also needs to be updated.
@ -2737,19 +2728,20 @@ pub fn updateDeclExports(
} }
/// Must be called only after a successful call to `updateDecl`. /// Must be called only after a successful call to `updateDecl`.
pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl) !void { pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.Index) !void {
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
const decl = mod.declPtr(decl_index);
const decl_name = try decl.getFullyQualifiedName(mod); const decl_name = try decl.getFullyQualifiedName(mod);
defer self.base.allocator.free(decl_name); defer self.base.allocator.free(decl_name);
log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
if (self.llvm_object) |_| return; if (self.llvm_object) |_| return;
// if (self.dwarf) |*dw| { if (self.dwarf) |*dw| {
// try dw.updateDeclLineNumber(decl); try dw.updateDeclLineNumber(mod, decl_index);
// } }
} }
pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void { pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void {

View file

@ -4,7 +4,6 @@ const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
const elf = std.elf; const elf = std.elf;
const Dwarf = @import("../Dwarf.zig");
const Elf = @import("../Elf.zig"); const Elf = @import("../Elf.zig");
/// Each decl always gets a local symbol with the fully qualified name. /// Each decl always gets a local symbol with the fully qualified name.
@ -23,8 +22,6 @@ offset_table_index: u32,
prev_index: ?Index, prev_index: ?Index,
next_index: ?Index, next_index: ?Index,
dbg_info_atom: Dwarf.Atom,
pub const Index = u32; pub const Index = u32;
pub const Reloc = struct { pub const Reloc = struct {

View file

@ -472,9 +472,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
// if (self.d_sym) |*d_sym| { if (self.d_sym) |*d_sym| {
// try d_sym.dwarf.flushModule(module); try d_sym.dwarf.flushModule(module);
// } }
var libs = std.StringArrayHashMap(link.SystemLib).init(arena); var libs = std.StringArrayHashMap(link.SystemLib).init(arena);
try resolveLibSystem( try resolveLibSystem(
@ -664,10 +664,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
try self.writeCodeSignature(comp, csig); // code signing always comes last try self.writeCodeSignature(comp, csig); // code signing always comes last
} }
// if (self.d_sym) |*d_sym| { if (self.d_sym) |*d_sym| {
// // Flush debug symbols bundle. // Flush debug symbols bundle.
// try d_sym.flushModule(self); try d_sym.flushModule(self);
// } }
// if (build_options.enable_link_snapshots) { // if (build_options.enable_link_snapshots) {
// if (self.base.options.enable_link_snapshots) // if (self.base.options.enable_link_snapshots)
@ -1089,7 +1089,6 @@ pub fn createAtom(self: *MachO) !Atom.Index {
.alignment = 0, .alignment = 0,
.prev_index = null, .prev_index = null,
.next_index = null, .next_index = null,
.dbg_info_atom = undefined,
}; };
log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index }); log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index });
return atom_index; return atom_index;
@ -1724,9 +1723,9 @@ pub fn deinit(self: *MachO) void {
if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa); if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
} }
// if (self.d_sym) |*d_sym| { if (self.d_sym) |*d_sym| {
// d_sym.deinit(); d_sym.deinit();
// } }
self.got_entries.deinit(gpa); self.got_entries.deinit(gpa);
self.got_entries_free_list.deinit(gpa); self.got_entries_free_list.deinit(gpa);
@ -1804,9 +1803,8 @@ pub fn deinit(self: *MachO) void {
} }
fn freeAtom(self: *MachO, atom_index: Atom.Index) void { fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
log.debug("freeAtom {d}", .{atom_index});
const gpa = self.base.allocator; const gpa = self.base.allocator;
log.debug("freeAtom {d}", .{atom_index});
// Remove any relocs and base relocs associated with this Atom // Remove any relocs and base relocs associated with this Atom
Atom.freeRelocations(self, atom_index); Atom.freeRelocations(self, atom_index);
@ -1876,9 +1874,9 @@ fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
}; };
_ = self.got_entries_table.remove(got_target); _ = self.got_entries_table.remove(got_target);
// if (self.d_sym) |*d_sym| { if (self.d_sym) |*d_sym| {
// d_sym.swapRemoveRelocs(sym_index); d_sym.swapRemoveRelocs(sym_index);
// } }
log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index });
} }
@ -1887,10 +1885,6 @@ fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
_ = self.atom_by_index_table.remove(sym_index); _ = self.atom_by_index_table.remove(sym_index);
log.debug(" adding local symbol index {d} to free list", .{sym_index}); log.debug(" adding local symbol index {d} to free list", .{sym_index});
self.getAtomPtr(atom_index).sym_index = 0; self.getAtomPtr(atom_index).sym_index = 0;
// if (self.d_sym) |*d_sym| {
// d_sym.dwarf.freeAtom(&atom.dbg_info_atom);
// }
} }
fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {
@ -2020,23 +2014,22 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
Atom.freeRelocations(self, atom_index); Atom.freeRelocations(self, atom_index);
const atom = self.getAtom(atom_index); const atom = self.getAtom(atom_index);
_ = atom;
var code_buffer = std.ArrayList(u8).init(self.base.allocator); var code_buffer = std.ArrayList(u8).init(self.base.allocator);
defer code_buffer.deinit(); defer code_buffer.deinit();
// var decl_state = if (self.d_sym) |*d_sym| var decl_state = if (self.d_sym) |*d_sym|
// try d_sym.dwarf.initDeclState(module, decl_index) try d_sym.dwarf.initDeclState(module, decl_index)
// else else
// null; null;
// defer if (decl_state) |*ds| ds.deinit(); defer if (decl_state) |*ds| ds.deinit();
// const res = if (decl_state) |*ds| const res = if (decl_state) |*ds|
// try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
// .dwarf = ds, .dwarf = ds,
// }) })
// else else
const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
const code = switch (res) { const code = switch (res) {
.ok => code_buffer.items, .ok => code_buffer.items,
@ -2048,11 +2041,10 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
}; };
const addr = try self.updateDeclCode(decl_index, code); const addr = try self.updateDeclCode(decl_index, code);
_ = addr;
// if (decl_state) |*ds| { if (decl_state) |*ds| {
// try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds);
// } }
// Since we updated the vaddr and the size, each corresponding export symbol also // Since we updated the vaddr and the size, each corresponding export symbol also
// needs to be updated. // needs to be updated.
@ -2154,24 +2146,24 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
var code_buffer = std.ArrayList(u8).init(self.base.allocator); var code_buffer = std.ArrayList(u8).init(self.base.allocator);
defer code_buffer.deinit(); defer code_buffer.deinit();
// var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym|
// try d_sym.dwarf.initDeclState(module, decl_index) try d_sym.dwarf.initDeclState(module, decl_index)
// else else
// null; null;
// defer if (decl_state) |*ds| ds.deinit(); defer if (decl_state) |*ds| ds.deinit();
const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
// const res = if (decl_state) |*ds| const res = if (decl_state) |*ds|
// try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
// .ty = decl.ty, .ty = decl.ty,
// .val = decl_val, .val = decl_val,
// }, &code_buffer, .{ }, &code_buffer, .{
// .dwarf = ds, .dwarf = ds,
// }, .{ }, .{
// .parent_atom_index = atom.getSymbolIndex().?, .parent_atom_index = atom.getSymbolIndex().?,
// }) })
// else else
const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
.ty = decl.ty, .ty = decl.ty,
.val = decl_val, .val = decl_val,
}, &code_buffer, .none, .{ }, &code_buffer, .none, .{
@ -2187,11 +2179,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
}, },
}; };
const addr = try self.updateDeclCode(decl_index, code); const addr = try self.updateDeclCode(decl_index, code);
_ = addr;
// if (decl_state) |*ds| { if (decl_state) |*ds| {
// try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds);
// } }
// Since we updated the vaddr and the size, each corresponding export symbol also // Since we updated the vaddr and the size, each corresponding export symbol also
// needs to be updated. // needs to be updated.
@ -2432,13 +2423,10 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8)
return atom.getSymbol(self).n_value; return atom.getSymbol(self).n_value;
} }
pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void { pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void {
_ = decl; if (self.d_sym) |*d_sym| {
_ = self; try d_sym.dwarf.updateDeclLineNumber(module, decl_index);
_ = module; }
// if (self.d_sym) |*d_sym| {
// try d_sym.dwarf.updateDeclLineNumber(decl);
// }
} }
pub fn updateDeclExports( pub fn updateDeclExports(
@ -2611,9 +2599,9 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {
kv.value.exports.deinit(self.base.allocator); kv.value.exports.deinit(self.base.allocator);
} }
// if (self.d_sym) |*d_sym| { if (self.d_sym) |*d_sym| {
// d_sym.dwarf.freeDecl(decl); d_sym.dwarf.freeDecl(decl_index);
// } }
} }
pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 { pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 {

View file

@ -13,7 +13,6 @@ const trace = @import("../../tracy.zig").trace;
const Allocator = mem.Allocator; const Allocator = mem.Allocator;
const Arch = std.Target.Cpu.Arch; const Arch = std.Target.Cpu.Arch;
const Dwarf = @import("../Dwarf.zig");
const MachO = @import("../MachO.zig"); const MachO = @import("../MachO.zig");
const Relocation = @import("Relocation.zig"); const Relocation = @import("Relocation.zig");
const SymbolWithLoc = MachO.SymbolWithLoc; const SymbolWithLoc = MachO.SymbolWithLoc;
@ -43,8 +42,6 @@ alignment: u32,
next_index: ?Index, next_index: ?Index,
prev_index: ?Index, prev_index: ?Index,
dbg_info_atom: Dwarf.Atom,
pub const Index = u32; pub const Index = u32;
pub const Binding = struct { pub const Binding = struct {

View file

@ -1018,10 +1018,10 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
} }
/// Must be called only after a successful call to `updateDecl`. /// Must be called only after a successful call to `updateDecl`.
pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl: *const Module.Decl) !void { pub fn updateDeclLineNumber(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void {
_ = self; _ = self;
_ = mod; _ = mod;
_ = decl; _ = decl_index;
} }
pub fn getDeclVAddr( pub fn getDeclVAddr(

View file

@ -183,13 +183,9 @@ pub const Segment = struct {
pub const FnData = struct { pub const FnData = struct {
/// Reference to the wasm type that represents this function. /// Reference to the wasm type that represents this function.
type_index: u32, type_index: u32,
/// Contains debug information related to this function.
/// For Wasm, the offset is relative to the code-section.
src_fn: Dwarf.SrcFn,
pub const empty: FnData = .{ pub const empty: FnData = .{
.type_index = undefined, .type_index = undefined,
.src_fn = Dwarf.SrcFn.empty,
}; };
}; };
@ -1122,17 +1118,18 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
return wasm.finishUpdateDecl(decl, code); return wasm.finishUpdateDecl(decl, code);
} }
pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl: *const Module.Decl) !void { pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !void {
if (wasm.llvm_object) |_| return; if (wasm.llvm_object) |_| return;
if (wasm.dwarf) |*dw| { if (wasm.dwarf) |*dw| {
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
const decl = mod.declPtr(decl_index);
const decl_name = try decl.getFullyQualifiedName(mod); const decl_name = try decl.getFullyQualifiedName(mod);
defer wasm.base.allocator.free(decl_name); defer wasm.base.allocator.free(decl_name);
log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
try dw.updateDeclLineNumber(decl); try dw.updateDeclLineNumber(mod, decl_index);
} }
} }
@ -1460,10 +1457,9 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
_ = wasm.resolved_symbols.swapRemove(atom.symbolLoc()); _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc());
_ = wasm.symbol_atom.remove(atom.symbolLoc()); _ = wasm.symbol_atom.remove(atom.symbolLoc());
if (wasm.dwarf) |*dwarf| { // if (wasm.dwarf) |*dwarf| {
dwarf.freeDecl(decl); // dwarf.freeDecl(decl_index);
dwarf.freeAtom(&atom.dbg_info_atom); // }
}
atom.deinit(wasm.base.allocator); atom.deinit(wasm.base.allocator);
} }
@ -1882,7 +1878,6 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
.next = null, .next = null,
.prev = null, .prev = null,
.code = function_body.moveToUnmanaged(), .code = function_body.moveToUnmanaged(),
.dbg_info_atom = undefined,
}; };
try wasm.managed_atoms.append(wasm.base.allocator, atom); try wasm.managed_atoms.append(wasm.base.allocator, atom);
try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom); try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom);

View file

@ -4,7 +4,6 @@ const std = @import("std");
const types = @import("types.zig"); const types = @import("types.zig");
const Wasm = @import("../Wasm.zig"); const Wasm = @import("../Wasm.zig");
const Symbol = @import("Symbol.zig"); const Symbol = @import("Symbol.zig");
const Dwarf = @import("../Dwarf.zig");
const leb = std.leb; const leb = std.leb;
const log = std.log.scoped(.link); const log = std.log.scoped(.link);
@ -39,9 +38,6 @@ prev: ?*Atom,
/// When the parent atom is being freed, it will also do so for all local atoms. /// When the parent atom is being freed, it will also do so for all local atoms.
locals: std.ArrayListUnmanaged(Atom) = .{}, locals: std.ArrayListUnmanaged(Atom) = .{},
/// Represents the debug Atom that holds all debug information of this Atom.
dbg_info_atom: Dwarf.Atom,
/// Represents a default empty wasm `Atom` /// Represents a default empty wasm `Atom`
pub const empty: Atom = .{ pub const empty: Atom = .{
.alignment = 0, .alignment = 0,
@ -51,7 +47,6 @@ pub const empty: Atom = .{
.prev = null, .prev = null,
.size = 0, .size = 0,
.sym_index = 0, .sym_index = 0,
.dbg_info_atom = undefined,
}; };
/// Frees all resources owned by this `Atom`. /// Frees all resources owned by this `Atom`.