authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-08-29 15:11:01-04:00
committergravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-09-18 19:43:26-04:00
logf388b575533b8e36999bc5ee406421feb7e80baa
treeb7739cce97e147a4fb6d8ed0de6ff18805e06bfd
parentf0b1eec8095e442218ff9171e284393102596dc4

plan9: emit line debug info in codegen


4 files changed, 74 insertions(+), 5 deletions(-)

src/Module.zig+3-1
...@@ -3674,7 +3674,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi...@@ -3674,7 +3674,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
3674 mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });3674 mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
3675 },3675 },
3676 .plan9 => {3676 .plan9 => {
3677 // TODO implement for plan93677 // TODO Look into detecting when this would be unnecessary by storing enough state
3678 // in `Decl` to notice that the line number did not change.
3679 mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
3678 },3680 },
3679 .c, .wasm, .spirv => {},3681 .c, .wasm, .spirv => {},
3680 }3682 }
src/codegen.zig+40-2
...@@ -48,6 +48,21 @@ pub const DebugInfoOutput = union(enum) {...@@ -48,6 +48,21 @@ pub const DebugInfoOutput = union(enum) {
48 dbg_info: *std.ArrayList(u8),48 dbg_info: *std.ArrayList(u8),
49 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,49 dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
50 },50 },
51 /// the plan9 debuginfo output is a bytecode with 4 opcodes
52 /// assume all numbers/variables are bytes
53 /// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset
54 /// x when x < 65 -> add x to line offset
55 /// x when x < 129 -> subtract 64 from x and add it to the line offset
56 /// x -> subtract 129 from x, multiply it by the quanta of the instruction size
57 /// (1 on x86_64), and add it to the pc
58 /// after every opcode, add the quanta of the instruction size to the pc
59 plan9: struct {
60 /// the actual opcodes
61 dbg_line: *std.ArrayList(u8),
62 /// what the line count ends on after codegen
63 /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl
64 end_line: *u32,
65 },
51 none,66 none,
52};67};
5368
...@@ -913,6 +928,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -913,6 +928,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
913 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);928 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
914 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);929 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
915 },930 },
931 .plan9 => {},
916 .none => {},932 .none => {},
917 }933 }
918 }934 }
...@@ -923,15 +939,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -923,15 +939,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
923 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);939 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
924 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);940 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
925 },941 },
942 .plan9 => {},
926 .none => {},943 .none => {},
927 }944 }
928 }945 }
929946
930 fn dbgAdvancePCAndLine(self: *Self, line: u32, column: u32) InnerError!void {947 fn dbgAdvancePCAndLine(self: *Self, line: u32, column: u32) InnerError!void {
948 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
949 const delta_pc = self.code.items.len - self.prev_di_pc;
931 switch (self.debug_output) {950 switch (self.debug_output) {
932 .dwarf => |dbg_out| {951 .dwarf => |dbg_out| {
933 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
934 const delta_pc = self.code.items.len - self.prev_di_pc;
935 // TODO Look into using the DWARF special opcodes to compress this data.952 // TODO Look into using the DWARF special opcodes to compress this data.
936 // It lets you emit single-byte opcodes that add different numbers to953 // It lets you emit single-byte opcodes that add different numbers to
937 // both the PC and the line number at the same time.954 // both the PC and the line number at the same time.
...@@ -944,6 +961,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -944,6 +961,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
944 }961 }
945 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);962 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
946 },963 },
964 .plan9 => |dbg_out| {
965 // we have already checked the target in the linker to make sure it is compatable
966 const quant = @import("link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
967
968 // increasing the line number
969 if (delta_line > 0 and delta_line < 65) {
970 try dbg_out.dbg_line.append(@intCast(u8, delta_line));
971 } else if (delta_line < 0 and delta_line > -65) {
972 try dbg_out.dbg_line.append(@intCast(u8, -delta_line + 64));
973 } else if (delta_line != 0) {
974 try dbg_out.dbg_line.writer().writeIntBig(i32, delta_line);
975 }
976 // increasing the pc
977 if (delta_pc - quant != 0) {
978 try dbg_out.dbg_line.append(@intCast(u8, delta_pc - quant + 129));
979 }
980 dbg_out.end_line.* = line;
981 },
947 .none => {},982 .none => {},
948 }983 }
949 self.prev_di_line = line;984 self.prev_di_line = line;
...@@ -1032,6 +1067,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1032,6 +1067,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1032 }1067 }
1033 try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index));1068 try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index));
1034 },1069 },
1070 .plan9 => {},
1035 .none => {},1071 .none => {},
1036 }1072 }
1037 }1073 }
...@@ -2457,6 +2493,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2457,6 +2493,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2457 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref42493 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
2458 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string2494 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
2459 },2495 },
2496 .plan9 => {},
2460 .none => {},2497 .none => {},
2461 }2498 }
2462 },2499 },
...@@ -2491,6 +2528,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2491,6 +2528,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2491 else => {},2528 else => {},
2492 }2529 }
2493 },2530 },
2531 .plan9 => {},
2494 .none => {},2532 .none => {},
2495 }2533 }
2496 },2534 },
src/link/Plan9.zig+22-2
...@@ -34,6 +34,8 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{},...@@ -34,6 +34,8 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{},
3434
35hdr: aout.ExecHdr = undefined,35hdr: aout.ExecHdr = undefined,
3636
37magic: u32,
38
37entry_val: ?u64 = null,39entry_val: ?u64 = null,
3840
39got_len: usize = 0,41got_len: usize = 0,
...@@ -113,6 +115,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {...@@ -113,6 +115,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
113 },115 },
114 .sixtyfour_bit = sixtyfour_bit,116 .sixtyfour_bit = sixtyfour_bit,
115 .bases = undefined,117 .bases = undefined,
118 .magic = try aout.magicFromArch(self.base.options.target.cpu.arch),
116 };119 };
117 return self;120 return self;
118}121}
...@@ -127,7 +130,24 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv...@@ -127,7 +130,24 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv
127130
128 var code_buffer = std.ArrayList(u8).init(self.base.allocator);131 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
129 defer code_buffer.deinit();132 defer code_buffer.deinit();
130 const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ .none = .{} });133 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
134 defer dbg_line_buffer.deinit();
135 var end_line: u32 = 0;
136
137 const res = try codegen.generateFunction(
138 &self.base,
139 decl.srcLoc(),
140 func,
141 air,
142 liveness,
143 &code_buffer,
144 .{
145 .plan9 = .{
146 .dbg_line = &dbg_line_buffer,
147 .end_line = &end_line,
148 },
149 },
150 );
131 const code = switch (res) {151 const code = switch (res) {
132 .appended => code_buffer.toOwnedSlice(),152 .appended => code_buffer.toOwnedSlice(),
133 .fail => |em| {153 .fail => |em| {
...@@ -313,7 +333,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -313,7 +333,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
313 iovecs_i += 1;333 iovecs_i += 1;
314 // generate the header334 // generate the header
315 self.hdr = .{335 self.hdr = .{
316 .magic = try aout.magicFromArch(self.base.options.target.cpu.arch),336 .magic = self.magic,
317 .text = @intCast(u32, text_i),337 .text = @intCast(u32, text_i),
318 .data = @intCast(u32, data_i),338 .data = @intCast(u32, data_i),
319 .syms = @intCast(u32, sym_buf.items.len),339 .syms = @intCast(u32, sym_buf.items.len),
src/link/Plan9/aout.zig+9
...@@ -112,3 +112,12 @@ pub fn magicFromArch(arch: std.Target.Cpu.Arch) !u32 {...@@ -112,3 +112,12 @@ pub fn magicFromArch(arch: std.Target.Cpu.Arch) !u32 {
112 else => error.ArchNotSupportedByPlan9,112 else => error.ArchNotSupportedByPlan9,
113 };113 };
114}114}
115
116/// gets the quantization of pc for the arch
117pub fn getPCQuant(arch: std.Target.Cpu.Arch) !u8 {
118 return switch (arch) {
119 .i386, .x86_64 => 1,
120 .powerpc, .powerpc64, .mips, .sparc, .arm, .aarch64 => 4,
121 else => error.ArchNotSupportedByPlan9,
122 };
123}