aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/aarch64/CodeGen.zig224
-rw-r--r--src/arch/arm/CodeGen.zig87
-rw-r--r--src/arch/riscv64/CodeGen.zig65
-rw-r--r--src/arch/sparc64/CodeGen.zig57
-rw-r--r--src/arch/wasm/CodeGen.zig69
-rw-r--r--src/arch/x86_64/CodeGen.zig247
-rw-r--r--src/codegen.zig13
-rw-r--r--src/link/Dwarf.zig234
8 files changed, 393 insertions, 603 deletions
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
index 52f9a544b1..9975e08ea9 100644
--- a/src/arch/aarch64/CodeGen.zig
+++ b/src/arch/aarch64/CodeGen.zig
@@ -146,11 +146,8 @@ const MCValue = union(enum) {
/// If the type is a pointer, it means the pointer address is at
/// this memory location.
memory: u64,
- /// The value is in memory but requires a linker relocation fixup:
- /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
- /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
- /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
- linker_load: struct { type: enum { got, direct, import }, sym_index: u32 },
+ /// The value is in memory but requires a linker relocation fixup.
+ linker_load: codegen.LinkerLoad,
/// The value is one of the stack variables.
///
/// If the type is a pointer, it means the pointer address is in
@@ -184,52 +181,34 @@ const DbgInfoReloc = struct {
else => unreachable,
}
}
-
fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {
- const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1];
-
switch (function.debug_output) {
.dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- switch (reloc.mcv) {
- .register => |reg| {
- try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // ULEB128 dwarf expression length
- reg.dwarfLocOp(),
- });
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try function.addDbgInfoTypeReloc(reloc.ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
- },
-
+ const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) {
+ .register => |reg| .{ .register = reg.dwarfLocOp() },
.stack_offset,
.stack_argument_offset,
- => |offset| {
+ => |offset| blk: {
const adjusted_offset = switch (reloc.mcv) {
.stack_offset => -@intCast(i32, offset),
.stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset),
else => unreachable,
};
-
- try dbg_info.ensureUnusedCapacity(8);
- dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
- const fixup = dbg_info.items.len;
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // we will backpatch it after we encode the displacement in LEB128
- Register.x29.dwarfLocOpDeref(), // frame pointer
- });
- leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable;
- dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try function.addDbgInfoTypeReloc(reloc.ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
-
+ break :blk .{ .stack = .{
+ .fp_register = Register.x29.dwarfLocOpDeref(),
+ .offset = adjusted_offset,
+ } };
},
-
else => unreachable, // not a possible argument
- }
+
+ };
+ try dw.genArgDbgInfo(
+ reloc.name,
+ reloc.ty,
+ function.bin_file.tag,
+ function.mod_fn.owner_decl,
+ loc,
+ );
},
.plan9 => {},
.none => {},
@@ -237,32 +216,20 @@ const DbgInfoReloc = struct {
}
fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
- const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1];
- const ty = switch (reloc.tag) {
- .dbg_var_ptr => reloc.ty.childType(),
- .dbg_var_val => reloc.ty,
+ const is_ptr = switch (reloc.tag) {
+ .dbg_var_ptr => true,
+ .dbg_var_val => false,
else => unreachable,
};
switch (function.debug_output) {
.dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
- const endian = function.target.cpu.arch.endian();
-
- switch (reloc.mcv) {
- .register => |reg| {
- try dbg_info.ensureUnusedCapacity(2);
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // ULEB128 dwarf expression length
- reg.dwarfLocOp(),
- });
- },
-
+ const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) {
+ .register => |reg| .{ .register = reg.dwarfLocOp() },
.ptr_stack_offset,
.stack_offset,
.stack_argument_offset,
- => |offset| {
+ => |offset| blk: {
const adjusted_offset = switch (reloc.mcv) {
.ptr_stack_offset,
.stack_offset,
@@ -270,110 +237,31 @@ const DbgInfoReloc = struct {
.stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset),
else => unreachable,
};
-
- try dbg_info.ensureUnusedCapacity(7);
- const fixup = dbg_info.items.len;
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // we will backpatch it after we encode the displacement in LEB128
- Register.x29.dwarfLocOpDeref(), // frame pointer
- });
- leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable;
- dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
- },
-
- .memory,
- .linker_load,
- => {
- const ptr_width = @intCast(u8, @divExact(function.target.cpu.arch.ptrBitWidth(), 8));
- const is_ptr = switch (reloc.tag) {
- .dbg_var_ptr => true,
- .dbg_var_val => false,
- else => unreachable,
- };
- try dbg_info.ensureUnusedCapacity(2 + ptr_width);
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1 + ptr_width + @boolToInt(is_ptr),
- DW.OP.addr, // literal address
- });
- const offset = @intCast(u32, dbg_info.items.len);
- const addr = switch (reloc.mcv) {
- .memory => |addr| addr,
- else => 0,
- };
- switch (ptr_width) {
- 0...4 => {
- try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
+ break :blk .{
+ .stack = .{
+ .fp_register = Register.x29.dwarfLocOpDeref(),
+ .offset = adjusted_offset,
},
- 5...8 => {
- try dbg_info.writer().writeInt(u64, addr, endian);
- },
- else => unreachable,
- }
- if (is_ptr) {
- // We need deref the address as we point to the value via GOT entry.
- try dbg_info.append(DW.OP.deref);
- }
- switch (reloc.mcv) {
- .linker_load => |load_struct| try dw.addExprlocReloc(
- load_struct.sym_index,
- offset,
- is_ptr,
- ),
- else => {},
- }
- },
-
- .immediate => |x| {
- try dbg_info.ensureUnusedCapacity(2);
- const fixup = dbg_info.items.len;
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1,
- if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
- });
- if (ty.isSignedInt()) {
- try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
- } else {
- try leb128.writeULEB128(dbg_info.writer(), x);
- }
- try dbg_info.append(DW.OP.stack_value);
- dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
- },
-
- .undef => {
- // DW.AT.location, DW.FORM.exprloc
- // uleb128(exprloc_len)
- // DW.OP.implicit_value uleb128(len_of_bytes) bytes
- const abi_size = @intCast(u32, ty.abiSize(function.target.*));
- var implicit_value_len = std.ArrayList(u8).init(function.gpa);
- defer implicit_value_len.deinit();
- try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
- const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
- try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
- try dbg_info.ensureUnusedCapacity(total_exprloc_len);
- dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
- dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
- dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
- },
-
- .none => {
- try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
- 2, DW.OP.lit0, DW.OP.stack_value,
- });
+ };
},
-
- else => {
- try dbg_info.ensureUnusedCapacity(2);
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, DW.OP.nop,
- });
+ .memory => |address| .{ .memory = address },
+ .linker_load => |linker_load| .{ .linker_load = linker_load },
+ .immediate => |x| .{ .immediate = x },
+ .undef => .undef,
+ .none => .none,
+ else => blk: {
log.debug("TODO generate debug info for {}", .{reloc.mcv});
+ break :blk .nop;
},
- }
-
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try function.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ };
+ try dw.genVarDbgInfo(
+ reloc.name,
+ reloc.ty,
+ function.bin_file.tag,
+ function.mod_fn.owner_decl,
+ is_ptr,
+ loc,
+ );
},
.plan9 => {},
.none => {},
@@ -1079,28 +967,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
try table.ensureUnusedCapacity(self.gpa, additional_count);
}
-/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
-/// after codegen for this symbol is done.
-fn addDbgInfoTypeReloc(self: Self, ty: Type) !void {
- switch (self.debug_output) {
- .dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- const index = dbg_info.items.len;
- try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
- const mod = self.bin_file.options.module.?;
- const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
- const atom = switch (self.bin_file.tag) {
- .elf => &fn_owner_decl.link.elf.dbg_info_atom,
- .macho => &fn_owner_decl.link.macho.dbg_info_atom,
- else => unreachable,
- };
- try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
- },
- .plan9 => {},
- .none => {},
- }
-}
-
fn allocMem(
self: *Self,
abi_size: u32,
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig
index 970b9376e5..7a9e00b83f 100644
--- a/src/arch/arm/CodeGen.zig
+++ b/src/arch/arm/CodeGen.zig
@@ -4029,86 +4029,35 @@ fn genInlineMemsetCode(
// end:
}
-/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
-/// after codegen for this symbol is done.
-fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
- switch (self.debug_output) {
- .dwarf => |dw| {
- assert(ty.hasRuntimeBits());
- const dbg_info = &dw.dbg_info;
- const index = dbg_info.items.len;
- try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
- const mod = self.bin_file.options.module.?;
- const atom = switch (self.bin_file.tag) {
- .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom,
- .macho => unreachable,
- else => unreachable,
- };
- try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
- },
- .plan9 => {},
- .none => {},
- }
-}
-
-fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void {
+fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void {
const mcv = self.args[arg_index];
const ty = self.air.instructions.items(.data)[inst].ty;
const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
- const name_with_null = name.ptr[0 .. name.len + 1];
- switch (mcv) {
- .register => |reg| {
- switch (self.debug_output) {
- .dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // ULEB128 dwarf expression length
- reg.dwarfLocOp(),
- });
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
- },
- .plan9 => {},
- .none => {},
- }
- },
- .stack_offset,
- .stack_argument_offset,
- => {
- switch (self.debug_output) {
- .dwarf => |dw| {
+ switch (self.debug_output) {
+ .dwarf => |dw| {
+ const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
+ .register => |reg| .{ .register = reg.dwarfLocOp() },
+ .stack_offset,
+ .stack_argument_offset,
+ => blk: {
const adjusted_stack_offset = switch (mcv) {
.stack_offset => |offset| -@intCast(i32, offset),
.stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset),
else => unreachable,
};
-
- const dbg_info = &dw.dbg_info;
- try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
-
- // Get length of the LEB128 stack offset
- var counting_writer = std.io.countingWriter(std.io.null_writer);
- leb128.writeILEB128(counting_writer.writer(), adjusted_stack_offset) catch unreachable;
-
- // DW.AT.location, DW.FORM.exprloc
- // ULEB128 dwarf expression length
- try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1);
- try dbg_info.append(DW.OP.breg11);
- try leb128.writeILEB128(dbg_info.writer(), adjusted_stack_offset);
-
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ break :blk .{ .stack = .{
+ .fp_register = DW.OP.breg11,
+ .offset = adjusted_stack_offset,
+ } };
},
- .plan9 => {},
- .none => {},
- }
+ else => unreachable, // not a possible argument
+
+ };
+ try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc);
},
- else => unreachable, // not a possible argument
+ .plan9 => {},
+ .none => {},
}
}
diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig
index ed132d3fbb..6a54ffeea2 100644
--- a/src/arch/riscv64/CodeGen.zig
+++ b/src/arch/riscv64/CodeGen.zig
@@ -772,28 +772,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
try table.ensureUnusedCapacity(self.gpa, additional_count);
}
-/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
-/// after codegen for this symbol is done.
-fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
- switch (self.debug_output) {
- .dwarf => |dw| {
- assert(ty.hasRuntimeBits());
- const dbg_info = &dw.dbg_info;
- const index = dbg_info.items.len;
- try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
- const mod = self.bin_file.options.module.?;
- const atom = switch (self.bin_file.tag) {
- .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom,
- .macho => unreachable,
- else => unreachable,
- };
- try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
- },
- .plan9 => {},
- .none => {},
- }
-}
-
fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
if (abi_align > self.stack_align)
self.stack_align = abi_align;
@@ -1624,39 +1602,24 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
return self.fail("TODO implement codegen airFieldParentPtr", .{});
}
-fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
+fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
const ty = self.air.instructions.items(.data)[inst].ty;
const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
- const name_with_null = name.ptr[0 .. name.len + 1];
- switch (mcv) {
- .register => |reg| {
- switch (self.debug_output) {
- .dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // ULEB128 dwarf expression length
- reg.dwarfLocOp(),
- });
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
- },
- .plan9 => {},
- .none => {},
- }
- },
- .stack_offset => |offset| {
- _ = offset;
- switch (self.debug_output) {
- .dwarf => {},
- .plan9 => {},
- .none => {},
- }
+ switch (self.debug_output) {
+ .dwarf => |dw| switch (mcv) {
+ .register => |reg| try dw.genArgDbgInfo(
+ name,
+ ty,
+ self.bin_file.tag,
+ self.mod_fn.owner_decl,
+ .{ .register = reg.dwarfLocOp() },
+ ),
+ .stack_offset => {},
+ else => {},
},
- else => {},
+ .plan9 => {},
+ .none => {},
}
}
diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig
index f22849c652..9f345767de 100644
--- a/src/arch/sparc64/CodeGen.zig
+++ b/src/arch/sparc64/CodeGen.zig
@@ -2460,26 +2460,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
// Common helper functions
-/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
-/// after codegen for this symbol is done.
-fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
- switch (self.debug_output) {
- .dwarf => |dw| {
- assert(ty.hasRuntimeBits());
- const dbg_info = &dw.dbg_info;
- const index = dbg_info.items.len;
- try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
- const mod = self.bin_file.options.module.?;
- const atom = switch (self.bin_file.tag) {
- .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom,
- else => unreachable,
- };
- try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
- },
- else => {},
- }
-}
-
fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
const gpa = self.gpa;
try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
@@ -3272,35 +3252,20 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
self.finishAirBookkeeping();
}
-fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
+fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
const ty = self.air.instructions.items(.data)[inst].ty;
const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
- const name_with_null = name.ptr[0 .. name.len + 1];
- switch (mcv) {
- .register => |reg| {
- switch (self.debug_output) {
- .dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // ULEB128 dwarf expression length
- reg.dwarfLocOp(),
- });
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
- },
- else => {},
- }
- },
- .stack_offset => |offset| {
- _ = offset;
- switch (self.debug_output) {
- .dwarf => {},
- else => {},
- }
+ switch (self.debug_output) {
+ .dwarf => |dw| switch (mcv) {
+ .register => |reg| try dw.genArgDbgInfo(
+ name,
+ ty,
+ self.bin_file.tag,
+ self.mod_fn.owner_decl,
+ .{ .register = reg.dwarfLocOp() },
+ ),
+ else => {},
},
else => {},
}
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index ebfff25b2f..c424c7b59d 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1291,23 +1291,6 @@ fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, target:
}
}
-/// For a given `Type`, add debug information to .debug_info at the current position.
-/// The actual bytes will be written to the position after relocation.
-fn addDbgInfoTypeReloc(func: *CodeGen, ty: Type) !void {
- switch (func.debug_output) {
- .dwarf => |dwarf| {
- assert(ty.hasRuntimeBitsIgnoreComptime());
- const dbg_info = &dwarf.dbg_info;
- const index = dbg_info.items.len;
- try dbg_info.resize(index + 4);
- const atom = &func.decl.link.wasm.dbg_info_atom;
- try dwarf.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
- },
- .plan9 => unreachable,
- .none => {},
- }
-}
-
/// Lowers a Zig type and its value based on a given calling convention to ensure
/// it matches the ABI.
fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void {
@@ -2358,24 +2341,9 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.dwarf => |dwarf| {
// TODO: Get the original arg index rather than wasm arg index
const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, arg_index);
- const leb_size = link.File.Wasm.getULEB128Size(arg.local.value);
- const dbg_info = &dwarf.dbg_info;
- try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1);
- // wasm locations are encoded as follow:
- // DW_OP_WASM_location wasm-op
- // where wasm-op is defined as
- // wasm-op := wasm-local | wasm-global | wasm-operand_stack
- // where each argument is encoded as
- // <opcode> i:uleb128
- dbg_info.appendSliceAssumeCapacity(&.{
- @enumToInt(link.File.Dwarf.AbbrevKind.parameter),
- std.dwarf.OP.WASM_location,
- std.dwarf.OP.WASM_local,
+ try dwarf.genArgDbgInfo(name, arg_ty, .wasm, func.mod_fn.owner_decl, .{
+ .wasm_local = arg.local.value,
});
- leb.writeULEB128(dbg_info.writer(), arg.local.value) catch unreachable;
- try func.addDbgInfoTypeReloc(arg_ty);
- dbg_info.appendSliceAssumeCapacity(name);
- dbg_info.appendAssumeCapacity(0);
},
else => {},
}
@@ -5345,38 +5313,21 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void {
const pl_op = func.air.instructions.items(.data)[inst].pl_op;
const ty = func.air.typeOf(pl_op.operand);
const operand = try func.resolveInst(pl_op.operand);
- const op_ty = if (is_ptr) ty.childType() else ty;
- log.debug("airDbgVar: %{d}: {}, {}", .{ inst, op_ty.fmtDebug(), operand });
+ log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand });
const name = func.air.nullTerminatedString(pl_op.payload);
log.debug(" var name = ({s})", .{name});
- const dbg_info = &func.debug_output.dwarf.dbg_info;
- try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
- switch (operand) {
- .local => |local| {
- const leb_size = link.File.Wasm.getULEB128Size(local.value);
- try dbg_info.ensureUnusedCapacity(2 + leb_size);
- // wasm locals are encoded as follow:
- // DW_OP_WASM_location wasm-op
- // where wasm-op is defined as
- // wasm-op := wasm-local | wasm-global | wasm-operand_stack
- // where wasm-local is encoded as
- // wasm-local := 0x00 i:uleb128
- dbg_info.appendSliceAssumeCapacity(&.{
- std.dwarf.OP.WASM_location,
- std.dwarf.OP.WASM_local,
- });
- leb.writeULEB128(dbg_info.writer(), local.value) catch unreachable;
+ const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (operand) {
+ .local => |local| .{ .wasm_local = local.value },
+ else => blk: {
+ log.debug("TODO generate debug info for {}", .{operand});
+ break :blk .nop;
},
- else => {}, // TODO
- }
+ };
+ try func.debug_output.dwarf.genVarDbgInfo(name, ty, .wasm, func.mod_fn.owner_decl, is_ptr, loc);
- try dbg_info.ensureUnusedCapacity(5 + name.len + 1);
- try func.addDbgInfoTypeReloc(op_ty);
- dbg_info.appendSliceAssumeCapacity(name);
- dbg_info.appendAssumeCapacity(0);
func.finishAir(inst, .none, &.{});
}
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 9efd50aec4..ae7cbc762d 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -128,11 +128,8 @@ pub const MCValue = union(enum) {
/// The value is in memory at a hard-coded address.
/// If the type is a pointer, it means the pointer address is at this memory location.
memory: u64,
- /// The value is in memory but requires a linker relocation fixup:
- /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
- /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
- /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
- linker_load: struct { type: enum { got, direct, import }, sym_index: u32 },
+ /// The value is in memory but requires a linker relocation fixup.
+ linker_load: codegen.LinkerLoad,
/// The value is one of the stack variables.
/// If the type is a pointer, it means the pointer address is in the stack at this offset.
stack_offset: i32,
@@ -3818,41 +3815,60 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
}
fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
- const name_with_null = name.ptr[0 .. name.len + 1];
switch (self.debug_output) {
.dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- switch (mcv) {
- .register => |reg| {
- try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // ULEB128 dwarf expression length
- reg.dwarfLocOp(),
- });
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
+ .register => |reg| .{ .register = reg.dwarfLocOp() },
+ .stack_offset => |off| .{
+ .stack = .{
+ // TODO handle -fomit-frame-pointer
+ .fp_register = Register.rbp.dwarfLocOpDeref(),
+ .offset = -off,
+ },
},
+ else => unreachable, // not a valid function parameter
+ };
+ try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc);
+ },
+ .plan9 => {},
+ .none => {},
+ }
+}
- .stack_offset => |off| {
- try dbg_info.ensureUnusedCapacity(8);
- dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
- const fixup = dbg_info.items.len;
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // we will backpatch it after we encode the displacement in LEB128
- Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer
- });
- leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
- dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+fn genVarDbgInfo(
+ self: Self,
+ tag: Air.Inst.Tag,
+ ty: Type,
+ mcv: MCValue,
+ name: [:0]const u8,
+) !void {
+ const is_ptr = switch (tag) {
+ .dbg_var_ptr => true,
+ .dbg_var_val => false,
+ else => unreachable,
+ };
+ switch (self.debug_output) {
+ .dwarf => |dw| {
+ const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
+ .register => |reg| .{ .register = reg.dwarfLocOp() },
+ .ptr_stack_offset,
+ .stack_offset,
+ => |off| .{ .stack = .{
+ .fp_register = Register.rbp.dwarfLocOpDeref(),
+ .offset = -off,
+ } },
+ .memory => |address| .{ .memory = address },
+ .linker_load => |linker_load| .{ .linker_load = linker_load },
+ .immediate => |x| .{ .immediate = x },
+ .undef => .undef,
+ .none => .none,
+ else => blk: {
+ log.debug("TODO generate debug info for {}", .{mcv});
+ break :blk .nop;
},
-
- else => unreachable, // not a valid function parameter
- }
+ };
+ try dw.genVarDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, is_ptr, loc);
},
.plan9 => {},
.none => {},
@@ -4418,172 +4434,11 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const name = self.air.nullTerminatedString(pl_op.payload);
const tag = self.air.instructions.items(.tag)[inst];
- switch (tag) {
- .dbg_var_ptr => try self.genVarDbgInfo(tag, ty.childType(), mcv, name),
- .dbg_var_val => try self.genVarDbgInfo(tag, ty, mcv, name),
- else => unreachable,
- }
+ try self.genVarDbgInfo(tag, ty, mcv, name);
return self.finishAir(inst, .dead, .{ operand, .none, .none });
}
-fn genVarDbgInfo(
- self: Self,
- tag: Air.Inst.Tag,
- ty: Type,
- mcv: MCValue,
- name: [:0]const u8,
-) !void {
- const name_with_null = name.ptr[0 .. name.len + 1];
- switch (self.debug_output) {
- .dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
- const endian = self.target.cpu.arch.endian();
-
- switch (mcv) {
- .register => |reg| {
- try dbg_info.ensureUnusedCapacity(2);
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // ULEB128 dwarf expression length
- reg.dwarfLocOp(),
- });
- },
-
- .ptr_stack_offset,
- .stack_offset,
- => |off| {
- try dbg_info.ensureUnusedCapacity(7);
- const fixup = dbg_info.items.len;
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, // we will backpatch it after we encode the displacement in LEB128
- Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer
- });
- leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
- dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
- },
-
- .memory,
- .linker_load,
- => {
- const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
- const is_ptr = switch (tag) {
- .dbg_var_ptr => true,
- .dbg_var_val => false,
- else => unreachable,
- };
- try dbg_info.ensureUnusedCapacity(2 + ptr_width);
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1 + ptr_width + @boolToInt(is_ptr),
- DW.OP.addr, // literal address
- });
- const offset = @intCast(u32, dbg_info.items.len);
- const addr = switch (mcv) {
- .memory => |addr| addr,
- else => 0,
- };
- switch (ptr_width) {
- 0...4 => {
- try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
- },
- 5...8 => {
- try dbg_info.writer().writeInt(u64, addr, endian);
- },
- else => unreachable,
- }
- if (is_ptr) {
- // We need deref the address as we point to the value via GOT entry.
- try dbg_info.append(DW.OP.deref);
- }
- switch (mcv) {
- .linker_load => |load_struct| try dw.addExprlocReloc(
- load_struct.sym_index,
- offset,
- is_ptr,
- ),
- else => {},
- }
- },
-
- .immediate => |x| {
- try dbg_info.ensureUnusedCapacity(2);
- const fixup = dbg_info.items.len;
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1,
- if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
- });
- if (ty.isSignedInt()) {
- try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
- } else {
- try leb128.writeULEB128(dbg_info.writer(), x);
- }
- try dbg_info.append(DW.OP.stack_value);
- dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
- },
-
- .undef => {
- // DW.AT.location, DW.FORM.exprloc
- // uleb128(exprloc_len)
- // DW.OP.implicit_value uleb128(len_of_bytes) bytes
- const abi_size = @intCast(u32, ty.abiSize(self.target.*));
- var implicit_value_len = std.ArrayList(u8).init(self.gpa);
- defer implicit_value_len.deinit();
- try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
- const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
- try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
- try dbg_info.ensureUnusedCapacity(total_exprloc_len);
- dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
- dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
- dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
- },
-
- .none => {
- try dbg_info.ensureUnusedCapacity(3);
- dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
- 2, DW.OP.lit0, DW.OP.stack_value,
- });
- },
-
- else => {
- try dbg_info.ensureUnusedCapacity(2);
- dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
- 1, DW.OP.nop,
- });
- log.debug("TODO generate debug info for {}", .{mcv});
- },
- }
-
- try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
- try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
- dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
- },
- .plan9 => {},
- .none => {},
- }
-}
-
-/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
-/// after codegen for this symbol is done.
-fn addDbgInfoTypeReloc(self: Self, ty: Type) !void {
- switch (self.debug_output) {
- .dwarf => |dw| {
- const dbg_info = &dw.dbg_info;
- const index = dbg_info.items.len;
- try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
- const mod = self.bin_file.options.module.?;
- const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
- const atom = switch (self.bin_file.tag) {
- .elf => &fn_owner_decl.link.elf.dbg_info_atom,
- .macho => &fn_owner_decl.link.macho.dbg_info_atom,
- else => unreachable,
- };
- try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
- },
- .plan9 => {},
- .none => {},
- }
-}
-
fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
const abi_size = ty.abiSize(self.target.*);
switch (mcv) {
diff --git a/src/codegen.zig b/src/codegen.zig
index 5a28ce1860..d6b2ed7d93 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -68,6 +68,19 @@ pub const DebugInfoOutput = union(enum) {
none,
};
+/// Helper struct to denote that the value is in memory but requires a linker relocation fixup:
+/// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
+/// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
+/// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
+pub const LinkerLoad = struct {
+ type: enum {
+ got,
+ direct,
+ import,
+ },
+ sym_index: u32,
+};
+
pub fn generateFunction(
bin_file: *link.File,
src_loc: Module.SrcLoc,
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
index 843d14edd7..63ccb57e77 100644
--- a/src/link/Dwarf.zig
+++ b/src/link/Dwarf.zig
@@ -16,6 +16,7 @@ const DW = std.dwarf;
const File = link.File;
const LinkBlock = File.LinkBlock;
const LinkFn = File.LinkFn;
+const LinkerLoad = @import("../codegen.zig").LinkerLoad;
const Module = @import("../Module.zig");
const Value = @import("../value.zig").Value;
const Type = @import("../type.zig").Type;
@@ -101,7 +102,7 @@ pub const DeclState = struct {
self.exprloc_relocs.deinit(self.gpa);
}
- pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void {
+ fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void {
log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr });
try self.exprloc_relocs.append(self.gpa, .{
.type = if (is_ptr) .got_load else .direct_load,
@@ -112,7 +113,7 @@ pub const DeclState = struct {
/// Adds local type relocation of the form: @offset => @this + addend
/// @this signifies the offset within the .debug_abbrev section of the containing atom.
- pub fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void {
+ fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void {
log.debug("{x}: @this + {x}", .{ offset, addend });
try self.abbrev_relocs.append(self.gpa, .{
.target = null,
@@ -125,7 +126,7 @@ pub const DeclState = struct {
/// Adds global type relocation of the form: @offset => @symbol + 0
/// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section
/// which we use as our target of the relocation.
- pub fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void {
+ fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void {
const resolv = self.abbrev_resolver.getContext(ty, .{
.mod = self.mod,
}) orelse blk: {
@@ -560,6 +561,233 @@ pub const DeclState = struct {
},
}
}
+
+ pub const DbgInfoLoc = union(enum) {
+ register: u8,
+ stack: struct {
+ fp_register: u8,
+ offset: i32,
+ },
+ wasm_local: u32,
+ memory: u64,
+ linker_load: LinkerLoad,
+ immediate: u64,
+ undef,
+ none,
+ nop,
+ };
+
+ pub fn genArgDbgInfo(
+ self: *DeclState,
+ name: [:0]const u8,
+ ty: Type,
+ tag: File.Tag,
+ owner_decl: Module.Decl.Index,
+ loc: DbgInfoLoc,
+ ) error{OutOfMemory}!void {
+ const dbg_info = &self.dbg_info;
+ const atom = self.getDbgInfoAtom(tag, owner_decl);
+ const name_with_null = name.ptr[0 .. name.len + 1];
+
+ switch (loc) {
+ .register => |reg| {
+ try dbg_info.ensureUnusedCapacity(3);
+ dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter));
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, // ULEB128 dwarf expression length
+ reg,
+ });
+ },
+ .stack => |info| {
+ try dbg_info.ensureUnusedCapacity(8);
+ dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter));
+ const fixup = dbg_info.items.len;
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, // we will backpatch it after we encode the displacement in LEB128
+ info.fp_register, // frame pointer
+ });
+ leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable;
+ dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
+ },
+ .wasm_local => |value| {
+ const leb_size = link.File.Wasm.getULEB128Size(value);
+ try dbg_info.ensureUnusedCapacity(3 + leb_size);
+ // wasm locations are encoded as follow:
+ // DW_OP_WASM_location wasm-op
+ // where wasm-op is defined as
+ // wasm-op := wasm-local | wasm-global | wasm-operand_stack
+ // where each argument is encoded as
+ // <opcode> i:uleb128
+ dbg_info.appendSliceAssumeCapacity(&.{
+ @enumToInt(AbbrevKind.parameter),
+ DW.OP.WASM_location,
+ DW.OP.WASM_local,
+ });
+ leb128.writeULEB128(dbg_info.writer(), value) catch unreachable;
+ },
+ else => unreachable,
+ }
+
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ const index = dbg_info.items.len;
+ 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
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ }
+
+ pub fn genVarDbgInfo(
+ self: *DeclState,
+ name: [:0]const u8,
+ ty: Type,
+ tag: File.Tag,
+ owner_decl: Module.Decl.Index,
+ is_ptr: bool,
+ loc: DbgInfoLoc,
+ ) error{OutOfMemory}!void {
+ const dbg_info = &self.dbg_info;
+ const atom = self.getDbgInfoAtom(tag, owner_decl);
+ const name_with_null = name.ptr[0 .. name.len + 1];
+ try dbg_info.append(@enumToInt(AbbrevKind.variable));
+ const target = self.mod.getTarget();
+ const endian = target.cpu.arch.endian();
+ const child_ty = if (is_ptr) ty.childType() else ty;
+
+ switch (loc) {
+ .register => |reg| {
+ try dbg_info.ensureUnusedCapacity(2);
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, // ULEB128 dwarf expression length
+ reg,
+ });
+ },
+
+ .stack => |info| {
+ try dbg_info.ensureUnusedCapacity(7);
+ const fixup = dbg_info.items.len;
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, // we will backpatch it after we encode the displacement in LEB128
+ info.fp_register,
+ });
+ leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable;
+ dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
+ },
+
+ .wasm_local => |value| {
+ const leb_size = link.File.Wasm.getULEB128Size(value);
+ try dbg_info.ensureUnusedCapacity(2 + leb_size);
+ // wasm locals are encoded as follow:
+ // DW_OP_WASM_location wasm-op
+ // where wasm-op is defined as
+ // wasm-op := wasm-local | wasm-global | wasm-operand_stack
+ // where wasm-local is encoded as
+ // wasm-local := 0x00 i:uleb128
+ dbg_info.appendSliceAssumeCapacity(&.{
+ DW.OP.WASM_location,
+ DW.OP.WASM_local,
+ });
+ leb128.writeULEB128(dbg_info.writer(), value) catch unreachable;
+ },
+
+ .memory,
+ .linker_load,
+ => {
+ const ptr_width = @intCast(u8, @divExact(target.cpu.arch.ptrBitWidth(), 8));
+ try dbg_info.ensureUnusedCapacity(2 + ptr_width);
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1 + ptr_width + @boolToInt(is_ptr),
+ DW.OP.addr, // literal address
+ });
+ const offset = @intCast(u32, dbg_info.items.len);
+ const addr = switch (loc) {
+ .memory => |x| x,
+ else => 0,
+ };
+ switch (ptr_width) {
+ 0...4 => {
+ try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
+ },
+ 5...8 => {
+ try dbg_info.writer().writeInt(u64, addr, endian);
+ },
+ else => unreachable,
+ }
+ if (is_ptr) {
+ // We need deref the address as we point to the value via GOT entry.
+ try dbg_info.append(DW.OP.deref);
+ }
+ switch (loc) {
+ .linker_load => |load_struct| try self.addExprlocReloc(
+ load_struct.sym_index,
+ offset,
+ is_ptr,
+ ),
+ else => {},
+ }
+ },
+
+ .immediate => |x| {
+ try dbg_info.ensureUnusedCapacity(2);
+ const fixup = dbg_info.items.len;
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1,
+ if (child_ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
+ });
+ if (child_ty.isSignedInt()) {
+ try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
+ } else {
+ try leb128.writeULEB128(dbg_info.writer(), x);
+ }
+ try dbg_info.append(DW.OP.stack_value);
+ dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
+ },
+
+ .undef => {
+ // DW.AT.location, DW.FORM.exprloc
+ // uleb128(exprloc_len)
+ // DW.OP.implicit_value uleb128(len_of_bytes) bytes
+ const abi_size = @intCast(u32, child_ty.abiSize(target));
+ var implicit_value_len = std.ArrayList(u8).init(self.gpa);
+ defer implicit_value_len.deinit();
+ try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
+ const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
+ try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
+ try dbg_info.ensureUnusedCapacity(total_exprloc_len);
+ dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
+ dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
+ dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
+ },
+
+ .none => {
+ try dbg_info.ensureUnusedCapacity(3);
+ dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
+ 2, DW.OP.lit0, DW.OP.stack_value,
+ });
+ },
+
+ .nop => {
+ try dbg_info.ensureUnusedCapacity(2);
+ dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
+ 1, DW.OP.nop,
+ });
+ },
+ }
+
+ try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
+ const index = dbg_info.items.len;
+ try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
+ try self.addTypeRelocGlobal(atom, child_ty, @intCast(u32, index));
+ dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
+ }
+
+ fn getDbgInfoAtom(self: *DeclState, tag: File.Tag, decl_index: Module.Decl.Index) *Atom {
+ const decl = self.mod.declPtr(decl_index);
+ return switch (tag) {
+ .elf => &decl.link.elf.dbg_info_atom,
+ .macho => &decl.link.macho.dbg_info_atom,
+ .wasm => &decl.link.wasm.dbg_info_atom,
+ else => unreachable,
+ };
+ }
};
pub const AbbrevEntry = struct {