authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-01 15:28:22+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-01 15:28:22+01:00
log00016ab6a0bd31bed77c86074a6666822b8d0f20
treec973ce7b2987a3edf6d63e10fcb0e9110ec7c2b2
parent7d0af639d82bc22b204e20b11f5f6aee1ed1766e

dwarf: extract common logic for generating func var dbg info


3 files changed, 206 insertions(+), 172 deletions(-)

src/arch/aarch64/CodeGen.zig+13-8
...@@ -184,15 +184,8 @@ const DbgInfoReloc = struct {...@@ -184,15 +184,8 @@ const DbgInfoReloc = struct {
184 else => unreachable,184 else => unreachable,
185 }185 }
186 }186 }
187
188 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {187 fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void {
189 const mod = function.bin_file.options.module.?;188 const atom = function.getDbgInfoAtomPtr();
190 const fn_owner_decl = mod.declPtr(function.mod_fn.owner_decl);
191 const atom = switch (function.bin_file.tag) {
192 .elf => &fn_owner_decl.link.elf.dbg_info_atom,
193 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
194 else => unreachable,
195 };
196189
197 switch (function.debug_output) {190 switch (function.debug_output) {
198 .dwarf => |dw| switch (reloc.mcv) {191 .dwarf => |dw| switch (reloc.mcv) {
...@@ -230,6 +223,7 @@ const DbgInfoReloc = struct {...@@ -230,6 +223,7 @@ const DbgInfoReloc = struct {
230 .dbg_var_val => reloc.ty,223 .dbg_var_val => reloc.ty,
231 else => unreachable,224 else => unreachable,
232 };225 };
226 // const atom= function.getDbgInfoAtomPtr();
233227
234 switch (function.debug_output) {228 switch (function.debug_output) {
235 .dwarf => |dw| {229 .dwarf => |dw| {
...@@ -368,6 +362,17 @@ const DbgInfoReloc = struct {...@@ -368,6 +362,17 @@ const DbgInfoReloc = struct {
368 }362 }
369};363};
370364
365fn getDbgInfoAtomPtr(self: Self) *link.File.Dwarf.Atom {
366 const mod = self.bin_file.options.module.?;
367 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
368 const atom = switch (self.bin_file.tag) {
369 .elf => &fn_owner_decl.link.elf.dbg_info_atom,
370 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
371 else => unreachable,
372 };
373 return atom;
374}
375
371const Branch = struct {376const Branch = struct {
372 inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{},377 inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{},
373378
src/arch/x86_64/CodeGen.zig+59-164
...@@ -3818,13 +3818,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -3818,13 +3818,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
3818}3818}
38193819
3820fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {3820fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
3821 const mod = self.bin_file.options.module.?;3821 const atom = self.getDbgInfoAtomPtr();
3822 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
3823 const atom = switch (self.bin_file.tag) {
3824 .elf => &fn_owner_decl.link.elf.dbg_info_atom,
3825 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
3826 else => unreachable,
3827 };
38283822
3829 switch (self.debug_output) {3823 switch (self.debug_output) {
3830 .dwarf => |dw| switch (mcv) {3824 .dwarf => |dw| switch (mcv) {
...@@ -3845,6 +3839,64 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {...@@ -3845,6 +3839,64 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
3845 }3839 }
3846}3840}
38473841
3842fn genVarDbgInfo(
3843 self: Self,
3844 tag: Air.Inst.Tag,
3845 ty: Type,
3846 mcv: MCValue,
3847 name: [:0]const u8,
3848) !void {
3849 const is_ptr = switch (tag) {
3850 .dbg_var_ptr => true,
3851 .dbg_var_val => false,
3852 else => unreachable,
3853 };
3854 const atom = self.getDbgInfoAtomPtr();
3855
3856 switch (self.debug_output) {
3857 .dwarf => |dw| {
3858 const loc: link.File.Dwarf.DeclState.VarArgDbgInfoLoc = switch (mcv) {
3859 .register => |reg| .{
3860 .register = reg.dwarfLocOp(),
3861 },
3862 .ptr_stack_offset,
3863 .stack_offset,
3864 => |off| .{ .stack = .{
3865 .fp_register = Register.rbp.dwarfLocOpDeref(),
3866 .offset = -off,
3867 } },
3868 .memory => |address| .{
3869 .memory = .{
3870 .address = address,
3871 .is_ptr = is_ptr,
3872 },
3873 },
3874 .immediate => |x| .{ .immediate = x },
3875 .undef => .undef,
3876 .none => .none,
3877 else => blk: {
3878 log.debug("TODO generate debug info for {}", .{mcv});
3879 break :blk .nop;
3880 },
3881 };
3882 try dw.genVarDbgInfo(name, ty, atom, loc);
3883 },
3884 .plan9 => {},
3885 .none => {},
3886 }
3887}
3888
3889fn getDbgInfoAtomPtr(self: Self) *link.File.Dwarf.Atom {
3890 const mod = self.bin_file.options.module.?;
3891 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
3892 const atom = switch (self.bin_file.tag) {
3893 .elf => &fn_owner_decl.link.elf.dbg_info_atom,
3894 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
3895 else => unreachable,
3896 };
3897 return atom;
3898}
3899
3848fn airBreakpoint(self: *Self) !void {3900fn airBreakpoint(self: *Self) !void {
3849 _ = try self.addInst(.{3901 _ = try self.addInst(.{
3850 .tag = .interrupt,3902 .tag = .interrupt,
...@@ -4413,163 +4465,6 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {...@@ -4413,163 +4465,6 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
4413 return self.finishAir(inst, .dead, .{ operand, .none, .none });4465 return self.finishAir(inst, .dead, .{ operand, .none, .none });
4414}4466}
44154467
4416fn genVarDbgInfo(
4417 self: Self,
4418 tag: Air.Inst.Tag,
4419 ty: Type,
4420 mcv: MCValue,
4421 name: [:0]const u8,
4422) !void {
4423 const name_with_null = name.ptr[0 .. name.len + 1];
4424 switch (self.debug_output) {
4425 .dwarf => |dw| {
4426 const dbg_info = &dw.dbg_info;
4427 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
4428 const endian = self.target.cpu.arch.endian();
4429
4430 switch (mcv) {
4431 .register => |reg| {
4432 try dbg_info.ensureUnusedCapacity(2);
4433 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4434 1, // ULEB128 dwarf expression length
4435 reg.dwarfLocOp(),
4436 });
4437 },
4438
4439 .ptr_stack_offset,
4440 .stack_offset,
4441 => |off| {
4442 try dbg_info.ensureUnusedCapacity(7);
4443 const fixup = dbg_info.items.len;
4444 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4445 1, // we will backpatch it after we encode the displacement in LEB128
4446 Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer
4447 });
4448 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
4449 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
4450 },
4451
4452 .memory,
4453 .linker_load,
4454 => {
4455 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
4456 const is_ptr = switch (tag) {
4457 .dbg_var_ptr => true,
4458 .dbg_var_val => false,
4459 else => unreachable,
4460 };
4461 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
4462 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4463 1 + ptr_width + @boolToInt(is_ptr),
4464 DW.OP.addr, // literal address
4465 });
4466 const offset = @intCast(u32, dbg_info.items.len);
4467 const addr = switch (mcv) {
4468 .memory => |addr| addr,
4469 else => 0,
4470 };
4471 switch (ptr_width) {
4472 0...4 => {
4473 try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
4474 },
4475 5...8 => {
4476 try dbg_info.writer().writeInt(u64, addr, endian);
4477 },
4478 else => unreachable,
4479 }
4480 if (is_ptr) {
4481 // We need deref the address as we point to the value via GOT entry.
4482 try dbg_info.append(DW.OP.deref);
4483 }
4484 switch (mcv) {
4485 .linker_load => |load_struct| try dw.addExprlocReloc(
4486 load_struct.sym_index,
4487 offset,
4488 is_ptr,
4489 ),
4490 else => {},
4491 }
4492 },
4493
4494 .immediate => |x| {
4495 try dbg_info.ensureUnusedCapacity(2);
4496 const fixup = dbg_info.items.len;
4497 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4498 1,
4499 if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
4500 });
4501 if (ty.isSignedInt()) {
4502 try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
4503 } else {
4504 try leb128.writeULEB128(dbg_info.writer(), x);
4505 }
4506 try dbg_info.append(DW.OP.stack_value);
4507 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
4508 },
4509
4510 .undef => {
4511 // DW.AT.location, DW.FORM.exprloc
4512 // uleb128(exprloc_len)
4513 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
4514 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4515 var implicit_value_len = std.ArrayList(u8).init(self.gpa);
4516 defer implicit_value_len.deinit();
4517 try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
4518 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
4519 try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
4520 try dbg_info.ensureUnusedCapacity(total_exprloc_len);
4521 dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
4522 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
4523 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
4524 },
4525
4526 .none => {
4527 try dbg_info.ensureUnusedCapacity(3);
4528 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
4529 2, DW.OP.lit0, DW.OP.stack_value,
4530 });
4531 },
4532
4533 else => {
4534 try dbg_info.ensureUnusedCapacity(2);
4535 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4536 1, DW.OP.nop,
4537 });
4538 log.debug("TODO generate debug info for {}", .{mcv});
4539 },
4540 }
4541
4542 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
4543 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
4544 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
4545 },
4546 .plan9 => {},
4547 .none => {},
4548 }
4549}
4550
4551/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
4552/// after codegen for this symbol is done.
4553fn addDbgInfoTypeReloc(self: Self, ty: Type) !void {
4554 switch (self.debug_output) {
4555 .dwarf => |dw| {
4556 const dbg_info = &dw.dbg_info;
4557 const index = dbg_info.items.len;
4558 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
4559 const mod = self.bin_file.options.module.?;
4560 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
4561 const atom = switch (self.bin_file.tag) {
4562 .elf => &fn_owner_decl.link.elf.dbg_info_atom,
4563 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
4564 else => unreachable,
4565 };
4566 try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
4567 },
4568 .plan9 => {},
4569 .none => {},
4570 }
4571}
4572
4573fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {4468fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
4574 const abi_size = ty.abiSize(self.target.*);4469 const abi_size = ty.abiSize(self.target.*);
4575 switch (mcv) {4470 switch (mcv) {
src/link/Dwarf.zig+134
...@@ -606,6 +606,140 @@ pub const DeclState = struct {...@@ -606,6 +606,140 @@ pub const DeclState = struct {
606 },606 },
607 }607 }
608 }608 }
609
610 pub const VarArgDbgInfoLoc = union(enum) {
611 register: u8,
612 stack: struct {
613 fp_register: u8,
614 offset: i32,
615 },
616 memory: struct {
617 address: u64,
618 is_ptr: bool,
619 linker_load: ?struct {
620 type: enum { got, direct, import },
621 sym_index: u32,
622 } = null,
623 },
624 immediate: u64,
625 undef,
626 none,
627 nop,
628 };
629
630 pub fn genVarDbgInfo(
631 self: *DeclState,
632 name: [:0]const u8,
633 ty: Type,
634 atom: *Atom,
635 loc: VarArgDbgInfoLoc,
636 ) error{OutOfMemory}!void {
637 const dbg_info = &self.dbg_info;
638 const name_with_null = name.ptr[0 .. name.len + 1];
639 try dbg_info.append(@enumToInt(AbbrevKind.variable));
640 const target = self.mod.getTarget();
641 const endian = target.cpu.arch.endian();
642
643 switch (loc) {
644 .register => |reg| {
645 try dbg_info.ensureUnusedCapacity(2);
646 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
647 1, // ULEB128 dwarf expression length
648 reg,
649 });
650 },
651
652 .stack => |info| {
653 try dbg_info.ensureUnusedCapacity(7);
654 const fixup = dbg_info.items.len;
655 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
656 1, // we will backpatch it after we encode the displacement in LEB128
657 info.fp_register,
658 });
659 leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable;
660 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
661 },
662
663 .memory => |info| {
664 const ptr_width = @intCast(u8, @divExact(target.cpu.arch.ptrBitWidth(), 8));
665 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
666 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
667 1 + ptr_width + @boolToInt(info.is_ptr),
668 DW.OP.addr, // literal address
669 });
670 const offset = @intCast(u32, dbg_info.items.len);
671 switch (ptr_width) {
672 0...4 => {
673 try dbg_info.writer().writeInt(u32, @intCast(u32, info.address), endian);
674 },
675 5...8 => {
676 try dbg_info.writer().writeInt(u64, info.address, endian);
677 },
678 else => unreachable,
679 }
680 if (info.is_ptr) {
681 // We need deref the address as we point to the value via GOT entry.
682 try dbg_info.append(DW.OP.deref);
683 }
684 if (info.linker_load) |load_struct| try self.addExprlocReloc(
685 load_struct.sym_index,
686 offset,
687 info.is_ptr,
688 );
689 },
690
691 .immediate => |x| {
692 try dbg_info.ensureUnusedCapacity(2);
693 const fixup = dbg_info.items.len;
694 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
695 1,
696 if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
697 });
698 if (ty.isSignedInt()) {
699 try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
700 } else {
701 try leb128.writeULEB128(dbg_info.writer(), x);
702 }
703 try dbg_info.append(DW.OP.stack_value);
704 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
705 },
706
707 .undef => {
708 // DW.AT.location, DW.FORM.exprloc
709 // uleb128(exprloc_len)
710 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
711 const abi_size = @intCast(u32, ty.abiSize(target));
712 var implicit_value_len = std.ArrayList(u8).init(self.gpa);
713 defer implicit_value_len.deinit();
714 try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
715 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
716 try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
717 try dbg_info.ensureUnusedCapacity(total_exprloc_len);
718 dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
719 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
720 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
721 },
722
723 .none => {
724 try dbg_info.ensureUnusedCapacity(3);
725 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
726 2, DW.OP.lit0, DW.OP.stack_value,
727 });
728 },
729
730 .nop => {
731 try dbg_info.ensureUnusedCapacity(2);
732 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
733 1, DW.OP.nop,
734 });
735 },
736 }
737
738 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
739 const index = dbg_info.items.len;
740 try self.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
741 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
742 }
609};743};
610744
611pub const AbbrevEntry = struct {745pub const AbbrevEntry = struct {