aboutsummaryrefslogtreecommitdiff
path: root/src/link/Wasm.zig
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2022-05-04 21:25:33 +0200
committerLuuk de Gram <luuk@degram.dev>2022-05-09 18:51:46 +0200
commit2ae2ac33d9ddd1fb181e08a811d97b1bf238bced (patch)
treea9b3d1f461ef443259d947f3840cb4e3da5e19b6 /src/link/Wasm.zig
parent9b6b7034c20a0089b88e58b5142c91b2d26bcef8 (diff)
downloadzig-2ae2ac33d9ddd1fb181e08a811d97b1bf238bced.tar.gz
zig-2ae2ac33d9ddd1fb181e08a811d97b1bf238bced.zip
wasm: Emit debug sections
This commit adds the ability to emit the following debug sections: .debug_info .debug_abbrev .debug_line .debug_str Line information and files are now being loaded correctly by browser debuggers.
Diffstat (limited to 'src/link/Wasm.zig')
-rw-r--r--src/link/Wasm.zig61
1 files changed, 54 insertions, 7 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index d2ef331a3d..4cc21260c3 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -90,6 +90,14 @@ string_table: StringTable = .{},
/// Debug information for wasm
dwarf: ?Dwarf = null,
+// *debug information* //
+/// Contains all bytes for the '.debug_info' section
+debug_info: std.ArrayListUnmanaged(u8) = .{},
+/// Contains all bytes for the '.debug_line' section
+debug_line: std.ArrayListUnmanaged(u8) = .{},
+/// Contains all bytes for the '.debug_abbrev' section
+debug_abbrev: std.ArrayListUnmanaged(u8) = .{},
+
// Output sections
/// Output type section
func_types: std.ArrayListUnmanaged(wasm.Type) = .{},
@@ -501,6 +509,10 @@ pub fn deinit(self: *Wasm) void {
if (self.dwarf) |*dwarf| {
dwarf.deinit();
}
+
+ self.debug_info.deinit(gpa);
+ self.debug_line.deinit(gpa);
+ self.debug_abbrev.deinit(gpa);
}
pub fn allocateDeclIndexes(self: *Wasm, decl_index: Module.Decl.Index) !void {
@@ -576,7 +588,9 @@ pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
&self.base,
mod,
decl,
- // Actual value will be written after relocation
+ // Actual value will be written after relocation.
+ // For Wasm, this is the offset relative to the code section
+ // which isn't known until flush().
0,
code.len,
&decl_state.?,
@@ -1016,10 +1030,12 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
// segment indexes can be off by 1 due to also containing a segment
// for the code section, so we must check if the existing segment
// is larger than that of the code section, and substract the index by 1 in such case.
- const info_add = if (self.code_section_index) |idx| blk: {
+ var info_add = if (self.code_section_index) |idx| blk: {
if (idx < index) break :blk @as(u32, 1);
break :blk 0;
} else @as(u32, 0);
+ if (self.debug_info_index != null) info_add += 1;
+ if (self.debug_line_index != null) info_add += 1;
symbol.index = index - info_add;
// segment info already exists, so free its memory
self.base.allocator.free(segment_name);
@@ -1320,11 +1336,8 @@ fn setupMemory(self: *Wasm) !void {
}
var offset: u32 = @intCast(u32, memory_ptr);
- for (self.segments.items) |*segment, i| {
- // skip 'code' segments
- if (self.code_section_index) |index| {
- if (index == i) continue;
- }
+ for (self.data_segments.values()) |segment_index| {
+ const segment = &self.segments.items[segment_index];
memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment);
memory_ptr += segment.size;
segment.offset = offset;
@@ -1588,6 +1601,7 @@ fn resetState(self: *Wasm) void {
self.symbol_atom.clearRetainingCapacity();
self.code_section_index = null;
self.debug_info_index = null;
+ self.debug_line_index = null;
}
pub fn flush(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {
@@ -2016,10 +2030,43 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
try self.emitDataRelocations(file, arena, data_index, symbol_table);
}
} else if (!self.base.options.strip) {
+ if (self.dwarf) |*dwarf| {
+ if (self.debug_info_index != null) {
+ _ = dwarf;
+ try dwarf.writeDbgAbbrev(&self.base);
+ try dwarf.writeDbgInfoHeader(&self.base, mod, 0, 0);
+ try dwarf.writeDbgLineHeader(&self.base, mod);
+
+ try emitDebugSection(file, self.debug_info.items, ".debug_info");
+ try emitDebugSection(file, self.debug_abbrev.items, ".debug_abbrev"); // TODO
+ try emitDebugSection(file, self.debug_line.items, ".debug_line");
+ try emitDebugSection(file, dwarf.strtab.items, ".debug_str");
+ }
+ }
try self.emitNameSection(file, arena);
}
}
+fn emitDebugSection(file: fs.File, data: []const u8, name: []const u8) !void {
+ const header_offset = try reserveCustomSectionHeader(file);
+ const writer = file.writer();
+ try leb.writeULEB128(writer, @intCast(u32, name.len));
+ try writer.writeAll(name);
+
+ try file.writevAll(&[_]std.os.iovec_const{.{
+ .iov_base = data.ptr,
+ .iov_len = data.len,
+ }});
+ const start = header_offset + 6 + name.len + getULEB128Size(@intCast(u32, name.len));
+ log.debug("Emit debug section: '{s}' start=0x{x:0>8} end=0x{x:0>8}", .{ name, start, start + data.len });
+
+ try writeCustomSectionHeader(
+ file,
+ header_offset,
+ @intCast(u32, (try file.getPos()) - header_offset - 6),
+ );
+}
+
fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
const Name = struct {
index: u32,