authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-28 07:40:33+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-28 07:40:33+02:00
logb8cd56dc94f68cda6616b4d9411d0419d2bb909f
tree57ff6e57dc9b041826e31e6ad7e652b605bedd91
parent7be340e3cc62285d77cbd13f19f4ff0a2a982e82
parent366ec2105249050fe88e5fa9f241e14f708db891
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11300 from ziglang/stage2-debug-error-sets


13 files changed, 557 insertions(+), 424 deletions(-)

src/arch/aarch64/Emit.zig+12-11
...@@ -386,18 +386,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -386,18 +386,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
386 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);386 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
387 const delta_pc: usize = self.code.items.len - self.prev_di_pc;387 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
388 switch (self.debug_output) {388 switch (self.debug_output) {
389 .dwarf => |dbg_out| {389 .dwarf => |dw| {
390 // TODO Look into using the DWARF special opcodes to compress this data.390 // TODO Look into using the DWARF special opcodes to compress this data.
391 // It lets you emit single-byte opcodes that add different numbers to391 // It lets you emit single-byte opcodes that add different numbers to
392 // both the PC and the line number at the same time.392 // both the PC and the line number at the same time.
393 try dbg_out.dbg_line.ensureUnusedCapacity(11);393 const dbg_line = dw.getDeclDebugLineBuffer();
394 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);394 try dbg_line.ensureUnusedCapacity(11);
395 leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;395 dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
396 leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
396 if (delta_line != 0) {397 if (delta_line != 0) {
397 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);398 dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
398 leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;399 leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
399 }400 }
400 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);401 dbg_line.appendAssumeCapacity(DW.LNS.copy);
401 self.prev_di_pc = self.code.items.len;402 self.prev_di_pc = self.code.items.len;
402 self.prev_di_line = line;403 self.prev_di_line = line;
403 self.prev_di_column = column;404 self.prev_di_column = column;
...@@ -586,8 +587,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -586,8 +587,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
586587
587fn mirDebugPrologueEnd(self: *Emit) !void {588fn mirDebugPrologueEnd(self: *Emit) !void {
588 switch (self.debug_output) {589 switch (self.debug_output) {
589 .dwarf => |dbg_out| {590 .dwarf => |dw| {
590 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);591 try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
591 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);592 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
592 },593 },
593 .plan9 => {},594 .plan9 => {},
...@@ -597,8 +598,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void {...@@ -597,8 +598,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void {
597598
598fn mirDebugEpilogueBegin(self: *Emit) !void {599fn mirDebugEpilogueBegin(self: *Emit) !void {
599 switch (self.debug_output) {600 switch (self.debug_output) {
600 .dwarf => |dbg_out| {601 .dwarf => |dw| {
601 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);602 try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin);
602 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);603 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
603 },604 },
604 .plan9 => {},605 .plan9 => {},
src/arch/arm/Emit.zig+37-36
...@@ -328,18 +328,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -328,18 +328,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
328 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);328 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
329 const delta_pc: usize = self.code.items.len - self.prev_di_pc;329 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
330 switch (self.debug_output) {330 switch (self.debug_output) {
331 .dwarf => |dbg_out| {331 .dwarf => |dw| {
332 // TODO Look into using the DWARF special opcodes to compress this data.332 // TODO Look into using the DWARF special opcodes to compress this data.
333 // It lets you emit single-byte opcodes that add different numbers to333 // It lets you emit single-byte opcodes that add different numbers to
334 // both the PC and the line number at the same time.334 // both the PC and the line number at the same time.
335 try dbg_out.dbg_line.ensureUnusedCapacity(11);335 const dbg_line = dw.getDeclDebugLineBuffer();
336 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);336 try dbg_line.ensureUnusedCapacity(11);
337 leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;337 dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
338 leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
338 if (delta_line != 0) {339 if (delta_line != 0) {
339 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);340 dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
340 leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;341 leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
341 }342 }
342 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);343 dbg_line.appendAssumeCapacity(DW.LNS.copy);
343 self.prev_di_pc = self.code.items.len;344 self.prev_di_pc = self.code.items.len;
344 self.prev_di_line = line;345 self.prev_di_line = line;
345 self.prev_di_column = column;346 self.prev_di_column = column;
...@@ -379,19 +380,17 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -379,19 +380,17 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
379/// after codegen for this symbol is done.380/// after codegen for this symbol is done.
380fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {381fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
381 switch (self.debug_output) {382 switch (self.debug_output) {
382 .dwarf => |dbg_out| {383 .dwarf => |dw| {
383 assert(ty.hasRuntimeBits());384 assert(ty.hasRuntimeBits());
384 const index = dbg_out.dbg_info.items.len;385 const dbg_info = dw.getDeclDebugInfoBuffer();
385 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4386 const index = dbg_info.items.len;
386387 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
387 const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.bin_file.allocator, ty, .{ .target = self.target.* });388 const atom = switch (self.bin_file.tag) {
388 if (!gop.found_existing) {389 .elf => &self.function.mod_fn.owner_decl.link.elf.dbg_info_atom,
389 gop.value_ptr.* = .{390 .macho => unreachable,
390 .off = undefined,391 else => unreachable,
391 .relocs = .{},392 };
392 };393 try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
393 }
394 try gop.value_ptr.relocs.append(self.bin_file.allocator, @intCast(u32, index));
395 },394 },
396 .plan9 => {},395 .plan9 => {},
397 .none => {},396 .none => {},
...@@ -409,16 +408,17 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {...@@ -409,16 +408,17 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
409 switch (mcv) {408 switch (mcv) {
410 .register => |reg| {409 .register => |reg| {
411 switch (self.debug_output) {410 switch (self.debug_output) {
412 .dwarf => |dbg_out| {411 .dwarf => |dw| {
413 try dbg_out.dbg_info.ensureUnusedCapacity(3);412 const dbg_info = dw.getDeclDebugInfoBuffer();
414 dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);413 try dbg_info.ensureUnusedCapacity(3);
415 dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc414 dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
415 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
416 1, // ULEB128 dwarf expression length416 1, // ULEB128 dwarf expression length
417 reg.dwarfLocOp(),417 reg.dwarfLocOp(),
418 });418 });
419 try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);419 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
420 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4420 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
421 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string421 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
422 },422 },
423 .plan9 => {},423 .plan9 => {},
424 .none => {},424 .none => {},
...@@ -428,7 +428,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {...@@ -428,7 +428,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
428 .stack_argument_offset,428 .stack_argument_offset,
429 => {429 => {
430 switch (self.debug_output) {430 switch (self.debug_output) {
431 .dwarf => |dbg_out| {431 .dwarf => |dw| {
432 const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {432 const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {
433 return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(target)});433 return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(target)});
434 };434 };
...@@ -442,7 +442,8 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {...@@ -442,7 +442,8 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
442 else => unreachable,442 else => unreachable,
443 };443 };
444444
445 try dbg_out.dbg_info.append(link.File.Dwarf.abbrev_parameter);445 const dbg_info = dw.getDeclDebugInfoBuffer();
446 try dbg_info.append(link.File.Dwarf.abbrev_parameter);
446447
447 // Get length of the LEB128 stack offset448 // Get length of the LEB128 stack offset
448 var counting_writer = std.io.countingWriter(std.io.null_writer);449 var counting_writer = std.io.countingWriter(std.io.null_writer);
...@@ -450,13 +451,13 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {...@@ -450,13 +451,13 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
450451
451 // DW.AT.location, DW.FORM.exprloc452 // DW.AT.location, DW.FORM.exprloc
452 // ULEB128 dwarf expression length453 // ULEB128 dwarf expression length
453 try leb128.writeULEB128(dbg_out.dbg_info.writer(), counting_writer.bytes_written + 1);454 try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1);
454 try dbg_out.dbg_info.append(DW.OP.breg11);455 try dbg_info.append(DW.OP.breg11);
455 try leb128.writeILEB128(dbg_out.dbg_info.writer(), adjusted_stack_offset);456 try leb128.writeILEB128(dbg_info.writer(), adjusted_stack_offset);
456457
457 try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);458 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
458 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4459 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
459 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string460 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
460 },461 },
461 .plan9 => {},462 .plan9 => {},
462 .none => {},463 .none => {},
...@@ -558,8 +559,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -558,8 +559,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
558559
559fn mirDebugPrologueEnd(emit: *Emit) !void {560fn mirDebugPrologueEnd(emit: *Emit) !void {
560 switch (emit.debug_output) {561 switch (emit.debug_output) {
561 .dwarf => |dbg_out| {562 .dwarf => |dw| {
562 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);563 try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
563 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);564 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
564 },565 },
565 .plan9 => {},566 .plan9 => {},
...@@ -569,8 +570,8 @@ fn mirDebugPrologueEnd(emit: *Emit) !void {...@@ -569,8 +570,8 @@ fn mirDebugPrologueEnd(emit: *Emit) !void {
569570
570fn mirDebugEpilogueBegin(emit: *Emit) !void {571fn mirDebugEpilogueBegin(emit: *Emit) !void {
571 switch (emit.debug_output) {572 switch (emit.debug_output) {
572 .dwarf => |dbg_out| {573 .dwarf => |dw| {
573 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);574 try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin);
574 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);575 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
575 },576 },
576 .plan9 => {},577 .plan9 => {},
src/arch/riscv64/CodeGen.zig+17-20
...@@ -745,21 +745,17 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -745,21 +745,17 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
745/// after codegen for this symbol is done.745/// after codegen for this symbol is done.
746fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {746fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
747 switch (self.debug_output) {747 switch (self.debug_output) {
748 .dwarf => |dbg_out| {748 .dwarf => |dw| {
749 assert(ty.hasRuntimeBits());749 assert(ty.hasRuntimeBits());
750 const index = dbg_out.dbg_info.items.len;750 const dbg_info = dw.getDeclDebugInfoBuffer();
751 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4751 const index = dbg_info.items.len;
752752 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
753 const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.gpa, ty, .{753 const atom = switch (self.bin_file.tag) {
754 .target = self.target.*,754 .elf => &self.mod_fn.owner_decl.link.elf.dbg_info_atom,
755 });755 .macho => unreachable,
756 if (!gop.found_existing) {756 else => unreachable,
757 gop.value_ptr.* = .{757 };
758 .off = undefined,758 try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
759 .relocs = .{},
760 };
761 }
762 try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index));
763 },759 },
764 .plan9 => {},760 .plan9 => {},
765 .none => {},761 .none => {},
...@@ -1573,16 +1569,17 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32...@@ -1573,16 +1569,17 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32
1573 switch (mcv) {1569 switch (mcv) {
1574 .register => |reg| {1570 .register => |reg| {
1575 switch (self.debug_output) {1571 switch (self.debug_output) {
1576 .dwarf => |dbg_out| {1572 .dwarf => |dw| {
1577 try dbg_out.dbg_info.ensureUnusedCapacity(3);1573 const dbg_info = dw.getDeclDebugInfoBuffer();
1578 dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);1574 try dbg_info.ensureUnusedCapacity(3);
1579 dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc1575 dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
1576 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1580 1, // ULEB128 dwarf expression length1577 1, // ULEB128 dwarf expression length
1581 reg.dwarfLocOp(),1578 reg.dwarfLocOp(),
1582 });1579 });
1583 try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);1580 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
1584 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref41581 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
1585 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string1582 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
1586 },1583 },
1587 .plan9 => {},1584 .plan9 => {},
1588 .none => {},1585 .none => {},
src/arch/riscv64/Emit.zig+12-11
...@@ -89,18 +89,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -89,18 +89,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
89 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);89 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
90 const delta_pc: usize = self.code.items.len - self.prev_di_pc;90 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
91 switch (self.debug_output) {91 switch (self.debug_output) {
92 .dwarf => |dbg_out| {92 .dwarf => |dw| {
93 // TODO Look into using the DWARF special opcodes to compress this data.93 // TODO Look into using the DWARF special opcodes to compress this data.
94 // It lets you emit single-byte opcodes that add different numbers to94 // It lets you emit single-byte opcodes that add different numbers to
95 // both the PC and the line number at the same time.95 // both the PC and the line number at the same time.
96 try dbg_out.dbg_line.ensureUnusedCapacity(11);96 const dbg_line = dw.getDeclDebugLineBuffer();
97 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);97 try dbg_line.ensureUnusedCapacity(11);
98 leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;98 dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
99 leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
99 if (delta_line != 0) {100 if (delta_line != 0) {
100 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);101 dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
101 leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;102 leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
102 }103 }
103 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);104 dbg_line.appendAssumeCapacity(DW.LNS.copy);
104 self.prev_di_pc = self.code.items.len;105 self.prev_di_pc = self.code.items.len;
105 self.prev_di_line = line;106 self.prev_di_line = line;
106 self.prev_di_column = column;107 self.prev_di_column = column;
...@@ -182,8 +183,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -182,8 +183,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
182183
183fn mirDebugPrologueEnd(self: *Emit) !void {184fn mirDebugPrologueEnd(self: *Emit) !void {
184 switch (self.debug_output) {185 switch (self.debug_output) {
185 .dwarf => |dbg_out| {186 .dwarf => |dw| {
186 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);187 try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
187 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);188 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
188 },189 },
189 .plan9 => {},190 .plan9 => {},
...@@ -193,8 +194,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void {...@@ -193,8 +194,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void {
193194
194fn mirDebugEpilogueBegin(self: *Emit) !void {195fn mirDebugEpilogueBegin(self: *Emit) !void {
195 switch (self.debug_output) {196 switch (self.debug_output) {
196 .dwarf => |dbg_out| {197 .dwarf => |dw| {
197 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);198 try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin);
198 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);199 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
199 },200 },
200 .plan9 => {},201 .plan9 => {},
src/arch/x86_64/CodeGen.zig+1
...@@ -350,6 +350,7 @@ pub fn generate(...@@ -350,6 +350,7 @@ pub fn generate(
350 var emit = Emit{350 var emit = Emit{
351 .mir = mir,351 .mir = mir,
352 .bin_file = bin_file,352 .bin_file = bin_file,
353 .function = &function,
353 .debug_output = debug_output,354 .debug_output = debug_output,
354 .target = &bin_file.options.target,355 .target = &bin_file.options.target,
355 .src_loc = src_loc,356 .src_loc = src_loc,
src/arch/x86_64/Emit.zig+41-40
...@@ -16,6 +16,7 @@ const testing = std.testing;...@@ -16,6 +16,7 @@ const testing = std.testing;
1616
17const Air = @import("../../Air.zig");17const Air = @import("../../Air.zig");
18const Allocator = mem.Allocator;18const Allocator = mem.Allocator;
19const CodeGen = @import("CodeGen.zig");
19const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;20const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
20const DW = std.dwarf;21const DW = std.dwarf;
21const Encoder = bits.Encoder;22const Encoder = bits.Encoder;
...@@ -29,6 +30,7 @@ const Type = @import("../../type.zig").Type;...@@ -29,6 +30,7 @@ const Type = @import("../../type.zig").Type;
2930
30mir: Mir,31mir: Mir,
31bin_file: *link.File,32bin_file: *link.File,
33function: *const CodeGen,
32debug_output: DebugInfoOutput,34debug_output: DebugInfoOutput,
33target: *const std.Target,35target: *const std.Target,
34err_msg: ?*ErrorMsg = null,36err_msg: ?*ErrorMsg = null,
...@@ -963,18 +965,19 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {...@@ -963,18 +965,19 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void {
963 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;965 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
964 log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });966 log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });
965 switch (emit.debug_output) {967 switch (emit.debug_output) {
966 .dwarf => |dbg_out| {968 .dwarf => |dw| {
967 // TODO Look into using the DWARF special opcodes to compress this data.969 // TODO Look into using the DWARF special opcodes to compress this data.
968 // It lets you emit single-byte opcodes that add different numbers to970 // It lets you emit single-byte opcodes that add different numbers to
969 // both the PC and the line number at the same time.971 // both the PC and the line number at the same time.
970 try dbg_out.dbg_line.ensureUnusedCapacity(11);972 const dbg_line = dw.getDeclDebugLineBuffer();
971 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);973 try dbg_line.ensureUnusedCapacity(11);
972 leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable;974 dbg_line.appendAssumeCapacity(DW.LNS.advance_pc);
975 leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable;
973 if (delta_line != 0) {976 if (delta_line != 0) {
974 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line);977 dbg_line.appendAssumeCapacity(DW.LNS.advance_line);
975 leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;978 leb128.writeILEB128(dbg_line.writer(), delta_line) catch unreachable;
976 }979 }
977 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);980 dbg_line.appendAssumeCapacity(DW.LNS.copy);
978 emit.prev_di_line = line;981 emit.prev_di_line = line;
979 emit.prev_di_column = column;982 emit.prev_di_column = column;
980 emit.prev_di_pc = emit.code.items.len;983 emit.prev_di_pc = emit.code.items.len;
...@@ -1022,8 +1025,8 @@ fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1022,8 +1025,8 @@ fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1022 const tag = emit.mir.instructions.items(.tag)[inst];1025 const tag = emit.mir.instructions.items(.tag)[inst];
1023 assert(tag == .dbg_prologue_end);1026 assert(tag == .dbg_prologue_end);
1024 switch (emit.debug_output) {1027 switch (emit.debug_output) {
1025 .dwarf => |dbg_out| {1028 .dwarf => |dw| {
1026 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);1029 try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end);
1027 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column });1030 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column });
1028 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);1031 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
1029 },1032 },
...@@ -1036,8 +1039,8 @@ fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1036,8 +1039,8 @@ fn mirDbgEpilogueBegin(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1036 const tag = emit.mir.instructions.items(.tag)[inst];1039 const tag = emit.mir.instructions.items(.tag)[inst];
1037 assert(tag == .dbg_epilogue_begin);1040 assert(tag == .dbg_epilogue_begin);
1038 switch (emit.debug_output) {1041 switch (emit.debug_output) {
1039 .dwarf => |dbg_out| {1042 .dwarf => |dw| {
1040 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);1043 try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin);
1041 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column });1044 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column });
1042 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);1045 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
1043 },1046 },
...@@ -1063,16 +1066,17 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32...@@ -1063,16 +1066,17 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32
1063 switch (mcv) {1066 switch (mcv) {
1064 .register => |reg| {1067 .register => |reg| {
1065 switch (emit.debug_output) {1068 switch (emit.debug_output) {
1066 .dwarf => |dbg_out| {1069 .dwarf => |dw| {
1067 try dbg_out.dbg_info.ensureUnusedCapacity(3);1070 const dbg_info = dw.getDeclDebugInfoBuffer();
1068 dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);1071 try dbg_info.ensureUnusedCapacity(3);
1069 dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc1072 dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
1073 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1070 1, // ULEB128 dwarf expression length1074 1, // ULEB128 dwarf expression length
1071 reg.dwarfLocOp(),1075 reg.dwarfLocOp(),
1072 });1076 });
1073 try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);1077 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
1074 try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref41078 try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
1075 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string1079 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
1076 },1080 },
1077 .plan9 => {},1081 .plan9 => {},
1078 .none => {},1082 .none => {},
...@@ -1080,25 +1084,26 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32...@@ -1080,25 +1084,26 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32
1080 },1084 },
1081 .stack_offset => |off| {1085 .stack_offset => |off| {
1082 switch (emit.debug_output) {1086 switch (emit.debug_output) {
1083 .dwarf => |dbg_out| {1087 .dwarf => |dw| {
1084 // we add here +16 like we do in airArg in CodeGen since we refer directly to1088 // we add here +16 like we do in airArg in CodeGen since we refer directly to
1085 // rbp as the start of function frame minus 8 bytes for caller's rbp preserved in the1089 // rbp as the start of function frame minus 8 bytes for caller's rbp preserved in the
1086 // prologue, and 8 bytes for return address.1090 // prologue, and 8 bytes for return address.
1087 // TODO we need to make this more generic if we don't use rbp as the frame pointer1091 // TODO we need to make this more generic if we don't use rbp as the frame pointer
1088 // for example when -fomit-frame-pointer is set.1092 // for example when -fomit-frame-pointer is set.
1089 const disp = @intCast(i32, max_stack) - off + 16;1093 const disp = @intCast(i32, max_stack) - off + 16;
1090 try dbg_out.dbg_info.ensureUnusedCapacity(8);1094 const dbg_info = dw.getDeclDebugInfoBuffer();
1091 dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);1095 try dbg_info.ensureUnusedCapacity(8);
1092 const fixup = dbg_out.dbg_info.items.len;1096 dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter);
1093 dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc1097 const fixup = dbg_info.items.len;
1098 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1094 1, // we will backpatch it after we encode the displacement in LEB1281099 1, // we will backpatch it after we encode the displacement in LEB128
1095 DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer1100 DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
1096 });1101 });
1097 leb128.writeILEB128(dbg_out.dbg_info.writer(), disp) catch unreachable;1102 leb128.writeILEB128(dbg_info.writer(), disp) catch unreachable;
1098 dbg_out.dbg_info.items[fixup] += @intCast(u8, dbg_out.dbg_info.items.len - fixup - 2);1103 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
1099 try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);1104 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
1100 try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref41105 try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
1101 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string1106 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
11021107
1103 },1108 },
1104 .plan9 => {},1109 .plan9 => {},
...@@ -1113,21 +1118,17 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32...@@ -1113,21 +1118,17 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32
1113/// after codegen for this symbol is done.1118/// after codegen for this symbol is done.
1114fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {1119fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
1115 switch (emit.debug_output) {1120 switch (emit.debug_output) {
1116 .dwarf => |dbg_out| {1121 .dwarf => |dw| {
1117 assert(ty.hasRuntimeBits());1122 assert(ty.hasRuntimeBits());
1118 const index = dbg_out.dbg_info.items.len;1123 const dbg_info = dw.getDeclDebugInfoBuffer();
1119 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref41124 const index = dbg_info.items.len;
11201125 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
1121 const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(emit.bin_file.allocator, ty, .{1126 const atom = switch (emit.bin_file.tag) {
1122 .target = emit.target.*,1127 .elf => &emit.function.mod_fn.owner_decl.link.elf.dbg_info_atom,
1123 });1128 .macho => &emit.function.mod_fn.owner_decl.link.macho.dbg_info_atom,
1124 if (!gop.found_existing) {1129 else => unreachable,
1125 gop.value_ptr.* = .{1130 };
1126 .off = undefined,1131 try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
1127 .relocs = .{},
1128 };
1129 }
1130 try gop.value_ptr.relocs.append(emit.bin_file.allocator, @intCast(u32, index));
1131 },1132 },
1132 .plan9 => {},1133 .plan9 => {},
1133 .none => {},1134 .none => {},
src/codegen.zig+15-23
...@@ -1,26 +1,25 @@...@@ -1,26 +1,25 @@
1const std = @import("std");1const std = @import("std");
2const build_options = @import("build_options");
2const builtin = @import("builtin");3const builtin = @import("builtin");
4const assert = std.debug.assert;
5const leb128 = std.leb;
6const link = @import("link.zig");
7const log = std.log.scoped(.codegen);
3const mem = std.mem;8const mem = std.mem;
4const math = std.math;9const math = std.math;
5const assert = std.debug.assert;10const trace = @import("tracy.zig").trace;
11
6const Air = @import("Air.zig");12const Air = @import("Air.zig");
7const Zir = @import("Zir.zig");13const Allocator = mem.Allocator;
8const Liveness = @import("Liveness.zig");
9const Type = @import("type.zig").Type;
10const Value = @import("value.zig").Value;
11const TypedValue = @import("TypedValue.zig");
12const link = @import("link.zig");
13const Module = @import("Module.zig");
14const Compilation = @import("Compilation.zig");14const Compilation = @import("Compilation.zig");
15const ErrorMsg = Module.ErrorMsg;15const ErrorMsg = Module.ErrorMsg;
16const Liveness = @import("Liveness.zig");
17const Module = @import("Module.zig");
16const Target = std.Target;18const Target = std.Target;
17const Allocator = mem.Allocator;19const Type = @import("type.zig").Type;
18const trace = @import("tracy.zig").trace;20const TypedValue = @import("TypedValue.zig");
19const DW = std.dwarf;21const Value = @import("value.zig").Value;
20const leb128 = std.leb;22const Zir = @import("Zir.zig");
21const log = std.log.scoped(.codegen);
22const build_options = @import("build_options");
23const RegisterManager = @import("register_manager.zig").RegisterManager;
2423
25pub const FnResult = union(enum) {24pub const FnResult = union(enum) {
26 /// The `code` parameter passed to `generateSymbol` has the value appended.25 /// The `code` parameter passed to `generateSymbol` has the value appended.
...@@ -43,11 +42,7 @@ pub const GenerateSymbolError = error{...@@ -43,11 +42,7 @@ pub const GenerateSymbolError = error{
43};42};
4443
45pub const DebugInfoOutput = union(enum) {44pub const DebugInfoOutput = union(enum) {
46 dwarf: struct {45 dwarf: *link.File.Dwarf,
47 dbg_line: *std.ArrayList(u8),
48 dbg_info: *std.ArrayList(u8),
49 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
50 },
51 /// the plan9 debuginfo output is a bytecode with 4 opcodes46 /// the plan9 debuginfo output is a bytecode with 4 opcodes
52 /// assume all numbers/variables are bytes47 /// assume all numbers/variables are bytes
53 /// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset48 /// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset
...@@ -573,7 +568,6 @@ pub fn generateSymbol(...@@ -573,7 +568,6 @@ pub fn generateSymbol(
573 return Result{ .appended = {} };568 return Result{ .appended = {} };
574 },569 },
575 .Union => {570 .Union => {
576 // TODO generate debug info for unions
577 const union_obj = typed_value.val.castTag(.@"union").?.data;571 const union_obj = typed_value.val.castTag(.@"union").?.data;
578 const layout = typed_value.ty.unionGetLayout(target);572 const layout = typed_value.ty.unionGetLayout(target);
579573
...@@ -695,7 +689,6 @@ pub fn generateSymbol(...@@ -695,7 +689,6 @@ pub fn generateSymbol(
695 return Result{ .appended = {} };689 return Result{ .appended = {} };
696 },690 },
697 .ErrorUnion => {691 .ErrorUnion => {
698 // TODO generate debug info for error unions
699 const error_ty = typed_value.ty.errorUnionSet();692 const error_ty = typed_value.ty.errorUnionSet();
700 const payload_ty = typed_value.ty.errorUnionPayload();693 const payload_ty = typed_value.ty.errorUnionPayload();
701 const is_payload = typed_value.val.errorUnionIsPayload();694 const is_payload = typed_value.val.errorUnionIsPayload();
...@@ -749,7 +742,6 @@ pub fn generateSymbol(...@@ -749,7 +742,6 @@ pub fn generateSymbol(
749 return Result{ .appended = {} };742 return Result{ .appended = {} };
750 },743 },
751 .ErrorSet => {744 .ErrorSet => {
752 // TODO generate debug info for error sets
753 switch (typed_value.val.tag()) {745 switch (typed_value.val.tag()) {
754 .@"error" => {746 .@"error" => {
755 const name = typed_value.val.getError().?;747 const name = typed_value.val.getError().?;
src/link.zig+10-28
...@@ -1,22 +1,22 @@...@@ -1,22 +1,22 @@
1const std = @import("std");1const std = @import("std");
2const build_options = @import("build_options");
2const builtin = @import("builtin");3const builtin = @import("builtin");
3const mem = std.mem;4const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;
5const fs = std.fs;5const fs = std.fs;
6const mem = std.mem;
6const log = std.log.scoped(.link);7const log = std.log.scoped(.link);
7const assert = std.debug.assert;8const trace = @import("tracy.zig").trace;
9const wasi_libc = @import("wasi_libc.zig");
810
11const Air = @import("Air.zig");
12const Allocator = std.mem.Allocator;
13const Cache = @import("Cache.zig");
9const Compilation = @import("Compilation.zig");14const Compilation = @import("Compilation.zig");
15const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
16const Liveness = @import("Liveness.zig");
10const Module = @import("Module.zig");17const Module = @import("Module.zig");
11const trace = @import("tracy.zig").trace;
12const Package = @import("Package.zig");18const Package = @import("Package.zig");
13const Type = @import("type.zig").Type;19const Type = @import("type.zig").Type;
14const Cache = @import("Cache.zig");
15const build_options = @import("build_options");
16const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
17const wasi_libc = @import("wasi_libc.zig");
18const Air = @import("Air.zig");
19const Liveness = @import("Liveness.zig");
20const TypedValue = @import("TypedValue.zig");20const TypedValue = @import("TypedValue.zig");
2121
22pub const SystemLib = struct {22pub const SystemLib = struct {
...@@ -245,24 +245,6 @@ pub const File = struct {...@@ -245,24 +245,6 @@ pub const File = struct {
245 nvptx: void,245 nvptx: void,
246 };246 };
247247
248 /// For DWARF .debug_info.
249 pub const DbgInfoTypeRelocsTable = std.ArrayHashMapUnmanaged(
250 Type,
251 DbgInfoTypeReloc,
252 Type.HashContext32,
253 true,
254 );
255
256 /// For DWARF .debug_info.
257 pub const DbgInfoTypeReloc = struct {
258 /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
259 /// This is where the .debug_info tag for the type is.
260 off: u32,
261 /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl).
262 /// List of DW.AT.type / DW.FORM.ref4 that points to the type.
263 relocs: std.ArrayListUnmanaged(u32),
264 };
265
266 /// Attempts incremental linking, if the file already exists. If248 /// Attempts incremental linking, if the file already exists. If
267 /// incremental linking fails, falls back to truncating the file and249 /// incremental linking fails, falls back to truncating the file and
268 /// rewriting it. A malicious file is detected as incremental link failure250 /// rewriting it. A malicious file is detected as incremental link failure
src/link/Dwarf.zig+369-139
...@@ -31,27 +31,89 @@ dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{},...@@ -31,27 +31,89 @@ dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{},
31dbg_line_fn_first: ?*SrcFn = null,31dbg_line_fn_first: ?*SrcFn = null,
32dbg_line_fn_last: ?*SrcFn = null,32dbg_line_fn_last: ?*SrcFn = null,
3333
34/// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity. /// This is the same concept as `text_block_free_list`; see those doc comments.34/// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity.
35dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*DebugInfoAtom, void) = .{},35/// This is the same concept as `text_block_free_list`; see those doc comments.
36dbg_info_decl_first: ?*DebugInfoAtom = null,36atom_free_list: std.AutoHashMapUnmanaged(*Atom, void) = .{},
37dbg_info_decl_last: ?*DebugInfoAtom = null,37atom_first: ?*Atom = null,
38atom_last: ?*Atom = null,
3839
39abbrev_table_offset: ?u64 = null,40abbrev_table_offset: ?u64 = null,
4041
42/// TODO replace with InternArena
41/// Table of debug symbol names.43/// Table of debug symbol names.
42strtab: std.ArrayListUnmanaged(u8) = .{},44strtab: std.ArrayListUnmanaged(u8) = .{},
4345
44pub const DebugInfoAtom = struct {46/// Lives only as long as the analysed Decl.
47/// Allocated with `initDeclState`.
48/// Freed with `commitDeclState`.
49decl_state: ?DeclState = null,
50
51/// List of atoms that are owned directly by the DWARF module.
52/// TODO convert links in DebugInfoAtom into indices and make
53/// sure every atom is owned by this module.
54managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
55
56global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
57
58pub const Atom = struct {
45 /// Previous/next linked list pointers.59 /// Previous/next linked list pointers.
46 /// This is the linked list node for this Decl's corresponding .debug_info tag.60 /// This is the linked list node for this Decl's corresponding .debug_info tag.
47 prev: ?*DebugInfoAtom,61 prev: ?*Atom,
48 next: ?*DebugInfoAtom,62 next: ?*Atom,
49 /// Offset into .debug_info pointing to the tag for this Decl.63 /// Offset into .debug_info pointing to the tag for this Decl.
50 off: u32,64 off: u32,
51 /// Size of the .debug_info tag for this Decl, not including padding.65 /// Size of the .debug_info tag for this Decl, not including padding.
52 len: u32,66 len: u32,
53};67};
5468
69/// Represents state of the analysed Decl.
70/// Includes Decl's abbrev table of type Types, matching arena
71/// and a set of relocations that will be resolved once this
72/// Decl's inner Atom is assigned an offset within the DWARF section.
73pub const DeclState = struct {
74 dbg_line: std.ArrayList(u8),
75 dbg_info: std.ArrayList(u8),
76 abbrev_type_arena: std.heap.ArenaAllocator,
77 abbrev_table: std.ArrayListUnmanaged(AbbrevEntry) = .{},
78 abbrev_resolver: std.HashMapUnmanaged(
79 Type,
80 u32,
81 Type.HashContext64,
82 std.hash_map.default_max_load_percentage,
83 ) = .{},
84 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
85
86 fn init(gpa: Allocator) DeclState {
87 return .{
88 .dbg_line = std.ArrayList(u8).init(gpa),
89 .dbg_info = std.ArrayList(u8).init(gpa),
90 .abbrev_type_arena = std.heap.ArenaAllocator.init(gpa),
91 };
92 }
93
94 fn deinit(self: *DeclState, gpa: Allocator) void {
95 self.dbg_line.deinit();
96 self.dbg_info.deinit();
97 self.abbrev_type_arena.deinit();
98 self.abbrev_table.deinit(gpa);
99 self.abbrev_resolver.deinit(gpa);
100 self.abbrev_relocs.deinit(gpa);
101 }
102};
103
104pub const AbbrevEntry = struct {
105 atom: *const Atom,
106 @"type": Type,
107 offset: u32,
108};
109
110pub const AbbrevRelocation = struct {
111 target: u32,
112 atom: *const Atom,
113 offset: u32,
114 addend: u32,
115};
116
55pub const SrcFn = struct {117pub const SrcFn = struct {
56 /// Offset from the beginning of the Debug Line Program header that contains this function.118 /// Offset from the beginning of the Debug Line Program header that contains this function.
57 off: u32,119 off: u32,
...@@ -117,29 +179,32 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf {...@@ -117,29 +179,32 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf {
117pub fn deinit(self: *Dwarf) void {179pub fn deinit(self: *Dwarf) void {
118 const gpa = self.allocator;180 const gpa = self.allocator;
119 self.dbg_line_fn_free_list.deinit(gpa);181 self.dbg_line_fn_free_list.deinit(gpa);
120 self.dbg_info_decl_free_list.deinit(gpa);182 self.atom_free_list.deinit(gpa);
121 self.strtab.deinit(gpa);183 self.strtab.deinit(gpa);
122}184 self.global_abbrev_relocs.deinit(gpa);
123185
124pub const DeclDebugBuffers = struct {186 for (self.managed_atoms.items) |atom| {
125 dbg_line_buffer: std.ArrayList(u8),187 gpa.destroy(atom);
126 dbg_info_buffer: std.ArrayList(u8),188 }
127 dbg_info_type_relocs: File.DbgInfoTypeRelocsTable,189 self.managed_atoms.deinit(gpa);
128};190}
129191
130pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {192/// Initializes Decl's state and its matching output buffers.
193/// Call this before `commitDeclState`.
194pub fn initDeclState(self: *Dwarf, decl: *Module.Decl) !void {
131 const tracy = trace(@src());195 const tracy = trace(@src());
132 defer tracy.end();196 defer tracy.end();
133197
134 const decl_name = try decl.getFullyQualifiedName(self.allocator);198 const decl_name = try decl.getFullyQualifiedName(self.allocator);
135 defer self.allocator.free(decl_name);199 defer self.allocator.free(decl_name);
136200
137 log.debug("initDeclDebugInfo {s}{*}", .{ decl_name, decl });201 log.debug("initDeclState {s}{*}", .{ decl_name, decl });
138202
139 const gpa = self.allocator;203 const gpa = self.allocator;
140 var dbg_line_buffer = std.ArrayList(u8).init(gpa);204 assert(self.decl_state == null);
141 var dbg_info_buffer = std.ArrayList(u8).init(gpa);205 self.decl_state = DeclState.init(gpa);
142 var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};206 const dbg_line_buffer = &self.decl_state.?.dbg_line;
207 const dbg_info_buffer = &self.decl_state.?.dbg_info;
143208
144 assert(decl.has_tv);209 assert(decl.has_tv);
145210
...@@ -202,19 +267,17 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {...@@ -202,19 +267,17 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {
202 dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT.low_pc, DW.FORM.addr267 dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT.low_pc, DW.FORM.addr
203 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);268 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
204 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4269 dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4
270 //
205 if (fn_ret_has_bits) {271 if (fn_ret_has_bits) {
206 const gop = try dbg_info_type_relocs.getOrPutContext(gpa, fn_ret_type, .{272 const atom = switch (self.tag) {
207 .target = self.target,273 .elf => &decl.link.elf.dbg_info_atom,
208 });274 .macho => &decl.link.macho.dbg_info_atom,
209 if (!gop.found_existing) {275 else => unreachable,
210 gop.value_ptr.* = .{276 };
211 .off = undefined,277 try self.addTypeReloc(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len), null);
212 .relocs = .{},
213 };
214 }
215 try gop.value_ptr.relocs.append(gpa, @intCast(u32, dbg_info_buffer.items.len));
216 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4278 dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4
217 }279 }
280
218 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string281 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string
219282
220 },283 },
...@@ -222,30 +285,28 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {...@@ -222,30 +285,28 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers {
222 // TODO implement .debug_info for global variables285 // TODO implement .debug_info for global variables
223 },286 },
224 }287 }
225
226 return DeclDebugBuffers{
227 .dbg_info_buffer = dbg_info_buffer,
228 .dbg_line_buffer = dbg_line_buffer,
229 .dbg_info_type_relocs = dbg_info_type_relocs,
230 };
231}288}
232289
233pub fn commitDeclDebugInfo(290pub fn commitDeclState(
234 self: *Dwarf,291 self: *Dwarf,
235 file: *File,292 file: *File,
236 module: *Module,293 module: *Module,
237 decl: *Module.Decl,294 decl: *Module.Decl,
238 sym_addr: u64,295 sym_addr: u64,
239 sym_size: u64,296 sym_size: u64,
240 debug_buffers: *DeclDebugBuffers,
241) !void {297) !void {
242 const tracy = trace(@src());298 const tracy = trace(@src());
243 defer tracy.end();299 defer tracy.end();
244300
301 assert(self.decl_state != null); // Caller forgot to call `initDeclState`
302 defer {
303 self.decl_state.?.deinit(self.allocator);
304 self.decl_state = null;
305 }
306
245 const gpa = self.allocator;307 const gpa = self.allocator;
246 var dbg_line_buffer = &debug_buffers.dbg_line_buffer;308 var dbg_line_buffer = &self.decl_state.?.dbg_line;
247 var dbg_info_buffer = &debug_buffers.dbg_info_buffer;309 var dbg_info_buffer = &self.decl_state.?.dbg_info;
248 var dbg_info_type_relocs = &debug_buffers.dbg_info_type_relocs;
249310
250 const target_endian = self.target.cpu.arch.endian();311 const target_endian = self.target.cpu.arch.endian();
251312
...@@ -443,68 +504,65 @@ pub fn commitDeclDebugInfo(...@@ -443,68 +504,65 @@ pub fn commitDeclDebugInfo(
443 if (dbg_info_buffer.items.len == 0)504 if (dbg_info_buffer.items.len == 0)
444 return;505 return;
445506
446 // We need this for the duration of this function only so that for composite507 const atom = switch (self.tag) {
447 // types such as []const u32, if the type *u32 is non-existent, we create508 .elf => &decl.link.elf.dbg_info_atom,
448 // it synthetically and store the backing bytes in this arena. After we are509 .macho => &decl.link.macho.dbg_info_atom,
449 // done with the relocations, we can safely deinit the entire memory slab.510 else => unreachable,
450 // TODO currently, we do not store the relocations for future use, however,511 };
451 // if that is the case, we should move memory management to a higher scope,512 const decl_state = &self.decl_state.?;
452 // such as linker scope, or whatnot.513
453 var dbg_type_arena = std.heap.ArenaAllocator.init(gpa);
454 defer dbg_type_arena.deinit();
455
456 var nested_ref4_relocs = std.ArrayList(u32).init(gpa);
457 defer nested_ref4_relocs.deinit();
458 {514 {
459 // Now we emit the .debug_info types of the Decl. These will count towards the size of515 // Now we emit the .debug_info types of the Decl. These will count towards the size of
460 // the buffer, so we have to do it before computing the offset, and we can't perform the actual516 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
461 // relocations yet.517 // relocations yet.
462 var it: usize = 0;518 var sym_index: usize = 0;
463 while (it < dbg_info_type_relocs.count()) : (it += 1) {519 while (sym_index < decl_state.abbrev_table.items.len) : (sym_index += 1) {
464 const ty = dbg_info_type_relocs.keys()[it];520 const symbol = &decl_state.abbrev_table.items[sym_index];
465 const value_ptr = dbg_info_type_relocs.getPtrContext(ty, .{521 const ty = symbol.@"type";
466 .target = self.target,522 const deferred: bool = blk: {
467 }).?;523 if (ty.isAnyError()) break :blk true;
468 value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);524 switch (ty.tag()) {
469 try self.addDbgInfoType(525 .error_set_inferred => {
470 dbg_type_arena.allocator(),526 if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true;
471 ty,527 },
472 dbg_info_buffer,528 else => {},
473 dbg_info_type_relocs,529 }
474 &nested_ref4_relocs,530 break :blk false;
475 );531 };
532 if (deferred) continue;
533
534 symbol.offset = @intCast(u32, dbg_info_buffer.items.len);
535 try self.addDbgInfoType(decl_state.abbrev_type_arena.allocator(), module, atom, ty, dbg_info_buffer);
476 }536 }
477 }537 }
478538
479 const atom = switch (self.tag) {
480 .elf => &decl.link.elf.dbg_info_atom,
481 .macho => &decl.link.macho.dbg_info_atom,
482 else => unreachable,
483 };
484 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));539 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
485540
486 {541 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
487 // Now that we have the offset assigned we can finally perform type relocations.542 const symbol = decl_state.abbrev_table.items[reloc.target];
488 for (dbg_info_type_relocs.values()) |value| {543 const ty = symbol.@"type";
489 for (value.relocs.items) |off| {544 const deferred: bool = blk: {
490 mem.writeInt(545 if (ty.isAnyError()) break :blk true;
491 u32,546 switch (ty.tag()) {
492 dbg_info_buffer.items[off..][0..4],547 .error_set_inferred => {
493 atom.off + value.off,548 if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true;
494 target_endian,549 },
495 );550 else => {},
496 }551 }
497 }552 break :blk false;
498 // Offsets to positions with known a priori relative displacement values.553 };
499 // Here, we just need to add the offset of the atom to the read value in the554 if (deferred) {
500 // relocated cell.555 try self.global_abbrev_relocs.append(gpa, .{
501 // TODO Should probably generalise this with type relocs.556 .target = undefined,
502 for (nested_ref4_relocs.items) |off| {557 .offset = reloc.offset,
503 const addend = mem.readInt(u32, dbg_info_buffer.items[off..][0..4], target_endian);558 .atom = reloc.atom,
559 .addend = reloc.addend,
560 });
561 } else {
504 mem.writeInt(562 mem.writeInt(
505 u32,563 u32,
506 dbg_info_buffer.items[off..][0..4],564 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
507 atom.off + addend,565 symbol.atom.off + symbol.offset + reloc.addend,
508 target_endian,566 target_endian,
509 );567 );
510 }568 }
...@@ -513,7 +571,7 @@ pub fn commitDeclDebugInfo(...@@ -513,7 +571,7 @@ pub fn commitDeclDebugInfo(
513 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);571 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
514}572}
515573
516fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom, len: u32) !void {574fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u32) !void {
517 const tracy = trace(@src());575 const tracy = trace(@src());
518 defer tracy.end();576 defer tracy.end();
519577
...@@ -523,14 +581,14 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom...@@ -523,14 +581,14 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom
523 const gpa = self.allocator;581 const gpa = self.allocator;
524582
525 atom.len = len;583 atom.len = len;
526 if (self.dbg_info_decl_last) |last| blk: {584 if (self.atom_last) |last| blk: {
527 if (atom == last) break :blk;585 if (atom == last) break :blk;
528 if (atom.next) |next| {586 if (atom.next) |next| {
529 // Update existing Decl - non-last item.587 // Update existing Decl - non-last item.
530 if (atom.off + atom.len + min_nop_size > next.off) {588 if (atom.off + atom.len + min_nop_size > next.off) {
531 // It grew too big, so we move it to a new location.589 // It grew too big, so we move it to a new location.
532 if (atom.prev) |prev| {590 if (atom.prev) |prev| {
533 self.dbg_info_decl_free_list.put(gpa, prev, {}) catch {};591 self.atom_free_list.put(gpa, prev, {}) catch {};
534 prev.next = atom.next;592 prev.next = atom.next;
535 }593 }
536 next.prev = atom.prev;594 next.prev = atom.prev;
...@@ -556,7 +614,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom...@@ -556,7 +614,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom
556 // TODO Look at the free list before appending at the end.614 // TODO Look at the free list before appending at the end.
557 atom.prev = last;615 atom.prev = last;
558 last.next = atom;616 last.next = atom;
559 self.dbg_info_decl_last = atom;617 self.atom_last = atom;
560618
561 atom.off = last.off + padToIdeal(last.len);619 atom.off = last.off + padToIdeal(last.len);
562 }620 }
...@@ -565,20 +623,20 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom...@@ -565,20 +623,20 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom
565 // TODO Look at the free list before appending at the end.623 // TODO Look at the free list before appending at the end.
566 atom.prev = last;624 atom.prev = last;
567 last.next = atom;625 last.next = atom;
568 self.dbg_info_decl_last = atom;626 self.atom_last = atom;
569627
570 atom.off = last.off + padToIdeal(last.len);628 atom.off = last.off + padToIdeal(last.len);
571 }629 }
572 } else {630 } else {
573 // This is the first Decl of the .debug_info631 // This is the first Decl of the .debug_info
574 self.dbg_info_decl_first = atom;632 self.atom_first = atom;
575 self.dbg_info_decl_last = atom;633 self.atom_last = atom;
576634
577 atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes()));635 atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes()));
578 }636 }
579}637}
580638
581fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *DebugInfoAtom, dbg_info_buf: []const u8) !void {639fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []const u8) !void {
582 const tracy = trace(@src());640 const tracy = trace(@src());
583 defer tracy.end();641 defer tracy.end();
584642
...@@ -587,7 +645,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *DebugInfoAtom, dbg_info_...@@ -587,7 +645,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *DebugInfoAtom, dbg_info_
587 // probably need to edit that logic too.645 // probably need to edit that logic too.
588 const gpa = self.allocator;646 const gpa = self.allocator;
589647
590 const last_decl = self.dbg_info_decl_last.?;648 const last_decl = self.atom_last.?;
591 // +1 for a trailing zero to end the children of the decl tag.649 // +1 for a trailing zero to end the children of the decl tag.
592 const needed_size = last_decl.off + last_decl.len + 1;650 const needed_size = last_decl.off + last_decl.len + 1;
593 const prev_padding_size: u32 = if (atom.prev) |prev| atom.off - (prev.off + prev.len) else 0;651 const prev_padding_size: u32 = if (atom.prev) |prev| atom.off - (prev.off + prev.len) else 0;
...@@ -712,13 +770,13 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)...@@ -712,13 +770,13 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)
712 }770 }
713}771}
714772
715pub fn freeAtom(self: *Dwarf, atom: *DebugInfoAtom) void {773pub fn freeAtom(self: *Dwarf, atom: *Atom) void {
716 if (self.dbg_info_decl_first == atom) {774 if (self.atom_first == atom) {
717 self.dbg_info_decl_first = atom.next;775 self.atom_first = atom.next;
718 }776 }
719 if (self.dbg_info_decl_last == atom) {777 if (self.atom_last == atom) {
720 // TODO shrink the .debug_info section size here778 // TODO shrink the .debug_info section size here
721 self.dbg_info_decl_last = atom.prev;779 self.atom_last = atom.prev;
722 }780 }
723781
724 if (atom.prev) |prev| {782 if (atom.prev) |prev| {
...@@ -771,14 +829,13 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {...@@ -771,14 +829,13 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void {
771fn addDbgInfoType(829fn addDbgInfoType(
772 self: *Dwarf,830 self: *Dwarf,
773 arena: Allocator,831 arena: Allocator,
832 module: *Module,
833 atom: *Atom,
774 ty: Type,834 ty: Type,
775 dbg_info_buffer: *std.ArrayList(u8),835 dbg_info_buffer: *std.ArrayList(u8),
776 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
777 nested_ref4_relocs: *std.ArrayList(u32),
778) error{OutOfMemory}!void {836) error{OutOfMemory}!void {
779 const target = self.target;837 const target = self.target;
780 const target_endian = self.target.cpu.arch.endian();838 const target_endian = self.target.cpu.arch.endian();
781 var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena);
782839
783 switch (ty.zigTypeTag()) {840 switch (ty.zigTypeTag()) {
784 .NoReturn => unreachable,841 .NoReturn => unreachable,
...@@ -837,7 +894,7 @@ fn addDbgInfoType(...@@ -837,7 +894,7 @@ fn addDbgInfoType(
837 // DW.AT.type, DW.FORM.ref4894 // DW.AT.type, DW.FORM.ref4
838 var index = dbg_info_buffer.items.len;895 var index = dbg_info_buffer.items.len;
839 try dbg_info_buffer.resize(index + 4);896 try dbg_info_buffer.resize(index + 4);
840 try relocs.append(.{ .ty = Type.bool, .reloc = @intCast(u32, index) });897 try self.addTypeReloc(atom, Type.bool, @intCast(u32, index), null);
841 // DW.AT.data_member_location, DW.FORM.sdata898 // DW.AT.data_member_location, DW.FORM.sdata
842 try dbg_info_buffer.ensureUnusedCapacity(6);899 try dbg_info_buffer.ensureUnusedCapacity(6);
843 dbg_info_buffer.appendAssumeCapacity(0);900 dbg_info_buffer.appendAssumeCapacity(0);
...@@ -849,7 +906,7 @@ fn addDbgInfoType(...@@ -849,7 +906,7 @@ fn addDbgInfoType(
849 // DW.AT.type, DW.FORM.ref4906 // DW.AT.type, DW.FORM.ref4
850 index = dbg_info_buffer.items.len;907 index = dbg_info_buffer.items.len;
851 try dbg_info_buffer.resize(index + 4);908 try dbg_info_buffer.resize(index + 4);
852 try relocs.append(.{ .ty = payload_ty, .reloc = @intCast(u32, index) });909 try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null);
853 // DW.AT.data_member_location, DW.FORM.sdata910 // DW.AT.data_member_location, DW.FORM.sdata
854 const offset = abi_size - payload_ty.abiSize(target);911 const offset = abi_size - payload_ty.abiSize(target);
855 try leb128.writeULEB128(dbg_info_buffer.writer(), offset);912 try leb128.writeULEB128(dbg_info_buffer.writer(), offset);
...@@ -878,7 +935,7 @@ fn addDbgInfoType(...@@ -878,7 +935,7 @@ fn addDbgInfoType(
878 try dbg_info_buffer.resize(index + 4);935 try dbg_info_buffer.resize(index + 4);
879 var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);936 var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
880 const ptr_ty = ty.slicePtrFieldType(buf);937 const ptr_ty = ty.slicePtrFieldType(buf);
881 try relocs.append(.{ .ty = ptr_ty, .reloc = @intCast(u32, index) });938 try self.addTypeReloc(atom, ptr_ty, @intCast(u32, index), null);
882 // DW.AT.data_member_location, DW.FORM.sdata939 // DW.AT.data_member_location, DW.FORM.sdata
883 try dbg_info_buffer.ensureUnusedCapacity(6);940 try dbg_info_buffer.ensureUnusedCapacity(6);
884 dbg_info_buffer.appendAssumeCapacity(0);941 dbg_info_buffer.appendAssumeCapacity(0);
...@@ -890,7 +947,7 @@ fn addDbgInfoType(...@@ -890,7 +947,7 @@ fn addDbgInfoType(
890 // DW.AT.type, DW.FORM.ref4947 // DW.AT.type, DW.FORM.ref4
891 index = dbg_info_buffer.items.len;948 index = dbg_info_buffer.items.len;
892 try dbg_info_buffer.resize(index + 4);949 try dbg_info_buffer.resize(index + 4);
893 try relocs.append(.{ .ty = Type.initTag(.usize), .reloc = @intCast(u32, index) });950 try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null);
894 // DW.AT.data_member_location, DW.FORM.sdata951 // DW.AT.data_member_location, DW.FORM.sdata
895 try dbg_info_buffer.ensureUnusedCapacity(2);952 try dbg_info_buffer.ensureUnusedCapacity(2);
896 dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize));953 dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize));
...@@ -902,7 +959,7 @@ fn addDbgInfoType(...@@ -902,7 +959,7 @@ fn addDbgInfoType(
902 // DW.AT.type, DW.FORM.ref4959 // DW.AT.type, DW.FORM.ref4
903 const index = dbg_info_buffer.items.len;960 const index = dbg_info_buffer.items.len;
904 try dbg_info_buffer.resize(index + 4);961 try dbg_info_buffer.resize(index + 4);
905 try relocs.append(.{ .ty = ty.childType(), .reloc = @intCast(u32, index) });962 try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);
906 }963 }
907 },964 },
908 .Struct => blk: {965 .Struct => blk: {
...@@ -926,7 +983,7 @@ fn addDbgInfoType(...@@ -926,7 +983,7 @@ fn addDbgInfoType(
926 // DW.AT.type, DW.FORM.ref4983 // DW.AT.type, DW.FORM.ref4
927 var index = dbg_info_buffer.items.len;984 var index = dbg_info_buffer.items.len;
928 try dbg_info_buffer.resize(index + 4);985 try dbg_info_buffer.resize(index + 4);
929 try relocs.append(.{ .ty = field, .reloc = @intCast(u32, index) });986 try self.addTypeReloc(atom, field, @intCast(u32, index), null);
930 // DW.AT.data_member_location, DW.FORM.sdata987 // DW.AT.data_member_location, DW.FORM.sdata
931 const field_off = ty.structFieldOffset(field_index, target);988 const field_off = ty.structFieldOffset(field_index, target);
932 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);989 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
...@@ -957,7 +1014,7 @@ fn addDbgInfoType(...@@ -957,7 +1014,7 @@ fn addDbgInfoType(
957 // DW.AT.type, DW.FORM.ref41014 // DW.AT.type, DW.FORM.ref4
958 var index = dbg_info_buffer.items.len;1015 var index = dbg_info_buffer.items.len;
959 try dbg_info_buffer.resize(index + 4);1016 try dbg_info_buffer.resize(index + 4);
960 try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) });1017 try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null);
961 // DW.AT.data_member_location, DW.FORM.sdata1018 // DW.AT.data_member_location, DW.FORM.sdata
962 const field_off = ty.structFieldOffset(field_index, target);1019 const field_off = ty.structFieldOffset(field_index, target);
963 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);1020 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
...@@ -1036,14 +1093,8 @@ fn addDbgInfoType(...@@ -1036,14 +1093,8 @@ fn addDbgInfoType(
1036 dbg_info_buffer.appendAssumeCapacity(0);1093 dbg_info_buffer.appendAssumeCapacity(0);
1037 // DW.AT.type, DW.FORM.ref41094 // DW.AT.type, DW.FORM.ref4
1038 const inner_union_index = dbg_info_buffer.items.len;1095 const inner_union_index = dbg_info_buffer.items.len;
1039 try dbg_info_buffer.ensureUnusedCapacity(4);1096 try dbg_info_buffer.resize(inner_union_index + 4);
1040 mem.writeInt(1097 try self.addTypeReloc(atom, ty, @intCast(u32, inner_union_index), 5);
1041 u32,
1042 dbg_info_buffer.addManyAsArrayAssumeCapacity(4),
1043 @intCast(u32, inner_union_index + 5),
1044 target_endian,
1045 );
1046 try nested_ref4_relocs.append(@intCast(u32, inner_union_index));
1047 // DW.AT.data_member_location, DW.FORM.sdata1098 // DW.AT.data_member_location, DW.FORM.sdata
1048 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);1099 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
1049 }1100 }
...@@ -1070,7 +1121,7 @@ fn addDbgInfoType(...@@ -1070,7 +1121,7 @@ fn addDbgInfoType(
1070 // DW.AT.type, DW.FORM.ref41121 // DW.AT.type, DW.FORM.ref4
1071 const index = dbg_info_buffer.items.len;1122 const index = dbg_info_buffer.items.len;
1072 try dbg_info_buffer.resize(index + 4);1123 try dbg_info_buffer.resize(index + 4);
1073 try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) });1124 try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null);
1074 // DW.AT.data_member_location, DW.FORM.sdata1125 // DW.AT.data_member_location, DW.FORM.sdata
1075 try dbg_info_buffer.append(0);1126 try dbg_info_buffer.append(0);
1076 }1127 }
...@@ -1087,7 +1138,7 @@ fn addDbgInfoType(...@@ -1087,7 +1138,7 @@ fn addDbgInfoType(
1087 // DW.AT.type, DW.FORM.ref41138 // DW.AT.type, DW.FORM.ref4
1088 const index = dbg_info_buffer.items.len;1139 const index = dbg_info_buffer.items.len;
1089 try dbg_info_buffer.resize(index + 4);1140 try dbg_info_buffer.resize(index + 4);
1090 try relocs.append(.{ .ty = union_obj.tag_ty, .reloc = @intCast(u32, index) });1141 try self.addTypeReloc(atom, union_obj.tag_ty, @intCast(u32, index), null);
1091 // DW.AT.data_member_location, DW.FORM.sdata1142 // DW.AT.data_member_location, DW.FORM.sdata
1092 try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);1143 try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
10931144
...@@ -1095,24 +1146,91 @@ fn addDbgInfoType(...@@ -1095,24 +1146,91 @@ fn addDbgInfoType(
1095 try dbg_info_buffer.append(0);1146 try dbg_info_buffer.append(0);
1096 }1147 }
1097 },1148 },
1149 .ErrorSet => {
1150 // DW.AT.enumeration_type
1151 try dbg_info_buffer.append(abbrev_enum_type);
1152 // DW.AT.byte_size, DW.FORM.sdata
1153 const abi_size = ty.abiSize(target);
1154 try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
1155 // DW.AT.name, DW.FORM.string
1156 const name = try ty.nameAllocArena(arena, target);
1157 try dbg_info_buffer.writer().print("{s}\x00", .{name});
1158
1159 // DW.AT.enumerator
1160 const no_error = "(no error)";
1161 try dbg_info_buffer.ensureUnusedCapacity(no_error.len + 2 + @sizeOf(u64));
1162 dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant);
1163 // DW.AT.name, DW.FORM.string
1164 dbg_info_buffer.appendSliceAssumeCapacity(no_error);
1165 dbg_info_buffer.appendAssumeCapacity(0);
1166 // DW.AT.const_value, DW.FORM.data8
1167 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian);
1168
1169 const error_names = ty.errorSetNames();
1170 for (error_names) |error_name| {
1171 const kv = module.getErrorValue(error_name) catch unreachable;
1172 // DW.AT.enumerator
1173 try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64));
1174 dbg_info_buffer.appendAssumeCapacity(abbrev_enum_variant);
1175 // DW.AT.name, DW.FORM.string
1176 dbg_info_buffer.appendSliceAssumeCapacity(error_name);
1177 dbg_info_buffer.appendAssumeCapacity(0);
1178 // DW.AT.const_value, DW.FORM.data8
1179 mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), kv.value, target_endian);
1180 }
1181
1182 // DW.AT.enumeration_type delimit children
1183 try dbg_info_buffer.append(0);
1184 },
1185 .ErrorUnion => {
1186 const error_ty = ty.errorUnionSet();
1187 const payload_ty = ty.errorUnionPayload();
1188 const abi_size = ty.abiSize(target);
1189 const abi_align = ty.abiAlignment(target);
1190 const payload_off = mem.alignForwardGeneric(u64, error_ty.abiSize(target), abi_align);
1191
1192 // DW.AT.structure_type
1193 try dbg_info_buffer.append(abbrev_struct_type);
1194 // DW.AT.byte_size, DW.FORM.sdata
1195 try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
1196 // DW.AT.name, DW.FORM.string
1197 const name = try ty.nameAllocArena(arena, target);
1198 try dbg_info_buffer.writer().print("{s}\x00", .{name});
1199
1200 // DW.AT.member
1201 try dbg_info_buffer.ensureUnusedCapacity(7);
1202 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
1203 // DW.AT.name, DW.FORM.string
1204 dbg_info_buffer.appendSliceAssumeCapacity("value");
1205 dbg_info_buffer.appendAssumeCapacity(0);
1206 // DW.AT.type, DW.FORM.ref4
1207 var index = dbg_info_buffer.items.len;
1208 try dbg_info_buffer.resize(index + 4);
1209 try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null);
1210 // DW.AT.data_member_location, DW.FORM.sdata
1211 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
1212
1213 // DW.AT.member
1214 try dbg_info_buffer.ensureUnusedCapacity(5);
1215 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
1216 // DW.AT.name, DW.FORM.string
1217 dbg_info_buffer.appendSliceAssumeCapacity("err");
1218 dbg_info_buffer.appendAssumeCapacity(0);
1219 // DW.AT.type, DW.FORM.ref4
1220 index = dbg_info_buffer.items.len;
1221 try dbg_info_buffer.resize(index + 4);
1222 try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null);
1223 // DW.AT.data_member_location, DW.FORM.sdata
1224 try dbg_info_buffer.append(0);
1225
1226 // DW.AT.structure_type delimit children
1227 try dbg_info_buffer.append(0);
1228 },
1098 else => {1229 else => {
1099 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()});1230 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()});
1100 try dbg_info_buffer.append(abbrev_pad1);1231 try dbg_info_buffer.append(abbrev_pad1);
1101 },1232 },
1102 }1233 }
1103
1104 for (relocs.items) |rel| {
1105 const gop = try dbg_info_type_relocs.getOrPutContext(self.allocator, rel.ty, .{
1106 .target = self.target,
1107 });
1108 if (!gop.found_existing) {
1109 gop.value_ptr.* = .{
1110 .off = undefined,
1111 .relocs = .{},
1112 };
1113 }
1114 try gop.value_ptr.relocs.append(self.allocator, rel.reloc);
1115 }
1116}1234}
11171235
1118pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {1236pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
...@@ -1763,12 +1881,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {...@@ -1763,12 +1881,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
1763}1881}
17641882
1765fn getDebugInfoOff(self: Dwarf) ?u32 {1883fn getDebugInfoOff(self: Dwarf) ?u32 {
1766 const first = self.dbg_info_decl_first orelse return null;1884 const first = self.atom_first orelse return null;
1767 return first.off;1885 return first.off;
1768}1886}
17691887
1770fn getDebugInfoEnd(self: Dwarf) ?u32 {1888fn getDebugInfoEnd(self: Dwarf) ?u32 {
1771 const last = self.dbg_info_decl_last orelse return null;1889 const last = self.atom_last orelse return null;
1772 return last.off + last.len;1890 return last.off + last.len;
1773}1891}
17741892
...@@ -1833,3 +1951,115 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -1833,3 +1951,115 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
1833 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch1951 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
1834 std.math.maxInt(@TypeOf(actual_size));1952 std.math.maxInt(@TypeOf(actual_size));
1835}1953}
1954
1955pub fn addTypeReloc(self: *Dwarf, atom: *const Atom, ty: Type, offset: u32, addend: ?u32) !void {
1956 const decl_state = &self.decl_state.?;
1957 const gpa = self.allocator;
1958 const resolv = decl_state.abbrev_resolver.getContext(ty, .{
1959 .target = self.target,
1960 }) orelse blk: {
1961 const sym_index = @intCast(u32, decl_state.abbrev_table.items.len);
1962 try decl_state.abbrev_table.append(gpa, .{
1963 .atom = atom,
1964 .@"type" = ty,
1965 .offset = undefined,
1966 });
1967 log.debug("@{d}: {}", .{ sym_index, ty.fmtDebug() });
1968 try decl_state.abbrev_resolver.putNoClobberContext(gpa, ty, sym_index, .{
1969 .target = self.target,
1970 });
1971 break :blk decl_state.abbrev_resolver.getContext(ty, .{
1972 .target = self.target,
1973 }).?;
1974 };
1975 const add: u32 = addend orelse 0;
1976
1977 log.debug("{x}: @{d} + {x}", .{ offset, resolv, add });
1978 try decl_state.abbrev_relocs.append(gpa, .{
1979 .target = resolv,
1980 .atom = atom,
1981 .offset = offset,
1982 .addend = add,
1983 });
1984}
1985
1986pub fn getDeclDebugLineBuffer(self: *Dwarf) *std.ArrayList(u8) {
1987 return &self.decl_state.?.dbg_line;
1988}
1989
1990pub fn getDeclDebugInfoBuffer(self: *Dwarf) *std.ArrayList(u8) {
1991 return &self.decl_state.?.dbg_info;
1992}
1993
1994pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
1995 if (self.global_abbrev_relocs.items.len > 0) {
1996 const gpa = self.allocator;
1997 var arena_alloc = std.heap.ArenaAllocator.init(gpa);
1998 defer arena_alloc.deinit();
1999 const arena = arena_alloc.allocator();
2000
2001 const error_set = try arena.create(Module.ErrorSet);
2002 const error_ty = try Type.Tag.error_set.create(arena, error_set);
2003 var names = Module.ErrorSet.NameMap{};
2004 try names.ensureUnusedCapacity(arena, module.global_error_set.count());
2005 var it = module.global_error_set.keyIterator();
2006 while (it.next()) |key| {
2007 names.putAssumeCapacityNoClobber(key.*, {});
2008 }
2009 error_set.names = names;
2010
2011 const atom = try gpa.create(Atom);
2012 errdefer gpa.destroy(atom);
2013 atom.* = .{
2014 .prev = null,
2015 .next = null,
2016 .off = 0,
2017 .len = 0,
2018 };
2019
2020 var dbg_info_buffer = std.ArrayList(u8).init(arena);
2021 try self.addDbgInfoType(arena, module, atom, error_ty, &dbg_info_buffer);
2022
2023 try self.managed_atoms.append(gpa, atom);
2024 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
2025 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
2026
2027 const file_pos = blk: {
2028 switch (self.tag) {
2029 .elf => {
2030 const elf_file = file.cast(File.Elf).?;
2031 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
2032 break :blk debug_info_sect.sh_offset;
2033 },
2034 .macho => {
2035 const macho_file = file.cast(File.MachO).?;
2036 const d_sym = &macho_file.d_sym.?;
2037 const dwarf_segment = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;
2038 const debug_info_sect = &dwarf_segment.sections.items[d_sym.debug_info_section_index.?];
2039 break :blk debug_info_sect.offset;
2040 },
2041 else => unreachable,
2042 }
2043 };
2044
2045 var buf: [@sizeOf(u32)]u8 = undefined;
2046 mem.writeInt(u32, &buf, atom.off, self.target.cpu.arch.endian());
2047
2048 while (self.global_abbrev_relocs.popOrNull()) |reloc| {
2049 switch (self.tag) {
2050 .elf => {
2051 const elf_file = file.cast(File.Elf).?;
2052 try elf_file.base.file.?.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
2053 },
2054 .macho => {
2055 const macho_file = file.cast(File.MachO).?;
2056 const d_sym = &macho_file.d_sym.?;
2057 try d_sym.file.pwriteAll(&buf, file_pos + reloc.atom.off + reloc.offset);
2058 },
2059 else => unreachable,
2060 }
2061 }
2062 }
2063
2064 assert(self.decl_state == null);
2065}
src/link/Elf.zig+17-46
...@@ -207,7 +207,7 @@ pub const TextBlock = struct {...@@ -207,7 +207,7 @@ pub const TextBlock = struct {
207 prev: ?*TextBlock,207 prev: ?*TextBlock,
208 next: ?*TextBlock,208 next: ?*TextBlock,
209209
210 dbg_info_atom: Dwarf.DebugInfoAtom,210 dbg_info_atom: Dwarf.Atom,
211211
212 pub const empty = TextBlock{212 pub const empty = TextBlock{
213 .local_sym_index = 0,213 .local_sym_index = 0,
...@@ -958,6 +958,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -958,6 +958,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
958 const target_endian = self.base.options.target.cpu.arch.endian();958 const target_endian = self.base.options.target.cpu.arch.endian();
959 const foreign_endian = target_endian != builtin.cpu.arch.endian();959 const foreign_endian = target_endian != builtin.cpu.arch.endian();
960960
961 if (self.dwarf) |*dw| {
962 try dw.flushModule(&self.base, module);
963 }
964
961 {965 {
962 var it = self.relocs.iterator();966 var it = self.relocs.iterator();
963 while (it.next()) |entry| {967 while (it.next()) |entry| {
...@@ -2228,13 +2232,6 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {...@@ -2228,13 +2232,6 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
2228 }2232 }
2229}2233}
22302234
2231fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {
2232 for (table.values()) |*value| {
2233 value.relocs.deinit(gpa);
2234 }
2235 table.deinit(gpa);
2236}
2237
2238fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 {2235fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 {
2239 const ty = decl.ty;2236 const ty = decl.ty;
2240 const zig_ty = ty.zigTypeTag();2237 const zig_ty = ty.zigTypeTag();
...@@ -2342,26 +2339,13 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2342,26 +2339,13 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2342 const decl = func.owner_decl;2339 const decl = func.owner_decl;
2343 self.freeUnnamedConsts(decl);2340 self.freeUnnamedConsts(decl);
23442341
2345 var debug_buffers_buf: Dwarf.DeclDebugBuffers = undefined;2342 if (self.dwarf) |*dw| {
2346 const debug_buffers = if (self.dwarf) |*dw| blk: {2343 try dw.initDeclState(decl);
2347 debug_buffers_buf = try dw.initDeclDebugInfo(decl);
2348 break :blk &debug_buffers_buf;
2349 } else null;
2350 defer {
2351 if (debug_buffers) |dbg| {
2352 dbg.dbg_line_buffer.deinit();
2353 dbg.dbg_info_buffer.deinit();
2354 deinitRelocs(self.base.allocator, &dbg.dbg_info_type_relocs);
2355 }
2356 }2344 }
23572345
2358 const res = if (debug_buffers) |dbg|2346 const res = if (self.dwarf) |*dw|
2359 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{2347 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
2360 .dwarf = .{2348 .dwarf = dw,
2361 .dbg_line = &dbg.dbg_line_buffer,
2362 .dbg_info = &dbg.dbg_info_buffer,
2363 .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
2364 },
2365 })2349 })
2366 else2350 else
2367 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);2351 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
...@@ -2375,8 +2359,8 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2375,8 +2359,8 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2375 },2359 },
2376 };2360 };
2377 const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC);2361 const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC);
2378 if (debug_buffers) |dbg| {2362 if (self.dwarf) |*dw| {
2379 try self.dwarf.?.commitDeclDebugInfo(&self.base, module, decl, local_sym.st_value, local_sym.st_size, dbg);2363 try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size);
2380 }2364 }
23812365
2382 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.2366 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
...@@ -2410,31 +2394,18 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2410,31 +2394,18 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2410 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2394 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2411 defer code_buffer.deinit();2395 defer code_buffer.deinit();
24122396
2413 var debug_buffers_buf: Dwarf.DeclDebugBuffers = undefined;2397 if (self.dwarf) |*dw| {
2414 const debug_buffers = if (self.dwarf) |*dw| blk: {2398 try dw.initDeclState(decl);
2415 debug_buffers_buf = try dw.initDeclDebugInfo(decl);
2416 break :blk &debug_buffers_buf;
2417 } else null;
2418 defer {
2419 if (debug_buffers) |dbg| {
2420 dbg.dbg_line_buffer.deinit();
2421 dbg.dbg_info_buffer.deinit();
2422 deinitRelocs(self.base.allocator, &dbg.dbg_info_type_relocs);
2423 }
2424 }2399 }
24252400
2426 // TODO implement .debug_info for global variables2401 // TODO implement .debug_info for global variables
2427 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;2402 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
2428 const res = if (debug_buffers) |dbg|2403 const res = if (self.dwarf) |*dw|
2429 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{2404 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2430 .ty = decl.ty,2405 .ty = decl.ty,
2431 .val = decl_val,2406 .val = decl_val,
2432 }, &code_buffer, .{2407 }, &code_buffer, .{
2433 .dwarf = .{2408 .dwarf = dw,
2434 .dbg_line = &dbg.dbg_line_buffer,
2435 .dbg_info = &dbg.dbg_info_buffer,
2436 .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
2437 },
2438 }, .{2409 }, .{
2439 .parent_atom_index = decl.link.elf.local_sym_index,2410 .parent_atom_index = decl.link.elf.local_sym_index,
2440 })2411 })
...@@ -2457,8 +2428,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2457,8 +2428,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2457 };2428 };
24582429
2459 const local_sym = try self.updateDeclCode(decl, code, elf.STT_OBJECT);2430 const local_sym = try self.updateDeclCode(decl, code, elf.STT_OBJECT);
2460 if (debug_buffers) |dbg| {2431 if (self.dwarf) |*dw| {
2461 try self.dwarf.?.commitDeclDebugInfo(&self.base, module, decl, local_sym.st_value, local_sym.st_size, dbg);2432 try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size);
2462 }2433 }
24632434
2464 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.2435 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
src/link/MachO.zig+25-47
...@@ -453,6 +453,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -453,6 +453,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
453 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.453 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
454 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});454 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
455455
456 if (self.d_sym) |*d_sym| {
457 if (self.base.options.module) |module| {
458 try d_sym.dwarf.flushModule(&self.base, module);
459 }
460 }
461
456 // If there is no Zig code to compile, then we should skip flushing the output file because it462 // If there is no Zig code to compile, then we should skip flushing the output file because it
457 // will not be part of the linker line anyway.463 // will not be part of the linker line anyway.
458 const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {464 const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
...@@ -3670,32 +3676,17 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -3670,32 +3676,17 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
3670 var code_buffer = std.ArrayList(u8).init(self.base.allocator);3676 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
3671 defer code_buffer.deinit();3677 defer code_buffer.deinit();
36723678
3673 var debug_buffers_buf: link.File.Dwarf.DeclDebugBuffers = undefined;3679 if (self.d_sym) |*d_sym| {
3674 const debug_buffers = if (self.d_sym) |*d_sym| blk: {3680 try d_sym.dwarf.initDeclState(decl);
3675 debug_buffers_buf = try d_sym.initDeclDebugInfo(module, decl);
3676 break :blk &debug_buffers_buf;
3677 } else null;
3678 defer {
3679 if (debug_buffers) |dbg| {
3680 dbg.dbg_line_buffer.deinit();
3681 dbg.dbg_info_buffer.deinit();
3682 for (dbg.dbg_info_type_relocs.values()) |*value| {
3683 value.relocs.deinit(self.base.allocator);
3684 }
3685 dbg.dbg_info_type_relocs.deinit(self.base.allocator);
3686 }
3687 }3681 }
36883682
3689 const res = if (debug_buffers) |dbg|3683 const res = if (self.d_sym) |*d_sym|
3690 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{3684 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
3691 .dwarf = .{3685 .dwarf = &d_sym.dwarf,
3692 .dbg_line = &dbg.dbg_line_buffer,
3693 .dbg_info = &dbg.dbg_info_buffer,
3694 .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
3695 },
3696 })3686 })
3697 else3687 else
3698 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);3688 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
3689
3699 switch (res) {3690 switch (res) {
3700 .appended => {3691 .appended => {
3701 try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);3692 try decl.link.macho.code.appendSlice(self.base.allocator, code_buffer.items);
...@@ -3707,12 +3698,10 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -3707,12 +3698,10 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
3707 },3698 },
3708 }3699 }
37093700
3710 _ = try self.placeDecl(decl, decl.link.macho.code.items.len);3701 const symbol = try self.placeDecl(decl, decl.link.macho.code.items.len);
37113702
3712 if (debug_buffers) |db| {3703 if (self.d_sym) |*d_sym| {
3713 if (self.d_sym) |*d_sym| {3704 try d_sym.dwarf.commitDeclState(&self.base, module, decl, symbol.n_value, decl.link.macho.size);
3714 try d_sym.commitDeclDebugInfo(module, decl, db);
3715 }
3716 }3705 }
37173706
3718 // Since we updated the vaddr and the size, each corresponding export symbol also3707 // Since we updated the vaddr and the size, each corresponding export symbol also
...@@ -3812,33 +3801,17 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3812,33 +3801,17 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3812 var code_buffer = std.ArrayList(u8).init(self.base.allocator);3801 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
3813 defer code_buffer.deinit();3802 defer code_buffer.deinit();
38143803
3815 var debug_buffers_buf: link.File.Dwarf.DeclDebugBuffers = undefined;3804 if (self.d_sym) |*d_sym| {
3816 const debug_buffers = if (self.d_sym) |*d_sym| blk: {3805 try d_sym.dwarf.initDeclState(decl);
3817 debug_buffers_buf = try d_sym.initDeclDebugInfo(module, decl);
3818 break :blk &debug_buffers_buf;
3819 } else null;
3820 defer {
3821 if (debug_buffers) |dbg| {
3822 dbg.dbg_line_buffer.deinit();
3823 dbg.dbg_info_buffer.deinit();
3824 for (dbg.dbg_info_type_relocs.values()) |*value| {
3825 value.relocs.deinit(self.base.allocator);
3826 }
3827 dbg.dbg_info_type_relocs.deinit(self.base.allocator);
3828 }
3829 }3806 }
38303807
3831 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;3808 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
3832 const res = if (debug_buffers) |dbg|3809 const res = if (self.d_sym) |*d_sym|
3833 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{3810 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
3834 .ty = decl.ty,3811 .ty = decl.ty,
3835 .val = decl_val,3812 .val = decl_val,
3836 }, &code_buffer, .{3813 }, &code_buffer, .{
3837 .dwarf = .{3814 .dwarf = &d_sym.dwarf,
3838 .dbg_line = &dbg.dbg_line_buffer,
3839 .dbg_info = &dbg.dbg_info_buffer,
3840 .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
3841 },
3842 }, .{3815 }, .{
3843 .parent_atom_index = decl.link.macho.local_sym_index,3816 .parent_atom_index = decl.link.macho.local_sym_index,
3844 })3817 })
...@@ -3870,7 +3843,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3870,7 +3843,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3870 },3843 },
3871 }3844 }
3872 };3845 };
3873 _ = try self.placeDecl(decl, code.len);3846 const symbol = try self.placeDecl(decl, code.len);
3847
3848 if (self.d_sym) |*d_sym| {
3849 try d_sym.dwarf.commitDeclState(&self.base, module, decl, symbol.n_value, decl.link.macho.size);
3850 }
38743851
3875 // Since we updated the vaddr and the size, each corresponding export symbol also3852 // Since we updated the vaddr and the size, each corresponding export symbol also
3876 // needs to be updated.3853 // needs to be updated.
...@@ -4084,8 +4061,9 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -4084,8 +4061,9 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
4084}4061}
40854062
4086pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {4063pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
4064 _ = module;
4087 if (self.d_sym) |*d_sym| {4065 if (self.d_sym) |*d_sym| {
4088 try d_sym.updateDeclLineNumber(module, decl);4066 try d_sym.dwarf.updateDeclLineNumber(&self.base, decl);
4089 }4067 }
4090}4068}
40914069
src/link/MachO/Atom.zig+1-1
...@@ -72,7 +72,7 @@ stab: ?Stab = null,...@@ -72,7 +72,7 @@ stab: ?Stab = null,
72next: ?*Atom,72next: ?*Atom,
73prev: ?*Atom,73prev: ?*Atom,
7474
75dbg_info_atom: Dwarf.DebugInfoAtom,75dbg_info_atom: Dwarf.Atom,
7676
77dirty: bool = true,77dirty: bool = true,
7878
src/link/MachO/DebugSymbols.zig-22
...@@ -645,25 +645,3 @@ fn writeStringTable(self: *DebugSymbols) !void {...@@ -645,25 +645,3 @@ fn writeStringTable(self: *DebugSymbols) !void {
645645
646 self.load_commands_dirty = true;646 self.load_commands_dirty = true;
647}647}
648
649pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const Module.Decl) !void {
650 _ = module;
651 return self.dwarf.updateDeclLineNumber(&self.base.base, decl);
652}
653
654/// Caller owns the returned memory.
655pub fn initDeclDebugInfo(self: *DebugSymbols, module: *Module, decl: *Module.Decl) !Dwarf.DeclDebugBuffers {
656 _ = module;
657 return self.dwarf.initDeclDebugInfo(decl);
658}
659
660pub fn commitDeclDebugInfo(
661 self: *DebugSymbols,
662 module: *Module,
663 decl: *Module.Decl,
664 debug_buffers: *Dwarf.DeclDebugBuffers,
665) !void {
666 const symbol = self.base.locals.items[decl.link.macho.local_sym_index];
667 const atom = &decl.link.macho;
668 return self.dwarf.commitDeclDebugInfo(&self.base.base, module, decl, symbol.n_value, atom.size, debug_buffers);
669}