authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-24 23:01:46+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-25 13:53:40+01:00
log1c33ea2c35e9260babedb116ad527256e0a4ef5e
treecfe1691710a5bfd9baefa02cf622997c195de7f0
parent0d5d353197114c614f8efde4a8c11c61a5f82519

dwarf: add debug info for unions


1 files changed, 126 insertions(+), 5 deletions(-)

src/link/Dwarf.zig+126-5
......@@ -83,8 +83,9 @@ pub const abbrev_struct_type = 6;
8383pub const abbrev_struct_member = 7;
8484pub const abbrev_enum_type = 8;
8585pub const abbrev_enum_variant = 9;
86pub const abbrev_pad1 = 10;
87pub const abbrev_parameter = 11;
86pub const abbrev_union_type = 10;
87pub const abbrev_pad1 = 11;
88pub const abbrev_parameter = 12;
8889
8990/// The reloc offset for the virtual address of a function in its Line Number Program.
9091/// Size is a virtual address integer.
......@@ -452,6 +453,8 @@ pub fn commitDeclDebugInfo(
452453 var dbg_type_arena = std.heap.ArenaAllocator.init(gpa);
453454 defer dbg_type_arena.deinit();
454455
456 var nested_ref4_relocs = std.ArrayList(u32).init(gpa);
457 defer nested_ref4_relocs.deinit();
455458 {
456459 // Now we emit the .debug_info types of the Decl. These will count towards the size of
457460 // 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(
463466 .target = self.target,
464467 }).?;
465468 value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
466 try self.addDbgInfoType(dbg_type_arena.allocator(), ty, dbg_info_buffer, dbg_info_type_relocs);
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 );
467476 }
468477 }
469478
......@@ -478,13 +487,27 @@ pub fn commitDeclDebugInfo(
478487 // Now that we have the offset assigned we can finally perform type relocations.
479488 for (dbg_info_type_relocs.values()) |value| {
480489 for (value.relocs.items) |off| {
481 mem.writeIntLittle(
490 mem.writeInt(
482491 u32,
483492 dbg_info_buffer.items[off..][0..4],
484493 atom.off + value.off,
494 target_endian,
485495 );
486496 }
487497 }
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);
504 mem.writeInt(
505 u32,
506 dbg_info_buffer.items[off..][0..4],
507 atom.off + addend,
508 target_endian,
509 );
510 }
488511 }
489512
490513 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
......@@ -751,8 +774,10 @@ fn addDbgInfoType(
751774 ty: Type,
752775 dbg_info_buffer: *std.ArrayList(u8),
753776 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
777 nested_ref4_relocs: *std.ArrayList(u32),
754778) error{OutOfMemory}!void {
755779 const target = self.target;
780 const target_endian = self.target.cpu.arch.endian();
756781 var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena);
757782
758783 switch (ty.zigTypeTag()) {
......@@ -962,7 +987,6 @@ fn addDbgInfoType(
962987 .enum_numbered => ty.castTag(.enum_numbered).?.data.values,
963988 else => unreachable,
964989 };
965 const target_endian = self.target.cpu.arch.endian();
966990 for (fields.keys()) |field_name, field_i| {
967991 // DW.AT.enumerator
968992 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));
......@@ -983,6 +1007,94 @@ fn addDbgInfoType(
9831007 // DW.AT.enumeration_type delimit children
9841008 try dbg_info_buffer.append(0);
9851009 },
1010 .Union => {
1011 const layout = ty.unionGetLayout(target);
1012 const union_obj = ty.cast(Type.Payload.Union).?.data;
1013 const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;
1014 const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;
1015 const is_tagged = layout.tag_size > 0;
1016 const union_name = try ty.nameAllocArena(arena, target);
1017
1018 // TODO this is temporary to match current state of unions in Zig - we don't yet have
1019 // safety checks implemented meaning the implicit tag is not yet stored and generated
1020 // for untagged unions.
1021 if (is_tagged) {
1022 // DW.AT.structure_type
1023 try dbg_info_buffer.append(abbrev_struct_type);
1024 // DW.AT.byte_size, DW.FORM.sdata
1025 try leb128.writeULEB128(dbg_info_buffer.writer(), layout.abi_size);
1026 // DW.AT.name, DW.FORM.string
1027 try dbg_info_buffer.ensureUnusedCapacity(union_name.len + 1);
1028 dbg_info_buffer.appendSliceAssumeCapacity(union_name);
1029 dbg_info_buffer.appendAssumeCapacity(0);
1030
1031 // DW.AT.member
1032 try dbg_info_buffer.ensureUnusedCapacity(9);
1033 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
1034 // DW.AT.name, DW.FORM.string
1035 dbg_info_buffer.appendSliceAssumeCapacity("payload");
1036 dbg_info_buffer.appendAssumeCapacity(0);
1037 // DW.AT.type, DW.FORM.ref4
1038 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));
1047 // DW.AT.data_member_location, DW.FORM.sdata
1048 try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset);
1049 }
1050
1051 // DW.AT.union_type
1052 try dbg_info_buffer.append(abbrev_union_type);
1053 // DW.AT.byte_size, DW.FORM.sdata,
1054 try leb128.writeULEB128(dbg_info_buffer.writer(), layout.payload_size);
1055 // DW.AT.name, DW.FORM.string
1056 if (is_tagged) {
1057 try dbg_info_buffer.writer().print("AnonUnion\x00", .{});
1058 } else {
1059 try dbg_info_buffer.writer().print("{s}\x00", .{union_name});
1060 }
1061
1062 const fields = ty.unionFields();
1063 for (fields.keys()) |field_name| {
1064 const field = fields.get(field_name).?;
1065 if (!field.ty.hasRuntimeBits()) continue;
1066 // DW.AT.member
1067 try dbg_info_buffer.append(abbrev_struct_member);
1068 // DW.AT.name, DW.FORM.string
1069 try dbg_info_buffer.writer().print("{s}\x00", .{field_name});
1070 // DW.AT.type, DW.FORM.ref4
1071 const index = dbg_info_buffer.items.len;
1072 try dbg_info_buffer.resize(index + 4);
1073 try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) });
1074 // DW.AT.data_member_location, DW.FORM.sdata
1075 try dbg_info_buffer.append(0);
1076 }
1077 // DW.AT.union_type delimit children
1078 try dbg_info_buffer.append(0);
1079
1080 if (is_tagged) {
1081 // DW.AT.member
1082 try dbg_info_buffer.ensureUnusedCapacity(5);
1083 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
1084 // DW.AT.name, DW.FORM.string
1085 dbg_info_buffer.appendSliceAssumeCapacity("tag");
1086 dbg_info_buffer.appendAssumeCapacity(0);
1087 // DW.AT.type, DW.FORM.ref4
1088 const index = dbg_info_buffer.items.len;
1089 try dbg_info_buffer.resize(index + 4);
1090 try relocs.append(.{ .ty = union_obj.tag_ty, .reloc = @intCast(u32, index) });
1091 // DW.AT.data_member_location, DW.FORM.sdata
1092 try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset);
1093
1094 // DW.AT.structure_type delimit children
1095 try dbg_info_buffer.append(0);
1096 }
1097 },
9861098 else => {
9871099 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()});
9881100 try dbg_info_buffer.append(abbrev_pad1);
......@@ -1089,6 +1201,15 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
10891201 DW.FORM.data8,
10901202 0,
10911203 0, // table sentinel
1204 abbrev_union_type,
1205 DW.TAG.union_type,
1206 DW.CHILDREN.yes, // header
1207 DW.AT.byte_size,
1208 DW.FORM.sdata,
1209 DW.AT.name,
1210 DW.FORM.string,
1211 0,
1212 0, // table sentinel
10921213 abbrev_pad1,
10931214 DW.TAG.unspecified_type,
10941215 DW.CHILDREN.no, // header