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;...@@ -83,8 +83,9 @@ pub const abbrev_struct_type = 6;
83pub const abbrev_struct_member = 7;83pub const abbrev_struct_member = 7;
84pub const abbrev_enum_type = 8;84pub const abbrev_enum_type = 8;
85pub const abbrev_enum_variant = 9;85pub const abbrev_enum_variant = 9;
86pub const abbrev_pad1 = 10;86pub const abbrev_union_type = 10;
87pub const abbrev_parameter = 11;87pub const abbrev_pad1 = 11;
88pub const abbrev_parameter = 12;
8889
89/// The reloc offset for the virtual address of a function in its Line Number Program.90/// The reloc offset for the virtual address of a function in its Line Number Program.
90/// Size is a virtual address integer.91/// Size is a virtual address integer.
...@@ -452,6 +453,8 @@ pub fn commitDeclDebugInfo(...@@ -452,6 +453,8 @@ pub fn commitDeclDebugInfo(
452 var dbg_type_arena = std.heap.ArenaAllocator.init(gpa);453 var dbg_type_arena = std.heap.ArenaAllocator.init(gpa);
453 defer dbg_type_arena.deinit();454 defer dbg_type_arena.deinit();
454455
456 var nested_ref4_relocs = std.ArrayList(u32).init(gpa);
457 defer nested_ref4_relocs.deinit();
455 {458 {
456 // Now we emit the .debug_info types of the Decl. These will count towards the size of459 // Now we emit the .debug_info types of the Decl. These will count towards the size of
457 // the buffer, so we have to do it before computing the offset, and we can't perform the actual460 // 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(...@@ -463,7 +466,13 @@ pub fn commitDeclDebugInfo(
463 .target = self.target,466 .target = self.target,
464 }).?;467 }).?;
465 value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);468 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 );
467 }476 }
468 }477 }
469478
...@@ -478,13 +487,27 @@ pub fn commitDeclDebugInfo(...@@ -478,13 +487,27 @@ pub fn commitDeclDebugInfo(
478 // Now that we have the offset assigned we can finally perform type relocations.487 // Now that we have the offset assigned we can finally perform type relocations.
479 for (dbg_info_type_relocs.values()) |value| {488 for (dbg_info_type_relocs.values()) |value| {
480 for (value.relocs.items) |off| {489 for (value.relocs.items) |off| {
481 mem.writeIntLittle(490 mem.writeInt(
482 u32,491 u32,
483 dbg_info_buffer.items[off..][0..4],492 dbg_info_buffer.items[off..][0..4],
484 atom.off + value.off,493 atom.off + value.off,
494 target_endian,
485 );495 );
486 }496 }
487 }497 }
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 }
488 }511 }
489512
490 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);513 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
...@@ -751,8 +774,10 @@ fn addDbgInfoType(...@@ -751,8 +774,10 @@ fn addDbgInfoType(
751 ty: Type,774 ty: Type,
752 dbg_info_buffer: *std.ArrayList(u8),775 dbg_info_buffer: *std.ArrayList(u8),
753 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,776 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
777 nested_ref4_relocs: *std.ArrayList(u32),
754) error{OutOfMemory}!void {778) error{OutOfMemory}!void {
755 const target = self.target;779 const target = self.target;
780 const target_endian = self.target.cpu.arch.endian();
756 var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena);781 var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena);
757782
758 switch (ty.zigTypeTag()) {783 switch (ty.zigTypeTag()) {
...@@ -962,7 +987,6 @@ fn addDbgInfoType(...@@ -962,7 +987,6 @@ fn addDbgInfoType(
962 .enum_numbered => ty.castTag(.enum_numbered).?.data.values,987 .enum_numbered => ty.castTag(.enum_numbered).?.data.values,
963 else => unreachable,988 else => unreachable,
964 };989 };
965 const target_endian = self.target.cpu.arch.endian();
966 for (fields.keys()) |field_name, field_i| {990 for (fields.keys()) |field_name, field_i| {
967 // DW.AT.enumerator991 // DW.AT.enumerator
968 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));992 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64));
...@@ -983,6 +1007,94 @@ fn addDbgInfoType(...@@ -983,6 +1007,94 @@ fn addDbgInfoType(
983 // DW.AT.enumeration_type delimit children1007 // DW.AT.enumeration_type delimit children
984 try dbg_info_buffer.append(0);1008 try dbg_info_buffer.append(0);
985 },1009 },
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 },
986 else => {1098 else => {
987 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()});1099 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()});
988 try dbg_info_buffer.append(abbrev_pad1);1100 try dbg_info_buffer.append(abbrev_pad1);
...@@ -1089,6 +1201,15 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {...@@ -1089,6 +1201,15 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
1089 DW.FORM.data8,1201 DW.FORM.data8,
1090 0,1202 0,
1091 0, // table sentinel1203 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
1092 abbrev_pad1,1213 abbrev_pad1,
1093 DW.TAG.unspecified_type,1214 DW.TAG.unspecified_type,
1094 DW.CHILDREN.no, // header1215 DW.CHILDREN.no, // header