authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-24 10:33:42+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-25 23:51:19+01:00
log53c668d3a9dad430749cbc642d7bf8cf45eefba1
tree38b4ab6279aa9cd396b2a6622451c78116f35dea
parent05c5bb9edd51e73c0d4a2619817fbff73b82f230

stage2: add naive impl of pointer type in ELF

Augment relocation tracking mechanism to de-duplicate potential creation of base as well as composite types while unrolling composite types in the linker - there is still potential for further space optimisation by moving all type information into a separate section `.debug_types` and providing references to entries within that section whenever required (e.g., `ref4` form). Currently, we duplicate type definitions on a per-decl basis. Anyhow, with this patch, an example function signature of the following type: ```zig fn byPtrPtr(ptr_ptr_x: **u32, ptr_x: *u32) void { ptr_ptr_x.* = ptr_x; } ``` will generate the following `.debug_info` for formal parameters: ``` <1><1aa>: Abbrev Number: 3 (DW_TAG_subprogram) <1ab> DW_AT_low_pc : 0x8000197 <1b3> DW_AT_high_pc : 0x2c <1b7> DW_AT_name : byPtrPtr <2><1c0>: Abbrev Number: 7 (DW_TAG_formal_parameter) <1c1> DW_AT_location : 1 byte block: 55 (DW_OP_reg5 (rdi)) <1c3> DW_AT_type : <0x1df> <1c7> DW_AT_name : ptr_ptr_x <2><1d1>: Abbrev Number: 7 (DW_TAG_formal_parameter) <1d2> DW_AT_location : 1 byte block: 54 (DW_OP_reg4 (rsi)) <1d4> DW_AT_type : <0x1e4> <1d8> DW_AT_name : ptr_x <2><1de>: Abbrev Number: 0 <1><1df>: Abbrev Number: 5 (DW_TAG_pointer_type) <1e0> DW_AT_type : <0x1e4> <1><1e4>: Abbrev Number: 5 (DW_TAG_pointer_type) <1e5> DW_AT_type : <0x1e9> <1><1e9>: Abbrev Number: 4 (DW_TAG_base_type) <1ea> DW_AT_encoding : 7 (unsigned) <1eb> DW_AT_byte_size : 4 <1ec> DW_AT_name : u32 ```

4 files changed, 66 insertions(+), 21 deletions(-)

src/link.zig+6-1
......@@ -235,7 +235,12 @@ pub const File = struct {
235235 };
236236
237237 /// For DWARF .debug_info.
238 pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.HashContext64, std.hash_map.default_max_load_percentage);
238 pub const DbgInfoTypeRelocsTable = std.ArrayHashMapUnmanaged(
239 Type,
240 DbgInfoTypeReloc,
241 Type.HashContext32,
242 true,
243 );
239244
240245 /// For DWARF .debug_info.
241246 pub const DbgInfoTypeReloc = struct {
src/link/Elf.zig+57-14
......@@ -783,8 +783,9 @@ pub const abbrev_compile_unit = 1;
783783pub const abbrev_subprogram = 2;
784784pub const abbrev_subprogram_retvoid = 3;
785785pub const abbrev_base_type = 4;
786pub const abbrev_pad1 = 5;
787pub const abbrev_parameter = 6;
786pub const abbrev_ptr_type = 5;
787pub const abbrev_pad1 = 6;
788pub const abbrev_parameter = 7;
788789
789790pub fn flush(self: *Elf, comp: *Compilation) !void {
790791 if (self.base.options.emit == null) {
......@@ -871,9 +872,21 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
871872 DW.AT.byte_size,
872873 DW.FORM.data1,
873874 DW.AT.name,
874 DW.FORM.string, 0, 0, // table sentinel
875 abbrev_pad1, DW.TAG.unspecified_type, DW.CHILDREN.no, // header
876 0, 0, // table sentinel
875 DW.FORM.string,
876 0,
877 0, // table sentinel
878 abbrev_ptr_type,
879 DW.TAG.pointer_type,
880 DW.CHILDREN.no, // header
881 DW.AT.type,
882 DW.FORM.ref4,
883 0,
884 0, // table sentinel
885 abbrev_pad1,
886 DW.TAG.unspecified_type,
887 DW.CHILDREN.no, // header
888 0,
889 0, // table sentinel
877890 abbrev_parameter,
878891 DW.TAG.formal_parameter, DW.CHILDREN.no, // header
879892 DW.AT.location, DW.FORM.exprloc,
......@@ -2309,8 +2322,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
23092322}
23102323
23112324fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {
2312 var it = table.valueIterator();
2313 while (it.next()) |value| {
2325 for (table.values()) |*value| {
23142326 value.relocs.deinit(gpa);
23152327 }
23162328 table.deinit(gpa);
......@@ -2387,10 +2399,12 @@ fn finishUpdateDecl(
23872399 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
23882400 // relocations yet.
23892401 {
2390 var it = dbg_info_type_relocs.iterator();
2391 while (it.next()) |entry| {
2392 entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
2393 try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer);
2402 var it: usize = 0;
2403 while (it < dbg_info_type_relocs.count()) : (it += 1) {
2404 const ty = dbg_info_type_relocs.keys()[it];
2405 const value_ptr = dbg_info_type_relocs.getPtr(ty).?;
2406 value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
2407 try self.addDbgInfoType(ty, dbg_info_buffer, dbg_info_type_relocs);
23942408 }
23952409 }
23962410
......@@ -2401,8 +2415,7 @@ fn finishUpdateDecl(
24012415
24022416 {
24032417 // Now that we have the offset assigned we can finally perform type relocations.
2404 var it = dbg_info_type_relocs.valueIterator();
2405 while (it.next()) |value| {
2418 for (dbg_info_type_relocs.values()) |value| {
24062419 for (value.relocs.items) |off| {
24072420 mem.writeInt(
24082421 u32,
......@@ -2706,7 +2719,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
27062719}
27072720
27082721/// Asserts the type has codegen bits.
2709fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
2722fn addDbgInfoType(
2723 self: *Elf,
2724 ty: Type,
2725 dbg_info_buffer: *std.ArrayList(u8),
2726 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
2727) error{OutOfMemory}!void {
2728 var reloc: ?struct { ty: Type, reloc: u32 } = null;
2729
27102730 switch (ty.zigTypeTag()) {
27112731 .Void => unreachable,
27122732 .NoReturn => unreachable,
......@@ -2747,11 +2767,34 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo
27472767 try dbg_info_buffer.append(abbrev_pad1);
27482768 }
27492769 },
2770 .Pointer => blk: {
2771 if (ty.isSlice()) {
2772 log.debug("TODO implement .debug_info for type '{}'", .{ty});
2773 try dbg_info_buffer.append(abbrev_pad1);
2774 break :blk;
2775 }
2776 try dbg_info_buffer.ensureUnusedCapacity(5);
2777 dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type);
2778 const index = dbg_info_buffer.items.len;
2779 try dbg_info_buffer.resize(index + 4); // DW.AT.type, DW.FORM.ref4
2780 reloc = .{ .ty = ty.childType(), .reloc = @intCast(u32, index) };
2781 },
27502782 else => {
27512783 log.debug("TODO implement .debug_info for type '{}'", .{ty});
27522784 try dbg_info_buffer.append(abbrev_pad1);
27532785 },
27542786 }
2787
2788 if (reloc) |rel| {
2789 const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, rel.ty);
2790 if (!gop.found_existing) {
2791 gop.value_ptr.* = .{
2792 .off = undefined,
2793 .relocs = .{},
2794 };
2795 }
2796 try gop.value_ptr.relocs.append(self.base.allocator, rel.reloc);
2797 }
27552798}
27562799
27572800fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void {
src/link/MachO.zig+2-4
......@@ -3578,8 +3578,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
35783578 if (debug_buffers) |dbg| {
35793579 dbg.dbg_line_buffer.deinit();
35803580 dbg.dbg_info_buffer.deinit();
3581 var it = dbg.dbg_info_type_relocs.valueIterator();
3582 while (it.next()) |value| {
3581 for (dbg.dbg_info_type_relocs.values()) |*value| {
35833582 value.relocs.deinit(self.base.allocator);
35843583 }
35853584 dbg.dbg_info_type_relocs.deinit(self.base.allocator);
......@@ -3659,8 +3658,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
36593658 if (debug_buffers) |dbg| {
36603659 dbg.dbg_line_buffer.deinit();
36613660 dbg.dbg_info_buffer.deinit();
3662 var it = dbg.dbg_info_type_relocs.valueIterator();
3663 while (it.next()) |value| {
3661 for (dbg.dbg_info_type_relocs.values()) |*value| {
36643662 value.relocs.deinit(self.base.allocator);
36653663 }
36663664 dbg.dbg_info_type_relocs.deinit(self.base.allocator);
src/link/MachO/DebugSymbols.zig+1-2
......@@ -1112,8 +1112,7 @@ pub fn commitDeclDebugInfo(
11121112
11131113 {
11141114 // Now that we have the offset assigned we can finally perform type relocations.
1115 var it = dbg_info_type_relocs.valueIterator();
1116 while (it.next()) |value| {
1115 for (dbg_info_type_relocs.values()) |value| {
11171116 for (value.relocs.items) |off| {
11181117 mem.writeIntLittle(
11191118 u32,