| author | |
| committer | |
| log | b8cd56dc94f68cda6616b4d9411d0419d2bb909f |
| tree | 57ff6e57dc9b041826e31e6ad7e652b605bedd91 |
| parent | 7be340e3cc62285d77cbd13f19f4ff0a2a982e82 |
| parent | 366ec2105249050fe88e5fa9f241e14f708db891 |
| signature |
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 to | 391 | // 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 { |
| 586 | 587 | ||
| 587 | fn mirDebugPrologueEnd(self: *Emit) !void { | 588 | fn 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 { |
| 597 | 598 | ||
| 598 | fn mirDebugEpilogueBegin(self: *Emit) !void { | 599 | fn 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 to | 333 | // 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. |
| 380 | fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void { | 381 | fn 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.ref4 | 386 | const index = dbg_info.items.len; |
| 386 | 387 | 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.exprloc | 414 | 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 length | 416 | 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.ref4 | 420 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 |
| 421 | dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | 421 | 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 | }; |
| 444 | 444 | ||
| 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); | ||
| 446 | 447 | ||
| 447 | // Get length of the LEB128 stack offset | 448 | // 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 { |
| 450 | 451 | ||
| 451 | // DW.AT.location, DW.FORM.exprloc | 452 | // DW.AT.location, DW.FORM.exprloc |
| 452 | // ULEB128 dwarf expression length | 453 | // 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); |
| 456 | 457 | ||
| 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.ref4 | 459 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 |
| 459 | dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | 460 | 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 { |
| 558 | 559 | ||
| 559 | fn mirDebugPrologueEnd(emit: *Emit) !void { | 560 | fn 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 { |
| 569 | 570 | ||
| 570 | fn mirDebugEpilogueBegin(emit: *Emit) !void { | 571 | fn 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. |
| 746 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { | 746 | fn 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.ref4 | 751 | const index = dbg_info.items.len; |
| 752 | 752 | 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.exprloc | 1575 | 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 length | 1577 | 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.ref4 | 1581 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 |
| 1585 | dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | 1582 | 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 to | 94 | // 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 { |
| 182 | 183 | ||
| 183 | fn mirDebugPrologueEnd(self: *Emit) !void { | 184 | fn 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 { |
| 193 | 194 | ||
| 194 | fn mirDebugEpilogueBegin(self: *Emit) !void { | 195 | fn 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; |
| 16 | 16 | ||
| 17 | const Air = @import("../../Air.zig"); | 17 | const Air = @import("../../Air.zig"); |
| 18 | const Allocator = mem.Allocator; | 18 | const Allocator = mem.Allocator; |
| 19 | const CodeGen = @import("CodeGen.zig"); | ||
| 19 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 20 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 20 | const DW = std.dwarf; | 21 | const DW = std.dwarf; |
| 21 | const Encoder = bits.Encoder; | 22 | const Encoder = bits.Encoder; |
| ... | @@ -29,6 +30,7 @@ const Type = @import("../../type.zig").Type; | ... | @@ -29,6 +30,7 @@ const Type = @import("../../type.zig").Type; |
| 29 | 30 | ||
| 30 | mir: Mir, | 31 | mir: Mir, |
| 31 | bin_file: *link.File, | 32 | bin_file: *link.File, |
| 33 | function: *const CodeGen, | ||
| 32 | debug_output: DebugInfoOutput, | 34 | debug_output: DebugInfoOutput, |
| 33 | target: *const std.Target, | 35 | target: *const std.Target, |
| 34 | err_msg: ?*ErrorMsg = null, | 36 | err_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 to | 970 | // 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.exprloc | 1072 | 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 length | 1074 | 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.ref4 | 1078 | try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 |
| 1075 | dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | 1079 | 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 to | 1088 | // 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 the | 1089 | // 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 pointer | 1091 | // 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.exprloc | 1097 | 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 LEB128 | 1099 | 1, // we will backpatch it after we encode the displacement in LEB128 |
| 1095 | DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer | 1100 | 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.ref4 | 1105 | try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 |
| 1101 | dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | 1106 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string |
| 1102 | 1107 | ||
| 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. |
| 1114 | fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void { | 1119 | fn 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.ref4 | 1124 | const index = dbg_info.items.len; |
| 1120 | 1125 | 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const build_options = @import("build_options"); | ||
| 2 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 4 | const assert = std.debug.assert; | ||
| 5 | const leb128 = std.leb; | ||
| 6 | const link = @import("link.zig"); | ||
| 7 | const log = std.log.scoped(.codegen); | ||
| 3 | const mem = std.mem; | 8 | const mem = std.mem; |
| 4 | const math = std.math; | 9 | const math = std.math; |
| 5 | const assert = std.debug.assert; | 10 | const trace = @import("tracy.zig").trace; |
| 11 | |||
| 6 | const Air = @import("Air.zig"); | 12 | const Air = @import("Air.zig"); |
| 7 | const Zir = @import("Zir.zig"); | 13 | const Allocator = mem.Allocator; |
| 8 | const Liveness = @import("Liveness.zig"); | ||
| 9 | const Type = @import("type.zig").Type; | ||
| 10 | const Value = @import("value.zig").Value; | ||
| 11 | const TypedValue = @import("TypedValue.zig"); | ||
| 12 | const link = @import("link.zig"); | ||
| 13 | const Module = @import("Module.zig"); | ||
| 14 | const Compilation = @import("Compilation.zig"); | 14 | const Compilation = @import("Compilation.zig"); |
| 15 | const ErrorMsg = Module.ErrorMsg; | 15 | const ErrorMsg = Module.ErrorMsg; |
| 16 | const Liveness = @import("Liveness.zig"); | ||
| 17 | const Module = @import("Module.zig"); | ||
| 16 | const Target = std.Target; | 18 | const Target = std.Target; |
| 17 | const Allocator = mem.Allocator; | 19 | const Type = @import("type.zig").Type; |
| 18 | const trace = @import("tracy.zig").trace; | 20 | const TypedValue = @import("TypedValue.zig"); |
| 19 | const DW = std.dwarf; | 21 | const Value = @import("value.zig").Value; |
| 20 | const leb128 = std.leb; | 22 | const Zir = @import("Zir.zig"); |
| 21 | const log = std.log.scoped(.codegen); | ||
| 22 | const build_options = @import("build_options"); | ||
| 23 | const RegisterManager = @import("register_manager.zig").RegisterManager; | ||
| 24 | 23 | ||
| 25 | pub const FnResult = union(enum) { | 24 | pub 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 | }; |
| 44 | 43 | ||
| 45 | pub const DebugInfoOutput = union(enum) { | 44 | pub 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 opcodes | 46 | /// the plan9 debuginfo output is a bytecode with 4 opcodes |
| 52 | /// assume all numbers/variables are bytes | 47 | /// 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 offset | 48 | /// 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); |
| 579 | 573 | ||
| ... | @@ -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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const build_options = @import("build_options"); | ||
| 2 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 3 | const mem = std.mem; | 4 | const assert = std.debug.assert; |
| 4 | const Allocator = std.mem.Allocator; | ||
| 5 | const fs = std.fs; | 5 | const fs = std.fs; |
| 6 | const mem = std.mem; | ||
| 6 | const log = std.log.scoped(.link); | 7 | const log = std.log.scoped(.link); |
| 7 | const assert = std.debug.assert; | 8 | const trace = @import("tracy.zig").trace; |
| 9 | const wasi_libc = @import("wasi_libc.zig"); | ||
| 8 | 10 | ||
| 11 | const Air = @import("Air.zig"); | ||
| 12 | const Allocator = std.mem.Allocator; | ||
| 13 | const Cache = @import("Cache.zig"); | ||
| 9 | const Compilation = @import("Compilation.zig"); | 14 | const Compilation = @import("Compilation.zig"); |
| 15 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | ||
| 16 | const Liveness = @import("Liveness.zig"); | ||
| 10 | const Module = @import("Module.zig"); | 17 | const Module = @import("Module.zig"); |
| 11 | const trace = @import("tracy.zig").trace; | ||
| 12 | const Package = @import("Package.zig"); | 18 | const Package = @import("Package.zig"); |
| 13 | const Type = @import("type.zig").Type; | 19 | const Type = @import("type.zig").Type; |
| 14 | const Cache = @import("Cache.zig"); | ||
| 15 | const build_options = @import("build_options"); | ||
| 16 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | ||
| 17 | const wasi_libc = @import("wasi_libc.zig"); | ||
| 18 | const Air = @import("Air.zig"); | ||
| 19 | const Liveness = @import("Liveness.zig"); | ||
| 20 | const TypedValue = @import("TypedValue.zig"); | 20 | const TypedValue = @import("TypedValue.zig"); |
| 21 | 21 | ||
| 22 | pub const SystemLib = struct { | 22 | pub 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 | }; |
| 247 | 247 | ||
| 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. If | 248 | /// Attempts incremental linking, if the file already exists. If |
| 267 | /// incremental linking fails, falls back to truncating the file and | 249 | /// incremental linking fails, falls back to truncating the file and |
| 268 | /// rewriting it. A malicious file is detected as incremental link failure | 250 | /// 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) = .{}, |
| 31 | dbg_line_fn_first: ?*SrcFn = null, | 31 | dbg_line_fn_first: ?*SrcFn = null, |
| 32 | dbg_line_fn_last: ?*SrcFn = null, | 32 | dbg_line_fn_last: ?*SrcFn = null, |
| 33 | 33 | ||
| 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. |
| 35 | dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*DebugInfoAtom, void) = .{}, | 35 | /// This is the same concept as `text_block_free_list`; see those doc comments. |
| 36 | dbg_info_decl_first: ?*DebugInfoAtom = null, | 36 | atom_free_list: std.AutoHashMapUnmanaged(*Atom, void) = .{}, |
| 37 | dbg_info_decl_last: ?*DebugInfoAtom = null, | 37 | atom_first: ?*Atom = null, |
| 38 | atom_last: ?*Atom = null, | ||
| 38 | 39 | ||
| 39 | abbrev_table_offset: ?u64 = null, | 40 | abbrev_table_offset: ?u64 = null, |
| 40 | 41 | ||
| 42 | /// TODO replace with InternArena | ||
| 41 | /// Table of debug symbol names. | 43 | /// Table of debug symbol names. |
| 42 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 44 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 43 | 45 | ||
| 44 | pub const DebugInfoAtom = struct { | 46 | /// Lives only as long as the analysed Decl. |
| 47 | /// Allocated with `initDeclState`. | ||
| 48 | /// Freed with `commitDeclState`. | ||
| 49 | decl_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. | ||
| 54 | managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, | ||
| 55 | |||
| 56 | global_abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, | ||
| 57 | |||
| 58 | pub 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 | }; |
| 54 | 68 | ||
| 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. | ||
| 73 | pub 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 | |||
| 104 | pub const AbbrevEntry = struct { | ||
| 105 | atom: *const Atom, | ||
| 106 | @"type": Type, | ||
| 107 | offset: u32, | ||
| 108 | }; | ||
| 109 | |||
| 110 | pub const AbbrevRelocation = struct { | ||
| 111 | target: u32, | ||
| 112 | atom: *const Atom, | ||
| 113 | offset: u32, | ||
| 114 | addend: u32, | ||
| 115 | }; | ||
| 116 | |||
| 55 | pub const SrcFn = struct { | 117 | pub 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 { |
| 117 | pub fn deinit(self: *Dwarf) void { | 179 | pub 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); |
| 123 | 185 | ||
| 124 | pub 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 | } |
| 129 | 191 | ||
| 130 | pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers { | 192 | /// Initializes Decl's state and its matching output buffers. |
| 193 | /// Call this before `commitDeclState`. | ||
| 194 | pub 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(); |
| 133 | 197 | ||
| 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); |
| 136 | 200 | ||
| 137 | log.debug("initDeclDebugInfo {s}{*}", .{ decl_name, decl }); | 201 | log.debug("initDeclState {s}{*}", .{ decl_name, decl }); |
| 138 | 202 | ||
| 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; | ||
| 143 | 208 | ||
| 144 | assert(decl.has_tv); | 209 | assert(decl.has_tv); |
| 145 | 210 | ||
| ... | @@ -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.addr | 267 | 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.data4 | 269 | 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.ref4 | 278 | 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.string | 281 | dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string |
| 219 | 282 | ||
| 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 variables | 285 | // 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 | } |
| 232 | 289 | ||
| 233 | pub fn commitDeclDebugInfo( | 290 | pub 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(); |
| 244 | 300 | ||
| 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; | ||
| 249 | 310 | ||
| 250 | const target_endian = self.target.cpu.arch.endian(); | 311 | const target_endian = self.target.cpu.arch.endian(); |
| 251 | 312 | ||
| ... | @@ -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; |
| 445 | 506 | ||
| 446 | // We need this for the duration of this function only so that for composite | 507 | const atom = switch (self.tag) { |
| 447 | // types such as []const u32, if the type *u32 is non-existent, we create | 508 | .elf => &decl.link.elf.dbg_info_atom, |
| 448 | // it synthetically and store the backing bytes in this arena. After we are | 509 | .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 of | 515 | // 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 actual | 516 | // 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 | } |
| 478 | 538 | ||
| 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)); |
| 485 | 540 | ||
| 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 the | 554 | 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 | } |
| 515 | 573 | ||
| 516 | fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom, len: u32) !void { | 574 | fn 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(); |
| 519 | 577 | ||
| ... | @@ -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; |
| 524 | 582 | ||
| 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; |
| 560 | 618 | ||
| 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; |
| 569 | 627 | ||
| 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_info | 631 | // 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; |
| 576 | 634 | ||
| 577 | atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes())); | 635 | atom.off = @intCast(u32, padToIdeal(self.dbgInfoHeaderBytes())); |
| 578 | } | 636 | } |
| 579 | } | 637 | } |
| 580 | 638 | ||
| 581 | fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *DebugInfoAtom, dbg_info_buf: []const u8) !void { | 639 | fn 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(); |
| 584 | 642 | ||
| ... | @@ -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; |
| 589 | 647 | ||
| 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 | } |
| 714 | 772 | ||
| 715 | pub fn freeAtom(self: *Dwarf, atom: *DebugInfoAtom) void { | 773 | pub 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 here | 778 | // TODO shrink the .debug_info section size here |
| 721 | self.dbg_info_decl_last = atom.prev; | 779 | self.atom_last = atom.prev; |
| 722 | } | 780 | } |
| 723 | 781 | ||
| 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 { |
| 771 | fn addDbgInfoType( | 829 | fn 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); | ||
| 782 | 839 | ||
| 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.ref4 | 894 | // 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.sdata | 898 | // 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.ref4 | 906 | // 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.sdata | 910 | // 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.sdata | 939 | // 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.ref4 | 947 | // 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.sdata | 951 | // 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.ref4 | 959 | // 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.ref4 | 983 | // 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.sdata | 987 | // 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.ref4 | 1014 | // 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.sdata | 1018 | // 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.ref4 | 1094 | // 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.sdata | 1098 | // 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.ref4 | 1121 | // 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.sdata | 1125 | // 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.ref4 | 1138 | // 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.sdata | 1142 | // 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); |
| 1093 | 1144 | ||
| ... | @@ -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 | } |
| 1117 | 1235 | ||
| 1118 | pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { | 1236 | pub 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 | } |
| 1764 | 1882 | ||
| 1765 | fn getDebugInfoOff(self: Dwarf) ?u32 { | 1883 | fn 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 | } |
| 1769 | 1887 | ||
| 1770 | fn getDebugInfoEnd(self: Dwarf) ?u32 { | 1888 | fn 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 | } |
| 1774 | 1892 | ||
| ... | @@ -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) catch | 1951 | 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 | |||
| 1955 | pub 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 | |||
| 1986 | pub fn getDeclDebugLineBuffer(self: *Dwarf) *std.ArrayList(u8) { | ||
| 1987 | return &self.decl_state.?.dbg_line; | ||
| 1988 | } | ||
| 1989 | |||
| 1990 | pub fn getDeclDebugInfoBuffer(self: *Dwarf) *std.ArrayList(u8) { | ||
| 1991 | return &self.decl_state.?.dbg_info; | ||
| 1992 | } | ||
| 1993 | |||
| 1994 | pub 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, |
| 209 | 209 | ||
| 210 | dbg_info_atom: Dwarf.DebugInfoAtom, | 210 | dbg_info_atom: Dwarf.Atom, |
| 211 | 211 | ||
| 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(); |
| 960 | 960 | ||
| 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 | } |
| 2230 | 2234 | ||
| 2231 | fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void { | ||
| 2232 | for (table.values()) |*value| { | ||
| 2233 | value.relocs.deinit(gpa); | ||
| 2234 | } | ||
| 2235 | table.deinit(gpa); | ||
| 2236 | } | ||
| 2237 | |||
| 2238 | fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 { | 2235 | fn 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); |
| 2344 | 2341 | ||
| 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 | } |
| 2357 | 2345 | ||
| 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 | else | 2350 | 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 | } |
| 2381 | 2365 | ||
| 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(); |
| 2412 | 2396 | ||
| 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 | } |
| 2425 | 2400 | ||
| 2426 | // TODO implement .debug_info for global variables | 2401 | // 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 | }; |
| 2458 | 2429 | ||
| 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 | } |
| 2463 | 2434 | ||
| 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}); |
| 455 | 455 | ||
| 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 it | 462 | // 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(); |
| 3672 | 3678 | ||
| 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 | } |
| 3688 | 3682 | ||
| 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 | else | 3687 | 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 | } |
| 3709 | 3700 | ||
| 3710 | _ = try self.placeDecl(decl, decl.link.macho.code.items.len); | 3701 | const symbol = try self.placeDecl(decl, decl.link.macho.code.items.len); |
| 3711 | 3702 | ||
| 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 | } |
| 3717 | 3706 | ||
| 3718 | // Since we updated the vaddr and the size, each corresponding export symbol also | 3707 | // 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(); |
| 3814 | 3803 | ||
| 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 | } |
| 3830 | 3807 | ||
| 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 | } | ||
| 3874 | 3851 | ||
| 3875 | // Since we updated the vaddr and the size, each corresponding export symbol also | 3852 | // 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 | } |
| 4085 | 4062 | ||
| 4086 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void { | 4063 | pub 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 | } |
| 4091 | 4069 |
src/link/MachO/Atom.zig+1-1| ... | @@ -72,7 +72,7 @@ stab: ?Stab = null, | ... | @@ -72,7 +72,7 @@ stab: ?Stab = null, |
| 72 | next: ?*Atom, | 72 | next: ?*Atom, |
| 73 | prev: ?*Atom, | 73 | prev: ?*Atom, |
| 74 | 74 | ||
| 75 | dbg_info_atom: Dwarf.DebugInfoAtom, | 75 | dbg_info_atom: Dwarf.Atom, |
| 76 | 76 | ||
| 77 | dirty: bool = true, | 77 | dirty: bool = true, |
| 78 | 78 |
src/link/MachO/DebugSymbols.zig-22| ... | @@ -645,25 +645,3 @@ fn writeStringTable(self: *DebugSymbols) !void { | ... | @@ -645,25 +645,3 @@ fn writeStringTable(self: *DebugSymbols) !void { |
| 645 | 645 | ||
| 646 | self.load_commands_dirty = true; | 646 | self.load_commands_dirty = true; |
| 647 | } | 647 | } |
| 648 | |||
| 649 | pub 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. | ||
| 655 | pub fn initDeclDebugInfo(self: *DebugSymbols, module: *Module, decl: *Module.Decl) !Dwarf.DeclDebugBuffers { | ||
| 656 | _ = module; | ||
| 657 | return self.dwarf.initDeclDebugInfo(decl); | ||
| 658 | } | ||
| 659 | |||
| 660 | pub 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 | } |