Commit e05de31a5f

Jakub Konka <kubkon@jakubkonka.com>
2022-06-06 09:44:07
dwarf: fix incorrect type reloc for unions
Split type relocs into two kinds: local and global. Global relocs use a global type resolver and calculate offset to the existing definition of a type abbreviation. Local relocs use offset in the abbrev section of the containing atom plus addend to generate a local relocation.
1 parent 0cab01a
Changed files (6)
src
src/arch/arm/CodeGen.zig
@@ -3187,7 +3187,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
                 .macho => unreachable,
                 else => unreachable,
             };
-            try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
+            try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
         },
         .plan9 => {},
         .none => {},
src/arch/riscv64/CodeGen.zig
@@ -754,7 +754,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
                 .macho => unreachable,
                 else => unreachable,
             };
-            try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
+            try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
         },
         .plan9 => {},
         .none => {},
src/arch/sparc64/CodeGen.zig
@@ -1550,7 +1550,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
                 .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom,
                 else => unreachable,
             };
-            try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
+            try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
         },
         else => {},
     }
src/arch/wasm/CodeGen.zig
@@ -1050,7 +1050,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
             const index = dbg_info.items.len;
             try dbg_info.resize(index + 4);
             const atom = &self.decl.link.wasm.dbg_info_atom;
-            try dwarf.addTypeReloc(atom, ty, @intCast(u32, index), null);
+            try dwarf.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
         },
         .plan9 => unreachable,
         .none => {},
src/arch/x86_64/CodeGen.zig
@@ -4371,7 +4371,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
                 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
                 else => unreachable,
             };
-            try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
+            try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
         },
         .plan9 => {},
         .none => {},
src/link/Dwarf.zig
@@ -110,13 +110,22 @@ pub const DeclState = struct {
         });
     }
 
-    pub fn addTypeReloc(
-        self: *DeclState,
-        atom: *const Atom,
-        ty: Type,
-        offset: u32,
-        addend: ?u32,
-    ) !void {
+    /// Adds local type relocation of the form: @offset => @this + addend
+    /// @this signifies the offset within the .debug_abbrev section of the containing atom.
+    pub fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void {
+        log.debug("{x}: @this + {x}", .{ offset, addend });
+        try self.abbrev_relocs.append(self.gpa, .{
+            .target = null,
+            .atom = atom,
+            .offset = offset,
+            .addend = addend,
+        });
+    }
+
+    /// Adds global type relocation of the form: @offset => @symbol + 0
+    /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section
+    /// which we use as our target of the relocation.
+    pub fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void {
         const resolv = self.abbrev_resolver.getContext(ty, .{
             .mod = self.mod,
         }) orelse blk: {
@@ -134,14 +143,12 @@ pub const DeclState = struct {
                 .mod = self.mod,
             }).?;
         };
-        const add: u32 = addend orelse 0;
-
-        log.debug("{x}: @{d} + {x}", .{ offset, resolv, add });
+        log.debug("{x}: @{d} + 0", .{ offset, resolv });
         try self.abbrev_relocs.append(self.gpa, .{
             .target = resolv,
             .atom = atom,
             .offset = offset,
-            .addend = add,
+            .addend = 0,
         });
     }
 
@@ -213,7 +220,7 @@ pub const DeclState = struct {
                     // DW.AT.type, DW.FORM.ref4
                     var index = dbg_info_buffer.items.len;
                     try dbg_info_buffer.resize(index + 4);
-                    try self.addTypeReloc(atom, Type.bool, @intCast(u32, index), null);
+                    try self.addTypeRelocGlobal(atom, Type.bool, @intCast(u32, index));
                     // DW.AT.data_member_location, DW.FORM.sdata
                     try dbg_info_buffer.ensureUnusedCapacity(6);
                     dbg_info_buffer.appendAssumeCapacity(0);
@@ -225,7 +232,7 @@ pub const DeclState = struct {
                     // DW.AT.type, DW.FORM.ref4
                     index = dbg_info_buffer.items.len;
                     try dbg_info_buffer.resize(index + 4);
-                    try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null);
+                    try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index));
                     // DW.AT.data_member_location, DW.FORM.sdata
                     const offset = abi_size - payload_ty.abiSize(target);
                     try leb128.writeULEB128(dbg_info_buffer.writer(), offset);
@@ -254,7 +261,7 @@ pub const DeclState = struct {
                     try dbg_info_buffer.resize(index + 4);
                     var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
                     const ptr_ty = ty.slicePtrFieldType(buf);
-                    try self.addTypeReloc(atom, ptr_ty, @intCast(u32, index), null);
+                    try self.addTypeRelocGlobal(atom, ptr_ty, @intCast(u32, index));
                     // DW.AT.data_member_location, DW.FORM.sdata
                     try dbg_info_buffer.ensureUnusedCapacity(6);
                     dbg_info_buffer.appendAssumeCapacity(0);
@@ -266,7 +273,7 @@ pub const DeclState = struct {
                     // DW.AT.type, DW.FORM.ref4
                     index = dbg_info_buffer.items.len;
                     try dbg_info_buffer.resize(index + 4);
-                    try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null);
+                    try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index));
                     // DW.AT.data_member_location, DW.FORM.sdata
                     try dbg_info_buffer.ensureUnusedCapacity(2);
                     dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize));
@@ -278,7 +285,7 @@ pub const DeclState = struct {
                     // DW.AT.type, DW.FORM.ref4
                     const index = dbg_info_buffer.items.len;
                     try dbg_info_buffer.resize(index + 4);
-                    try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);
+                    try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index));
                 }
             },
             .Array => {
@@ -289,13 +296,13 @@ pub const DeclState = struct {
                 // DW.AT.type, DW.FORM.ref4
                 var index = dbg_info_buffer.items.len;
                 try dbg_info_buffer.resize(index + 4);
-                try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);
+                try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index));
                 // DW.AT.subrange_type
                 try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim));
                 // DW.AT.type, DW.FORM.ref4
                 index = dbg_info_buffer.items.len;
                 try dbg_info_buffer.resize(index + 4);
-                try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null);
+                try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index));
                 // DW.AT.count, DW.FORM.udata
                 const len = ty.arrayLenIncludingSentinel();
                 try leb128.writeULEB128(dbg_info_buffer.writer(), len);
@@ -323,7 +330,7 @@ pub const DeclState = struct {
                             // DW.AT.type, DW.FORM.ref4
                             var index = dbg_info_buffer.items.len;
                             try dbg_info_buffer.resize(index + 4);
-                            try self.addTypeReloc(atom, field, @intCast(u32, index), null);
+                            try self.addTypeRelocGlobal(atom, field, @intCast(u32, index));
                             // DW.AT.data_member_location, DW.FORM.sdata
                             const field_off = ty.structFieldOffset(field_index, target);
                             try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
@@ -354,7 +361,7 @@ pub const DeclState = struct {
                             // DW.AT.type, DW.FORM.ref4
                             var index = dbg_info_buffer.items.len;
                             try dbg_info_buffer.resize(index + 4);
-                            try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null);
+                            try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index));
                             // DW.AT.data_member_location, DW.FORM.sdata
                             const field_off = ty.structFieldOffset(field_index, target);
                             try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
@@ -434,7 +441,7 @@ pub const DeclState = struct {
                     // DW.AT.type, DW.FORM.ref4
                     const inner_union_index = dbg_info_buffer.items.len;
                     try dbg_info_buffer.resize(inner_union_index + 4);
-                    try self.addTypeReloc(atom, ty, @intCast(u32, inner_union_index), 5);
+                    try self.addTypeRelocLocal(atom, @intCast(u32, inner_union_index), 5);
                     // DW.AT.data_member_location, DW.FORM.sdata
                     try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
                 }
@@ -461,7 +468,7 @@ pub const DeclState = struct {
                     // DW.AT.type, DW.FORM.ref4
                     const index = dbg_info_buffer.items.len;
                     try dbg_info_buffer.resize(index + 4);
-                    try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null);
+                    try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index));
                     // DW.AT.data_member_location, DW.FORM.sdata
                     try dbg_info_buffer.append(0);
                 }
@@ -478,7 +485,7 @@ pub const DeclState = struct {
                     // DW.AT.type, DW.FORM.ref4
                     const index = dbg_info_buffer.items.len;
                     try dbg_info_buffer.resize(index + 4);
-                    try self.addTypeReloc(atom, union_obj.tag_ty, @intCast(u32, index), null);
+                    try self.addTypeRelocGlobal(atom, union_obj.tag_ty, @intCast(u32, index));
                     // DW.AT.data_member_location, DW.FORM.sdata
                     try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
 
@@ -521,7 +528,7 @@ pub const DeclState = struct {
                 // DW.AT.type, DW.FORM.ref4
                 var index = dbg_info_buffer.items.len;
                 try dbg_info_buffer.resize(index + 4);
-                try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null);
+                try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index));
                 // DW.AT.data_member_location, DW.FORM.sdata
                 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off);
 
@@ -534,7 +541,7 @@ pub const DeclState = struct {
                 // DW.AT.type, DW.FORM.ref4
                 index = dbg_info_buffer.items.len;
                 try dbg_info_buffer.resize(index + 4);
-                try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null);
+                try self.addTypeRelocGlobal(atom, error_ty, @intCast(u32, index));
                 // DW.AT.data_member_location, DW.FORM.sdata
                 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
 
@@ -556,7 +563,9 @@ pub const AbbrevEntry = struct {
 };
 
 pub const AbbrevRelocation = struct {
-    target: u32,
+    /// If target is null, we deal with a local relocation that is based on simple offset + addend
+    /// only.
+    target: ?u32,
     atom: *const Atom,
     offset: u32,
     addend: u32,
@@ -740,12 +749,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl: *Module.Decl) !DeclState
                     .wasm => &decl.link.wasm.dbg_info_atom,
                     else => unreachable,
                 };
-                try decl_state.addTypeReloc(
-                    atom,
-                    fn_ret_type,
-                    @intCast(u32, dbg_info_buffer.items.len),
-                    null,
-                );
+                try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len));
                 dbg_info_buffer.items.len += 4; // DW.AT.type,  DW.FORM.ref4
             }
 
@@ -1036,30 +1040,39 @@ pub fn commitDeclState(
     try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
 
     while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
-        const symbol = decl_state.abbrev_table.items[reloc.target];
-        const ty = symbol.@"type";
-        const deferred: bool = blk: {
-            if (ty.isAnyError()) break :blk true;
-            switch (ty.tag()) {
-                .error_set_inferred => {
-                    if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true;
-                },
-                else => {},
+        if (reloc.target) |target| {
+            const symbol = decl_state.abbrev_table.items[target];
+            const ty = symbol.@"type";
+            const deferred: bool = blk: {
+                if (ty.isAnyError()) break :blk true;
+                switch (ty.tag()) {
+                    .error_set_inferred => {
+                        if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true;
+                    },
+                    else => {},
+                }
+                break :blk false;
+            };
+            if (deferred) {
+                try self.global_abbrev_relocs.append(gpa, .{
+                    .target = null,
+                    .offset = reloc.offset,
+                    .atom = reloc.atom,
+                    .addend = reloc.addend,
+                });
+            } else {
+                mem.writeInt(
+                    u32,
+                    dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
+                    symbol.atom.off + symbol.offset + reloc.addend,
+                    target_endian,
+                );
             }
-            break :blk false;
-        };
-        if (deferred) {
-            try self.global_abbrev_relocs.append(gpa, .{
-                .target = undefined,
-                .offset = reloc.offset,
-                .atom = reloc.atom,
-                .addend = reloc.addend,
-            });
         } else {
             mem.writeInt(
                 u32,
                 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
-                symbol.atom.off + symbol.offset + reloc.addend,
+                reloc.atom.off + reloc.offset + reloc.addend,
                 target_endian,
             );
         }