diff options
| -rw-r--r-- | src/link/Dwarf.zig | 131 |
1 files changed, 126 insertions, 5 deletions
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 5e1af101de..370aac2734 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -83,8 +83,9 @@ pub const abbrev_struct_type = 6; pub const abbrev_struct_member = 7; pub const abbrev_enum_type = 8; pub const abbrev_enum_variant = 9; -pub const abbrev_pad1 = 10; -pub const abbrev_parameter = 11; +pub const abbrev_union_type = 10; +pub const abbrev_pad1 = 11; +pub const abbrev_parameter = 12; /// The reloc offset for the virtual address of a function in its Line Number Program. /// Size is a virtual address integer. @@ -452,6 +453,8 @@ pub fn commitDeclDebugInfo( var dbg_type_arena = std.heap.ArenaAllocator.init(gpa); defer dbg_type_arena.deinit(); + var nested_ref4_relocs = std.ArrayList(u32).init(gpa); + defer nested_ref4_relocs.deinit(); { // Now we emit the .debug_info types of the Decl. These will count towards the size of // the buffer, so we have to do it before computing the offset, and we can't perform the actual @@ -463,7 +466,13 @@ pub fn commitDeclDebugInfo( .target = self.target, }).?; value_ptr.off = @intCast(u32, dbg_info_buffer.items.len); - try self.addDbgInfoType(dbg_type_arena.allocator(), ty, dbg_info_buffer, dbg_info_type_relocs); + try self.addDbgInfoType( + dbg_type_arena.allocator(), + ty, + dbg_info_buffer, + dbg_info_type_relocs, + &nested_ref4_relocs, + ); } } @@ -478,13 +487,27 @@ pub fn commitDeclDebugInfo( // Now that we have the offset assigned we can finally perform type relocations. for (dbg_info_type_relocs.values()) |value| { for (value.relocs.items) |off| { - mem.writeIntLittle( + mem.writeInt( u32, dbg_info_buffer.items[off..][0..4], atom.off + value.off, + target_endian, ); } } + // Offsets to positions with known a priori relative displacement values. + // Here, we just need to add the offset of the atom to the read value in the + // relocated cell. + // TODO Should probably generalise this with type relocs. + for (nested_ref4_relocs.items) |off| { + const addend = mem.readInt(u32, dbg_info_buffer.items[off..][0..4], target_endian); + mem.writeInt( + u32, + dbg_info_buffer.items[off..][0..4], + atom.off + addend, + target_endian, + ); + } } try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items); @@ -751,8 +774,10 @@ fn addDbgInfoType( ty: Type, dbg_info_buffer: *std.ArrayList(u8), dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable, + nested_ref4_relocs: *std.ArrayList(u32), ) error{OutOfMemory}!void { const target = self.target; + const target_endian = self.target.cpu.arch.endian(); var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena); switch (ty.zigTypeTag()) { @@ -962,7 +987,6 @@ fn addDbgInfoType( .enum_numbered => ty.castTag(.enum_numbered).?.data.values, else => unreachable, }; - const target_endian = self.target.cpu.arch.endian(); for (fields.keys()) |field_name, field_i| { // DW.AT.enumerator try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64)); @@ -983,6 +1007,94 @@ fn addDbgInfoType( // DW.AT.enumeration_type delimit children try dbg_info_buffer.append(0); }, + .Union => { + const layout = ty.unionGetLayout(target); + const union_obj = ty.cast(Type.Payload.Union).?.data; + const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0; + const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size; + const is_tagged = layout.tag_size > 0; + const union_name = try ty.nameAllocArena(arena, target); + + // TODO this is temporary to match current state of unions in Zig - we don't yet have + // safety checks implemented meaning the implicit tag is not yet stored and generated + // for untagged unions. + if (is_tagged) { + // DW.AT.structure_type + try dbg_info_buffer.append(abbrev_struct_type); + // DW.AT.byte_size, DW.FORM.sdata + try leb128.writeULEB128(dbg_info_buffer.writer(), layout.abi_size); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.ensureUnusedCapacity(union_name.len + 1); + dbg_info_buffer.appendSliceAssumeCapacity(union_name); + dbg_info_buffer.appendAssumeCapacity(0); + + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(9); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("payload"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + const inner_union_index = dbg_info_buffer.items.len; + try dbg_info_buffer.ensureUnusedCapacity(4); + mem.writeInt( + u32, + dbg_info_buffer.addManyAsArrayAssumeCapacity(4), + @intCast(u32, inner_union_index + 5), + target_endian, + ); + try nested_ref4_relocs.append(@intCast(u32, inner_union_index)); + // DW.AT.data_member_location, DW.FORM.sdata + try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset); + } + + // DW.AT.union_type + try dbg_info_buffer.append(abbrev_union_type); + // DW.AT.byte_size, DW.FORM.sdata, + try leb128.writeULEB128(dbg_info_buffer.writer(), layout.payload_size); + // DW.AT.name, DW.FORM.string + if (is_tagged) { + try dbg_info_buffer.writer().print("AnonUnion\x00", .{}); + } else { + try dbg_info_buffer.writer().print("{s}\x00", .{union_name}); + } + + const fields = ty.unionFields(); + for (fields.keys()) |field_name| { + const field = fields.get(field_name).?; + if (!field.ty.hasRuntimeBits()) continue; + // DW.AT.member + try dbg_info_buffer.append(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{s}\x00", .{field_name}); + // DW.AT.type, DW.FORM.ref4 + const index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) }); + // DW.AT.data_member_location, DW.FORM.sdata + try dbg_info_buffer.append(0); + } + // DW.AT.union_type delimit children + try dbg_info_buffer.append(0); + + if (is_tagged) { + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(5); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity("tag"); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + const index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try relocs.append(.{ .ty = union_obj.tag_ty, .reloc = @intCast(u32, index) }); + // DW.AT.data_member_location, DW.FORM.sdata + try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset); + + // DW.AT.structure_type delimit children + try dbg_info_buffer.append(0); + } + }, else => { log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()}); try dbg_info_buffer.append(abbrev_pad1); @@ -1089,6 +1201,15 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { DW.FORM.data8, 0, 0, // table sentinel + abbrev_union_type, + DW.TAG.union_type, + DW.CHILDREN.yes, // header + DW.AT.byte_size, + DW.FORM.sdata, + DW.AT.name, + DW.FORM.string, + 0, + 0, // table sentinel abbrev_pad1, DW.TAG.unspecified_type, DW.CHILDREN.no, // header |
