authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-11-11 16:06:01-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-12 03:21:52-05:00
log2eeb7358227d13ff4d77ef73c54a0e2ae12c1d58
tree94660b851f8734a6b9520e6754937bb30511e648
parent3fc6a2f11399e84b9cfa4cfef65ef40aa6de173b

Dwarf: improve x86_64 backend debug info

Closes #17811

6 files changed, 432 insertions(+), 287 deletions(-)

lib/std/leb128.zig+61-2
......@@ -148,10 +148,10 @@ pub fn writeUnsignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.uns
148148 value >>= 7;
149149 ptr[i] = byte;
150150 }
151 ptr[i] = @as(u8, @truncate(value));
151 ptr[i] = @truncate(value);
152152}
153153
154test "writeUnsignedFixed" {
154test writeUnsignedFixed {
155155 {
156156 var buf: [4]u8 = undefined;
157157 writeUnsignedFixed(4, &buf, 0);
......@@ -174,6 +174,65 @@ test "writeUnsignedFixed" {
174174 }
175175}
176176
177/// This is an "advanced" function. It allows one to use a fixed amount of memory to store an
178/// ILEB128. This defeats the entire purpose of using this data encoding; it will no longer use
179/// fewer bytes to store smaller numbers. The advantage of using a fixed width is that it makes
180/// fields have a predictable size and so depending on the use case this tradeoff can be worthwhile.
181/// An example use case of this is in emitting DWARF info where one wants to make a ILEB128 field
182/// "relocatable", meaning that it becomes possible to later go back and patch the number to be a
183/// different value without shifting all the following code.
184pub fn writeSignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.signed, l * 7)) void {
185 const T = @TypeOf(int);
186 const U = if (@typeInfo(T).Int.bits < 8) u8 else T;
187 var value: U = @intCast(int);
188
189 comptime var i = 0;
190 inline while (i < (l - 1)) : (i += 1) {
191 const byte: u8 = @bitCast(@as(i8, @truncate(value)) | -0b1000_0000);
192 value >>= 7;
193 ptr[i] = byte;
194 }
195 ptr[i] = @as(u7, @bitCast(@as(i7, @truncate(value))));
196}
197
198test writeSignedFixed {
199 {
200 var buf: [4]u8 = undefined;
201 writeSignedFixed(4, &buf, 0);
202 try testing.expect((try test_read_ileb128(i64, &buf)) == 0);
203 }
204 {
205 var buf: [4]u8 = undefined;
206 writeSignedFixed(4, &buf, 1);
207 try testing.expect((try test_read_ileb128(i64, &buf)) == 1);
208 }
209 {
210 var buf: [4]u8 = undefined;
211 writeSignedFixed(4, &buf, -1);
212 try testing.expect((try test_read_ileb128(i64, &buf)) == -1);
213 }
214 {
215 var buf: [4]u8 = undefined;
216 writeSignedFixed(4, &buf, 1000);
217 try testing.expect((try test_read_ileb128(i64, &buf)) == 1000);
218 }
219 {
220 var buf: [4]u8 = undefined;
221 writeSignedFixed(4, &buf, -1000);
222 try testing.expect((try test_read_ileb128(i64, &buf)) == -1000);
223 }
224 {
225 var buf: [4]u8 = undefined;
226 writeSignedFixed(4, &buf, -10000000);
227 try testing.expect((try test_read_ileb128(i64, &buf)) == -10000000);
228 }
229 {
230 var buf: [4]u8 = undefined;
231 writeSignedFixed(4, &buf, 10000000);
232 try testing.expect((try test_read_ileb128(i64, &buf)) == 10000000);
233 }
234}
235
177236// tests
178237fn test_read_stream_ileb128(comptime T: type, encoded: []const u8) !T {
179238 var reader = std.io.fixedBufferStream(encoded);
src/arch/x86_64/CodeGen.zig+17-16
......@@ -10576,12 +10576,12 @@ fn genVarDbgInfo(
1057610576
1057710577fn airTrap(self: *Self) !void {
1057810578 try self.asmOpOnly(.{ ._, .ud2 });
10579 return self.finishAirBookkeeping();
10579 self.finishAirBookkeeping();
1058010580}
1058110581
1058210582fn airBreakpoint(self: *Self) !void {
1058310583 try self.asmOpOnly(.{ ._, .int3 });
10584 return self.finishAirBookkeeping();
10584 self.finishAirBookkeeping();
1058510585}
1058610586
1058710587fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
......@@ -10603,7 +10603,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {
1060310603 .Acquire, .Release, .AcqRel => {},
1060410604 .SeqCst => try self.asmOpOnly(.{ ._, .mfence }),
1060510605 }
10606 return self.finishAirBookkeeping();
10606 self.finishAirBookkeeping();
1060710607}
1060810608
1060910609fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
......@@ -11419,21 +11419,23 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
1141911419 .column = dbg_stmt.column,
1142011420 } },
1142111421 });
11422 return self.finishAirBookkeeping();
11422 self.finishAirBookkeeping();
1142311423}
1142411424
1142511425fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
11426 const mod = self.bin_file.options.module.?;
1142711426 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
11428 const func = mod.funcInfo(ty_fn.func);
11429 // TODO emit debug info for function change
11430 _ = func;
11431 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
11427 _ = try self.addInst(.{
11428 .tag = .pseudo,
11429 .ops = .pseudo_dbg_inline_func,
11430 .data = .{ .func = ty_fn.func },
11431 });
11432 self.finishAirBookkeeping();
1143211433}
1143311434
1143411435fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
11436 _ = inst;
1143511437 // TODO emit debug info lexical block
11436 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
11438 self.finishAirBookkeeping();
1143711439}
1143811440
1143911441fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
......@@ -11518,9 +11520,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
1151811520 .close_scope = true,
1151911521 });
1152011522
11521 // We already took care of pl_op.operand earlier, so we're going
11522 // to pass .none here
11523 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
11523 // We already took care of pl_op.operand earlier, so there's nothing left to do.
11524 self.finishAirBookkeeping();
1152411525}
1152511526
1152611527fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue {
......@@ -11865,7 +11866,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
1186511866 });
1186611867 _ = try self.asmJmpReloc(jmp_target);
1186711868
11868 return self.finishAirBookkeeping();
11869 self.finishAirBookkeeping();
1186911870}
1187011871
1187111872fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
......@@ -11977,8 +11978,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
1197711978 });
1197811979 }
1197911980
11980 // We already took care of pl_op.operand earlier, so we're going to pass .none here
11981 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
11981 // We already took care of pl_op.operand earlier, so there's nothing left to do
11982 self.finishAirBookkeeping();
1198211983}
1198311984
1198411985fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
src/arch/x86_64/Emit.zig+23-10
......@@ -151,7 +151,7 @@ pub fn emitMir(emit: *Emit) Error!void {
151151 else => unreachable,
152152 },
153153 .target = target,
154 .offset = @as(u32, @intCast(end_offset - 4)),
154 .offset = @intCast(end_offset - 4),
155155 .addend = 0,
156156 .pcrel = true,
157157 .length = 2,
......@@ -173,7 +173,7 @@ pub fn emitMir(emit: *Emit) Error!void {
173173 else => unreachable,
174174 },
175175 .target = target,
176 .offset = @as(u32, @intCast(end_offset - 4)),
176 .offset = @intCast(end_offset - 4),
177177 .addend = 0,
178178 .pcrel = true,
179179 .length = 2,
......@@ -182,7 +182,7 @@ pub fn emitMir(emit: *Emit) Error!void {
182182 const atom_index = symbol.atom_index;
183183 try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct
184184 .target = symbol.sym_index, // we set sym_index to just be the atom index
185 .offset = @as(u32, @intCast(end_offset - 4)),
185 .offset = @intCast(end_offset - 4),
186186 .addend = 0,
187187 .type = .pcrel,
188188 });
......@@ -229,6 +229,18 @@ pub fn emitMir(emit: *Emit) Error!void {
229229 .none => {},
230230 }
231231 },
232 .pseudo_dbg_inline_func => {
233 switch (emit.debug_output) {
234 .dwarf => |dw| {
235 log.debug("mirDbgInline (line={d}, col={d})", .{
236 emit.prev_di_line, emit.prev_di_column,
237 });
238 try dw.setInlineFunc(mir_inst.data.func);
239 },
240 .plan9 => {},
241 .none => {},
242 }
243 },
232244 .pseudo_dead_none => {},
233245 },
234246 }
......@@ -269,17 +281,18 @@ fn fixupRelocs(emit: *Emit) Error!void {
269281 for (emit.relocs.items) |reloc| {
270282 const target = emit.code_offset_mapping.get(reloc.target) orelse
271283 return emit.fail("JMP/CALL relocation target not found!", .{});
272 const disp = @as(i32, @intCast(@as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length))));
273 mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], disp, .little);
284 const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length));
285 mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], @intCast(disp), .little);
274286 }
275287}
276288
277289fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
278 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
290 const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line);
279291 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
280292 log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });
281293 switch (emit.debug_output) {
282294 .dwarf => |dw| {
295 if (column != emit.prev_di_column) try dw.setColumn(column);
283296 try dw.advancePCAndLine(delta_line, delta_pc);
284297 emit.prev_di_line = line;
285298 emit.prev_di_column = column;
......@@ -289,7 +302,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
289302 if (delta_pc <= 0) return; // only do this when the pc changes
290303
291304 // increasing the line number
292 try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line);
305 try link.File.Plan9.changeLine(&dbg_out.dbg_line, @intCast(delta_line));
293306 // increasing the pc
294307 const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta;
295308 if (d_pc_p9 > 0) {
......@@ -297,16 +310,16 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
297310 var diff = @divExact(d_pc_p9, dbg_out.pc_quanta) - dbg_out.pc_quanta;
298311 while (diff > 0) {
299312 if (diff < 64) {
300 try dbg_out.dbg_line.append(@as(u8, @intCast(diff + 128)));
313 try dbg_out.dbg_line.append(@intCast(diff + 128));
301314 diff = 0;
302315 } else {
303 try dbg_out.dbg_line.append(@as(u8, @intCast(64 + 128)));
316 try dbg_out.dbg_line.append(@intCast(64 + 128));
304317 diff -= 64;
305318 }
306319 }
307320 if (dbg_out.pcop_change_index) |pci|
308321 dbg_out.dbg_line.items[pci] += 1;
309 dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
322 dbg_out.pcop_change_index = @intCast(dbg_out.dbg_line.items.len - 1);
310323 } else if (d_pc_p9 == 0) {
311324 // we don't need to do anything, because adding the pc quanta does it for us
312325 } else unreachable;
src/arch/x86_64/Lower.zig+1
......@@ -259,6 +259,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
259259 .pseudo_dbg_prologue_end_none,
260260 .pseudo_dbg_line_line_column,
261261 .pseudo_dbg_epilogue_begin_none,
262 .pseudo_dbg_inline_func,
262263 .pseudo_dead_none,
263264 => {},
264265 else => unreachable,
src/arch/x86_64/Mir.zig+14-13
......@@ -6,19 +6,6 @@
66//! The main purpose of MIR is to postpone the assignment of offsets until Isel,
77//! so that, for example, the smaller encodings of jump instructions can be used.
88
9const Mir = @This();
10const std = @import("std");
11const builtin = @import("builtin");
12const assert = std.debug.assert;
13
14const bits = @import("bits.zig");
15const encoder = @import("encoder.zig");
16
17const Air = @import("../../Air.zig");
18const CodeGen = @import("CodeGen.zig");
19const IntegerBitSet = std.bit_set.IntegerBitSet;
20const Register = bits.Register;
21
229instructions: std.MultiArrayList(Inst).Slice,
2310/// The meaning of this data is determined by `Inst.Tag` value.
2411extra: []const u32,
......@@ -884,6 +871,8 @@ pub const Inst = struct {
884871 pseudo_dbg_line_line_column,
885872 /// Start of epilogue
886873 pseudo_dbg_epilogue_begin_none,
874 /// Start or end of inline function
875 pseudo_dbg_inline_func,
887876
888877 /// Tombstone
889878 /// Emitter should skip this instruction.
......@@ -987,6 +976,7 @@ pub const Inst = struct {
987976 line: u32,
988977 column: u32,
989978 },
979 func: InternPool.Index,
990980 /// Register list
991981 reg_list: RegisterList,
992982 };
......@@ -1198,3 +1188,14 @@ pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
11981188 } else mem,
11991189 };
12001190}
1191
1192const assert = std.debug.assert;
1193const bits = @import("bits.zig");
1194const builtin = @import("builtin");
1195const encoder = @import("encoder.zig");
1196const std = @import("std");
1197
1198const IntegerBitSet = std.bit_set.IntegerBitSet;
1199const InternPool = @import("../../InternPool.zig");
1200const Mir = @This();
1201const Register = bits.Register;
src/link/Dwarf.zig+316-246
......@@ -19,6 +19,8 @@ di_atom_last_index: ?Atom.Index = null,
1919di_atoms: std.ArrayListUnmanaged(Atom) = .{},
2020di_atom_decls: AtomTable = .{},
2121
22dbg_line_header: DbgLineHeader,
23
2224abbrev_table_offset: ?u64 = null,
2325
2426/// TODO replace with InternPool
......@@ -50,48 +52,48 @@ const Atom = struct {
5052 pub const Index = u32;
5153};
5254
55const DbgLineHeader = struct {
56 minimum_instruction_length: u8,
57 maximum_operations_per_instruction: u8,
58 default_is_stmt: bool,
59 line_base: i8,
60 line_range: u8,
61 opcode_base: u8,
62};
63
5364/// Represents state of the analysed Decl.
5465/// Includes Decl's abbrev table of type Types, matching arena
5566/// and a set of relocations that will be resolved once this
5667/// Decl's inner Atom is assigned an offset within the DWARF section.
5768pub const DeclState = struct {
58 gpa: Allocator,
69 dwarf: *Dwarf,
5970 mod: *Module,
6071 di_atom_decls: *const AtomTable,
72 dbg_line_func: InternPool.Index,
6173 dbg_line: std.ArrayList(u8),
6274 dbg_info: std.ArrayList(u8),
6375 abbrev_type_arena: std.heap.ArenaAllocator,
64 abbrev_table: std.ArrayListUnmanaged(AbbrevEntry) = .{},
65 abbrev_resolver: std.AutoHashMapUnmanaged(InternPool.Index, u32) = .{},
66 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
67 exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{},
68
69 fn init(gpa: Allocator, mod: *Module, di_atom_decls: *const AtomTable) DeclState {
70 return .{
71 .gpa = gpa,
72 .mod = mod,
73 .di_atom_decls = di_atom_decls,
74 .dbg_line = std.ArrayList(u8).init(gpa),
75 .dbg_info = std.ArrayList(u8).init(gpa),
76 .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),
77 };
78 }
76 abbrev_table: std.ArrayListUnmanaged(AbbrevEntry),
77 abbrev_resolver: std.AutoHashMapUnmanaged(InternPool.Index, u32),
78 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation),
79 exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation),
7980
8081 pub fn deinit(self: *DeclState) void {
82 const gpa = self.dwarf.allocator;
8183 self.dbg_line.deinit();
8284 self.dbg_info.deinit();
8385 self.abbrev_type_arena.deinit();
84 self.abbrev_table.deinit(self.gpa);
85 self.abbrev_resolver.deinit(self.gpa);
86 self.abbrev_relocs.deinit(self.gpa);
87 self.exprloc_relocs.deinit(self.gpa);
86 self.abbrev_table.deinit(gpa);
87 self.abbrev_resolver.deinit(gpa);
88 self.abbrev_relocs.deinit(gpa);
89 self.exprloc_relocs.deinit(gpa);
8890 }
8991
9092 /// Adds local type relocation of the form: @offset => @this + addend
9193 /// @this signifies the offset within the .debug_abbrev section of the containing atom.
9294 fn addTypeRelocLocal(self: *DeclState, atom_index: Atom.Index, offset: u32, addend: u32) !void {
9395 log.debug("{x}: @this + {x}", .{ offset, addend });
94 try self.abbrev_relocs.append(self.gpa, .{
96 try self.abbrev_relocs.append(self.dwarf.allocator, .{
9597 .target = null,
9698 .atom_index = atom_index,
9799 .offset = offset,
......@@ -103,19 +105,20 @@ pub const DeclState = struct {
103105 /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section
104106 /// which we use as our target of the relocation.
105107 fn addTypeRelocGlobal(self: *DeclState, atom_index: Atom.Index, ty: Type, offset: u32) !void {
108 const gpa = self.dwarf.allocator;
106109 const resolv = self.abbrev_resolver.get(ty.toIntern()) orelse blk: {
107 const sym_index = @as(u32, @intCast(self.abbrev_table.items.len));
108 try self.abbrev_table.append(self.gpa, .{
110 const sym_index: u32 = @intCast(self.abbrev_table.items.len);
111 try self.abbrev_table.append(gpa, .{
109112 .atom_index = atom_index,
110113 .type = ty,
111114 .offset = undefined,
112115 });
113116 log.debug("%{d}: {}", .{ sym_index, ty.fmt(self.mod) });
114 try self.abbrev_resolver.putNoClobber(self.gpa, ty.toIntern(), sym_index);
117 try self.abbrev_resolver.putNoClobber(gpa, ty.toIntern(), sym_index);
115118 break :blk sym_index;
116119 };
117120 log.debug("{x}: %{d} + 0", .{ offset, resolv });
118 try self.abbrev_relocs.append(self.gpa, .{
121 try self.abbrev_relocs.append(gpa, .{
119122 .target = resolv,
120123 .atom_index = atom_index,
121124 .offset = offset,
......@@ -192,7 +195,7 @@ pub const DeclState = struct {
192195 // DW.AT.type, DW.FORM.ref4
193196 var index = dbg_info_buffer.items.len;
194197 try dbg_info_buffer.resize(index + 4);
195 try self.addTypeRelocGlobal(atom_index, Type.bool, @as(u32, @intCast(index)));
198 try self.addTypeRelocGlobal(atom_index, Type.bool, @intCast(index));
196199 // DW.AT.data_member_location, DW.FORM.udata
197200 try dbg_info_buffer.ensureUnusedCapacity(6);
198201 dbg_info_buffer.appendAssumeCapacity(0);
......@@ -204,7 +207,7 @@ pub const DeclState = struct {
204207 // DW.AT.type, DW.FORM.ref4
205208 index = dbg_info_buffer.items.len;
206209 try dbg_info_buffer.resize(index + 4);
207 try self.addTypeRelocGlobal(atom_index, payload_ty, @as(u32, @intCast(index)));
210 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(index));
208211 // DW.AT.data_member_location, DW.FORM.udata
209212 const offset = abi_size - payload_ty.abiSize(mod);
210213 try leb128.writeULEB128(dbg_info_buffer.writer(), offset);
......@@ -216,7 +219,7 @@ pub const DeclState = struct {
216219 if (ty.isSlice(mod)) {
217220 // Slices are structs: struct { .ptr = *, .len = N }
218221 const ptr_bits = target.ptrBitWidth();
219 const ptr_bytes = @as(u8, @intCast(@divExact(ptr_bits, 8)));
222 const ptr_bytes: u8 = @intCast(@divExact(ptr_bits, 8));
220223 // DW.AT.structure_type
221224 try dbg_info_buffer.ensureUnusedCapacity(2);
222225 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.struct_type));
......@@ -234,7 +237,7 @@ pub const DeclState = struct {
234237 var index = dbg_info_buffer.items.len;
235238 try dbg_info_buffer.resize(index + 4);
236239 const ptr_ty = ty.slicePtrFieldType(mod);
237 try self.addTypeRelocGlobal(atom_index, ptr_ty, @as(u32, @intCast(index)));
240 try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(index));
238241 // DW.AT.data_member_location, DW.FORM.udata
239242 try dbg_info_buffer.ensureUnusedCapacity(6);
240243 dbg_info_buffer.appendAssumeCapacity(0);
......@@ -246,7 +249,7 @@ pub const DeclState = struct {
246249 // DW.AT.type, DW.FORM.ref4
247250 index = dbg_info_buffer.items.len;
248251 try dbg_info_buffer.resize(index + 4);
249 try self.addTypeRelocGlobal(atom_index, Type.usize, @as(u32, @intCast(index)));
252 try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(index));
250253 // DW.AT.data_member_location, DW.FORM.udata
251254 try dbg_info_buffer.ensureUnusedCapacity(2);
252255 dbg_info_buffer.appendAssumeCapacity(ptr_bytes);
......@@ -258,7 +261,7 @@ pub const DeclState = struct {
258261 // DW.AT.type, DW.FORM.ref4
259262 const index = dbg_info_buffer.items.len;
260263 try dbg_info_buffer.resize(index + 4);
261 try self.addTypeRelocGlobal(atom_index, ty.childType(mod), @as(u32, @intCast(index)));
264 try self.addTypeRelocGlobal(atom_index, ty.childType(mod), @intCast(index));
262265 }
263266 },
264267 .Array => {
......@@ -269,13 +272,13 @@ pub const DeclState = struct {
269272 // DW.AT.type, DW.FORM.ref4
270273 var index = dbg_info_buffer.items.len;
271274 try dbg_info_buffer.resize(index + 4);
272 try self.addTypeRelocGlobal(atom_index, ty.childType(mod), @as(u32, @intCast(index)));
275 try self.addTypeRelocGlobal(atom_index, ty.childType(mod), @intCast(index));
273276 // DW.AT.subrange_type
274277 try dbg_info_buffer.append(@intFromEnum(AbbrevKind.array_dim));
275278 // DW.AT.type, DW.FORM.ref4
276279 index = dbg_info_buffer.items.len;
277280 try dbg_info_buffer.resize(index + 4);
278 try self.addTypeRelocGlobal(atom_index, Type.usize, @as(u32, @intCast(index)));
281 try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(index));
279282 // DW.AT.count, DW.FORM.udata
280283 const len = ty.arrayLenIncludingSentinel(mod);
281284 try leb128.writeULEB128(dbg_info_buffer.writer(), len);
......@@ -302,7 +305,7 @@ pub const DeclState = struct {
302305 // DW.AT.type, DW.FORM.ref4
303306 var index = dbg_info_buffer.items.len;
304307 try dbg_info_buffer.resize(index + 4);
305 try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @as(u32, @intCast(index)));
308 try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @intCast(index));
306309 // DW.AT.data_member_location, DW.FORM.udata
307310 const field_off = ty.structFieldOffset(field_index, mod);
308311 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
......@@ -328,7 +331,7 @@ pub const DeclState = struct {
328331 // DW.AT.type, DW.FORM.ref4
329332 var index = dbg_info_buffer.items.len;
330333 try dbg_info_buffer.resize(index + 4);
331 try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @as(u32, @intCast(index)));
334 try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @intCast(index));
332335 // DW.AT.data_member_location, DW.FORM.udata
333336 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
334337 }
......@@ -387,7 +390,7 @@ pub const DeclState = struct {
387390 // TODO do not assume a 64bit enum value - could be bigger.
388391 // See https://github.com/ziglang/zig/issues/645
389392 const field_int_val = try value.toValue().intFromEnum(ty, mod);
390 break :value @as(u64, @bitCast(field_int_val.toSignedInt(mod)));
393 break :value @bitCast(field_int_val.toSignedInt(mod));
391394 };
392395 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian);
393396 }
......@@ -422,7 +425,7 @@ pub const DeclState = struct {
422425 // DW.AT.type, DW.FORM.ref4
423426 const inner_union_index = dbg_info_buffer.items.len;
424427 try dbg_info_buffer.resize(inner_union_index + 4);
425 try self.addTypeRelocLocal(atom_index, @as(u32, @intCast(inner_union_index)), 5);
428 try self.addTypeRelocLocal(atom_index, @intCast(inner_union_index), 5);
426429 // DW.AT.data_member_location, DW.FORM.udata
427430 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
428431 }
......@@ -502,7 +505,7 @@ pub const DeclState = struct {
502505 // DW.AT.type, DW.FORM.ref4
503506 const index = dbg_info_buffer.items.len;
504507 try dbg_info_buffer.resize(index + 4);
505 try self.addTypeRelocGlobal(atom_index, payload_ty, @as(u32, @intCast(index)));
508 try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(index));
506509 // DW.AT.data_member_location, DW.FORM.udata
507510 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
508511 }
......@@ -517,7 +520,7 @@ pub const DeclState = struct {
517520 // DW.AT.type, DW.FORM.ref4
518521 const index = dbg_info_buffer.items.len;
519522 try dbg_info_buffer.resize(index + 4);
520 try self.addTypeRelocGlobal(atom_index, error_ty, @as(u32, @intCast(index)));
523 try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(index));
521524 // DW.AT.data_member_location, DW.FORM.udata
522525 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
523526 }
......@@ -581,7 +584,7 @@ pub const DeclState = struct {
581584 },
582585 .register_pair => |regs| {
583586 const reg_bits = self.mod.getTarget().ptrBitWidth();
584 const reg_bytes = @as(u8, @intCast(@divExact(reg_bits, 8)));
587 const reg_bytes: u8 = @intCast(@divExact(reg_bits, 8));
585588 const abi_size = ty.abiSize(self.mod);
586589 try dbg_info.ensureUnusedCapacity(10);
587590 dbg_info.appendAssumeCapacity(@intFromEnum(AbbrevKind.parameter));
......@@ -658,7 +661,7 @@ pub const DeclState = struct {
658661 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
659662 const index = dbg_info.items.len;
660663 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
661 try self.addTypeRelocGlobal(atom_index, ty, @as(u32, @intCast(index))); // DW.AT.type, DW.FORM.ref4
664 try self.addTypeRelocGlobal(atom_index, ty, @intCast(index)); // DW.AT.type, DW.FORM.ref4
662665 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
663666 }
664667
......@@ -674,6 +677,7 @@ pub const DeclState = struct {
674677 const atom_index = self.di_atom_decls.get(owner_decl).?;
675678 const name_with_null = name.ptr[0 .. name.len + 1];
676679 try dbg_info.append(@intFromEnum(AbbrevKind.variable));
680 const gpa = self.dwarf.allocator;
677681 const mod = self.mod;
678682 const target = mod.getTarget();
679683 const endian = target.cpu.arch.endian();
......@@ -701,7 +705,7 @@ pub const DeclState = struct {
701705
702706 .register_pair => |regs| {
703707 const reg_bits = self.mod.getTarget().ptrBitWidth();
704 const reg_bytes = @as(u8, @intCast(@divExact(reg_bits, 8)));
708 const reg_bytes: u8 = @intCast(@divExact(reg_bits, 8));
705709 const abi_size = child_ty.abiSize(self.mod);
706710 try dbg_info.ensureUnusedCapacity(9);
707711 // DW.AT.location, DW.FORM.exprloc
......@@ -775,20 +779,20 @@ pub const DeclState = struct {
775779 .memory,
776780 .linker_load,
777781 => {
778 const ptr_width = @as(u8, @intCast(@divExact(target.ptrBitWidth(), 8)));
782 const ptr_width: u8 = @intCast(@divExact(target.ptrBitWidth(), 8));
779783 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
780784 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
781785 1 + ptr_width + @intFromBool(is_ptr),
782786 DW.OP.addr, // literal address
783787 });
784 const offset = @as(u32, @intCast(dbg_info.items.len));
788 const offset: u32 = @intCast(dbg_info.items.len);
785789 const addr = switch (loc) {
786790 .memory => |x| x,
787791 else => 0,
788792 };
789793 switch (ptr_width) {
790794 0...4 => {
791 try dbg_info.writer().writeInt(u32, @as(u32, @intCast(addr)), endian);
795 try dbg_info.writer().writeInt(u32, @intCast(addr), endian);
792796 },
793797 5...8 => {
794798 try dbg_info.writer().writeInt(u64, addr, endian);
......@@ -803,7 +807,7 @@ pub const DeclState = struct {
803807 .linker_load => |load_struct| switch (load_struct.type) {
804808 .direct => {
805809 log.debug("{x}: target sym %{d}", .{ offset, load_struct.sym_index });
806 try self.exprloc_relocs.append(self.gpa, .{
810 try self.exprloc_relocs.append(gpa, .{
807811 .type = .direct_load,
808812 .target = load_struct.sym_index,
809813 .offset = offset,
......@@ -811,7 +815,7 @@ pub const DeclState = struct {
811815 },
812816 .got => {
813817 log.debug("{x}: target sym %{d} via GOT", .{ offset, load_struct.sym_index });
814 try self.exprloc_relocs.append(self.gpa, .{
818 try self.exprloc_relocs.append(gpa, .{
815819 .type = .got_load,
816820 .target = load_struct.sym_index,
817821 .offset = offset,
......@@ -836,15 +840,15 @@ pub const DeclState = struct {
836840 try leb128.writeULEB128(dbg_info.writer(), x);
837841 }
838842 try dbg_info.append(DW.OP.stack_value);
839 dbg_info.items[fixup] += @as(u8, @intCast(dbg_info.items.len - fixup - 2));
843 dbg_info.items[fixup] += @intCast(dbg_info.items.len - fixup - 2);
840844 },
841845
842846 .undef => {
843847 // DW.AT.location, DW.FORM.exprloc
844848 // uleb128(exprloc_len)
845849 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
846 const abi_size = @as(u32, @intCast(child_ty.abiSize(mod)));
847 var implicit_value_len = std.ArrayList(u8).init(self.gpa);
850 const abi_size: u32 = @intCast(child_ty.abiSize(mod));
851 var implicit_value_len = std.ArrayList(u8).init(gpa);
848852 defer implicit_value_len.deinit();
849853 try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
850854 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
......@@ -873,27 +877,55 @@ pub const DeclState = struct {
873877 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
874878 const index = dbg_info.items.len;
875879 try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4
876 try self.addTypeRelocGlobal(atom_index, child_ty, @as(u32, @intCast(index)));
880 try self.addTypeRelocGlobal(atom_index, child_ty, @intCast(index));
877881 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
878882 }
879883
880884 pub fn advancePCAndLine(
881885 self: *DeclState,
882 delta_line: i32,
883 delta_pc: usize,
886 delta_line: i33,
887 delta_pc: u64,
884888 ) error{OutOfMemory}!void {
885 // TODO Look into using the DWARF special opcodes to compress this data.
886 // It lets you emit single-byte opcodes that add different numbers to
887 // both the PC and the line number at the same time.
888889 const dbg_line = &self.dbg_line;
889 try dbg_line.ensureUnusedCapacity(11);
890 dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
891 leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
892 if (delta_line != 0) {
890 try dbg_line.ensureUnusedCapacity(5 + 5 + 1);
891
892 const header = self.dwarf.dbg_line_header;
893 assert(header.maximum_operations_per_instruction == 1);
894 const delta_op: u64 = 0;
895
896 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
897 delta_line - header.line_base >= header.line_range)
898 remaining: {
899 assert(delta_line != 0);
893900 dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
894901 leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
902 break :remaining 0;
903 } else delta_line);
904
905 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
906 header.maximum_operations_per_instruction + delta_op;
907 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
908 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {
909 dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
910 leb128.writeULEB128(dbg_line.writer(), op_advance) catch unreachable;
911 break :remaining 0;
912 } else if (op_advance >= max_op_advance) remaining: {
913 dbg_line.appendAssumeCapacity(DW.LNS.const_add_pc);
914 break :remaining op_advance - max_op_advance;
915 } else op_advance);
916
917 if (remaining_delta_line == 0 and remaining_op_advance == 0) {
918 dbg_line.appendAssumeCapacity(DW.LNS.copy);
919 } else {
920 dbg_line.appendAssumeCapacity(@intCast((remaining_delta_line - header.line_base) +
921 (header.line_range * remaining_op_advance) + header.opcode_base));
895922 }
896 dbg_line.appendAssumeCapacity(DW.LNS.copy);
923 }
924
925 pub fn setColumn(self: *DeclState, column: u32) error{OutOfMemory}!void {
926 try self.dbg_line.ensureUnusedCapacity(1 + 5);
927 self.dbg_line.appendAssumeCapacity(DW.LNS.set_column);
928 leb128.writeULEB128(self.dbg_line.writer(), column + 1) catch unreachable;
897929 }
898930
899931 pub fn setPrologueEnd(self: *DeclState) error{OutOfMemory}!void {
......@@ -903,6 +935,31 @@ pub const DeclState = struct {
903935 pub fn setEpilogueBegin(self: *DeclState) error{OutOfMemory}!void {
904936 try self.dbg_line.append(DW.LNS.set_epilogue_begin);
905937 }
938
939 pub fn setInlineFunc(self: *DeclState, func: InternPool.Index) error{OutOfMemory}!void {
940 if (self.dbg_line_func == func) return;
941
942 try self.dbg_line.ensureUnusedCapacity((1 + 4) + (1 + 5));
943
944 const old_func_info = self.mod.funcInfo(self.dbg_line_func);
945 const new_func_info = self.mod.funcInfo(func);
946
947 const old_file = try self.dwarf.addDIFile(self.mod, old_func_info.owner_decl);
948 const new_file = try self.dwarf.addDIFile(self.mod, new_func_info.owner_decl);
949 if (old_file != new_file) {
950 self.dbg_line.appendAssumeCapacity(DW.LNS.set_file);
951 leb128.writeUnsignedFixed(4, self.dbg_line.addManyAsArrayAssumeCapacity(4), new_file);
952 }
953
954 const old_src_line: i33 = self.mod.declPtr(old_func_info.owner_decl).src_line;
955 const new_src_line: i33 = self.mod.declPtr(new_func_info.owner_decl).src_line;
956 if (new_src_line != old_src_line) {
957 self.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
958 leb128.writeSignedFixed(5, self.dbg_line.addManyAsArrayAssumeCapacity(5), new_src_line - old_src_line);
959 }
960
961 self.dbg_line_func = func;
962 }
906963};
907964
908965pub const AbbrevEntry = struct {
......@@ -966,7 +1023,8 @@ const min_nop_size = 2;
9661023const ideal_factor = 3;
9671024
9681025pub fn init(allocator: Allocator, bin_file: *File, format: Format) Dwarf {
969 const ptr_width: PtrWidth = switch (bin_file.options.target.ptrBitWidth()) {
1026 const target = &bin_file.options.target;
1027 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
9701028 0...32 => .p32,
9711029 33...64 => .p64,
9721030 else => unreachable,
......@@ -976,6 +1034,24 @@ pub fn init(allocator: Allocator, bin_file: *File, format: Format) Dwarf {
9761034 .bin_file = bin_file,
9771035 .format = format,
9781036 .ptr_width = ptr_width,
1037 .dbg_line_header = switch (target.cpu.arch) {
1038 .x86_64 => .{
1039 .minimum_instruction_length = 1,
1040 .maximum_operations_per_instruction = 1,
1041 .default_is_stmt = true,
1042 .line_base = -5,
1043 .line_range = 14,
1044 .opcode_base = DW.LNS.set_isa + 1,
1045 },
1046 else => .{
1047 .minimum_instruction_length = 1,
1048 .maximum_operations_per_instruction = 1,
1049 .default_is_stmt = true,
1050 .line_base = 1,
1051 .line_range = 1,
1052 .opcode_base = DW.LNS.set_isa + 1,
1053 },
1054 },
9791055 };
9801056}
9811057
......@@ -1002,12 +1078,24 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
10021078 defer tracy.end();
10031079
10041080 const decl = mod.declPtr(decl_index);
1005 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1081 const decl_linkage_name = try decl.getFullyQualifiedName(mod);
10061082
1007 log.debug("initDeclState {s}{*}", .{ decl_name, decl });
1083 log.debug("initDeclState {}{*}", .{ decl_linkage_name.fmt(&mod.intern_pool), decl });
10081084
10091085 const gpa = self.allocator;
1010 var decl_state = DeclState.init(gpa, mod, &self.di_atom_decls);
1086 var decl_state: DeclState = .{
1087 .dwarf = self,
1088 .mod = mod,
1089 .di_atom_decls = &self.di_atom_decls,
1090 .dbg_line_func = undefined,
1091 .dbg_line = std.ArrayList(u8).init(gpa),
1092 .dbg_info = std.ArrayList(u8).init(gpa),
1093 .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),
1094 .abbrev_table = .{},
1095 .abbrev_resolver = .{},
1096 .abbrev_relocs = .{},
1097 .exprloc_relocs = .{},
1098 };
10111099 errdefer decl_state.deinit();
10121100 const dbg_line_buffer = &decl_state.dbg_line;
10131101 const dbg_info_buffer = &decl_state.dbg_info;
......@@ -1021,18 +1109,19 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
10211109 _ = try self.getOrCreateAtomForDecl(.src_fn, decl_index);
10221110
10231111 // For functions we need to add a prologue to the debug line program.
1024 try dbg_line_buffer.ensureTotalCapacity(26);
1112 const ptr_width_bytes = self.ptrWidthBytes();
1113 try dbg_line_buffer.ensureTotalCapacity((3 + ptr_width_bytes) + (1 + 4) + (1 + 4) + (1 + 5) + 1);
10251114
1115 decl_state.dbg_line_func = decl.val.toIntern();
10261116 const func = decl.val.getFunction(mod).?;
10271117 log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{
10281118 decl.src_line,
10291119 func.lbrace_line,
10301120 func.rbrace_line,
10311121 });
1032 const line = @as(u28, @intCast(decl.src_line + func.lbrace_line));
1122 const line: u28 = @intCast(decl.src_line + func.lbrace_line);
10331123
1034 const ptr_width_bytes = self.ptrWidthBytes();
1035 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
1124 dbg_line_buffer.appendSliceAssumeCapacity(&.{
10361125 DW.LNS.extended_op,
10371126 ptr_width_bytes + 1,
10381127 DW.LNE.set_address,
......@@ -1055,21 +1144,24 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
10551144 const file_index = try self.addDIFile(mod, decl_index);
10561145 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
10571146
1147 dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_column);
1148 leb128.writeULEB128(dbg_line_buffer.writer(), func.lbrace_column + 1) catch unreachable;
1149
10581150 // Emit a line for the begin curly with prologue_end=false. The codegen will
10591151 // do the work of setting prologue_end=true and epilogue_begin=true.
10601152 dbg_line_buffer.appendAssumeCapacity(DW.LNS.copy);
10611153
10621154 // .debug_info subprogram
1063 const decl_name_with_null = decl_name[0 .. decl_name.len + 1];
1064 try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len);
1155 const decl_name_slice = mod.intern_pool.stringToSlice(decl.name);
1156 const decl_linkage_name_slice = mod.intern_pool.stringToSlice(decl_linkage_name);
1157 try dbg_info_buffer.ensureUnusedCapacity(1 + ptr_width_bytes + 4 + 4 +
1158 (decl_name_slice.len + 1) + (decl_linkage_name_slice.len + 1));
10651159
10661160 const fn_ret_type = decl.ty.fnReturnType(mod);
10671161 const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(mod);
1068 if (fn_ret_has_bits) {
1069 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.subprogram));
1070 } else {
1071 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.subprogram_retvoid));
1072 }
1162 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(
1163 @as(AbbrevKind, if (fn_ret_has_bits) .subprogram else .subprogram_retvoid),
1164 ));
10731165 // These get overwritten after generating the machine code. These values are
10741166 // "relocations" and have to be in this fixed place so that functions can be
10751167 // moved in virtual address space.
......@@ -1077,14 +1169,16 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index)
10771169 dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT.low_pc, DW.FORM.addr
10781170 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
10791171 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
1080 //
10811172 if (fn_ret_has_bits) {
1082 try decl_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @as(u32, @intCast(dbg_info_buffer.items.len)));
1173 try decl_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @intCast(dbg_info_buffer.items.len));
10831174 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
10841175 }
1085
1086 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string
1087
1176 dbg_info_buffer.appendSliceAssumeCapacity(
1177 decl_name_slice[0 .. decl_name_slice.len + 1],
1178 ); // DW.AT.name, DW.FORM.string
1179 dbg_info_buffer.appendSliceAssumeCapacity(
1180 decl_linkage_name_slice[0 .. decl_linkage_name_slice.len + 1],
1181 ); // DW.AT.linkage_name, DW.FORM.string
10881182 },
10891183 else => {
10901184 // TODO implement .debug_info for global variables
......@@ -1116,17 +1210,19 @@ pub fn commitDeclState(
11161210 assert(decl.has_tv);
11171211 switch (decl.ty.zigTypeTag(mod)) {
11181212 .Fn => {
1213 try decl_state.setInlineFunc(decl.val.toIntern());
1214
11191215 // Since the Decl is a function, we need to update the .debug_line program.
11201216 // Perform the relocations based on vaddr.
11211217 switch (self.ptr_width) {
11221218 .p32 => {
11231219 {
11241220 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
1125 mem.writeInt(u32, ptr, @as(u32, @intCast(sym_addr)), target_endian);
1221 mem.writeInt(u32, ptr, @intCast(sym_addr), target_endian);
11261222 }
11271223 {
11281224 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
1129 mem.writeInt(u32, ptr, @as(u32, @intCast(sym_addr)), target_endian);
1225 mem.writeInt(u32, ptr, @intCast(sym_addr), target_endian);
11301226 }
11311227 },
11321228 .p64 => {
......@@ -1146,7 +1242,7 @@ pub fn commitDeclState(
11461242 sym_size,
11471243 });
11481244 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
1149 mem.writeInt(u32, ptr, @as(u32, @intCast(sym_size)), target_endian);
1245 mem.writeInt(u32, ptr, @intCast(sym_size), target_endian);
11501246 }
11511247
11521248 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS.extended_op, 1, DW.LNE.end_sequence });
......@@ -1158,7 +1254,7 @@ pub fn commitDeclState(
11581254 // probably need to edit that logic too.
11591255 const src_fn_index = self.src_fn_decls.get(decl_index).?;
11601256 const src_fn = self.getAtomPtr(.src_fn, src_fn_index);
1161 src_fn.len = @as(u32, @intCast(dbg_line_buffer.items.len));
1257 src_fn.len = @intCast(dbg_line_buffer.items.len);
11621258
11631259 if (self.src_fn_last_index) |last_index| blk: {
11641260 if (src_fn_index == last_index) break :blk;
......@@ -1315,7 +1411,7 @@ pub fn commitDeclState(
13151411 }
13161412 }
13171413
1318 try self.updateDeclDebugInfoAllocation(di_atom_index, @as(u32, @intCast(dbg_info_buffer.items.len)));
1414 try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(dbg_info_buffer.items.len));
13191415
13201416 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
13211417 if (reloc.target) |target| {
......@@ -1448,7 +1544,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32)
14481544 self.di_atom_first_index = atom_index;
14491545 self.di_atom_last_index = atom_index;
14501546
1451 atom.off = @as(u32, @intCast(padToIdeal(self.dbgInfoHeaderBytes())));
1547 atom.off = @intCast(padToIdeal(self.dbgInfoHeaderBytes()));
14521548 }
14531549}
14541550
......@@ -1559,7 +1655,7 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: Module.Decl.
15591655 func.lbrace_line,
15601656 func.rbrace_line,
15611657 });
1562 const line = @as(u28, @intCast(decl.src_line + func.lbrace_line));
1658 const line: u28 = @intCast(decl.src_line + func.lbrace_line);
15631659 var data: [4]u8 = undefined;
15641660 leb128.writeUnsignedFixed(4, &data, line);
15651661
......@@ -1647,131 +1743,122 @@ pub fn freeDecl(self: *Dwarf, decl_index: Module.Decl.Index) void {
16471743pub fn writeDbgAbbrev(self: *Dwarf) !void {
16481744 // These are LEB encoded but since the values are all less than 127
16491745 // we can simply append these bytes.
1746 // zig fmt: off
16501747 const abbrev_buf = [_]u8{
1651 @intFromEnum(AbbrevKind.compile_unit), DW.TAG.compile_unit, DW.CHILDREN.yes, // header
1652 DW.AT.stmt_list, DW.FORM.sec_offset, DW.AT.low_pc,
1653 DW.FORM.addr, DW.AT.high_pc, DW.FORM.addr,
1654 DW.AT.name, DW.FORM.strp, DW.AT.comp_dir,
1655 DW.FORM.strp, DW.AT.producer, DW.FORM.strp,
1656 DW.AT.language, DW.FORM.data2, 0,
1657 0, // table sentinel
1748 @intFromEnum(AbbrevKind.compile_unit),
1749 DW.TAG.compile_unit,
1750 DW.CHILDREN.yes,
1751 DW.AT.stmt_list, DW.FORM.sec_offset,
1752 DW.AT.low_pc, DW.FORM.addr,
1753 DW.AT.high_pc, DW.FORM.addr,
1754 DW.AT.name, DW.FORM.strp,
1755 DW.AT.comp_dir, DW.FORM.strp,
1756 DW.AT.producer, DW.FORM.strp,
1757 DW.AT.language, DW.FORM.data2,
1758 0, 0,
1759
16581760 @intFromEnum(AbbrevKind.subprogram),
16591761 DW.TAG.subprogram,
1660 DW.CHILDREN.yes, // header
1661 DW.AT.low_pc,
1662 DW.FORM.addr,
1663 DW.AT.high_pc,
1664 DW.FORM.data4,
1665 DW.AT.type,
1666 DW.FORM.ref4,
1667 DW.AT.name,
1668 DW.FORM.string,
1669 0, 0, // table sentinel
1762 DW.CHILDREN.yes,
1763 DW.AT.low_pc, DW.FORM.addr,
1764 DW.AT.high_pc, DW.FORM.data4,
1765 DW.AT.type, DW.FORM.ref4,
1766 DW.AT.name, DW.FORM.string,
1767 DW.AT.linkage_name, DW.FORM.string,
1768 0, 0,
1769
16701770 @intFromEnum(AbbrevKind.subprogram_retvoid),
1671 DW.TAG.subprogram, DW.CHILDREN.yes, // header
1672 DW.AT.low_pc, DW.FORM.addr,
1673 DW.AT.high_pc, DW.FORM.data4,
1674 DW.AT.name, DW.FORM.string,
1675 0,
1676 0, // table sentinel
1771 DW.TAG.subprogram,
1772 DW.CHILDREN.yes,
1773 DW.AT.low_pc, DW.FORM.addr,
1774 DW.AT.high_pc, DW.FORM.data4,
1775 DW.AT.name, DW.FORM.string,
1776 DW.AT.linkage_name, DW.FORM.string,
1777 0, 0,
1778
16771779 @intFromEnum(AbbrevKind.base_type),
1678 DW.TAG.base_type,
1679 DW.CHILDREN.no, // header
1680 DW.AT.encoding,
1681 DW.FORM.data1,
1682 DW.AT.byte_size,
1683 DW.FORM.udata,
1684 DW.AT.name,
1685 DW.FORM.string,
1686 0,
1687 0, // table sentinel
1780 DW.TAG.base_type, DW.CHILDREN.no,
1781 DW.AT.encoding, DW.FORM.data1,
1782 DW.AT.byte_size, DW.FORM.udata,
1783 DW.AT.name, DW.FORM.string,
1784 0, 0,
1785
16881786 @intFromEnum(AbbrevKind.ptr_type),
1689 DW.TAG.pointer_type,
1690 DW.CHILDREN.no, // header
1691 DW.AT.type,
1692 DW.FORM.ref4,
1693 0,
1694 0, // table sentinel
1787 DW.TAG.pointer_type, DW.CHILDREN.no,
1788 DW.AT.type, DW.FORM.ref4,
1789 0, 0,
1790
16951791 @intFromEnum(AbbrevKind.struct_type),
1696 DW.TAG.structure_type,
1697 DW.CHILDREN.yes, // header
1698 DW.AT.byte_size,
1699 DW.FORM.udata,
1700 DW.AT.name,
1701 DW.FORM.string,
1702 0,
1703 0, // table sentinel
1792 DW.TAG.structure_type, DW.CHILDREN.yes,
1793 DW.AT.byte_size, DW.FORM.udata,
1794 DW.AT.name, DW.FORM.string,
1795 0, 0,
1796
17041797 @intFromEnum(AbbrevKind.struct_member),
17051798 DW.TAG.member,
1706 DW.CHILDREN.no, // header
1707 DW.AT.name,
1708 DW.FORM.string,
1709 DW.AT.type,
1710 DW.FORM.ref4,
1711 DW.AT.data_member_location,
1712 DW.FORM.udata,
1713 0,
1714 0, // table sentinel
1799 DW.CHILDREN.no,
1800 DW.AT.name, DW.FORM.string,
1801 DW.AT.type, DW.FORM.ref4,
1802 DW.AT.data_member_location, DW.FORM.udata,
1803 0, 0,
1804
17151805 @intFromEnum(AbbrevKind.enum_type),
17161806 DW.TAG.enumeration_type,
1717 DW.CHILDREN.yes, // header
1718 DW.AT.byte_size,
1719 DW.FORM.udata,
1720 DW.AT.name,
1721 DW.FORM.string,
1722 0,
1723 0, // table sentinel
1807 DW.CHILDREN.yes,
1808 DW.AT.byte_size, DW.FORM.udata,
1809 DW.AT.name, DW.FORM.string,
1810 0, 0,
1811
17241812 @intFromEnum(AbbrevKind.enum_variant),
1725 DW.TAG.enumerator,
1726 DW.CHILDREN.no, // header
1727 DW.AT.name,
1728 DW.FORM.string,
1729 DW.AT.const_value,
1730 DW.FORM.data8,
1731 0,
1732 0, // table sentinel
1813 DW.TAG.enumerator, DW.CHILDREN.no,
1814 DW.AT.name, DW.FORM.string,
1815 DW.AT.const_value, DW.FORM.data8,
1816 0, 0,
1817
17331818 @intFromEnum(AbbrevKind.union_type),
1734 DW.TAG.union_type,
1735 DW.CHILDREN.yes, // header
1736 DW.AT.byte_size,
1737 DW.FORM.udata,
1738 DW.AT.name,
1739 DW.FORM.string,
1740 0,
1741 0, // table sentinel
1819 DW.TAG.union_type, DW.CHILDREN.yes,
1820 DW.AT.byte_size, DW.FORM.udata,
1821 DW.AT.name, DW.FORM.string,
1822 0, 0,
1823
17421824 @intFromEnum(AbbrevKind.pad1),
17431825 DW.TAG.unspecified_type,
1744 DW.CHILDREN.no, // header
1745 0,
1746 0, // table sentinel
1826 DW.CHILDREN.no,
1827 0, 0,
1828
17471829 @intFromEnum(AbbrevKind.parameter),
1748 DW.TAG.formal_parameter, DW.CHILDREN.no, // header
1749 DW.AT.location, DW.FORM.exprloc,
1750 DW.AT.type, DW.FORM.ref4,
1751 DW.AT.name, DW.FORM.string,
1752 0,
1753 0, // table sentinel
1830 DW.TAG.formal_parameter,
1831 DW.CHILDREN.no,
1832 DW.AT.location, DW.FORM.exprloc,
1833 DW.AT.type, DW.FORM.ref4,
1834 DW.AT.name, DW.FORM.string,
1835 0, 0,
1836
17541837 @intFromEnum(AbbrevKind.variable),
1755 DW.TAG.variable, DW.CHILDREN.no, // header
1756 DW.AT.location, DW.FORM.exprloc,
1757 DW.AT.type, DW.FORM.ref4,
1758 DW.AT.name, DW.FORM.string,
1759 0,
1760 0, // table sentinel
1838 DW.TAG.variable,
1839 DW.CHILDREN.no,
1840 DW.AT.location, DW.FORM.exprloc,
1841 DW.AT.type, DW.FORM.ref4,
1842 DW.AT.name, DW.FORM.string,
1843 0, 0,
1844
17611845 @intFromEnum(AbbrevKind.array_type),
1762 DW.TAG.array_type, DW.CHILDREN.yes, // header
1763 DW.AT.name, DW.FORM.string,
1764 DW.AT.type, DW.FORM.ref4,
1765 0,
1766 0, // table sentinel
1846 DW.TAG.array_type,
1847 DW.CHILDREN.yes,
1848 DW.AT.name, DW.FORM.string,
1849 DW.AT.type, DW.FORM.ref4,
1850 0, 0,
1851
17671852 @intFromEnum(AbbrevKind.array_dim),
1768 DW.TAG.subrange_type, DW.CHILDREN.no, // header
1769 DW.AT.type, DW.FORM.ref4,
1770 DW.AT.count, DW.FORM.udata,
1853 DW.TAG.subrange_type,
1854 DW.CHILDREN.no,
1855 DW.AT.type, DW.FORM.ref4,
1856 DW.AT.count, DW.FORM.udata,
1857 0, 0,
1858
17711859 0,
1772 0, // table sentinel
1773 0, // section sentinel
17741860 };
1861 // zig fmt: on
17751862 const abbrev_offset = 0;
17761863 self.abbrev_table_offset = abbrev_offset;
17771864
......@@ -1910,7 +1997,7 @@ fn resolveCompilationDir(module: *Module, buffer: *[std.fs.MAX_PATH_BYTES]u8) []
19101997fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void {
19111998 const target_endian = self.bin_file.options.target.cpu.arch.endian();
19121999 switch (self.ptr_width) {
1913 .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(addr)), target_endian),
2000 .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(addr), target_endian),
19142001 .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian),
19152002 }
19162003}
......@@ -1918,12 +2005,7 @@ fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) voi
19182005fn writeOffsetAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), off: u64) void {
19192006 const target_endian = self.bin_file.options.target.cpu.arch.endian();
19202007 switch (self.format) {
1921 .dwarf32 => mem.writeInt(
1922 u32,
1923 buf.addManyAsArrayAssumeCapacity(4),
1924 @as(u32, @intCast(off)),
1925 target_endian,
1926 ),
2008 .dwarf32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(off), target_endian),
19272009 .dwarf64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), off, target_endian),
19282010 }
19292011}
......@@ -2182,16 +2264,11 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
21822264 // Go back and populate the initial length.
21832265 const init_len = di_buf.items.len - after_init_len;
21842266 switch (self.format) {
2185 .dwarf32 => mem.writeInt(
2186 u32,
2187 di_buf.items[init_len_index..][0..4],
2188 @as(u32, @intCast(init_len)),
2189 target_endian,
2190 ),
2267 .dwarf32 => mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(init_len), target_endian),
21912268 .dwarf64 => mem.writeInt(u64, di_buf.items[init_len_index..][0..8], init_len, target_endian),
21922269 }
21932270
2194 const needed_size = @as(u32, @intCast(di_buf.items.len));
2271 const needed_size: u32 = @intCast(di_buf.items.len);
21952272 switch (self.bin_file.tag) {
21962273 .elf => {
21972274 const elf_file = self.bin_file.cast(File.Elf).?;
......@@ -2256,14 +2333,14 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
22562333 self.writeOffsetAssumeCapacity(&di_buf, 0); // We will come back and write this.
22572334 const after_header_len = di_buf.items.len;
22582335
2259 const opcode_base = DW.LNS.set_isa + 1;
2336 assert(self.dbg_line_header.opcode_base == DW.LNS.set_isa + 1);
22602337 di_buf.appendSliceAssumeCapacity(&[_]u8{
2261 1, // minimum_instruction_length
2262 1, // maximum_operations_per_instruction
2263 1, // default_is_stmt
2264 1, // line_base (signed)
2265 1, // line_range
2266 opcode_base,
2338 self.dbg_line_header.minimum_instruction_length,
2339 self.dbg_line_header.maximum_operations_per_instruction,
2340 @intFromBool(self.dbg_line_header.default_is_stmt),
2341 @bitCast(self.dbg_line_header.line_base),
2342 self.dbg_line_header.line_range,
2343 self.dbg_line_header.opcode_base,
22672344
22682345 // Standard opcode lengths. The number of items here is based on `opcode_base`.
22692346 // The value is the number of LEB128 operands the instruction takes.
......@@ -2298,7 +2375,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
22982375 di_buf.appendSliceAssumeCapacity(file);
22992376 di_buf.appendSliceAssumeCapacity(&[_]u8{
23002377 0, // null byte for the relative path name
2301 @as(u8, @intCast(dir_index)), // directory_index
2378 @intCast(dir_index), // directory_index
23022379 0, // mtime (TODO supply this)
23032380 0, // file size bytes (TODO supply this)
23042381 });
......@@ -2307,12 +2384,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
23072384
23082385 const header_len = di_buf.items.len - after_header_len;
23092386 switch (self.format) {
2310 .dwarf32 => mem.writeInt(
2311 u32,
2312 di_buf.items[before_header_len..][0..4],
2313 @as(u32, @intCast(header_len)),
2314 target_endian,
2315 ),
2387 .dwarf32 => mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(header_len), target_endian),
23162388 .dwarf64 => mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian),
23172389 }
23182390
......@@ -2348,7 +2420,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
23482420 .macho => {
23492421 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
23502422 const sect_index = d_sym.debug_line_section_index.?;
2351 const needed_size = @as(u32, @intCast(d_sym.getSection(sect_index).size + delta));
2423 const needed_size: u32 = @intCast(d_sym.getSection(sect_index).size + delta);
23522424 try d_sym.growSection(sect_index, needed_size, true);
23532425 const file_pos = d_sym.getSection(sect_index).offset + first_fn.off;
23542426
......@@ -2384,7 +2456,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
23842456 const init_len = self.getDebugLineProgramEnd().? - init_len_size;
23852457 switch (self.format) {
23862458 .dwarf32 => {
2387 mem.writeInt(u32, di_buf.items[0..4], @as(u32, @intCast(init_len)), target_endian);
2459 mem.writeInt(u32, di_buf.items[0..4], @intCast(init_len), target_endian);
23882460 },
23892461 .dwarf64 => {
23902462 mem.writeInt(u64, di_buf.items[4..][0..8], init_len, target_endian);
......@@ -2449,12 +2521,12 @@ fn ptrWidthBytes(self: Dwarf) u8 {
24492521
24502522fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 {
24512523 var size: usize = switch (self.format) { // length field
2452 .dwarf32 => @as(usize, 4),
2524 .dwarf32 => 4,
24532525 .dwarf64 => 12,
24542526 };
24552527 size += @sizeOf(u16); // version field
24562528 size += switch (self.format) { // offset to end-of-header
2457 .dwarf32 => @as(usize, 4),
2529 .dwarf32 => 4,
24582530 .dwarf64 => 8,
24592531 };
24602532 size += 18; // opcodes
......@@ -2469,7 +2541,7 @@ fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []cons
24692541 }
24702542 size += 1; // file names sentinel
24712543
2472 return @as(u32, @intCast(size));
2544 return @intCast(size);
24732545}
24742546
24752547/// The reloc offset for the line offset of a function from the previous function's line.
......@@ -2514,22 +2586,20 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
25142586 log.debug("writeDeclDebugInfo in flushModule", .{});
25152587 try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items);
25162588
2517 const file_pos = blk: {
2518 switch (self.bin_file.tag) {
2519 .elf => {
2520 const elf_file = self.bin_file.cast(File.Elf).?;
2521 const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
2522 break :blk debug_info_sect.sh_offset;
2523 },
2524 .macho => {
2525 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2526 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
2527 break :blk debug_info_sect.offset;
2528 },
2529 // for wasm, the offset is always 0 as we write to memory first
2530 .wasm => break :blk @as(u32, 0),
2531 else => unreachable,
2532 }
2589 const file_pos = switch (self.bin_file.tag) {
2590 .elf => pos: {
2591 const elf_file = self.bin_file.cast(File.Elf).?;
2592 const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
2593 break :pos debug_info_sect.sh_offset;
2594 },
2595 .macho => pos: {
2596 const d_sym = self.bin_file.cast(File.MachO).?.getDebugSymbols().?;
2597 const debug_info_sect = d_sym.getSectionPtr(d_sym.debug_info_section_index.?);
2598 break :pos debug_info_sect.offset;
2599 },
2600 // for wasm, the offset is always 0 as we write to memory first
2601 .wasm => 0,
2602 else => unreachable,
25332603 };
25342604
25352605 var buf: [@sizeOf(u32)]u8 = undefined;
......@@ -2575,7 +2645,7 @@ fn addDIFile(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !u28 {
25752645 else => unreachable,
25762646 }
25772647 }
2578 return @as(u28, @intCast(gop.index + 1));
2648 return @intCast(gop.index + 1);
25792649}
25802650
25812651fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct {
......@@ -2603,9 +2673,9 @@ fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct {
26032673 else
26042674 dir_path;
26052675
2606 const dir_index: u28 = blk: {
2676 const dir_index: u28 = index: {
26072677 const dirs_gop = dirs.getOrPutAssumeCapacity(try arena.dupe(u8, resolved));
2608 break :blk @as(u28, @intCast(dirs_gop.index + 1));
2678 break :index @intCast(dirs_gop.index + 1);
26092679 };
26102680
26112681 files_dir_indexes.appendAssumeCapacity(dir_index);
......@@ -2680,12 +2750,12 @@ fn createAtom(self: *Dwarf, comptime kind: Kind) !Atom.Index {
26802750 const index = blk: {
26812751 switch (kind) {
26822752 .src_fn => {
2683 const index = @as(Atom.Index, @intCast(self.src_fns.items.len));
2753 const index: Atom.Index = @intCast(self.src_fns.items.len);
26842754 _ = try self.src_fns.addOne(self.allocator);
26852755 break :blk index;
26862756 },
26872757 .di_atom => {
2688 const index = @as(Atom.Index, @intCast(self.di_atoms.items.len));
2758 const index: Atom.Index = @intCast(self.di_atoms.items.len);
26892759 _ = try self.di_atoms.addOne(self.allocator);
26902760 break :blk index;
26912761 },