authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-25 21:47:21+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-26 17:28:58+01:00
log4192be84039cfac9ec458dc42370f67d700bd8ed
tree0cd4faa2a22d76730ebcc008cfc6e232957aef49
parentaa4eaea778d090e7f0fde74409106d02c075d1ec

elf: implement slice types in debug info

Implements slice types including `[]const u8` for passing as formal parameters in DWARF. Breaking on a function accepting a slice in `gdb` will now yield the same behavior as stage1 and/or LLVM backend: ```zig fn sumArrayLens(a: []const u32, b: []const u8) usize { return a.len + b.len; } ``` Both `a` and `b` can now be inspected in the debugger: ``` Breakpoint 1, sumArrayLens (a=..., b=...) at arr.zig:59 (gdb) p a $1 = {ptr = 0x7fffffff685c, len = 5} (gdb) p b $2 = {ptr = 0x7fffffff683d "\252\252\252\\h\377\377\377\177", len = 3} (gdb) ```

1 files changed, 76 insertions(+), 14 deletions(-)

src/link/Elf.zig+76-14
...@@ -784,8 +784,10 @@ pub const abbrev_subprogram = 2;...@@ -784,8 +784,10 @@ pub const abbrev_subprogram = 2;
784pub const abbrev_subprogram_retvoid = 3;784pub const abbrev_subprogram_retvoid = 3;
785pub const abbrev_base_type = 4;785pub const abbrev_base_type = 4;
786pub const abbrev_ptr_type = 5;786pub const abbrev_ptr_type = 5;
787pub const abbrev_pad1 = 6;787pub const abbrev_anon_struct_type = 6;
788pub const abbrev_parameter = 7;788pub const abbrev_struct_member = 7;
789pub const abbrev_pad1 = 8;
790pub const abbrev_parameter = 9;
789791
790pub fn flush(self: *Elf, comp: *Compilation) !void {792pub fn flush(self: *Elf, comp: *Compilation) !void {
791 if (self.base.options.emit == null) {793 if (self.base.options.emit == null) {
...@@ -882,6 +884,24 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -882,6 +884,24 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
882 DW.FORM.ref4,884 DW.FORM.ref4,
883 0,885 0,
884 0, // table sentinel886 0, // table sentinel
887 abbrev_anon_struct_type,
888 DW.TAG.structure_type,
889 DW.CHILDREN.yes, // header
890 DW.AT.byte_size,
891 DW.FORM.sdata,
892 0,
893 0, // table sentinel
894 abbrev_struct_member,
895 DW.TAG.member,
896 DW.CHILDREN.no, // header
897 DW.AT.name,
898 DW.FORM.string,
899 DW.AT.type,
900 DW.FORM.ref4,
901 DW.AT.data_member_location,
902 DW.FORM.sdata,
903 0,
904 0, // table sentinel
885 abbrev_pad1,905 abbrev_pad1,
886 DW.TAG.unspecified_type,906 DW.TAG.unspecified_type,
887 DW.CHILDREN.no, // header907 DW.CHILDREN.no, // header
...@@ -2395,6 +2415,16 @@ fn finishUpdateDecl(...@@ -2395,6 +2415,16 @@ fn finishUpdateDecl(
2395 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,2415 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
2396 dbg_info_buffer: *std.ArrayList(u8),2416 dbg_info_buffer: *std.ArrayList(u8),
2397) !void {2417) !void {
2418 // We need this for the duration of this function only so that for composite
2419 // types such as []const u32, if the type *u32 is non-existent, we create
2420 // it synthetically and store the backing bytes in this arena. After we are
2421 // done with the relocations, we can safely deinit the entire memory slab.
2422 // TODO currently, we do not store the relocations for future use, however,
2423 // if that is the case, we should move memory management to a higher scope,
2424 // such as linker scope, or whatnot.
2425 var dbg_type_arena = std.heap.ArenaAllocator.init(self.base.allocator);
2426 defer dbg_type_arena.deinit();
2427
2398 // Now we emit the .debug_info types of the Decl. These will count towards the size of2428 // Now we emit the .debug_info types of the Decl. These will count towards the size of
2399 // the buffer, so we have to do it before computing the offset, and we can't perform the actual2429 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
2400 // relocations yet.2430 // relocations yet.
...@@ -2404,7 +2434,7 @@ fn finishUpdateDecl(...@@ -2404,7 +2434,7 @@ fn finishUpdateDecl(
2404 const ty = dbg_info_type_relocs.keys()[it];2434 const ty = dbg_info_type_relocs.keys()[it];
2405 const value_ptr = dbg_info_type_relocs.getPtr(ty).?;2435 const value_ptr = dbg_info_type_relocs.getPtr(ty).?;
2406 value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);2436 value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
2407 try self.addDbgInfoType(ty, dbg_info_buffer, dbg_info_type_relocs);2437 try self.addDbgInfoType(dbg_type_arena.allocator(), ty, dbg_info_buffer, dbg_info_type_relocs);
2408 }2438 }
2409 }2439 }
24102440
...@@ -2721,11 +2751,12 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2721,11 +2751,12 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2721/// Asserts the type has codegen bits.2751/// Asserts the type has codegen bits.
2722fn addDbgInfoType(2752fn addDbgInfoType(
2723 self: *Elf,2753 self: *Elf,
2754 arena: Allocator,
2724 ty: Type,2755 ty: Type,
2725 dbg_info_buffer: *std.ArrayList(u8),2756 dbg_info_buffer: *std.ArrayList(u8),
2726 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,2757 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
2727) error{OutOfMemory}!void {2758) error{OutOfMemory}!void {
2728 var reloc: ?struct { ty: Type, reloc: u32 } = null;2759 var relocs = std.ArrayList(struct { ty: Type, reloc: u32 }).init(arena);
27292760
2730 switch (ty.zigTypeTag()) {2761 switch (ty.zigTypeTag()) {
2731 .Void => unreachable,2762 .Void => unreachable,
...@@ -2767,17 +2798,48 @@ fn addDbgInfoType(...@@ -2767,17 +2798,48 @@ fn addDbgInfoType(
2767 try dbg_info_buffer.append(abbrev_pad1);2798 try dbg_info_buffer.append(abbrev_pad1);
2768 }2799 }
2769 },2800 },
2770 .Pointer => blk: {2801 .Pointer => {
2771 if (ty.isSlice()) {2802 if (ty.isSlice()) {
2772 log.debug("TODO implement .debug_info for type '{}'", .{ty});2803 // Slices are anonymous structs: struct { .ptr = *, .len = N }
2773 try dbg_info_buffer.append(abbrev_pad1);2804 try dbg_info_buffer.ensureUnusedCapacity(23);
2774 break :blk;2805 // DW.AT.structure_type
2806 dbg_info_buffer.appendAssumeCapacity(abbrev_anon_struct_type);
2807 // DW.AT.byte_size, DW.FORM.sdata
2808 dbg_info_buffer.appendAssumeCapacity(16);
2809 // DW.AT.member
2810 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
2811 // DW.AT.name, DW.FORM.string
2812 dbg_info_buffer.appendSliceAssumeCapacity("ptr");
2813 dbg_info_buffer.appendAssumeCapacity(0);
2814 // DW.AT.type, DW.FORM.ref4
2815 var index = dbg_info_buffer.items.len;
2816 try dbg_info_buffer.resize(index + 4);
2817 var buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
2818 const ptr_ty = ty.slicePtrFieldType(buf);
2819 try relocs.append(.{ .ty = ptr_ty, .reloc = @intCast(u32, index) });
2820 // DW.AT.data_member_location, DW.FORM.sdata
2821 dbg_info_buffer.appendAssumeCapacity(0);
2822 // DW.AT.member
2823 dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member);
2824 // DW.AT.name, DW.FORM.string
2825 dbg_info_buffer.appendSliceAssumeCapacity("len");
2826 dbg_info_buffer.appendAssumeCapacity(0);
2827 // DW.AT.type, DW.FORM.ref4
2828 index = dbg_info_buffer.items.len;
2829 try dbg_info_buffer.resize(index + 4);
2830 try relocs.append(.{ .ty = Type.initTag(.usize), .reloc = @intCast(u32, index) });
2831 // DW.AT.data_member_location, DW.FORM.sdata
2832 dbg_info_buffer.appendAssumeCapacity(8);
2833 // DW.AT.structure_type delimit children
2834 dbg_info_buffer.appendAssumeCapacity(0);
2835 } else {
2836 try dbg_info_buffer.ensureUnusedCapacity(5);
2837 dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type);
2838 // DW.AT.type, DW.FORM.ref4
2839 const index = dbg_info_buffer.items.len;
2840 try dbg_info_buffer.resize(index + 4);
2841 try relocs.append(.{ .ty = ty.childType(), .reloc = @intCast(u32, index) });
2775 }2842 }
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 },2843 },
2782 else => {2844 else => {
2783 log.debug("TODO implement .debug_info for type '{}'", .{ty});2845 log.debug("TODO implement .debug_info for type '{}'", .{ty});
...@@ -2785,7 +2847,7 @@ fn addDbgInfoType(...@@ -2785,7 +2847,7 @@ fn addDbgInfoType(
2785 },2847 },
2786 }2848 }
27872849
2788 if (reloc) |rel| {2850 for (relocs.items) |rel| {
2789 const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, rel.ty);2851 const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, rel.ty);
2790 if (!gop.found_existing) {2852 if (!gop.found_existing) {
2791 gop.value_ptr.* = .{2853 gop.value_ptr.* = .{