| 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 | 386 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); |
| 387 | 387 | const delta_pc: usize = self.code.items.len - self.prev_di_pc; |
| 388 | 388 | switch (self.debug_output) { |
| 389 | .dwarf => |dbg_out| { | |
| 389 | .dwarf => |dw| { | |
| 390 | 390 | // TODO Look into using the DWARF special opcodes to compress this data. |
| 391 | 391 | // It lets you emit single-byte opcodes that add different numbers to |
| 392 | 392 | // both the PC and the line number at the same time. |
| 393 | try dbg_out.dbg_line.ensureUnusedCapacity(11); | |
| 394 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | |
| 395 | leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; | |
| 393 | const dbg_line = dw.getDeclDebugLineBuffer(); | |
| 394 | try dbg_line.ensureUnusedCapacity(11); | |
| 395 | dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | |
| 396 | leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable; | |
| 396 | 397 | if (delta_line != 0) { |
| 397 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | |
| 398 | leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; | |
| 398 | dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | |
| 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 | 402 | self.prev_di_pc = self.code.items.len; |
| 402 | 403 | self.prev_di_line = line; |
| 403 | 404 | self.prev_di_column = column; |
| ... | ... | @@ -586,8 +587,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 586 | 587 | |
| 587 | 588 | fn mirDebugPrologueEnd(self: *Emit) !void { |
| 588 | 589 | switch (self.debug_output) { |
| 589 | .dwarf => |dbg_out| { | |
| 590 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); | |
| 590 | .dwarf => |dw| { | |
| 591 | try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end); | |
| 591 | 592 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 592 | 593 | }, |
| 593 | 594 | .plan9 => {}, |
| ... | ... | @@ -597,8 +598,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void { |
| 597 | 598 | |
| 598 | 599 | fn mirDebugEpilogueBegin(self: *Emit) !void { |
| 599 | 600 | switch (self.debug_output) { |
| 600 | .dwarf => |dbg_out| { | |
| 601 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); | |
| 601 | .dwarf => |dw| { | |
| 602 | try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin); | |
| 602 | 603 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 603 | 604 | }, |
| 604 | 605 | .plan9 => {}, |
src/arch/arm/Emit.zig+37-36| ... | ... | @@ -328,18 +328,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 328 | 328 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); |
| 329 | 329 | const delta_pc: usize = self.code.items.len - self.prev_di_pc; |
| 330 | 330 | switch (self.debug_output) { |
| 331 | .dwarf => |dbg_out| { | |
| 331 | .dwarf => |dw| { | |
| 332 | 332 | // TODO Look into using the DWARF special opcodes to compress this data. |
| 333 | 333 | // It lets you emit single-byte opcodes that add different numbers to |
| 334 | 334 | // both the PC and the line number at the same time. |
| 335 | try dbg_out.dbg_line.ensureUnusedCapacity(11); | |
| 336 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | |
| 337 | leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; | |
| 335 | const dbg_line = dw.getDeclDebugLineBuffer(); | |
| 336 | try dbg_line.ensureUnusedCapacity(11); | |
| 337 | dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | |
| 338 | leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable; | |
| 338 | 339 | if (delta_line != 0) { |
| 339 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | |
| 340 | leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; | |
| 340 | dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | |
| 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 | 344 | self.prev_di_pc = self.code.items.len; |
| 344 | 345 | self.prev_di_line = line; |
| 345 | 346 | self.prev_di_column = column; |
| ... | ... | @@ -379,19 +380,17 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 379 | 380 | /// after codegen for this symbol is done. |
| 380 | 381 | fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void { |
| 381 | 382 | switch (self.debug_output) { |
| 382 | .dwarf => |dbg_out| { | |
| 383 | .dwarf => |dw| { | |
| 383 | 384 | assert(ty.hasRuntimeBits()); |
| 384 | const index = dbg_out.dbg_info.items.len; | |
| 385 | try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 386 | ||
| 387 | const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.bin_file.allocator, ty, .{ .target = self.target.* }); | |
| 388 | if (!gop.found_existing) { | |
| 389 | gop.value_ptr.* = .{ | |
| 390 | .off = undefined, | |
| 391 | .relocs = .{}, | |
| 392 | }; | |
| 393 | } | |
| 394 | try gop.value_ptr.relocs.append(self.bin_file.allocator, @intCast(u32, index)); | |
| 385 | const dbg_info = dw.getDeclDebugInfoBuffer(); | |
| 386 | const index = dbg_info.items.len; | |
| 387 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 388 | const atom = switch (self.bin_file.tag) { | |
| 389 | .elf => &self.function.mod_fn.owner_decl.link.elf.dbg_info_atom, | |
| 390 | .macho => unreachable, | |
| 391 | else => unreachable, | |
| 392 | }; | |
| 393 | try dw.addTypeReloc(atom, ty, @intCast(u32, index), null); | |
| 395 | 394 | }, |
| 396 | 395 | .plan9 => {}, |
| 397 | 396 | .none => {}, |
| ... | ... | @@ -409,16 +408,17 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void { |
| 409 | 408 | switch (mcv) { |
| 410 | 409 | .register => |reg| { |
| 411 | 410 | switch (self.debug_output) { |
| 412 | .dwarf => |dbg_out| { | |
| 413 | try dbg_out.dbg_info.ensureUnusedCapacity(3); | |
| 414 | dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); | |
| 415 | dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 411 | .dwarf => |dw| { | |
| 412 | const dbg_info = dw.getDeclDebugInfoBuffer(); | |
| 413 | try dbg_info.ensureUnusedCapacity(3); | |
| 414 | dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); | |
| 415 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 416 | 416 | 1, // ULEB128 dwarf expression length |
| 417 | 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 | 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 | 423 | .plan9 => {}, |
| 424 | 424 | .none => {}, |
| ... | ... | @@ -428,7 +428,7 @@ fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void { |
| 428 | 428 | .stack_argument_offset, |
| 429 | 429 | => { |
| 430 | 430 | switch (self.debug_output) { |
| 431 | .dwarf => |dbg_out| { | |
| 431 | .dwarf => |dw| { | |
| 432 | 432 | const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch { |
| 433 | 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 | 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 | 448 | // Get length of the LEB128 stack offset |
| 448 | 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 | 451 | |
| 451 | 452 | // DW.AT.location, DW.FORM.exprloc |
| 452 | 453 | // ULEB128 dwarf expression length |
| 453 | try leb128.writeULEB128(dbg_out.dbg_info.writer(), counting_writer.bytes_written + 1); | |
| 454 | try dbg_out.dbg_info.append(DW.OP.breg11); | |
| 455 | try leb128.writeILEB128(dbg_out.dbg_info.writer(), adjusted_stack_offset); | |
| 454 | try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1); | |
| 455 | try dbg_info.append(DW.OP.breg11); | |
| 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 | 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 | 462 | .plan9 => {}, |
| 462 | 463 | .none => {}, |
| ... | ... | @@ -558,8 +559,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 558 | 559 | |
| 559 | 560 | fn mirDebugPrologueEnd(emit: *Emit) !void { |
| 560 | 561 | switch (emit.debug_output) { |
| 561 | .dwarf => |dbg_out| { | |
| 562 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); | |
| 562 | .dwarf => |dw| { | |
| 563 | try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end); | |
| 563 | 564 | try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); |
| 564 | 565 | }, |
| 565 | 566 | .plan9 => {}, |
| ... | ... | @@ -569,8 +570,8 @@ fn mirDebugPrologueEnd(emit: *Emit) !void { |
| 569 | 570 | |
| 570 | 571 | fn mirDebugEpilogueBegin(emit: *Emit) !void { |
| 571 | 572 | switch (emit.debug_output) { |
| 572 | .dwarf => |dbg_out| { | |
| 573 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); | |
| 573 | .dwarf => |dw| { | |
| 574 | try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin); | |
| 574 | 575 | try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); |
| 575 | 576 | }, |
| 576 | 577 | .plan9 => {}, |
src/arch/riscv64/CodeGen.zig+17-20| ... | ... | @@ -745,21 +745,17 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 745 | 745 | /// after codegen for this symbol is done. |
| 746 | 746 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { |
| 747 | 747 | switch (self.debug_output) { |
| 748 | .dwarf => |dbg_out| { | |
| 748 | .dwarf => |dw| { | |
| 749 | 749 | assert(ty.hasRuntimeBits()); |
| 750 | const index = dbg_out.dbg_info.items.len; | |
| 751 | try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 752 | ||
| 753 | const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.gpa, ty, .{ | |
| 754 | .target = self.target.*, | |
| 755 | }); | |
| 756 | if (!gop.found_existing) { | |
| 757 | gop.value_ptr.* = .{ | |
| 758 | .off = undefined, | |
| 759 | .relocs = .{}, | |
| 760 | }; | |
| 761 | } | |
| 762 | try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index)); | |
| 750 | const dbg_info = dw.getDeclDebugInfoBuffer(); | |
| 751 | const index = dbg_info.items.len; | |
| 752 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 753 | const atom = switch (self.bin_file.tag) { | |
| 754 | .elf => &self.mod_fn.owner_decl.link.elf.dbg_info_atom, | |
| 755 | .macho => unreachable, | |
| 756 | else => unreachable, | |
| 757 | }; | |
| 758 | try dw.addTypeReloc(atom, ty, @intCast(u32, index), null); | |
| 763 | 759 | }, |
| 764 | 760 | .plan9 => {}, |
| 765 | 761 | .none => {}, |
| ... | ... | @@ -1573,16 +1569,17 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32 |
| 1573 | 1569 | switch (mcv) { |
| 1574 | 1570 | .register => |reg| { |
| 1575 | 1571 | switch (self.debug_output) { |
| 1576 | .dwarf => |dbg_out| { | |
| 1577 | try dbg_out.dbg_info.ensureUnusedCapacity(3); | |
| 1578 | dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); | |
| 1579 | dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 1572 | .dwarf => |dw| { | |
| 1573 | const dbg_info = dw.getDeclDebugInfoBuffer(); | |
| 1574 | try dbg_info.ensureUnusedCapacity(3); | |
| 1575 | dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); | |
| 1576 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 1580 | 1577 | 1, // ULEB128 dwarf expression length |
| 1581 | 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 | 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 | 1584 | .plan9 => {}, |
| 1588 | 1585 | .none => {}, |
src/arch/riscv64/Emit.zig+12-11| ... | ... | @@ -89,18 +89,19 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 89 | 89 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); |
| 90 | 90 | const delta_pc: usize = self.code.items.len - self.prev_di_pc; |
| 91 | 91 | switch (self.debug_output) { |
| 92 | .dwarf => |dbg_out| { | |
| 92 | .dwarf => |dw| { | |
| 93 | 93 | // TODO Look into using the DWARF special opcodes to compress this data. |
| 94 | 94 | // It lets you emit single-byte opcodes that add different numbers to |
| 95 | 95 | // both the PC and the line number at the same time. |
| 96 | try dbg_out.dbg_line.ensureUnusedCapacity(11); | |
| 97 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | |
| 98 | leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; | |
| 96 | const dbg_line = dw.getDeclDebugLineBuffer(); | |
| 97 | try dbg_line.ensureUnusedCapacity(11); | |
| 98 | dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | |
| 99 | leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable; | |
| 99 | 100 | if (delta_line != 0) { |
| 100 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | |
| 101 | leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; | |
| 101 | dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | |
| 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 | 105 | self.prev_di_pc = self.code.items.len; |
| 105 | 106 | self.prev_di_line = line; |
| 106 | 107 | self.prev_di_column = column; |
| ... | ... | @@ -182,8 +183,8 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 182 | 183 | |
| 183 | 184 | fn mirDebugPrologueEnd(self: *Emit) !void { |
| 184 | 185 | switch (self.debug_output) { |
| 185 | .dwarf => |dbg_out| { | |
| 186 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); | |
| 186 | .dwarf => |dw| { | |
| 187 | try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end); | |
| 187 | 188 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 188 | 189 | }, |
| 189 | 190 | .plan9 => {}, |
| ... | ... | @@ -193,8 +194,8 @@ fn mirDebugPrologueEnd(self: *Emit) !void { |
| 193 | 194 | |
| 194 | 195 | fn mirDebugEpilogueBegin(self: *Emit) !void { |
| 195 | 196 | switch (self.debug_output) { |
| 196 | .dwarf => |dbg_out| { | |
| 197 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); | |
| 197 | .dwarf => |dw| { | |
| 198 | try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin); | |
| 198 | 199 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| 199 | 200 | }, |
| 200 | 201 | .plan9 => {}, |
src/arch/x86_64/CodeGen.zig+1| ... | ... | @@ -350,6 +350,7 @@ pub fn generate( |
| 350 | 350 | var emit = Emit{ |
| 351 | 351 | .mir = mir, |
| 352 | 352 | .bin_file = bin_file, |
| 353 | .function = &function, | |
| 353 | 354 | .debug_output = debug_output, |
| 354 | 355 | .target = &bin_file.options.target, |
| 355 | 356 | .src_loc = src_loc, |
src/arch/x86_64/Emit.zig+41-40| ... | ... | @@ -16,6 +16,7 @@ const testing = std.testing; |
| 16 | 16 | |
| 17 | 17 | const Air = @import("../../Air.zig"); |
| 18 | 18 | const Allocator = mem.Allocator; |
| 19 | const CodeGen = @import("CodeGen.zig"); | |
| 19 | 20 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 20 | 21 | const DW = std.dwarf; |
| 21 | 22 | const Encoder = bits.Encoder; |
| ... | ... | @@ -29,6 +30,7 @@ const Type = @import("../../type.zig").Type; |
| 29 | 30 | |
| 30 | 31 | mir: Mir, |
| 31 | 32 | bin_file: *link.File, |
| 33 | function: *const CodeGen, | |
| 32 | 34 | debug_output: DebugInfoOutput, |
| 33 | 35 | target: *const std.Target, |
| 34 | 36 | err_msg: ?*ErrorMsg = null, |
| ... | ... | @@ -963,18 +965,19 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void { |
| 963 | 965 | const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; |
| 964 | 966 | log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc }); |
| 965 | 967 | switch (emit.debug_output) { |
| 966 | .dwarf => |dbg_out| { | |
| 968 | .dwarf => |dw| { | |
| 967 | 969 | // TODO Look into using the DWARF special opcodes to compress this data. |
| 968 | 970 | // It lets you emit single-byte opcodes that add different numbers to |
| 969 | 971 | // both the PC and the line number at the same time. |
| 970 | try dbg_out.dbg_line.ensureUnusedCapacity(11); | |
| 971 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | |
| 972 | leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; | |
| 972 | const dbg_line = dw.getDeclDebugLineBuffer(); | |
| 973 | try dbg_line.ensureUnusedCapacity(11); | |
| 974 | dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); | |
| 975 | leb128.writeULEB128(dbg_line.writer(), delta_pc) catch unreachable; | |
| 973 | 976 | if (delta_line != 0) { |
| 974 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | |
| 975 | leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; | |
| 977 | dbg_line.appendAssumeCapacity(DW.LNS.advance_line); | |
| 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 | 981 | emit.prev_di_line = line; |
| 979 | 982 | emit.prev_di_column = column; |
| 980 | 983 | emit.prev_di_pc = emit.code.items.len; |
| ... | ... | @@ -1022,8 +1025,8 @@ fn mirDbgPrologueEnd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 1022 | 1025 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 1023 | 1026 | assert(tag == .dbg_prologue_end); |
| 1024 | 1027 | switch (emit.debug_output) { |
| 1025 | .dwarf => |dbg_out| { | |
| 1026 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); | |
| 1028 | .dwarf => |dw| { | |
| 1029 | try dw.getDeclDebugLineBuffer().append(DW.LNS.set_prologue_end); | |
| 1027 | 1030 | log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column }); |
| 1028 | 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 | 1039 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 1037 | 1040 | assert(tag == .dbg_epilogue_begin); |
| 1038 | 1041 | switch (emit.debug_output) { |
| 1039 | .dwarf => |dbg_out| { | |
| 1040 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); | |
| 1042 | .dwarf => |dw| { | |
| 1043 | try dw.getDeclDebugLineBuffer().append(DW.LNS.set_epilogue_begin); | |
| 1041 | 1044 | log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column }); |
| 1042 | 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 | 1066 | switch (mcv) { |
| 1064 | 1067 | .register => |reg| { |
| 1065 | 1068 | switch (emit.debug_output) { |
| 1066 | .dwarf => |dbg_out| { | |
| 1067 | try dbg_out.dbg_info.ensureUnusedCapacity(3); | |
| 1068 | dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); | |
| 1069 | dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 1069 | .dwarf => |dw| { | |
| 1070 | const dbg_info = dw.getDeclDebugInfoBuffer(); | |
| 1071 | try dbg_info.ensureUnusedCapacity(3); | |
| 1072 | dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); | |
| 1073 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 1070 | 1074 | 1, // ULEB128 dwarf expression length |
| 1071 | 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 | 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 | 1081 | .plan9 => {}, |
| 1078 | 1082 | .none => {}, |
| ... | ... | @@ -1080,25 +1084,26 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32 |
| 1080 | 1084 | }, |
| 1081 | 1085 | .stack_offset => |off| { |
| 1082 | 1086 | switch (emit.debug_output) { |
| 1083 | .dwarf => |dbg_out| { | |
| 1087 | .dwarf => |dw| { | |
| 1084 | 1088 | // we add here +16 like we do in airArg in CodeGen since we refer directly to |
| 1085 | 1089 | // rbp as the start of function frame minus 8 bytes for caller's rbp preserved in the |
| 1086 | 1090 | // prologue, and 8 bytes for return address. |
| 1087 | 1091 | // TODO we need to make this more generic if we don't use rbp as the frame pointer |
| 1088 | 1092 | // for example when -fomit-frame-pointer is set. |
| 1089 | 1093 | const disp = @intCast(i32, max_stack) - off + 16; |
| 1090 | try dbg_out.dbg_info.ensureUnusedCapacity(8); | |
| 1091 | dbg_out.dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); | |
| 1092 | const fixup = dbg_out.dbg_info.items.len; | |
| 1093 | dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 1094 | const dbg_info = dw.getDeclDebugInfoBuffer(); | |
| 1095 | try dbg_info.ensureUnusedCapacity(8); | |
| 1096 | dbg_info.appendAssumeCapacity(link.File.Dwarf.abbrev_parameter); | |
| 1097 | const fixup = dbg_info.items.len; | |
| 1098 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 1094 | 1099 | 1, // we will backpatch it after we encode the displacement in LEB128 |
| 1095 | 1100 | DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer |
| 1096 | 1101 | }); |
| 1097 | leb128.writeILEB128(dbg_out.dbg_info.writer(), disp) catch unreachable; | |
| 1098 | dbg_out.dbg_info.items[fixup] += @intCast(u8, dbg_out.dbg_info.items.len - fixup - 2); | |
| 1099 | try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 1102 | leb128.writeILEB128(dbg_info.writer(), disp) catch unreachable; | |
| 1103 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 1104 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 1100 | 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 | 1109 | .plan9 => {}, |
| ... | ... | @@ -1113,21 +1118,17 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32 |
| 1113 | 1118 | /// after codegen for this symbol is done. |
| 1114 | 1119 | fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void { |
| 1115 | 1120 | switch (emit.debug_output) { |
| 1116 | .dwarf => |dbg_out| { | |
| 1121 | .dwarf => |dw| { | |
| 1117 | 1122 | assert(ty.hasRuntimeBits()); |
| 1118 | const index = dbg_out.dbg_info.items.len; | |
| 1119 | try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 1120 | ||
| 1121 | const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(emit.bin_file.allocator, ty, .{ | |
| 1122 | .target = emit.target.*, | |
| 1123 | }); | |
| 1124 | if (!gop.found_existing) { | |
| 1125 | gop.value_ptr.* = .{ | |
| 1126 | .off = undefined, | |
| 1127 | .relocs = .{}, | |
| 1128 | }; | |
| 1129 | } | |
| 1130 | try gop.value_ptr.relocs.append(emit.bin_file.allocator, @intCast(u32, index)); | |
| 1123 | const dbg_info = dw.getDeclDebugInfoBuffer(); | |
| 1124 | const index = dbg_info.items.len; | |
| 1125 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 1126 | const atom = switch (emit.bin_file.tag) { | |
| 1127 | .elf => &emit.function.mod_fn.owner_decl.link.elf.dbg_info_atom, | |
| 1128 | .macho => &emit.function.mod_fn.owner_decl.link.macho.dbg_info_atom, | |
| 1129 | else => unreachable, | |
| 1130 | }; | |
| 1131 | try dw.addTypeReloc(atom, ty, @intCast(u32, index), null); | |
| 1131 | 1132 | }, |
| 1132 | 1133 | .plan9 => {}, |
| 1133 | 1134 | .none => {}, |
src/codegen.zig+15-23| ... | ... | @@ -1,26 +1,25 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const build_options = @import("build_options"); | |
| 2 | 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 | 8 | const mem = std.mem; |
| 4 | 9 | const math = std.math; |
| 5 | const assert = std.debug.assert; | |
| 10 | const trace = @import("tracy.zig").trace; | |
| 11 | ||
| 6 | 12 | const Air = @import("Air.zig"); |
| 7 | const Zir = @import("Zir.zig"); | |
| 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"); | |
| 13 | const Allocator = mem.Allocator; | |
| 14 | 14 | const Compilation = @import("Compilation.zig"); |
| 15 | 15 | const ErrorMsg = Module.ErrorMsg; |
| 16 | const Liveness = @import("Liveness.zig"); | |
| 17 | const Module = @import("Module.zig"); | |
| 16 | 18 | const Target = std.Target; |
| 17 | const Allocator = mem.Allocator; | |
| 18 | const trace = @import("tracy.zig").trace; | |
| 19 | const DW = std.dwarf; | |
| 20 | const leb128 = std.leb; | |
| 21 | const log = std.log.scoped(.codegen); | |
| 22 | const build_options = @import("build_options"); | |
| 23 | const RegisterManager = @import("register_manager.zig").RegisterManager; | |
| 19 | const Type = @import("type.zig").Type; | |
| 20 | const TypedValue = @import("TypedValue.zig"); | |
| 21 | const Value = @import("value.zig").Value; | |
| 22 | const Zir = @import("Zir.zig"); | |
| 24 | 23 | |
| 25 | 24 | pub const FnResult = union(enum) { |
| 26 | 25 | /// The `code` parameter passed to `generateSymbol` has the value appended. |
| ... | ... | @@ -43,11 +42,7 @@ pub const GenerateSymbolError = error{ |
| 43 | 42 | }; |
| 44 | 43 | |
| 45 | 44 | pub const DebugInfoOutput = union(enum) { |
| 46 | dwarf: struct { | |
| 47 | dbg_line: *std.ArrayList(u8), | |
| 48 | dbg_info: *std.ArrayList(u8), | |
| 49 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, | |
| 50 | }, | |
| 45 | dwarf: *link.File.Dwarf, | |
| 51 | 46 | /// the plan9 debuginfo output is a bytecode with 4 opcodes |
| 52 | 47 | /// assume all numbers/variables are bytes |
| 53 | 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 | 568 | return Result{ .appended = {} }; |
| 574 | 569 | }, |
| 575 | 570 | .Union => { |
| 576 | // TODO generate debug info for unions | |
| 577 | 571 | const union_obj = typed_value.val.castTag(.@"union").?.data; |
| 578 | 572 | const layout = typed_value.ty.unionGetLayout(target); |
| 579 | 573 | |
| ... | ... | @@ -695,7 +689,6 @@ pub fn generateSymbol( |
| 695 | 689 | return Result{ .appended = {} }; |
| 696 | 690 | }, |
| 697 | 691 | .ErrorUnion => { |
| 698 | // TODO generate debug info for error unions | |
| 699 | 692 | const error_ty = typed_value.ty.errorUnionSet(); |
| 700 | 693 | const payload_ty = typed_value.ty.errorUnionPayload(); |
| 701 | 694 | const is_payload = typed_value.val.errorUnionIsPayload(); |
| ... | ... | @@ -749,7 +742,6 @@ pub fn generateSymbol( |
| 749 | 742 | return Result{ .appended = {} }; |
| 750 | 743 | }, |
| 751 | 744 | .ErrorSet => { |
| 752 | // TODO generate debug info for error sets | |
| 753 | 745 | switch (typed_value.val.tag()) { |
| 754 | 746 | .@"error" => { |
| 755 | 747 | const name = typed_value.val.getError().?; |
src/link.zig+10-28| ... | ... | @@ -1,22 +1,22 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const build_options = @import("build_options"); | |
| 2 | 3 | const builtin = @import("builtin"); |
| 3 | const mem = std.mem; | |
| 4 | const Allocator = std.mem.Allocator; | |
| 4 | const assert = std.debug.assert; | |
| 5 | 5 | const fs = std.fs; |
| 6 | const mem = std.mem; | |
| 6 | 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 | 14 | const Compilation = @import("Compilation.zig"); |
| 15 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | |
| 16 | const Liveness = @import("Liveness.zig"); | |
| 10 | 17 | const Module = @import("Module.zig"); |
| 11 | const trace = @import("tracy.zig").trace; | |
| 12 | 18 | const Package = @import("Package.zig"); |
| 13 | 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 | 20 | const TypedValue = @import("TypedValue.zig"); |
| 21 | 21 | |
| 22 | 22 | pub const SystemLib = struct { |
| ... | ... | @@ -245,24 +245,6 @@ pub const File = struct { |
| 245 | 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 | 248 | /// Attempts incremental linking, if the file already exists. If |
| 267 | 249 | /// incremental linking fails, falls back to truncating the file and |
| 268 | 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 | 31 | dbg_line_fn_first: ?*SrcFn = null, |
| 32 | 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. | |
| 35 | dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*DebugInfoAtom, void) = .{}, | |
| 36 | dbg_info_decl_first: ?*DebugInfoAtom = null, | |
| 37 | dbg_info_decl_last: ?*DebugInfoAtom = null, | |
| 34 | /// A list of `Atom`s whose corresponding .debug_info tags have surplus capacity. | |
| 35 | /// This is the same concept as `text_block_free_list`; see those doc comments. | |
| 36 | atom_free_list: std.AutoHashMapUnmanaged(*Atom, void) = .{}, | |
| 37 | atom_first: ?*Atom = null, | |
| 38 | atom_last: ?*Atom = null, | |
| 38 | 39 | |
| 39 | 40 | abbrev_table_offset: ?u64 = null, |
| 40 | 41 | |
| 42 | /// TODO replace with InternArena | |
| 41 | 43 | /// Table of debug symbol names. |
| 42 | 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 | 59 | /// Previous/next linked list pointers. |
| 46 | 60 | /// This is the linked list node for this Decl's corresponding .debug_info tag. |
| 47 | prev: ?*DebugInfoAtom, | |
| 48 | next: ?*DebugInfoAtom, | |
| 61 | prev: ?*Atom, | |
| 62 | next: ?*Atom, | |
| 49 | 63 | /// Offset into .debug_info pointing to the tag for this Decl. |
| 50 | 64 | off: u32, |
| 51 | 65 | /// Size of the .debug_info tag for this Decl, not including padding. |
| 52 | 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 | 117 | pub const SrcFn = struct { |
| 56 | 118 | /// Offset from the beginning of the Debug Line Program header that contains this function. |
| 57 | 119 | off: u32, |
| ... | ... | @@ -117,29 +179,32 @@ pub fn init(allocator: Allocator, tag: File.Tag, target: std.Target) Dwarf { |
| 117 | 179 | pub fn deinit(self: *Dwarf) void { |
| 118 | 180 | const gpa = self.allocator; |
| 119 | 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 | 183 | self.strtab.deinit(gpa); |
| 122 | } | |
| 184 | self.global_abbrev_relocs.deinit(gpa); | |
| 123 | 185 | |
| 124 | pub const DeclDebugBuffers = struct { | |
| 125 | dbg_line_buffer: std.ArrayList(u8), | |
| 126 | dbg_info_buffer: std.ArrayList(u8), | |
| 127 | dbg_info_type_relocs: File.DbgInfoTypeRelocsTable, | |
| 128 | }; | |
| 186 | for (self.managed_atoms.items) |atom| { | |
| 187 | gpa.destroy(atom); | |
| 188 | } | |
| 189 | self.managed_atoms.deinit(gpa); | |
| 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 | 195 | const tracy = trace(@src()); |
| 132 | 196 | defer tracy.end(); |
| 133 | 197 | |
| 134 | 198 | const decl_name = try decl.getFullyQualifiedName(self.allocator); |
| 135 | 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 | 203 | const gpa = self.allocator; |
| 140 | var dbg_line_buffer = std.ArrayList(u8).init(gpa); | |
| 141 | var dbg_info_buffer = std.ArrayList(u8).init(gpa); | |
| 142 | var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{}; | |
| 204 | assert(self.decl_state == null); | |
| 205 | self.decl_state = DeclState.init(gpa); | |
| 206 | const dbg_line_buffer = &self.decl_state.?.dbg_line; | |
| 207 | const dbg_info_buffer = &self.decl_state.?.dbg_info; | |
| 143 | 208 | |
| 144 | 209 | assert(decl.has_tv); |
| 145 | 210 | |
| ... | ... | @@ -202,19 +267,17 @@ pub fn initDeclDebugInfo(self: *Dwarf, decl: *Module.Decl) !DeclDebugBuffers { |
| 202 | 267 | dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT.low_pc, DW.FORM.addr |
| 203 | 268 | assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); |
| 204 | 269 | dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 |
| 270 | // | |
| 205 | 271 | if (fn_ret_has_bits) { |
| 206 | const gop = try dbg_info_type_relocs.getOrPutContext(gpa, fn_ret_type, .{ | |
| 207 | .target = self.target, | |
| 208 | }); | |
| 209 | if (!gop.found_existing) { | |
| 210 | gop.value_ptr.* = .{ | |
| 211 | .off = undefined, | |
| 212 | .relocs = .{}, | |
| 213 | }; | |
| 214 | } | |
| 215 | try gop.value_ptr.relocs.append(gpa, @intCast(u32, dbg_info_buffer.items.len)); | |
| 272 | const atom = switch (self.tag) { | |
| 273 | .elf => &decl.link.elf.dbg_info_atom, | |
| 274 | .macho => &decl.link.macho.dbg_info_atom, | |
| 275 | else => unreachable, | |
| 276 | }; | |
| 277 | try self.addTypeReloc(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len), null); | |
| 216 | 278 | dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 |
| 217 | 279 | } |
| 280 | ||
| 218 | 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 | 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 | 291 | self: *Dwarf, |
| 235 | 292 | file: *File, |
| 236 | 293 | module: *Module, |
| 237 | 294 | decl: *Module.Decl, |
| 238 | 295 | sym_addr: u64, |
| 239 | 296 | sym_size: u64, |
| 240 | debug_buffers: *DeclDebugBuffers, | |
| 241 | 297 | ) !void { |
| 242 | 298 | const tracy = trace(@src()); |
| 243 | 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 | 307 | const gpa = self.allocator; |
| 246 | var dbg_line_buffer = &debug_buffers.dbg_line_buffer; | |
| 247 | var dbg_info_buffer = &debug_buffers.dbg_info_buffer; | |
| 248 | var dbg_info_type_relocs = &debug_buffers.dbg_info_type_relocs; | |
| 308 | var dbg_line_buffer = &self.decl_state.?.dbg_line; | |
| 309 | var dbg_info_buffer = &self.decl_state.?.dbg_info; | |
| 249 | 310 | |
| 250 | 311 | const target_endian = self.target.cpu.arch.endian(); |
| 251 | 312 | |
| ... | ... | @@ -443,68 +504,65 @@ pub fn commitDeclDebugInfo( |
| 443 | 504 | if (dbg_info_buffer.items.len == 0) |
| 444 | 505 | return; |
| 445 | 506 | |
| 446 | // We need this for the duration of this function only so that for composite | |
| 447 | // types such as []const u32, if the type *u32 is non-existent, we create | |
| 448 | // it synthetically and store the backing bytes in this arena. After we are | |
| 449 | // done with the relocations, we can safely deinit the entire memory slab. | |
| 450 | // TODO currently, we do not store the relocations for future use, however, | |
| 451 | // if that is the case, we should move memory management to a higher scope, | |
| 452 | // such as linker scope, or whatnot. | |
| 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(); | |
| 507 | const atom = switch (self.tag) { | |
| 508 | .elf => &decl.link.elf.dbg_info_atom, | |
| 509 | .macho => &decl.link.macho.dbg_info_atom, | |
| 510 | else => unreachable, | |
| 511 | }; | |
| 512 | const decl_state = &self.decl_state.?; | |
| 513 | ||
| 458 | 514 | { |
| 459 | 515 | // Now we emit the .debug_info types of the Decl. These will count towards the size of |
| 460 | 516 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual |
| 461 | 517 | // relocations yet. |
| 462 | var it: usize = 0; | |
| 463 | while (it < dbg_info_type_relocs.count()) : (it += 1) { | |
| 464 | const ty = dbg_info_type_relocs.keys()[it]; | |
| 465 | const value_ptr = dbg_info_type_relocs.getPtrContext(ty, .{ | |
| 466 | .target = self.target, | |
| 467 | }).?; | |
| 468 | value_ptr.off = @intCast(u32, dbg_info_buffer.items.len); | |
| 469 | try self.addDbgInfoType( | |
| 470 | dbg_type_arena.allocator(), | |
| 471 | ty, | |
| 472 | dbg_info_buffer, | |
| 473 | dbg_info_type_relocs, | |
| 474 | &nested_ref4_relocs, | |
| 475 | ); | |
| 518 | var sym_index: usize = 0; | |
| 519 | while (sym_index < decl_state.abbrev_table.items.len) : (sym_index += 1) { | |
| 520 | const symbol = &decl_state.abbrev_table.items[sym_index]; | |
| 521 | const ty = symbol.@"type"; | |
| 522 | const deferred: bool = blk: { | |
| 523 | if (ty.isAnyError()) break :blk true; | |
| 524 | switch (ty.tag()) { | |
| 525 | .error_set_inferred => { | |
| 526 | if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; | |
| 527 | }, | |
| 528 | else => {}, | |
| 529 | } | |
| 530 | break :blk false; | |
| 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 | 539 | try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len)); |
| 485 | 540 | |
| 486 | { | |
| 487 | // Now that we have the offset assigned we can finally perform type relocations. | |
| 488 | for (dbg_info_type_relocs.values()) |value| { | |
| 489 | for (value.relocs.items) |off| { | |
| 490 | mem.writeInt( | |
| 491 | u32, | |
| 492 | dbg_info_buffer.items[off..][0..4], | |
| 493 | atom.off + value.off, | |
| 494 | target_endian, | |
| 495 | ); | |
| 541 | while (decl_state.abbrev_relocs.popOrNull()) |reloc| { | |
| 542 | const symbol = decl_state.abbrev_table.items[reloc.target]; | |
| 543 | const ty = symbol.@"type"; | |
| 544 | const deferred: bool = blk: { | |
| 545 | if (ty.isAnyError()) break :blk true; | |
| 546 | switch (ty.tag()) { | |
| 547 | .error_set_inferred => { | |
| 548 | if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; | |
| 549 | }, | |
| 550 | else => {}, | |
| 496 | 551 | } |
| 497 | } | |
| 498 | // Offsets to positions with known a priori relative displacement values. | |
| 499 | // Here, we just need to add the offset of the atom to the read value in the | |
| 500 | // relocated cell. | |
| 501 | // TODO Should probably generalise this with type relocs. | |
| 502 | for (nested_ref4_relocs.items) |off| { | |
| 503 | const addend = mem.readInt(u32, dbg_info_buffer.items[off..][0..4], target_endian); | |
| 552 | break :blk false; | |
| 553 | }; | |
| 554 | if (deferred) { | |
| 555 | try self.global_abbrev_relocs.append(gpa, .{ | |
| 556 | .target = undefined, | |
| 557 | .offset = reloc.offset, | |
| 558 | .atom = reloc.atom, | |
| 559 | .addend = reloc.addend, | |
| 560 | }); | |
| 561 | } else { | |
| 504 | 562 | mem.writeInt( |
| 505 | 563 | u32, |
| 506 | dbg_info_buffer.items[off..][0..4], | |
| 507 | atom.off + addend, | |
| 564 | dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], | |
| 565 | symbol.atom.off + symbol.offset + reloc.addend, | |
| 508 | 566 | target_endian, |
| 509 | 567 | ); |
| 510 | 568 | } |
| ... | ... | @@ -513,7 +571,7 @@ pub fn commitDeclDebugInfo( |
| 513 | 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 | 575 | const tracy = trace(@src()); |
| 518 | 576 | defer tracy.end(); |
| 519 | 577 | |
| ... | ... | @@ -523,14 +581,14 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom |
| 523 | 581 | const gpa = self.allocator; |
| 524 | 582 | |
| 525 | 583 | atom.len = len; |
| 526 | if (self.dbg_info_decl_last) |last| blk: { | |
| 584 | if (self.atom_last) |last| blk: { | |
| 527 | 585 | if (atom == last) break :blk; |
| 528 | 586 | if (atom.next) |next| { |
| 529 | 587 | // Update existing Decl - non-last item. |
| 530 | 588 | if (atom.off + atom.len + min_nop_size > next.off) { |
| 531 | 589 | // It grew too big, so we move it to a new location. |
| 532 | 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 | 592 | prev.next = atom.next; |
| 535 | 593 | } |
| 536 | 594 | next.prev = atom.prev; |
| ... | ... | @@ -556,7 +614,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom |
| 556 | 614 | // TODO Look at the free list before appending at the end. |
| 557 | 615 | atom.prev = last; |
| 558 | 616 | last.next = atom; |
| 559 | self.dbg_info_decl_last = atom; | |
| 617 | self.atom_last = atom; | |
| 560 | 618 | |
| 561 | 619 | atom.off = last.off + padToIdeal(last.len); |
| 562 | 620 | } |
| ... | ... | @@ -565,20 +623,20 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *DebugInfoAtom |
| 565 | 623 | // TODO Look at the free list before appending at the end. |
| 566 | 624 | atom.prev = last; |
| 567 | 625 | last.next = atom; |
| 568 | self.dbg_info_decl_last = atom; | |
| 626 | self.atom_last = atom; | |
| 569 | 627 | |
| 570 | 628 | atom.off = last.off + padToIdeal(last.len); |
| 571 | 629 | } |
| 572 | 630 | } else { |
| 573 | 631 | // This is the first Decl of the .debug_info |
| 574 | self.dbg_info_decl_first = atom; | |
| 575 | self.dbg_info_decl_last = atom; | |
| 632 | self.atom_first = atom; | |
| 633 | self.atom_last = atom; | |
| 576 | 634 | |
| 577 | 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 | 640 | const tracy = trace(@src()); |
| 583 | 641 | defer tracy.end(); |
| 584 | 642 | |
| ... | ... | @@ -587,7 +645,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *DebugInfoAtom, dbg_info_ |
| 587 | 645 | // probably need to edit that logic too. |
| 588 | 646 | const gpa = self.allocator; |
| 589 | 647 | |
| 590 | const last_decl = self.dbg_info_decl_last.?; | |
| 648 | const last_decl = self.atom_last.?; | |
| 591 | 649 | // +1 for a trailing zero to end the children of the decl tag. |
| 592 | 650 | const needed_size = last_decl.off + last_decl.len + 1; |
| 593 | 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 | 770 | } |
| 713 | 771 | } |
| 714 | 772 | |
| 715 | pub fn freeAtom(self: *Dwarf, atom: *DebugInfoAtom) void { | |
| 716 | if (self.dbg_info_decl_first == atom) { | |
| 717 | self.dbg_info_decl_first = atom.next; | |
| 773 | pub fn freeAtom(self: *Dwarf, atom: *Atom) void { | |
| 774 | if (self.atom_first == atom) { | |
| 775 | self.atom_first = atom.next; | |
| 718 | 776 | } |
| 719 | if (self.dbg_info_decl_last == atom) { | |
| 777 | if (self.atom_last == atom) { | |
| 720 | 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 | 782 | if (atom.prev) |prev| { |
| ... | ... | @@ -771,14 +829,13 @@ pub fn freeDecl(self: *Dwarf, decl: *Module.Decl) void { |
| 771 | 829 | fn addDbgInfoType( |
| 772 | 830 | self: *Dwarf, |
| 773 | 831 | arena: Allocator, |
| 832 | module: *Module, | |
| 833 | atom: *Atom, | |
| 774 | 834 | ty: Type, |
| 775 | 835 | dbg_info_buffer: *std.ArrayList(u8), |
| 776 | dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable, | |
| 777 | nested_ref4_relocs: *std.ArrayList(u32), | |
| 778 | 836 | ) error{OutOfMemory}!void { |
| 779 | 837 | const target = self.target; |
| 780 | 838 | const target_endian = self.target.cpu.arch.endian(); |
| 781 | var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena); | |
| 782 | 839 | |
| 783 | 840 | switch (ty.zigTypeTag()) { |
| 784 | 841 | .NoReturn => unreachable, |
| ... | ... | @@ -837,7 +894,7 @@ fn addDbgInfoType( |
| 837 | 894 | // DW.AT.type, DW.FORM.ref4 |
| 838 | 895 | var index = dbg_info_buffer.items.len; |
| 839 | 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 | 898 | // DW.AT.data_member_location, DW.FORM.sdata |
| 842 | 899 | try dbg_info_buffer.ensureUnusedCapacity(6); |
| 843 | 900 | dbg_info_buffer.appendAssumeCapacity(0); |
| ... | ... | @@ -849,7 +906,7 @@ fn addDbgInfoType( |
| 849 | 906 | // DW.AT.type, DW.FORM.ref4 |
| 850 | 907 | index = dbg_info_buffer.items.len; |
| 851 | 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 | 910 | // DW.AT.data_member_location, DW.FORM.sdata |
| 854 | 911 | const offset = abi_size - payload_ty.abiSize(target); |
| 855 | 912 | try leb128.writeULEB128(dbg_info_buffer.writer(), offset); |
| ... | ... | @@ -878,7 +935,7 @@ fn addDbgInfoType( |
| 878 | 935 | try dbg_info_buffer.resize(index + 4); |
| 879 | 936 | var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); |
| 880 | 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 | 939 | // DW.AT.data_member_location, DW.FORM.sdata |
| 883 | 940 | try dbg_info_buffer.ensureUnusedCapacity(6); |
| 884 | 941 | dbg_info_buffer.appendAssumeCapacity(0); |
| ... | ... | @@ -890,7 +947,7 @@ fn addDbgInfoType( |
| 890 | 947 | // DW.AT.type, DW.FORM.ref4 |
| 891 | 948 | index = dbg_info_buffer.items.len; |
| 892 | 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 | 951 | // DW.AT.data_member_location, DW.FORM.sdata |
| 895 | 952 | try dbg_info_buffer.ensureUnusedCapacity(2); |
| 896 | 953 | dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize)); |
| ... | ... | @@ -902,7 +959,7 @@ fn addDbgInfoType( |
| 902 | 959 | // DW.AT.type, DW.FORM.ref4 |
| 903 | 960 | const index = dbg_info_buffer.items.len; |
| 904 | 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 | 965 | .Struct => blk: { |
| ... | ... | @@ -926,7 +983,7 @@ fn addDbgInfoType( |
| 926 | 983 | // DW.AT.type, DW.FORM.ref4 |
| 927 | 984 | var index = dbg_info_buffer.items.len; |
| 928 | 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 | 987 | // DW.AT.data_member_location, DW.FORM.sdata |
| 931 | 988 | const field_off = ty.structFieldOffset(field_index, target); |
| 932 | 989 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| ... | ... | @@ -957,7 +1014,7 @@ fn addDbgInfoType( |
| 957 | 1014 | // DW.AT.type, DW.FORM.ref4 |
| 958 | 1015 | var index = dbg_info_buffer.items.len; |
| 959 | 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 | 1018 | // DW.AT.data_member_location, DW.FORM.sdata |
| 962 | 1019 | const field_off = ty.structFieldOffset(field_index, target); |
| 963 | 1020 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| ... | ... | @@ -1036,14 +1093,8 @@ fn addDbgInfoType( |
| 1036 | 1093 | dbg_info_buffer.appendAssumeCapacity(0); |
| 1037 | 1094 | // DW.AT.type, DW.FORM.ref4 |
| 1038 | 1095 | const inner_union_index = dbg_info_buffer.items.len; |
| 1039 | try dbg_info_buffer.ensureUnusedCapacity(4); | |
| 1040 | mem.writeInt( | |
| 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)); | |
| 1096 | try dbg_info_buffer.resize(inner_union_index + 4); | |
| 1097 | try self.addTypeReloc(atom, ty, @intCast(u32, inner_union_index), 5); | |
| 1047 | 1098 | // DW.AT.data_member_location, DW.FORM.sdata |
| 1048 | 1099 | try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset); |
| 1049 | 1100 | } |
| ... | ... | @@ -1070,7 +1121,7 @@ fn addDbgInfoType( |
| 1070 | 1121 | // DW.AT.type, DW.FORM.ref4 |
| 1071 | 1122 | const index = dbg_info_buffer.items.len; |
| 1072 | 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 | 1125 | // DW.AT.data_member_location, DW.FORM.sdata |
| 1075 | 1126 | try dbg_info_buffer.append(0); |
| 1076 | 1127 | } |
| ... | ... | @@ -1087,7 +1138,7 @@ fn addDbgInfoType( |
| 1087 | 1138 | // DW.AT.type, DW.FORM.ref4 |
| 1088 | 1139 | const index = dbg_info_buffer.items.len; |
| 1089 | 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 | 1142 | // DW.AT.data_member_location, DW.FORM.sdata |
| 1092 | 1143 | try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset); |
| 1093 | 1144 | |
| ... | ... | @@ -1095,24 +1146,91 @@ fn addDbgInfoType( |
| 1095 | 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 | 1229 | else => { |
| 1099 | 1230 | log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()}); |
| 1100 | 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 | 1236 | pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { |
| ... | ... | @@ -1763,12 +1881,12 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { |
| 1763 | 1881 | } |
| 1764 | 1882 | |
| 1765 | 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 | 1885 | return first.off; |
| 1768 | 1886 | } |
| 1769 | 1887 | |
| 1770 | 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 | 1890 | return last.off + last.len; |
| 1773 | 1891 | } |
| 1774 | 1892 | |
| ... | ... | @@ -1833,3 +1951,115 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 1833 | 1951 | return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch |
| 1834 | 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 | 207 | prev: ?*TextBlock, |
| 208 | 208 | next: ?*TextBlock, |
| 209 | 209 | |
| 210 | dbg_info_atom: Dwarf.DebugInfoAtom, | |
| 210 | dbg_info_atom: Dwarf.Atom, | |
| 211 | 211 | |
| 212 | 212 | pub const empty = TextBlock{ |
| 213 | 213 | .local_sym_index = 0, |
| ... | ... | @@ -958,6 +958,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { |
| 958 | 958 | const target_endian = self.base.options.target.cpu.arch.endian(); |
| 959 | 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 | 966 | var it = self.relocs.iterator(); |
| 963 | 967 | while (it.next()) |entry| { |
| ... | ... | @@ -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 | 2235 | fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 { |
| 2239 | 2236 | const ty = decl.ty; |
| 2240 | 2237 | const zig_ty = ty.zigTypeTag(); |
| ... | ... | @@ -2342,26 +2339,13 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven |
| 2342 | 2339 | const decl = func.owner_decl; |
| 2343 | 2340 | self.freeUnnamedConsts(decl); |
| 2344 | 2341 | |
| 2345 | var debug_buffers_buf: Dwarf.DeclDebugBuffers = undefined; | |
| 2346 | const debug_buffers = if (self.dwarf) |*dw| blk: { | |
| 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 | } | |
| 2342 | if (self.dwarf) |*dw| { | |
| 2343 | try dw.initDeclState(decl); | |
| 2356 | 2344 | } |
| 2357 | 2345 | |
| 2358 | const res = if (debug_buffers) |dbg| | |
| 2346 | const res = if (self.dwarf) |*dw| | |
| 2359 | 2347 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ |
| 2360 | .dwarf = .{ | |
| 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 | }, | |
| 2348 | .dwarf = dw, | |
| 2365 | 2349 | }) |
| 2366 | 2350 | else |
| 2367 | 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 | 2359 | }, |
| 2376 | 2360 | }; |
| 2377 | 2361 | const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC); |
| 2378 | if (debug_buffers) |dbg| { | |
| 2379 | try self.dwarf.?.commitDeclDebugInfo(&self.base, module, decl, local_sym.st_value, local_sym.st_size, dbg); | |
| 2362 | if (self.dwarf) |*dw| { | |
| 2363 | try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size); | |
| 2380 | 2364 | } |
| 2381 | 2365 | |
| 2382 | 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 | 2394 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2411 | 2395 | defer code_buffer.deinit(); |
| 2412 | 2396 | |
| 2413 | var debug_buffers_buf: Dwarf.DeclDebugBuffers = undefined; | |
| 2414 | const debug_buffers = if (self.dwarf) |*dw| blk: { | |
| 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 | } | |
| 2397 | if (self.dwarf) |*dw| { | |
| 2398 | try dw.initDeclState(decl); | |
| 2424 | 2399 | } |
| 2425 | 2400 | |
| 2426 | 2401 | // TODO implement .debug_info for global variables |
| 2427 | 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 | 2404 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 2430 | 2405 | .ty = decl.ty, |
| 2431 | 2406 | .val = decl_val, |
| 2432 | 2407 | }, &code_buffer, .{ |
| 2433 | .dwarf = .{ | |
| 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 | }, | |
| 2408 | .dwarf = dw, | |
| 2438 | 2409 | }, .{ |
| 2439 | 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 | 2428 | }; |
| 2458 | 2429 | |
| 2459 | 2430 | const local_sym = try self.updateDeclCode(decl, code, elf.STT_OBJECT); |
| 2460 | if (debug_buffers) |dbg| { | |
| 2461 | try self.dwarf.?.commitDeclDebugInfo(&self.base, module, decl, local_sym.st_value, local_sym.st_size, dbg); | |
| 2431 | if (self.dwarf) |*dw| { | |
| 2432 | try dw.commitDeclState(&self.base, module, decl, local_sym.st_value, local_sym.st_size); | |
| 2462 | 2433 | } |
| 2463 | 2434 | |
| 2464 | 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 | 453 | const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. |
| 454 | 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 | 462 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| 457 | 463 | // will not be part of the linker line anyway. |
| 458 | 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 | 3676 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 3671 | 3677 | defer code_buffer.deinit(); |
| 3672 | 3678 | |
| 3673 | var debug_buffers_buf: link.File.Dwarf.DeclDebugBuffers = undefined; | |
| 3674 | const debug_buffers = if (self.d_sym) |*d_sym| blk: { | |
| 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 | } | |
| 3679 | if (self.d_sym) |*d_sym| { | |
| 3680 | try d_sym.dwarf.initDeclState(decl); | |
| 3687 | 3681 | } |
| 3688 | 3682 | |
| 3689 | const res = if (debug_buffers) |dbg| | |
| 3683 | const res = if (self.d_sym) |*d_sym| | |
| 3690 | 3684 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ |
| 3691 | .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 | }, | |
| 3685 | .dwarf = &d_sym.dwarf, | |
| 3696 | 3686 | }) |
| 3697 | 3687 | else |
| 3698 | 3688 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); |
| 3689 | ||
| 3699 | 3690 | switch (res) { |
| 3700 | 3691 | .appended => { |
| 3701 | 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 | 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| { | |
| 3713 | if (self.d_sym) |*d_sym| { | |
| 3714 | try d_sym.commitDeclDebugInfo(module, decl, db); | |
| 3715 | } | |
| 3703 | if (self.d_sym) |*d_sym| { | |
| 3704 | try d_sym.dwarf.commitDeclState(&self.base, module, decl, symbol.n_value, decl.link.macho.size); | |
| 3716 | 3705 | } |
| 3717 | 3706 | |
| 3718 | 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 | 3801 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 3813 | 3802 | defer code_buffer.deinit(); |
| 3814 | 3803 | |
| 3815 | var debug_buffers_buf: link.File.Dwarf.DeclDebugBuffers = undefined; | |
| 3816 | const debug_buffers = if (self.d_sym) |*d_sym| blk: { | |
| 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 | } | |
| 3804 | if (self.d_sym) |*d_sym| { | |
| 3805 | try d_sym.dwarf.initDeclState(decl); | |
| 3829 | 3806 | } |
| 3830 | 3807 | |
| 3831 | 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 | 3810 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 3834 | 3811 | .ty = decl.ty, |
| 3835 | 3812 | .val = decl_val, |
| 3836 | 3813 | }, &code_buffer, .{ |
| 3837 | .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 | }, | |
| 3814 | .dwarf = &d_sym.dwarf, | |
| 3842 | 3815 | }, .{ |
| 3843 | 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 | 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 | 3852 | // Since we updated the vaddr and the size, each corresponding export symbol also |
| 3876 | 3853 | // needs to be updated. |
| ... | ... | @@ -4084,8 +4061,9 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 4084 | 4061 | } |
| 4085 | 4062 | |
| 4086 | 4063 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void { |
| 4064 | _ = module; | |
| 4087 | 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 | 72 | next: ?*Atom, |
| 73 | 73 | prev: ?*Atom, |
| 74 | 74 | |
| 75 | dbg_info_atom: Dwarf.DebugInfoAtom, | |
| 75 | dbg_info_atom: Dwarf.Atom, | |
| 76 | 76 | |
| 77 | 77 | dirty: bool = true, |
| 78 | 78 |
src/link/MachO/DebugSymbols.zig-22| ... | ... | @@ -645,25 +645,3 @@ fn writeStringTable(self: *DebugSymbols) !void { |
| 645 | 645 | |
| 646 | 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 | } |