From 9b6b7034c20a0089b88e58b5142c91b2d26bcef8 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Mon, 2 May 2022 21:41:47 +0200 Subject: [PATCH] wasm: Flush debug information + commit decl This implements parts to commit a decl's debug information into a linear memory buffer. The goal is to write this buffer at once after we finished linking. --- src/link/Dwarf.zig | 29 ++++++++++++++++++++++++++- src/link/Wasm.zig | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index bf02c22f7ba1e841bdca376b91a68e2f5ce757fe..bf054c524c06d50a511f5129f523a6072ae6dc1d 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -818,6 +818,7 @@ pub fn commitDeclState( const src_fn = switch (self.tag) { .elf => &decl.fn_link.elf, .macho => &decl.fn_link.macho, + .wasm => &decl.fn_link.wasm.src_fn, else => unreachable, // TODO }; src_fn.len = @intCast(u32, dbg_line_buffer.items.len); @@ -958,6 +959,26 @@ pub fn commitDeclState( next_padding_size, ); }, + .wasm => { + const wasm_file = file.cast(File.Wasm).?; + const segment_index = try wasm_file.getDebugLineIndex(); + const segment = &wasm_file.segments.items[segment_index]; + const debug_atom = wasm_file.atoms.get(segment_index).?; + if (needed_size != segment.size) { + log.debug(" needed size does not equal allocated size: {d}", .{needed_size}); + if (needed_size > segment.size) { + log.debug(" allocating {d} bytes for debug line information", .{needed_size - segment.size}); + try debug_atom.code.resize(self.allocator, needed_size); + std.mem.set(u8, debug_atom.code.items[segment.size..], 0); + } + debug_atom.size = needed_size; + segment.size = needed_size; + } + // since we can tighly pack the debug lines, wasm does not require + // us to pad with Nops. + const offset = segment.offset + src_fn.off; + std.mem.copy(u8, debug_atom.code.items[offset..], dbg_line_buffer.items); + }, else => unreachable, } @@ -973,6 +994,7 @@ pub fn commitDeclState( const atom = switch (self.tag) { .elf => &decl.link.elf.dbg_info_atom, .macho => &decl.link.macho.dbg_info_atom, + .wasm => &decl.link.wasm.dbg_info_atom, else => unreachable, }; @@ -1094,6 +1116,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3 const file_pos = debug_info_sect.offset + atom.off; try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false); }, + .wasm => {}, else => unreachable, } // TODO Look at the free list before appending at the end. @@ -1253,7 +1276,11 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl) }, .wasm => { const wasm_file = file.cast(File.Wasm).?; - _ = wasm_file; // TODO, update .debug_line + const segment_index = wasm_file.getDebugLineIndex() catch unreachable; + const segment = wasm_file.segments.items[segment_index]; + const offset = segment.offset + decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff(); + const debug_atom = wasm_file.atoms.get(segment_index).?; + std.mem.copy(u8, debug_atom.code.items[offset..], &data); }, else => unreachable, } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index f9c40fd767adeed818bb131ffdadab463b9ba587..d2ef331a3ddb799d00fde055149f5a576f71d203 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -62,6 +62,10 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, /// Represents the index into `segments` where the 'code' section /// lives. code_section_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_info' section. +debug_info_index: ?u32 = null, +/// The index of the segment representing the custom '.debug_line' section. +debug_line_index: ?u32 = null, /// The count of imported functions. This number will be appended /// to the function indexes as their index starts at the lowest non-extern function. imported_functions_count: u32 = 0, @@ -311,6 +315,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option .init = .{ .i32_const = 0 }, }; } + return wasm_bin; } @@ -566,6 +571,17 @@ pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes }, }; + if (self.dwarf) |*dwarf| { + try dwarf.commitDeclState( + &self.base, + mod, + decl, + // Actual value will be written after relocation + 0, + code.len, + &decl_state.?, + ); + } return self.finishUpdateDecl(decl, code); } @@ -1517,6 +1533,35 @@ fn populateErrorNameTable(self: *Wasm) !void { try self.parseAtom(names_atom, .data); } +pub fn getDebugInfoIndex(self: *Wasm) !u32 { + assert(self.dwarf != null); + return self.debug_info_index orelse { + self.debug_info_index = @intCast(u32, self.segments.items.len); + const segment = try self.segments.addOne(self.base.allocator); + segment.* = .{ + .size = 0, + .offset = 0, + // debug sections always have alignment '1' + .alignment = 1, + }; + return self.debug_info_index.?; + }; +} + +pub fn getDebugLineIndex(self: *Wasm) !u32 { + assert(self.dwarf != null); + return self.debug_line_index orelse { + self.debug_line_index = @intCast(u32, self.segments.items.len); + const segment = try self.segments.addOne(self.base.allocator); + segment.* = .{ + .size = 0, + .offset = 0, + .alignment = 1, + }; + return self.debug_line_index.?; + }; +} + fn resetState(self: *Wasm) void { for (self.segment_info.items) |*segment_info| { self.base.allocator.free(segment_info.name); @@ -1542,6 +1587,7 @@ fn resetState(self: *Wasm) void { self.atoms.clearRetainingCapacity(); self.symbol_atom.clearRetainingCapacity(); self.code_section_index = null; + self.debug_info_index = null; } pub fn flush(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void { @@ -1636,6 +1682,9 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod try self.objects.items[object_index].parseIntoAtoms(self.base.allocator, object_index, self); } + if (self.dwarf) |*dwarf| { + try dwarf.flushModule(&self.base, self.base.options.module.?); + } try self.allocateAtoms(); try self.setupMemory(); self.mapFunctionTable(); -- 2.54.0