| ... | @@ -83,8 +83,9 @@ pub const abbrev_struct_type = 6; | ... | @@ -83,8 +83,9 @@ pub const abbrev_struct_type = 6; |
| 83 | pub const abbrev_struct_member = 7; | 83 | pub const abbrev_struct_member = 7; |
| 84 | pub const abbrev_enum_type = 8; | 84 | pub const abbrev_enum_type = 8; |
| 85 | pub const abbrev_enum_variant = 9; | 85 | pub const abbrev_enum_variant = 9; |
| 86 | pub const abbrev_pad1 = 10; | 86 | pub const abbrev_union_type = 10; |
| 87 | pub const abbrev_parameter = 11; | 87 | pub const abbrev_pad1 = 11; |
| | 88 | pub const abbrev_parameter = 12; |
| 88 | | 89 | |
| 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(); |
| 454 | | 455 | |
| | 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 of | 459 | // 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 actual | 460 | // 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 | } |
| 469 | | 478 | |
| ... | @@ -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 | } |
| 489 | | 512 | |
| 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); |
| 757 | | 782 | |
| 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.enumerator | 991 | // 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 children | 1007 | // 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 sentinel | 1203 | 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, // header | 1215 | DW.CHILDREN.no, // header |