From b4427bc300cd768721891e6747e59102c8cb06fc Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 4 Oct 2023 19:22:52 -0400 Subject: [PATCH] plan9: refactor debug info The main goal is to stop depending on `emit.lower.target`. --- src/arch/aarch64/Emit.zig | 22 ++++++++-------- src/arch/arm/Emit.zig | 22 ++++++++-------- src/arch/riscv64/Emit.zig | 22 ++++++++-------- src/arch/x86_64/Emit.zig | 22 ++++++++-------- src/codegen.zig | 23 +---------------- src/link/Plan9.zig | 54 +++++++++++++++++++++++++++------------ 6 files changed, 79 insertions(+), 86 deletions(-) diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index 68c28ed8aa..9ba722f393 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -445,25 +445,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { }, .plan9 => |dbg_out| { if (delta_pc <= 0) return; // only do this when the pc changes - // we have already checked the target in the linker to make sure it is compatable - const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable; // increasing the line number - try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line); + try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line); // increasing the pc - const d_pc_p9 = @as(i64, @intCast(delta_pc)) - quant; + const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; if (d_pc_p9 > 0) { - // minus one because if its the last one, we want to leave space to change the line which is one quanta - try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant); - if (dbg_out.pcop_change_index.*) |pci| + // minus one because if its the last one, we want to leave space to change the line which is one pc quanta + try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta); + if (dbg_out.pcop_change_index) |pci| dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index.* = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); + dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); } else if (d_pc_p9 == 0) { - // we don't need to do anything, because adding the quant does it for us + // we don't need to do anything, because adding the pc quanta does it for us } else unreachable; - if (dbg_out.start_line.* == null) - dbg_out.start_line.* = self.prev_di_line; - dbg_out.end_line.* = line; + if (dbg_out.start_line == null) + dbg_out.start_line = self.prev_di_line; + dbg_out.end_line = line; // only do this if the pc changed self.prev_di_line = line; self.prev_di_column = column; diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index 54062d00a7..45c3392918 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -362,25 +362,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { }, .plan9 => |dbg_out| { if (delta_pc <= 0) return; // only do this when the pc changes - // we have already checked the target in the linker to make sure it is compatable - const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable; // increasing the line number - try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line); + try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line); // increasing the pc - const d_pc_p9 = @as(i64, @intCast(delta_pc)) - quant; + const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; if (d_pc_p9 > 0) { - // minus one because if its the last one, we want to leave space to change the line which is one quanta - try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant); - if (dbg_out.pcop_change_index.*) |pci| + // minus one because if its the last one, we want to leave space to change the line which is one pc quanta + try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta); + if (dbg_out.pcop_change_index) |pci| dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index.* = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); + dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); } else if (d_pc_p9 == 0) { - // we don't need to do anything, because adding the quant does it for us + // we don't need to do anything, because adding the pc quanta does it for us } else unreachable; - if (dbg_out.start_line.* == null) - dbg_out.start_line.* = self.prev_di_line; - dbg_out.end_line.* = line; + if (dbg_out.start_line == null) + dbg_out.start_line = self.prev_di_line; + dbg_out.end_line = line; // only do this if the pc changed self.prev_di_line = line; self.prev_di_column = column; diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index 20f2c40ba4..9d82cc38cc 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -96,25 +96,23 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { }, .plan9 => |dbg_out| { if (delta_pc <= 0) return; // only do this when the pc changes - // we have already checked the target in the linker to make sure it is compatable - const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable; // increasing the line number - try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line); + try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line); // increasing the pc - const d_pc_p9 = @as(i64, @intCast(delta_pc)) - quant; + const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; if (d_pc_p9 > 0) { - // minus one because if its the last one, we want to leave space to change the line which is one quanta - try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, quant) + 128)) - quant); - if (dbg_out.pcop_change_index.*) |pci| + // minus one because if its the last one, we want to leave space to change the line which is one pc quanta + try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta); + if (dbg_out.pcop_change_index) |pci| dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index.* = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); + dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); } else if (d_pc_p9 == 0) { - // we don't need to do anything, because adding the quant does it for us + // we don't need to do anything, because adding the pc quanta does it for us } else unreachable; - if (dbg_out.start_line.* == null) - dbg_out.start_line.* = self.prev_di_line; - dbg_out.end_line.* = line; + if (dbg_out.start_line == null) + dbg_out.start_line = self.prev_di_line; + dbg_out.end_line = line; // only do this if the pc changed self.prev_di_line = line; self.prev_di_column = column; diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index f17eda57eb..d2a199da42 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -242,16 +242,14 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { }, .plan9 => |dbg_out| { if (delta_pc <= 0) return; // only do this when the pc changes - // we have already checked the target in the linker to make sure it is compatable - const quant = @import("../../link/Plan9/aout.zig").getPCQuant(emit.lower.target.cpu.arch) catch unreachable; // increasing the line number - try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line); + try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line); // increasing the pc - const d_pc_p9 = @as(i64, @intCast(delta_pc)) - quant; + const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; if (d_pc_p9 > 0) { - // minus one because if its the last one, we want to leave space to change the line which is one quanta - var diff = @divExact(d_pc_p9, quant) - quant; + // minus one because if its the last one, we want to leave space to change the line which is one pc quanta + var diff = @divExact(d_pc_p9, dbg_out.pc_quanta) - dbg_out.pc_quanta; while (diff > 0) { if (diff < 64) { try dbg_out.dbg_line.append(@as(u8, @intCast(diff + 128))); @@ -261,15 +259,15 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { diff -= 64; } } - if (dbg_out.pcop_change_index.*) |pci| + if (dbg_out.pcop_change_index) |pci| dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index.* = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); + dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); } else if (d_pc_p9 == 0) { - // we don't need to do anything, because adding the quant does it for us + // we don't need to do anything, because adding the pc quanta does it for us } else unreachable; - if (dbg_out.start_line.* == null) - dbg_out.start_line.* = emit.prev_di_line; - dbg_out.end_line.* = line; + if (dbg_out.start_line == null) + dbg_out.start_line = emit.prev_di_line; + dbg_out.end_line = line; // only do this if the pc changed emit.prev_di_line = line; emit.prev_di_column = column; diff --git a/src/codegen.zig b/src/codegen.zig index dd1b6e0cbf..2c5fd7b630 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -40,28 +40,7 @@ pub const CodeGenError = error{ pub const DebugInfoOutput = union(enum) { dwarf: *link.File.Dwarf.DeclState, - /// the plan9 debuginfo output is a bytecode with 4 opcodes - /// assume all numbers/variables are bytes - /// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset - /// x when x < 65 -> add x to line offset - /// x when x < 129 -> subtract 64 from x and subtract it from the line offset - /// x -> subtract 129 from x, multiply it by the quanta of the instruction size - /// (1 on x86_64), and add it to the pc - /// after every opcode, add the quanta of the instruction size to the pc - plan9: struct { - /// the actual opcodes - dbg_line: *std.ArrayList(u8), - /// what line the debuginfo starts on - /// 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 - start_line: *?u32, - /// what the line count ends on after codegen - /// 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 - end_line: *u32, - /// the last pc change op - /// This is very useful for adding quanta - /// to it if its not actually the last one. - pcop_change_index: *?u32, - }, + plan9: *link.File.Plan9.DebugInfoOutput, none, }; diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index a7a571e9ff..b519fdda00 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -211,6 +211,31 @@ pub const Atom = struct { } }; +/// the plan9 debuginfo output is a bytecode with 4 opcodes +/// assume all numbers/variables are bytes +/// 0 w x y z -> interpret w x y z as a big-endian i32, and add it to the line offset +/// x when x < 65 -> add x to line offset +/// x when x < 129 -> subtract 64 from x and subtract it from the line offset +/// x -> subtract 129 from x, multiply it by the quanta of the instruction size +/// (1 on x86_64), and add it to the pc +/// after every opcode, add the quanta of the instruction size to the pc +pub const DebugInfoOutput = struct { + /// the actual opcodes + dbg_line: std.ArrayList(u8), + /// what line the debuginfo starts on + /// 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 + start_line: ?u32, + /// what the line count ends on after codegen + /// 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 + end_line: u32, + /// the last pc change op + /// This is very useful for adding quanta + /// to it if its not actually the last one. + pcop_change_index: ?u32, + /// cached pc quanta + pc_quanta: u8, +}; + const DeclMetadata = struct { index: Atom.Index, exports: std.ArrayListUnmanaged(usize) = .{}, @@ -376,11 +401,15 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air: var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); - defer dbg_line_buffer.deinit(); - var start_line: ?u32 = null; - var end_line: u32 = undefined; - var pcop_change_index: ?u32 = null; + var dbg_info_output: DebugInfoOutput = .{ + .dbg_line = std.ArrayList(u8).init(self.base.allocator), + .start_line = null, + .end_line = undefined, + .pcop_change_index = null, + // we have already checked the target in the linker to make sure it is compatable + .pc_quanta = aout.getPCQuant(self.base.options.target.cpu.arch) catch unreachable, + }; + defer dbg_info_output.dbg_line.deinit(); const res = try codegen.generateFunction( &self.base, @@ -389,14 +418,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air: air, liveness, &code_buffer, - .{ - .plan9 = .{ - .dbg_line = &dbg_line_buffer, - .end_line = &end_line, - .start_line = &start_line, - .pcop_change_index = &pcop_change_index, - }, - }, + .{ .plan9 = &dbg_info_output }, ); const code = switch (res) { .ok => try code_buffer.toOwnedSlice(), @@ -412,9 +434,9 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air: }; const out: FnDeclOutput = .{ .code = code, - .lineinfo = try dbg_line_buffer.toOwnedSlice(), - .start_line = start_line.?, - .end_line = end_line, + .lineinfo = try dbg_info_output.dbg_line.toOwnedSlice(), + .start_line = dbg_info_output.start_line.?, + .end_line = dbg_info_output.end_line, }; try self.putFn(decl_index, out); return self.updateFinish(decl_index);