From f2f1bb7cb675fc14dc7754f06329b5780091baaf Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 11 Aug 2022 10:13:16 +0200 Subject: [PATCH 1/2] macho: update __DWARF sections before and after writing out __LINKEDIT --- src/link/Dwarf.zig | 2 +- src/link/MachO/DebugSymbols.zig | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 2cd00f5a87..73891a81f5 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1259,7 +1259,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co debug_info_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff; } debug_info_sect.size = needed_size; - d_sym.debug_line_header_dirty = true; + d_sym.debug_info_header_dirty = true; } const file_pos = debug_info_sect.offset + atom.off; try pwriteDbgInfoNops( diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 3bfe334302..c2aa562db5 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -63,17 +63,16 @@ pub const Reloc = struct { pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void { if (self.linkedit_segment_cmd_index == null) { self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len); - log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{ - self.base.page_size, - self.base.page_size * 2, - }); + const fileoff = @intCast(u64, self.base.page_size); + const needed_size = @intCast(u64, self.base.page_size) * 2; + log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{ fileoff, needed_size }); // TODO this needs reworking try self.segments.append(allocator, .{ .segname = makeStaticString("__LINKEDIT"), - .vmaddr = self.base.page_size, - .vmsize = self.base.page_size, - .fileoff = self.base.page_size, - .filesize = self.base.page_size, + .vmaddr = fileoff, + .vmsize = needed_size, + .fileoff = fileoff, + .filesize = needed_size, .maxprot = macho.PROT.READ, .initprot = macho.PROT.READ, .cmdsize = @sizeOf(macho.segment_command_64), @@ -284,6 +283,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti const lc_writer = lc_buffer.writer(); var ncmds: u32 = 0; + self.updateDwarfSegment(); try self.writeLinkeditSegmentData(&ncmds, lc_writer); self.updateDwarfSegment(); From aeaffd42f6d1c8fc92fa7669a579a8e6c46eb641 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 12 Aug 2022 11:55:38 +0200 Subject: [PATCH 2/2] x86: fix generating debug info for variables Add handling for these additional `MCValue`s: * `.immediate` - lower to `DW.OP.consts` or `DW.OP.constu` depending on signedness followed by popping off the DWARF stack with `DW.OP.stack_value` * `.undef` - lower to `DW.OP.implicit_value` * `.none` - lower to `DW.OP.lit0` followed by popping off the DWARF stack with `DW.OP.stack_value` For any remaining unhandled case, we generate `DW.OP.nop` in order not to mess up remaining DWARF info. --- src/arch/x86_64/CodeGen.zig | 48 ++++++++++++++++++++++++++++++++++++- src/link/Dwarf.zig | 11 +++++---- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 7f7473bc66..e58163875c 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -4370,6 +4370,7 @@ fn genVarDbgInfo( .dwarf => |dw| { const dbg_info = &dw.dbg_info; try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); + const endian = self.target.cpu.arch.endian(); switch (mcv) { .register => |reg| { @@ -4390,7 +4391,6 @@ fn genVarDbgInfo( dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); }, .memory, .got_load, .direct_load => { - const endian = self.target.cpu.arch.endian(); const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)); const is_ptr = switch (tag) { .dbg_var_ptr => true, @@ -4425,7 +4425,53 @@ fn genVarDbgInfo( else => {}, } }, + .immediate => |x| { + const signedness: std.builtin.Signedness = blk: { + if (ty.zigTypeTag() != .Int) break :blk .unsigned; + break :blk ty.intInfo(self.target.*).signedness; + }; + try dbg_info.ensureUnusedCapacity(2); + const fixup = dbg_info.items.len; + dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc + 1, + switch (signedness) { + .signed => DW.OP.consts, + .unsigned => DW.OP.constu, + }, + }); + switch (signedness) { + .signed => try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)), + .unsigned => try leb128.writeULEB128(dbg_info.writer(), x), + } + try dbg_info.append(DW.OP.stack_value); + dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); + }, + .undef => { + // DW.AT.location, DW.FORM.exprloc + // uleb128(exprloc_len) + // DW.OP.implicit_value uleb128(len_of_bytes) bytes + const abi_size = @intCast(u32, ty.abiSize(self.target.*)); + var implicit_value_len = std.ArrayList(u8).init(self.gpa); + defer implicit_value_len.deinit(); + try leb128.writeULEB128(implicit_value_len.writer(), abi_size); + const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size; + try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len); + try dbg_info.ensureUnusedCapacity(total_exprloc_len); + dbg_info.appendAssumeCapacity(DW.OP.implicit_value); + dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); + dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); + }, + .none => { + try dbg_info.ensureUnusedCapacity(3); + dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc + 2, DW.OP.lit0, DW.OP.stack_value, + }); + }, else => { + try dbg_info.ensureUnusedCapacity(2); + dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc + 1, DW.OP.nop, + }); log.debug("TODO generate debug info for {}", .{mcv}); }, } diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 73891a81f5..3ae151491f 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -102,7 +102,7 @@ pub const DeclState = struct { } pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void { - log.debug("{x}: target sym @{d}, via GOT {}", .{ offset, target, is_ptr }); + log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr }); try self.exprloc_relocs.append(self.gpa, .{ .@"type" = if (is_ptr) .got_load else .direct_load, .target = target, @@ -135,7 +135,7 @@ pub const DeclState = struct { .@"type" = ty, .offset = undefined, }); - log.debug("@{d}: {}", .{ sym_index, ty.fmtDebug() }); + log.debug("%{d}: {}", .{ sym_index, ty.fmtDebug() }); try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{ .mod = self.mod, }); @@ -143,7 +143,7 @@ pub const DeclState = struct { .mod = self.mod, }).?; }; - log.debug("{x}: @{d} + 0", .{ offset, resolv }); + log.debug("{x}: %{d} + 0", .{ offset, resolv }); try self.abbrev_relocs.append(self.gpa, .{ .target = resolv, .atom = atom, @@ -1056,6 +1056,7 @@ pub fn commitDeclState( break :blk false; }; if (deferred) { + log.debug("resolving %{d} deferred until flush", .{target}); try self.global_abbrev_relocs.append(gpa, .{ .target = null, .offset = reloc.offset, @@ -1063,10 +1064,12 @@ pub fn commitDeclState( .addend = reloc.addend, }); } else { + const value = symbol.atom.off + symbol.offset + reloc.addend; + log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() }); mem.writeInt( u32, dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], - symbol.atom.off + symbol.offset + reloc.addend, + value, target_endian, ); }