authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-02 17:13:52+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-12-02 17:13:52+01:00
log16dc86a49e1e92d036d196be40a4fc073314bcf7
tree8842f844da54874ff384398382bf3b2374a071a4
parent665eba93c1733f83614c443c19cd9a5f1be910df
parentbfd36cbf97bfa012e5c399c16578b8756782e1d8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13730 from ziglang/gen-dwarf-simple

dwarf: dedup generation of dwarf info for func args and vars in Dwarf module

8 files changed, 393 insertions(+), 603 deletions(-)

src/arch/aarch64/CodeGen.zig+45-179
...@@ -146,11 +146,8 @@ const MCValue = union(enum) {...@@ -146,11 +146,8 @@ const MCValue = union(enum) {
146 /// If the type is a pointer, it means the pointer address is at146 /// If the type is a pointer, it means the pointer address is at
147 /// this memory location.147 /// this memory location.
148 memory: u64,148 memory: u64,
149 /// The value is in memory but requires a linker relocation fixup:149 /// The value is in memory but requires a linker relocation fixup.
150 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)150 linker_load: codegen.LinkerLoad,
151 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
152 /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
153 linker_load: struct { type: enum { got, direct, import }, sym_index: u32 },
154 /// The value is one of the stack variables.151 /// The value is one of the stack variables.
155 ///152 ///
156 /// If the type is a pointer, it means the pointer address is in153 /// If the type is a pointer, it means the pointer address is in
...@@ -184,52 +181,34 @@ const DbgInfoReloc = struct {...@@ -184,52 +181,34 @@ const DbgInfoReloc = struct {
184 else => unreachable,181 else => unreachable,
185 }182 }
186 }183 }
187
188 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {184 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {
189 const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1];
190
191 switch (function.debug_output) {185 switch (function.debug_output) {
192 .dwarf => |dw| {186 .dwarf => |dw| {
193 const dbg_info = &dw.dbg_info;187 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) {
194 switch (reloc.mcv) {188 .register => |reg| .{ .register = reg.dwarfLocOp() },
195 .register => |reg| {
196 try dbg_info.ensureUnusedCapacity(3);
197 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
198 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
199 1, // ULEB128 dwarf expression length
200 reg.dwarfLocOp(),
201 });
202 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
203 try function.addDbgInfoTypeReloc(reloc.ty); // DW.AT.type, DW.FORM.ref4
204 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
205 },
206
207 .stack_offset,189 .stack_offset,
208 .stack_argument_offset,190 .stack_argument_offset,
209 => |offset| {191 => |offset| blk: {
210 const adjusted_offset = switch (reloc.mcv) {192 const adjusted_offset = switch (reloc.mcv) {
211 .stack_offset => -@intCast(i32, offset),193 .stack_offset => -@intCast(i32, offset),
212 .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset),194 .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset),
213 else => unreachable,195 else => unreachable,
214 };196 };
215197 break :blk .{ .stack = .{
216 try dbg_info.ensureUnusedCapacity(8);198 .fp_register = Register.x29.dwarfLocOpDeref(),
217 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));199 .offset = adjusted_offset,
218 const fixup = dbg_info.items.len;200 } };
219 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
220 1, // we will backpatch it after we encode the displacement in LEB128
221 Register.x29.dwarfLocOpDeref(), // frame pointer
222 });
223 leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable;
224 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
225 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
226 try function.addDbgInfoTypeReloc(reloc.ty); // DW.AT.type, DW.FORM.ref4
227 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
228
229 },201 },
230
231 else => unreachable, // not a possible argument202 else => unreachable, // not a possible argument
232 }203
204 };
205 try dw.genArgDbgInfo(
206 reloc.name,
207 reloc.ty,
208 function.bin_file.tag,
209 function.mod_fn.owner_decl,
210 loc,
211 );
233 },212 },
234 .plan9 => {},213 .plan9 => {},
235 .none => {},214 .none => {},
...@@ -237,32 +216,20 @@ const DbgInfoReloc = struct {...@@ -237,32 +216,20 @@ const DbgInfoReloc = struct {
237 }216 }
238217
239 fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void {218 fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
240 const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1];219 const is_ptr = switch (reloc.tag) {
241 const ty = switch (reloc.tag) {220 .dbg_var_ptr => true,
242 .dbg_var_ptr => reloc.ty.childType(),221 .dbg_var_val => false,
243 .dbg_var_val => reloc.ty,
244 else => unreachable,222 else => unreachable,
245 };223 };
246224
247 switch (function.debug_output) {225 switch (function.debug_output) {
248 .dwarf => |dw| {226 .dwarf => |dw| {
249 const dbg_info = &dw.dbg_info;227 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) {
250 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));228 .register => |reg| .{ .register = reg.dwarfLocOp() },
251 const endian = function.target.cpu.arch.endian();
252
253 switch (reloc.mcv) {
254 .register => |reg| {
255 try dbg_info.ensureUnusedCapacity(2);
256 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
257 1, // ULEB128 dwarf expression length
258 reg.dwarfLocOp(),
259 });
260 },
261
262 .ptr_stack_offset,229 .ptr_stack_offset,
263 .stack_offset,230 .stack_offset,
264 .stack_argument_offset,231 .stack_argument_offset,
265 => |offset| {232 => |offset| blk: {
266 const adjusted_offset = switch (reloc.mcv) {233 const adjusted_offset = switch (reloc.mcv) {
267 .ptr_stack_offset,234 .ptr_stack_offset,
268 .stack_offset,235 .stack_offset,
...@@ -270,110 +237,31 @@ const DbgInfoReloc = struct {...@@ -270,110 +237,31 @@ const DbgInfoReloc = struct {
270 .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset),237 .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset),
271 else => unreachable,238 else => unreachable,
272 };239 };
273240 break :blk .{
274 try dbg_info.ensureUnusedCapacity(7);241 .stack = .{
275 const fixup = dbg_info.items.len;242 .fp_register = Register.x29.dwarfLocOpDeref(),
276 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc243 .offset = adjusted_offset,
277 1, // we will backpatch it after we encode the displacement in LEB128
278 Register.x29.dwarfLocOpDeref(), // frame pointer
279 });
280 leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable;
281 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
282 },
283
284 .memory,
285 .linker_load,
286 => {
287 const ptr_width = @intCast(u8, @divExact(function.target.cpu.arch.ptrBitWidth(), 8));
288 const is_ptr = switch (reloc.tag) {
289 .dbg_var_ptr => true,
290 .dbg_var_val => false,
291 else => unreachable,
292 };
293 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
294 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
295 1 + ptr_width + @boolToInt(is_ptr),
296 DW.OP.addr, // literal address
297 });
298 const offset = @intCast(u32, dbg_info.items.len);
299 const addr = switch (reloc.mcv) {
300 .memory => |addr| addr,
301 else => 0,
302 };
303 switch (ptr_width) {
304 0...4 => {
305 try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
306 },244 },
307 5...8 => {245 };
308 try dbg_info.writer().writeInt(u64, addr, endian);
309 },
310 else => unreachable,
311 }
312 if (is_ptr) {
313 // We need deref the address as we point to the value via GOT entry.
314 try dbg_info.append(DW.OP.deref);
315 }
316 switch (reloc.mcv) {
317 .linker_load => |load_struct| try dw.addExprlocReloc(
318 load_struct.sym_index,
319 offset,
320 is_ptr,
321 ),
322 else => {},
323 }
324 },
325
326 .immediate => |x| {
327 try dbg_info.ensureUnusedCapacity(2);
328 const fixup = dbg_info.items.len;
329 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
330 1,
331 if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
332 });
333 if (ty.isSignedInt()) {
334 try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
335 } else {
336 try leb128.writeULEB128(dbg_info.writer(), x);
337 }
338 try dbg_info.append(DW.OP.stack_value);
339 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
340 },
341
342 .undef => {
343 // DW.AT.location, DW.FORM.exprloc
344 // uleb128(exprloc_len)
345 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
346 const abi_size = @intCast(u32, ty.abiSize(function.target.*));
347 var implicit_value_len = std.ArrayList(u8).init(function.gpa);
348 defer implicit_value_len.deinit();
349 try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
350 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
351 try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
352 try dbg_info.ensureUnusedCapacity(total_exprloc_len);
353 dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
354 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
355 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
356 },
357
358 .none => {
359 try dbg_info.ensureUnusedCapacity(3);
360 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
361 2, DW.OP.lit0, DW.OP.stack_value,
362 });
363 },246 },
364247 .memory => |address| .{ .memory = address },
365 else => {248 .linker_load => |linker_load| .{ .linker_load = linker_load },
366 try dbg_info.ensureUnusedCapacity(2);249 .immediate => |x| .{ .immediate = x },
367 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc250 .undef => .undef,
368 1, DW.OP.nop,251 .none => .none,
369 });252 else => blk: {
370 log.debug("TODO generate debug info for {}", .{reloc.mcv});253 log.debug("TODO generate debug info for {}", .{reloc.mcv});
254 break :blk .nop;
371 },255 },
372 }256 };
373257 try dw.genVarDbgInfo(
374 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);258 reloc.name,
375 try function.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4259 reloc.ty,
376 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string260 function.bin_file.tag,
261 function.mod_fn.owner_decl,
262 is_ptr,
263 loc,
264 );
377 },265 },
378 .plan9 => {},266 .plan9 => {},
379 .none => {},267 .none => {},
...@@ -1079,28 +967,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -1079,28 +967,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
1079 try table.ensureUnusedCapacity(self.gpa, additional_count);967 try table.ensureUnusedCapacity(self.gpa, additional_count);
1080}968}
1081969
1082/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
1083/// after codegen for this symbol is done.
1084fn addDbgInfoTypeReloc(self: Self, ty: Type) !void {
1085 switch (self.debug_output) {
1086 .dwarf => |dw| {
1087 const dbg_info = &dw.dbg_info;
1088 const index = dbg_info.items.len;
1089 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
1090 const mod = self.bin_file.options.module.?;
1091 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
1092 const atom = switch (self.bin_file.tag) {
1093 .elf => &fn_owner_decl.link.elf.dbg_info_atom,
1094 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
1095 else => unreachable,
1096 };
1097 try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
1098 },
1099 .plan9 => {},
1100 .none => {},
1101 }
1102}
1103
1104fn allocMem(970fn allocMem(
1105 self: *Self,971 self: *Self,
1106 abi_size: u32,972 abi_size: u32,
src/arch/arm/CodeGen.zig+18-69
...@@ -4029,86 +4029,35 @@ fn genInlineMemsetCode(...@@ -4029,86 +4029,35 @@ fn genInlineMemsetCode(
4029 // end:4029 // end:
4030}4030}
40314031
4032/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,4032fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void {
4033/// after codegen for this symbol is done.
4034fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
4035 switch (self.debug_output) {
4036 .dwarf => |dw| {
4037 assert(ty.hasRuntimeBits());
4038 const dbg_info = &dw.dbg_info;
4039 const index = dbg_info.items.len;
4040 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
4041 const mod = self.bin_file.options.module.?;
4042 const atom = switch (self.bin_file.tag) {
4043 .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom,
4044 .macho => unreachable,
4045 else => unreachable,
4046 };
4047 try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
4048 },
4049 .plan9 => {},
4050 .none => {},
4051 }
4052}
4053
4054fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void {
4055 const mcv = self.args[arg_index];4033 const mcv = self.args[arg_index];
4056 const ty = self.air.instructions.items(.data)[inst].ty;4034 const ty = self.air.instructions.items(.data)[inst].ty;
4057 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);4035 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
4058 const name_with_null = name.ptr[0 .. name.len + 1];
40594036
4060 switch (mcv) {4037 switch (self.debug_output) {
4061 .register => |reg| {4038 .dwarf => |dw| {
4062 switch (self.debug_output) {4039 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
4063 .dwarf => |dw| {4040 .register => |reg| .{ .register = reg.dwarfLocOp() },
4064 const dbg_info = &dw.dbg_info;4041 .stack_offset,
4065 try dbg_info.ensureUnusedCapacity(3);4042 .stack_argument_offset,
4066 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));4043 => blk: {
4067 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4068 1, // ULEB128 dwarf expression length
4069 reg.dwarfLocOp(),
4070 });
4071 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
4072 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
4073 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
4074 },
4075 .plan9 => {},
4076 .none => {},
4077 }
4078 },
4079 .stack_offset,
4080 .stack_argument_offset,
4081 => {
4082 switch (self.debug_output) {
4083 .dwarf => |dw| {
4084 const adjusted_stack_offset = switch (mcv) {4044 const adjusted_stack_offset = switch (mcv) {
4085 .stack_offset => |offset| -@intCast(i32, offset),4045 .stack_offset => |offset| -@intCast(i32, offset),
4086 .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset),4046 .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset),
4087 else => unreachable,4047 else => unreachable,
4088 };4048 };
40894049 break :blk .{ .stack = .{
4090 const dbg_info = &dw.dbg_info;4050 .fp_register = DW.OP.breg11,
4091 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));4051 .offset = adjusted_stack_offset,
40924052 } };
4093 // Get length of the LEB128 stack offset
4094 var counting_writer = std.io.countingWriter(std.io.null_writer);
4095 leb128.writeILEB128(counting_writer.writer(), adjusted_stack_offset) catch unreachable;
4096
4097 // DW.AT.location, DW.FORM.exprloc
4098 // ULEB128 dwarf expression length
4099 try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1);
4100 try dbg_info.append(DW.OP.breg11);
4101 try leb128.writeILEB128(dbg_info.writer(), adjusted_stack_offset);
4102
4103 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
4104 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
4105 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
4106 },4053 },
4107 .plan9 => {},4054 else => unreachable, // not a possible argument
4108 .none => {},4055
4109 }4056 };
4057 try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc);
4110 },4058 },
4111 else => unreachable, // not a possible argument4059 .plan9 => {},
4060 .none => {},
4112 }4061 }
4113}4062}
41144063
src/arch/riscv64/CodeGen.zig+14-51
...@@ -772,28 +772,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -772,28 +772,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
772 try table.ensureUnusedCapacity(self.gpa, additional_count);772 try table.ensureUnusedCapacity(self.gpa, additional_count);
773}773}
774774
775/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
776/// after codegen for this symbol is done.
777fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
778 switch (self.debug_output) {
779 .dwarf => |dw| {
780 assert(ty.hasRuntimeBits());
781 const dbg_info = &dw.dbg_info;
782 const index = dbg_info.items.len;
783 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
784 const mod = self.bin_file.options.module.?;
785 const atom = switch (self.bin_file.tag) {
786 .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom,
787 .macho => unreachable,
788 else => unreachable,
789 };
790 try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
791 },
792 .plan9 => {},
793 .none => {},
794 }
795}
796
797fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {775fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
798 if (abi_align > self.stack_align)776 if (abi_align > self.stack_align)
799 self.stack_align = abi_align;777 self.stack_align = abi_align;
...@@ -1624,39 +1602,24 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1624,39 +1602,24 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
1624 return self.fail("TODO implement codegen airFieldParentPtr", .{});1602 return self.fail("TODO implement codegen airFieldParentPtr", .{});
1625}1603}
16261604
1627fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {1605fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
1628 const ty = self.air.instructions.items(.data)[inst].ty;1606 const ty = self.air.instructions.items(.data)[inst].ty;
1629 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);1607 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
1630 const name_with_null = name.ptr[0 .. name.len + 1];
16311608
1632 switch (mcv) {1609 switch (self.debug_output) {
1633 .register => |reg| {1610 .dwarf => |dw| switch (mcv) {
1634 switch (self.debug_output) {1611 .register => |reg| try dw.genArgDbgInfo(
1635 .dwarf => |dw| {1612 name,
1636 const dbg_info = &dw.dbg_info;1613 ty,
1637 try dbg_info.ensureUnusedCapacity(3);1614 self.bin_file.tag,
1638 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));1615 self.mod_fn.owner_decl,
1639 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc1616 .{ .register = reg.dwarfLocOp() },
1640 1, // ULEB128 dwarf expression length1617 ),
1641 reg.dwarfLocOp(),1618 .stack_offset => {},
1642 });1619 else => {},
1643 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
1644 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
1645 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
1646 },
1647 .plan9 => {},
1648 .none => {},
1649 }
1650 },
1651 .stack_offset => |offset| {
1652 _ = offset;
1653 switch (self.debug_output) {
1654 .dwarf => {},
1655 .plan9 => {},
1656 .none => {},
1657 }
1658 },1620 },
1659 else => {},1621 .plan9 => {},
1622 .none => {},
1660 }1623 }
1661}1624}
16621625
src/arch/sparc64/CodeGen.zig+11-46
...@@ -2460,26 +2460,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {...@@ -2460,26 +2460,6 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
24602460
2461// Common helper functions2461// Common helper functions
24622462
2463/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
2464/// after codegen for this symbol is done.
2465fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
2466 switch (self.debug_output) {
2467 .dwarf => |dw| {
2468 assert(ty.hasRuntimeBits());
2469 const dbg_info = &dw.dbg_info;
2470 const index = dbg_info.items.len;
2471 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
2472 const mod = self.bin_file.options.module.?;
2473 const atom = switch (self.bin_file.tag) {
2474 .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom,
2475 else => unreachable,
2476 };
2477 try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
2478 },
2479 else => {},
2480 }
2481}
2482
2483fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {2463fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
2484 const gpa = self.gpa;2464 const gpa = self.gpa;
2485 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);2465 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
...@@ -3272,35 +3252,20 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live...@@ -3272,35 +3252,20 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
3272 self.finishAirBookkeeping();3252 self.finishAirBookkeeping();
3273}3253}
32743254
3275fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {3255fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
3276 const ty = self.air.instructions.items(.data)[inst].ty;3256 const ty = self.air.instructions.items(.data)[inst].ty;
3277 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);3257 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
3278 const name_with_null = name.ptr[0 .. name.len + 1];
32793258
3280 switch (mcv) {3259 switch (self.debug_output) {
3281 .register => |reg| {3260 .dwarf => |dw| switch (mcv) {
3282 switch (self.debug_output) {3261 .register => |reg| try dw.genArgDbgInfo(
3283 .dwarf => |dw| {3262 name,
3284 const dbg_info = &dw.dbg_info;3263 ty,
3285 try dbg_info.ensureUnusedCapacity(3);3264 self.bin_file.tag,
3286 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));3265 self.mod_fn.owner_decl,
3287 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc3266 .{ .register = reg.dwarfLocOp() },
3288 1, // ULEB128 dwarf expression length3267 ),
3289 reg.dwarfLocOp(),3268 else => {},
3290 });
3291 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3292 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3293 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3294 },
3295 else => {},
3296 }
3297 },
3298 .stack_offset => |offset| {
3299 _ = offset;
3300 switch (self.debug_output) {
3301 .dwarf => {},
3302 else => {},
3303 }
3304 },3269 },
3305 else => {},3270 else => {},
3306 }3271 }
src/arch/wasm/CodeGen.zig+10-59
...@@ -1291,23 +1291,6 @@ fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, target:...@@ -1291,23 +1291,6 @@ fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, target:
1291 }1291 }
1292}1292}
12931293
1294/// For a given `Type`, add debug information to .debug_info at the current position.
1295/// The actual bytes will be written to the position after relocation.
1296fn addDbgInfoTypeReloc(func: *CodeGen, ty: Type) !void {
1297 switch (func.debug_output) {
1298 .dwarf => |dwarf| {
1299 assert(ty.hasRuntimeBitsIgnoreComptime());
1300 const dbg_info = &dwarf.dbg_info;
1301 const index = dbg_info.items.len;
1302 try dbg_info.resize(index + 4);
1303 const atom = &func.decl.link.wasm.dbg_info_atom;
1304 try dwarf.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
1305 },
1306 .plan9 => unreachable,
1307 .none => {},
1308 }
1309}
1310
1311/// Lowers a Zig type and its value based on a given calling convention to ensure1294/// Lowers a Zig type and its value based on a given calling convention to ensure
1312/// it matches the ABI.1295/// it matches the ABI.
1313fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void {1296fn 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 {...@@ -2358,24 +2341,9 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2358 .dwarf => |dwarf| {2341 .dwarf => |dwarf| {
2359 // TODO: Get the original arg index rather than wasm arg index2342 // TODO: Get the original arg index rather than wasm arg index
2360 const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, arg_index);2343 const name = func.mod_fn.getParamName(func.bin_file.base.options.module.?, arg_index);
2361 const leb_size = link.File.Wasm.getULEB128Size(arg.local.value);2344 try dwarf.genArgDbgInfo(name, arg_ty, .wasm, func.mod_fn.owner_decl, .{
2362 const dbg_info = &dwarf.dbg_info;2345 .wasm_local = arg.local.value,
2363 try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1);
2364 // wasm locations are encoded as follow:
2365 // DW_OP_WASM_location wasm-op
2366 // where wasm-op is defined as
2367 // wasm-op := wasm-local | wasm-global | wasm-operand_stack
2368 // where each argument is encoded as
2369 // <opcode> i:uleb128
2370 dbg_info.appendSliceAssumeCapacity(&.{
2371 @enumToInt(link.File.Dwarf.AbbrevKind.parameter),
2372 std.dwarf.OP.WASM_location,
2373 std.dwarf.OP.WASM_local,
2374 });2346 });
2375 leb.writeULEB128(dbg_info.writer(), arg.local.value) catch unreachable;
2376 try func.addDbgInfoTypeReloc(arg_ty);
2377 dbg_info.appendSliceAssumeCapacity(name);
2378 dbg_info.appendAssumeCapacity(0);
2379 },2347 },
2380 else => {},2348 else => {},
2381 }2349 }
...@@ -5345,38 +5313,21 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void {...@@ -5345,38 +5313,21 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void {
5345 const pl_op = func.air.instructions.items(.data)[inst].pl_op;5313 const pl_op = func.air.instructions.items(.data)[inst].pl_op;
5346 const ty = func.air.typeOf(pl_op.operand);5314 const ty = func.air.typeOf(pl_op.operand);
5347 const operand = try func.resolveInst(pl_op.operand);5315 const operand = try func.resolveInst(pl_op.operand);
5348 const op_ty = if (is_ptr) ty.childType() else ty;
53495316
5350 log.debug("airDbgVar: %{d}: {}, {}", .{ inst, op_ty.fmtDebug(), operand });5317 log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand });
53515318
5352 const name = func.air.nullTerminatedString(pl_op.payload);5319 const name = func.air.nullTerminatedString(pl_op.payload);
5353 log.debug(" var name = ({s})", .{name});5320 log.debug(" var name = ({s})", .{name});
53545321
5355 const dbg_info = &func.debug_output.dwarf.dbg_info;5322 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (operand) {
5356 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));5323 .local => |local| .{ .wasm_local = local.value },
5357 switch (operand) {5324 else => blk: {
5358 .local => |local| {5325 log.debug("TODO generate debug info for {}", .{operand});
5359 const leb_size = link.File.Wasm.getULEB128Size(local.value);5326 break :blk .nop;
5360 try dbg_info.ensureUnusedCapacity(2 + leb_size);
5361 // wasm locals are encoded as follow:
5362 // DW_OP_WASM_location wasm-op
5363 // where wasm-op is defined as
5364 // wasm-op := wasm-local | wasm-global | wasm-operand_stack
5365 // where wasm-local is encoded as
5366 // wasm-local := 0x00 i:uleb128
5367 dbg_info.appendSliceAssumeCapacity(&.{
5368 std.dwarf.OP.WASM_location,
5369 std.dwarf.OP.WASM_local,
5370 });
5371 leb.writeULEB128(dbg_info.writer(), local.value) catch unreachable;
5372 },5327 },
5373 else => {}, // TODO5328 };
5374 }5329 try func.debug_output.dwarf.genVarDbgInfo(name, ty, .wasm, func.mod_fn.owner_decl, is_ptr, loc);
53755330
5376 try dbg_info.ensureUnusedCapacity(5 + name.len + 1);
5377 try func.addDbgInfoTypeReloc(op_ty);
5378 dbg_info.appendSliceAssumeCapacity(name);
5379 dbg_info.appendAssumeCapacity(0);
5380 func.finishAir(inst, .none, &.{});5331 func.finishAir(inst, .none, &.{});
5381}5332}
53825333
src/arch/x86_64/CodeGen.zig+51-196
...@@ -128,11 +128,8 @@ pub const MCValue = union(enum) {...@@ -128,11 +128,8 @@ pub const MCValue = union(enum) {
128 /// The value is in memory at a hard-coded address.128 /// The value is in memory at a hard-coded address.
129 /// If the type is a pointer, it means the pointer address is at this memory location.129 /// If the type is a pointer, it means the pointer address is at this memory location.
130 memory: u64,130 memory: u64,
131 /// The value is in memory but requires a linker relocation fixup:131 /// The value is in memory but requires a linker relocation fixup.
132 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)132 linker_load: codegen.LinkerLoad,
133 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
134 /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
135 linker_load: struct { type: enum { got, direct, import }, sym_index: u32 },
136 /// The value is one of the stack variables.133 /// The value is one of the stack variables.
137 /// If the type is a pointer, it means the pointer address is in the stack at this offset.134 /// If the type is a pointer, it means the pointer address is in the stack at this offset.
138 stack_offset: i32,135 stack_offset: i32,
...@@ -3818,41 +3815,60 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -3818,41 +3815,60 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
3818}3815}
38193816
3820fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {3817fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
3821 const name_with_null = name.ptr[0 .. name.len + 1];
3822 switch (self.debug_output) {3818 switch (self.debug_output) {
3823 .dwarf => |dw| {3819 .dwarf => |dw| {
3824 const dbg_info = &dw.dbg_info;3820 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
3825 switch (mcv) {3821 .register => |reg| .{ .register = reg.dwarfLocOp() },
3826 .register => |reg| {3822 .stack_offset => |off| .{
3827 try dbg_info.ensureUnusedCapacity(3);3823 .stack = .{
3828 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));3824 // TODO handle -fomit-frame-pointer
3829 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc3825 .fp_register = Register.rbp.dwarfLocOpDeref(),
3830 1, // ULEB128 dwarf expression length3826 .offset = -off,
3831 reg.dwarfLocOp(),3827 },
3832 });
3833 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3834 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3835 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3836 },3828 },
3829 else => unreachable, // not a valid function parameter
3830 };
3831 try dw.genArgDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, loc);
3832 },
3833 .plan9 => {},
3834 .none => {},
3835 }
3836}
38373837
3838 .stack_offset => |off| {3838fn genVarDbgInfo(
3839 try dbg_info.ensureUnusedCapacity(8);3839 self: Self,
3840 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));3840 tag: Air.Inst.Tag,
3841 const fixup = dbg_info.items.len;3841 ty: Type,
3842 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc3842 mcv: MCValue,
3843 1, // we will backpatch it after we encode the displacement in LEB1283843 name: [:0]const u8,
3844 Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer3844) !void {
3845 });3845 const is_ptr = switch (tag) {
3846 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;3846 .dbg_var_ptr => true,
3847 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);3847 .dbg_var_val => false,
3848 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);3848 else => unreachable,
3849 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref43849 };
3850 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
38513850
3851 switch (self.debug_output) {
3852 .dwarf => |dw| {
3853 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
3854 .register => |reg| .{ .register = reg.dwarfLocOp() },
3855 .ptr_stack_offset,
3856 .stack_offset,
3857 => |off| .{ .stack = .{
3858 .fp_register = Register.rbp.dwarfLocOpDeref(),
3859 .offset = -off,
3860 } },
3861 .memory => |address| .{ .memory = address },
3862 .linker_load => |linker_load| .{ .linker_load = linker_load },
3863 .immediate => |x| .{ .immediate = x },
3864 .undef => .undef,
3865 .none => .none,
3866 else => blk: {
3867 log.debug("TODO generate debug info for {}", .{mcv});
3868 break :blk .nop;
3852 },3869 },
38533870 };
3854 else => unreachable, // not a valid function parameter3871 try dw.genVarDbgInfo(name, ty, self.bin_file.tag, self.mod_fn.owner_decl, is_ptr, loc);
3855 }
3856 },3872 },
3857 .plan9 => {},3873 .plan9 => {},
3858 .none => {},3874 .none => {},
...@@ -4418,172 +4434,11 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {...@@ -4418,172 +4434,11 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
4418 const name = self.air.nullTerminatedString(pl_op.payload);4434 const name = self.air.nullTerminatedString(pl_op.payload);
44194435
4420 const tag = self.air.instructions.items(.tag)[inst];4436 const tag = self.air.instructions.items(.tag)[inst];
4421 switch (tag) {4437 try self.genVarDbgInfo(tag, ty, mcv, name);
4422 .dbg_var_ptr => try self.genVarDbgInfo(tag, ty.childType(), mcv, name),
4423 .dbg_var_val => try self.genVarDbgInfo(tag, ty, mcv, name),
4424 else => unreachable,
4425 }
44264438
4427 return self.finishAir(inst, .dead, .{ operand, .none, .none });4439 return self.finishAir(inst, .dead, .{ operand, .none, .none });
4428}4440}
44294441
4430fn genVarDbgInfo(
4431 self: Self,
4432 tag: Air.Inst.Tag,
4433 ty: Type,
4434 mcv: MCValue,
4435 name: [:0]const u8,
4436) !void {
4437 const name_with_null = name.ptr[0 .. name.len + 1];
4438 switch (self.debug_output) {
4439 .dwarf => |dw| {
4440 const dbg_info = &dw.dbg_info;
4441 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
4442 const endian = self.target.cpu.arch.endian();
4443
4444 switch (mcv) {
4445 .register => |reg| {
4446 try dbg_info.ensureUnusedCapacity(2);
4447 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4448 1, // ULEB128 dwarf expression length
4449 reg.dwarfLocOp(),
4450 });
4451 },
4452
4453 .ptr_stack_offset,
4454 .stack_offset,
4455 => |off| {
4456 try dbg_info.ensureUnusedCapacity(7);
4457 const fixup = dbg_info.items.len;
4458 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4459 1, // we will backpatch it after we encode the displacement in LEB128
4460 Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer
4461 });
4462 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
4463 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
4464 },
4465
4466 .memory,
4467 .linker_load,
4468 => {
4469 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
4470 const is_ptr = switch (tag) {
4471 .dbg_var_ptr => true,
4472 .dbg_var_val => false,
4473 else => unreachable,
4474 };
4475 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
4476 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4477 1 + ptr_width + @boolToInt(is_ptr),
4478 DW.OP.addr, // literal address
4479 });
4480 const offset = @intCast(u32, dbg_info.items.len);
4481 const addr = switch (mcv) {
4482 .memory => |addr| addr,
4483 else => 0,
4484 };
4485 switch (ptr_width) {
4486 0...4 => {
4487 try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
4488 },
4489 5...8 => {
4490 try dbg_info.writer().writeInt(u64, addr, endian);
4491 },
4492 else => unreachable,
4493 }
4494 if (is_ptr) {
4495 // We need deref the address as we point to the value via GOT entry.
4496 try dbg_info.append(DW.OP.deref);
4497 }
4498 switch (mcv) {
4499 .linker_load => |load_struct| try dw.addExprlocReloc(
4500 load_struct.sym_index,
4501 offset,
4502 is_ptr,
4503 ),
4504 else => {},
4505 }
4506 },
4507
4508 .immediate => |x| {
4509 try dbg_info.ensureUnusedCapacity(2);
4510 const fixup = dbg_info.items.len;
4511 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4512 1,
4513 if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
4514 });
4515 if (ty.isSignedInt()) {
4516 try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
4517 } else {
4518 try leb128.writeULEB128(dbg_info.writer(), x);
4519 }
4520 try dbg_info.append(DW.OP.stack_value);
4521 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
4522 },
4523
4524 .undef => {
4525 // DW.AT.location, DW.FORM.exprloc
4526 // uleb128(exprloc_len)
4527 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
4528 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4529 var implicit_value_len = std.ArrayList(u8).init(self.gpa);
4530 defer implicit_value_len.deinit();
4531 try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
4532 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
4533 try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
4534 try dbg_info.ensureUnusedCapacity(total_exprloc_len);
4535 dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
4536 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
4537 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
4538 },
4539
4540 .none => {
4541 try dbg_info.ensureUnusedCapacity(3);
4542 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
4543 2, DW.OP.lit0, DW.OP.stack_value,
4544 });
4545 },
4546
4547 else => {
4548 try dbg_info.ensureUnusedCapacity(2);
4549 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4550 1, DW.OP.nop,
4551 });
4552 log.debug("TODO generate debug info for {}", .{mcv});
4553 },
4554 }
4555
4556 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
4557 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
4558 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
4559 },
4560 .plan9 => {},
4561 .none => {},
4562 }
4563}
4564
4565/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
4566/// after codegen for this symbol is done.
4567fn addDbgInfoTypeReloc(self: Self, ty: Type) !void {
4568 switch (self.debug_output) {
4569 .dwarf => |dw| {
4570 const dbg_info = &dw.dbg_info;
4571 const index = dbg_info.items.len;
4572 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
4573 const mod = self.bin_file.options.module.?;
4574 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
4575 const atom = switch (self.bin_file.tag) {
4576 .elf => &fn_owner_decl.link.elf.dbg_info_atom,
4577 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
4578 else => unreachable,
4579 };
4580 try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
4581 },
4582 .plan9 => {},
4583 .none => {},
4584 }
4585}
4586
4587fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {4442fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
4588 const abi_size = ty.abiSize(self.target.*);4443 const abi_size = ty.abiSize(self.target.*);
4589 switch (mcv) {4444 switch (mcv) {
src/codegen.zig+13
...@@ -68,6 +68,19 @@ pub const DebugInfoOutput = union(enum) {...@@ -68,6 +68,19 @@ pub const DebugInfoOutput = union(enum) {
68 none,68 none,
69};69};
7070
71/// Helper struct to denote that the value is in memory but requires a linker relocation fixup:
72/// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
73/// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
74/// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
75pub const LinkerLoad = struct {
76 type: enum {
77 got,
78 direct,
79 import,
80 },
81 sym_index: u32,
82};
83
71pub fn generateFunction(84pub fn generateFunction(
72 bin_file: *link.File,85 bin_file: *link.File,
73 src_loc: Module.SrcLoc,86 src_loc: Module.SrcLoc,
src/link/Dwarf.zig+231-3
...@@ -16,6 +16,7 @@ const DW = std.dwarf;...@@ -16,6 +16,7 @@ const DW = std.dwarf;
16const File = link.File;16const File = link.File;
17const LinkBlock = File.LinkBlock;17const LinkBlock = File.LinkBlock;
18const LinkFn = File.LinkFn;18const LinkFn = File.LinkFn;
19const LinkerLoad = @import("../codegen.zig").LinkerLoad;
19const Module = @import("../Module.zig");20const Module = @import("../Module.zig");
20const Value = @import("../value.zig").Value;21const Value = @import("../value.zig").Value;
21const Type = @import("../type.zig").Type;22const Type = @import("../type.zig").Type;
...@@ -101,7 +102,7 @@ pub const DeclState = struct {...@@ -101,7 +102,7 @@ pub const DeclState = struct {
101 self.exprloc_relocs.deinit(self.gpa);102 self.exprloc_relocs.deinit(self.gpa);
102 }103 }
103104
104 pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void {105 fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void {
105 log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr });106 log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr });
106 try self.exprloc_relocs.append(self.gpa, .{107 try self.exprloc_relocs.append(self.gpa, .{
107 .type = if (is_ptr) .got_load else .direct_load,108 .type = if (is_ptr) .got_load else .direct_load,
...@@ -112,7 +113,7 @@ pub const DeclState = struct {...@@ -112,7 +113,7 @@ pub const DeclState = struct {
112113
113 /// Adds local type relocation of the form: @offset => @this + addend114 /// Adds local type relocation of the form: @offset => @this + addend
114 /// @this signifies the offset within the .debug_abbrev section of the containing atom.115 /// @this signifies the offset within the .debug_abbrev section of the containing atom.
115 pub fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void {116 fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void {
116 log.debug("{x}: @this + {x}", .{ offset, addend });117 log.debug("{x}: @this + {x}", .{ offset, addend });
117 try self.abbrev_relocs.append(self.gpa, .{118 try self.abbrev_relocs.append(self.gpa, .{
118 .target = null,119 .target = null,
...@@ -125,7 +126,7 @@ pub const DeclState = struct {...@@ -125,7 +126,7 @@ pub const DeclState = struct {
125 /// Adds global type relocation of the form: @offset => @symbol + 0126 /// Adds global type relocation of the form: @offset => @symbol + 0
126 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section127 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section
127 /// which we use as our target of the relocation.128 /// which we use as our target of the relocation.
128 pub fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void {129 fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void {
129 const resolv = self.abbrev_resolver.getContext(ty, .{130 const resolv = self.abbrev_resolver.getContext(ty, .{
130 .mod = self.mod,131 .mod = self.mod,
131 }) orelse blk: {132 }) orelse blk: {
...@@ -560,6 +561,233 @@ pub const DeclState = struct {...@@ -560,6 +561,233 @@ pub const DeclState = struct {
560 },561 },
561 }562 }
562 }563 }
564
565 pub const DbgInfoLoc = union(enum) {
566 register: u8,
567 stack: struct {
568 fp_register: u8,
569 offset: i32,
570 },
571 wasm_local: u32,
572 memory: u64,
573 linker_load: LinkerLoad,
574 immediate: u64,
575 undef,
576 none,
577 nop,
578 };
579
580 pub fn genArgDbgInfo(
581 self: *DeclState,
582 name: [:0]const u8,
583 ty: Type,
584 tag: File.Tag,
585 owner_decl: Module.Decl.Index,
586 loc: DbgInfoLoc,
587 ) error{OutOfMemory}!void {
588 const dbg_info = &self.dbg_info;
589 const atom = self.getDbgInfoAtom(tag, owner_decl);
590 const name_with_null = name.ptr[0 .. name.len + 1];
591
592 switch (loc) {
593 .register => |reg| {
594 try dbg_info.ensureUnusedCapacity(3);
595 dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter));
596 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
597 1, // ULEB128 dwarf expression length
598 reg,
599 });
600 },
601 .stack => |info| {
602 try dbg_info.ensureUnusedCapacity(8);
603 dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter));
604 const fixup = dbg_info.items.len;
605 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
606 1, // we will backpatch it after we encode the displacement in LEB128
607 info.fp_register, // frame pointer
608 });
609 leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable;
610 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
611 },
612 .wasm_local => |value| {
613 const leb_size = link.File.Wasm.getULEB128Size(value);
614 try dbg_info.ensureUnusedCapacity(3 + leb_size);
615 // wasm locations are encoded as follow:
616 // DW_OP_WASM_location wasm-op
617 // where wasm-op is defined as
618 // wasm-op := wasm-local | wasm-global | wasm-operand_stack
619 // where each argument is encoded as
620 // <opcode> i:uleb128
621 dbg_info.appendSliceAssumeCapacity(&.{
622 @enumToInt(AbbrevKind.parameter),
623 DW.OP.WASM_location,
624 DW.OP.WASM_local,
625 });
626 leb128.writeULEB128(dbg_info.writer(), value) catch unreachable;
627 },
628 else => unreachable,
629 }
630
631 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
632 const index = dbg_info.items.len;
633 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
634 try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); // DW.AT.type, DW.FORM.ref4
635 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
636 }
637
638 pub fn genVarDbgInfo(
639 self: *DeclState,
640 name: [:0]const u8,
641 ty: Type,
642 tag: File.Tag,
643 owner_decl: Module.Decl.Index,
644 is_ptr: bool,
645 loc: DbgInfoLoc,
646 ) error{OutOfMemory}!void {
647 const dbg_info = &self.dbg_info;
648 const atom = self.getDbgInfoAtom(tag, owner_decl);
649 const name_with_null = name.ptr[0 .. name.len + 1];
650 try dbg_info.append(@enumToInt(AbbrevKind.variable));
651 const target = self.mod.getTarget();
652 const endian = target.cpu.arch.endian();
653 const child_ty = if (is_ptr) ty.childType() else ty;
654
655 switch (loc) {
656 .register => |reg| {
657 try dbg_info.ensureUnusedCapacity(2);
658 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
659 1, // ULEB128 dwarf expression length
660 reg,
661 });
662 },
663
664 .stack => |info| {
665 try dbg_info.ensureUnusedCapacity(7);
666 const fixup = dbg_info.items.len;
667 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
668 1, // we will backpatch it after we encode the displacement in LEB128
669 info.fp_register,
670 });
671 leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable;
672 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
673 },
674
675 .wasm_local => |value| {
676 const leb_size = link.File.Wasm.getULEB128Size(value);
677 try dbg_info.ensureUnusedCapacity(2 + leb_size);
678 // wasm locals are encoded as follow:
679 // DW_OP_WASM_location wasm-op
680 // where wasm-op is defined as
681 // wasm-op := wasm-local | wasm-global | wasm-operand_stack
682 // where wasm-local is encoded as
683 // wasm-local := 0x00 i:uleb128
684 dbg_info.appendSliceAssumeCapacity(&.{
685 DW.OP.WASM_location,
686 DW.OP.WASM_local,
687 });
688 leb128.writeULEB128(dbg_info.writer(), value) catch unreachable;
689 },
690
691 .memory,
692 .linker_load,
693 => {
694 const ptr_width = @intCast(u8, @divExact(target.cpu.arch.ptrBitWidth(), 8));
695 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
696 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
697 1 + ptr_width + @boolToInt(is_ptr),
698 DW.OP.addr, // literal address
699 });
700 const offset = @intCast(u32, dbg_info.items.len);
701 const addr = switch (loc) {
702 .memory => |x| x,
703 else => 0,
704 };
705 switch (ptr_width) {
706 0...4 => {
707 try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
708 },
709 5...8 => {
710 try dbg_info.writer().writeInt(u64, addr, endian);
711 },
712 else => unreachable,
713 }
714 if (is_ptr) {
715 // We need deref the address as we point to the value via GOT entry.
716 try dbg_info.append(DW.OP.deref);
717 }
718 switch (loc) {
719 .linker_load => |load_struct| try self.addExprlocReloc(
720 load_struct.sym_index,
721 offset,
722 is_ptr,
723 ),
724 else => {},
725 }
726 },
727
728 .immediate => |x| {
729 try dbg_info.ensureUnusedCapacity(2);
730 const fixup = dbg_info.items.len;
731 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
732 1,
733 if (child_ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
734 });
735 if (child_ty.isSignedInt()) {
736 try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
737 } else {
738 try leb128.writeULEB128(dbg_info.writer(), x);
739 }
740 try dbg_info.append(DW.OP.stack_value);
741 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
742 },
743
744 .undef => {
745 // DW.AT.location, DW.FORM.exprloc
746 // uleb128(exprloc_len)
747 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
748 const abi_size = @intCast(u32, child_ty.abiSize(target));
749 var implicit_value_len = std.ArrayList(u8).init(self.gpa);
750 defer implicit_value_len.deinit();
751 try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
752 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
753 try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
754 try dbg_info.ensureUnusedCapacity(total_exprloc_len);
755 dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
756 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
757 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
758 },
759
760 .none => {
761 try dbg_info.ensureUnusedCapacity(3);
762 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
763 2, DW.OP.lit0, DW.OP.stack_value,
764 });
765 },
766
767 .nop => {
768 try dbg_info.ensureUnusedCapacity(2);
769 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
770 1, DW.OP.nop,
771 });
772 },
773 }
774
775 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
776 const index = dbg_info.items.len;
777 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
778 try self.addTypeRelocGlobal(atom, child_ty, @intCast(u32, index));
779 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
780 }
781
782 fn getDbgInfoAtom(self: *DeclState, tag: File.Tag, decl_index: Module.Decl.Index) *Atom {
783 const decl = self.mod.declPtr(decl_index);
784 return switch (tag) {
785 .elf => &decl.link.elf.dbg_info_atom,
786 .macho => &decl.link.macho.dbg_info_atom,
787 .wasm => &decl.link.wasm.dbg_info_atom,
788 else => unreachable,
789 };
790 }
563};791};
564792
565pub const AbbrevEntry = struct {793pub const AbbrevEntry = struct {