authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-09-06 20:21:33+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-09-07 18:59:36+02:00
loga8d137d05ae36870d4e896cf5e37b591d9fa219c
tree720dde8e8f150bb6bb2e63e5506ca337e50eee3d
parent971327d6e0a2cdcfd1a7695d1dea86dbbebd730e
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: support incremental debug info

Although the wasm-linker previously already supported debug information in incremental-mode, this was no longer working as-is with the addition of supporting object-file-parsed debug information. This commit implements the Zig-created debug information structure from scratch which is a lot more robust and also allows being linked with debug information from other object files.

4 files changed, 141 insertions(+), 98 deletions(-)

src/link/Dwarf.zig+27-46
...@@ -861,9 +861,7 @@ pub fn commitDeclState(...@@ -861,9 +861,7 @@ pub fn commitDeclState(
861 },861 },
862 .wasm => {862 .wasm => {
863 const wasm_file = file.cast(File.Wasm).?;863 const wasm_file = file.cast(File.Wasm).?;
864 const segment_index = wasm_file.debug_line_index.?;864 const debug_line = wasm_file.debug_line_atom.?.code;
865 const atom = wasm_file.atoms.get(segment_index).?;
866 const debug_line = atom.getFirstZigAtom().code;
867 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);865 writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len);
868 },866 },
869 else => unreachable,867 else => unreachable,
...@@ -975,24 +973,21 @@ pub fn commitDeclState(...@@ -975,24 +973,21 @@ pub fn commitDeclState(
975 },973 },
976 .wasm => {974 .wasm => {
977 const wasm_file = file.cast(File.Wasm).?;975 const wasm_file = file.cast(File.Wasm).?;
978 const segment_index = wasm_file.debug_line_index.?;976 const atom = wasm_file.debug_line_atom.?;
979 const segment = &wasm_file.segments.items[segment_index];977 const debug_line = &atom.code;
980 const atom = wasm_file.atoms.get(segment_index).?;978 const segment_size = debug_line.items.len;
981 const debug_line = &atom.getFirstZigAtom().code;979 if (needed_size != segment_size) {
982 if (needed_size != segment.size) {
983 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});980 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});
984 if (needed_size > segment.size) {981 if (needed_size > segment_size) {
985 log.debug(" allocating {d} bytes for 'debug line' information", .{needed_size - segment.size});982 log.debug(" allocating {d} bytes for 'debug line' information", .{needed_size - segment_size});
986 try debug_line.resize(self.allocator, needed_size);983 try debug_line.resize(self.allocator, needed_size);
987 mem.set(u8, debug_line.items[segment.size..], 0);984 mem.set(u8, debug_line.items[segment_size..], 0);
988 }985 }
989 segment.size = needed_size;
990 debug_line.items.len = needed_size;986 debug_line.items.len = needed_size;
991 }987 }
992 const offset = segment.offset + src_fn.off;
993 writeDbgLineNopsBuffered(988 writeDbgLineNopsBuffered(
994 debug_line.items,989 debug_line.items,
995 offset,990 src_fn.off,
996 prev_padding_size,991 prev_padding_size,
997 dbg_line_buffer.items,992 dbg_line_buffer.items,
998 next_padding_size,993 next_padding_size,
...@@ -1150,12 +1145,8 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3...@@ -1150,12 +1145,8 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3
1150 },1145 },
1151 .wasm => {1146 .wasm => {
1152 const wasm_file = file.cast(File.Wasm).?;1147 const wasm_file = file.cast(File.Wasm).?;
1153 const segment_index = wasm_file.debug_info_index.?;1148 const debug_info = &wasm_file.debug_info_atom.?.code;
1154 const segment = &wasm_file.segments.items[segment_index];1149 try writeDbgInfoNopsToArrayList(gpa, debug_info, atom.off, 0, &.{0}, atom.len, false);
1155 const info_atom = wasm_file.atoms.get(segment_index).?;
1156 const debug_info = &info_atom.getFirstZigAtom().code;
1157 const offset = segment.offset + atom.off;
1158 try writeDbgInfoNopsToArrayList(gpa, debug_info, offset, 0, &.{0}, atom.len, false);
1159 },1150 },
1160 else => unreachable,1151 else => unreachable,
1161 }1152 }
...@@ -1282,28 +1273,25 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1282,28 +1273,25 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
1282 },1273 },
1283 .wasm => {1274 .wasm => {
1284 const wasm_file = file.cast(File.Wasm).?;1275 const wasm_file = file.cast(File.Wasm).?;
1285 const segment_index = wasm_file.debug_info_index.?;1276 const info_atom = wasm_file.debug_info_atom.?;
1286 const segment = &wasm_file.segments.items[segment_index];1277 const debug_info = &info_atom.code;
1287 const info_atom = wasm_file.atoms.get(segment_index).?;1278 const segment_size = debug_info.items.len;
1288 const debug_info = &info_atom.getFirstZigAtom().code;1279 if (needed_size != segment_size) {
1289 if (needed_size != segment.size) {
1290 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});1280 log.debug(" needed size does not equal allocated size: {d}", .{needed_size});
1291 if (needed_size > segment.size) {1281 if (needed_size > segment_size) {
1292 log.debug(" allocating {d} bytes for 'debug info' information", .{needed_size - segment.size});1282 log.debug(" allocating {d} bytes for 'debug info' information", .{needed_size - segment_size});
1293 try debug_info.resize(self.allocator, needed_size);1283 try debug_info.resize(self.allocator, needed_size);
1294 mem.set(u8, debug_info.items[segment.size..], 0);1284 mem.set(u8, debug_info.items[segment_size..], 0);
1295 }1285 }
1296 segment.size = needed_size;
1297 debug_info.items.len = needed_size;1286 debug_info.items.len = needed_size;
1298 }1287 }
1299 const offset = segment.offset + atom.off;
1300 log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{1288 log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{
1301 debug_info.items.len, offset, dbg_info_buf.len, next_padding_size,1289 debug_info.items.len, atom.off, dbg_info_buf.len, next_padding_size,
1302 });1290 });
1303 try writeDbgInfoNopsToArrayList(1291 try writeDbgInfoNopsToArrayList(
1304 gpa,1292 gpa,
1305 debug_info,1293 debug_info,
1306 offset,1294 atom.off,
1307 prev_padding_size,1295 prev_padding_size,
1308 dbg_info_buf,1296 dbg_info_buf,
1309 next_padding_size,1297 next_padding_size,
...@@ -1344,10 +1332,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)...@@ -1344,10 +1332,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)
1344 },1332 },
1345 .wasm => {1333 .wasm => {
1346 const wasm_file = file.cast(File.Wasm).?;1334 const wasm_file = file.cast(File.Wasm).?;
1347 const segment_index = wasm_file.debug_line_index.?;1335 const offset = decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff();
1348 const segment = wasm_file.segments.items[segment_index];1336 const atom = wasm_file.debug_line_atom.?;
1349 const offset = segment.offset + decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff();
1350 const atom = wasm_file.atoms.get(segment_index).?.getFirstZigAtom();
1351 mem.copy(u8, atom.code.items[offset..], &data);1337 mem.copy(u8, atom.code.items[offset..], &data);
1352 },1338 },
1353 else => unreachable,1339 else => unreachable,
...@@ -1584,8 +1570,7 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {...@@ -1584,8 +1570,7 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
1584 },1570 },
1585 .wasm => {1571 .wasm => {
1586 const wasm_file = file.cast(File.Wasm).?;1572 const wasm_file = file.cast(File.Wasm).?;
1587 const segment_index = wasm_file.debug_abbrev_index.?;1573 const debug_abbrev = &wasm_file.debug_abbrev_atom.?.code;
1588 const debug_abbrev = &wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code;
1589 try debug_abbrev.resize(wasm_file.base.allocator, needed_size);1574 try debug_abbrev.resize(wasm_file.base.allocator, needed_size);
1590 mem.copy(u8, debug_abbrev.items, &abbrev_buf);1575 mem.copy(u8, debug_abbrev.items, &abbrev_buf);
1591 },1576 },
...@@ -1697,8 +1682,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6...@@ -1697,8 +1682,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1697 },1682 },
1698 .wasm => {1683 .wasm => {
1699 const wasm_file = file.cast(File.Wasm).?;1684 const wasm_file = file.cast(File.Wasm).?;
1700 const segment_index = wasm_file.debug_info_index.?;1685 const debug_info = &wasm_file.debug_info_atom.?.code;
1701 const debug_info = &wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code;
1702 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);1686 try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false);
1703 },1687 },
1704 else => unreachable,1688 else => unreachable,
...@@ -2028,8 +2012,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {...@@ -2028,8 +2012,7 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
2028 },2012 },
2029 .wasm => {2013 .wasm => {
2030 const wasm_file = file.cast(File.Wasm).?;2014 const wasm_file = file.cast(File.Wasm).?;
2031 const segment_index = wasm_file.debug_ranges_index.?;2015 const debug_ranges = &wasm_file.debug_ranges_atom.?.code;
2032 const debug_ranges = &wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code;
2033 try debug_ranges.resize(wasm_file.base.allocator, needed_size);2016 try debug_ranges.resize(wasm_file.base.allocator, needed_size);
2034 mem.copy(u8, debug_ranges.items, di_buf.items);2017 mem.copy(u8, debug_ranges.items, di_buf.items);
2035 },2018 },
...@@ -2153,8 +2136,7 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2153,8 +2136,7 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
2153 },2136 },
2154 .wasm => {2137 .wasm => {
2155 const wasm_file = file.cast(File.Wasm).?;2138 const wasm_file = file.cast(File.Wasm).?;
2156 const segment_index = wasm_file.debug_line_index.?;2139 const debug_line = wasm_file.debug_line_atom.?.code;
2157 const debug_line = wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code;
2158 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);2140 writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt);
2159 },2141 },
2160 else => unreachable,2142 else => unreachable,
...@@ -2303,8 +2285,7 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2303,8 +2285,7 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
2303 },2285 },
2304 .wasm => {2286 .wasm => {
2305 const wasm_file = file.cast(File.Wasm).?;2287 const wasm_file = file.cast(File.Wasm).?;
2306 const segment_index = wasm_file.debug_info_index.?;2288 const debug_info = wasm_file.debug_info_atom.?.code;
2307 const debug_info = wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code;
2308 mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf);2289 mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf);
2309 },2290 },
2310 else => unreachable,2291 else => unreachable,
src/link/Wasm.zig+112-44
...@@ -95,9 +95,10 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, types.Import) = .{},...@@ -95,9 +95,10 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, types.Import) = .{},
95segments: std.ArrayListUnmanaged(Segment) = .{},95segments: std.ArrayListUnmanaged(Segment) = .{},
96/// Maps a data segment key (such as .rodata) to the index into `segments`.96/// Maps a data segment key (such as .rodata) to the index into `segments`.
97data_segments: std.StringArrayHashMapUnmanaged(u32) = .{},97data_segments: std.StringArrayHashMapUnmanaged(u32) = .{},
98/// A list of `types.Segment` which provide meta data98/// A table of `types.Segment` which provide meta data
99/// about a data symbol such as its name99/// about a data symbol such as its name where the key is
100segment_info: std.ArrayListUnmanaged(types.Segment) = .{},100/// the segment index, which can be found from `data_segments`
101segment_info: std.AutoArrayHashMapUnmanaged(u32, types.Segment) = .{},
101/// Deduplicated string table for strings used by symbols, imports and exports.102/// Deduplicated string table for strings used by symbols, imports and exports.
102string_table: StringTable = .{},103string_table: StringTable = .{},
103/// Debug information for wasm104/// Debug information for wasm
...@@ -158,6 +159,19 @@ export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},...@@ -158,6 +159,19 @@ export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{},
158/// The actual table is populated during `flush`.159/// The actual table is populated during `flush`.
159error_table_symbol: ?u32 = null,160error_table_symbol: ?u32 = null,
160161
162// Debug section atoms. These are only set when the current compilation
163// unit contains Zig code. The lifetime of these atoms are extended
164// until the end of the compiler's lifetime. Meaning they're not freed
165// during `flush()` in incremental-mode.
166debug_info_atom: ?*Atom = null,
167debug_line_atom: ?*Atom = null,
168debug_loc_atom: ?*Atom = null,
169debug_ranges_atom: ?*Atom = null,
170debug_abbrev_atom: ?*Atom = null,
171debug_str_atom: ?*Atom = null,
172debug_pubnames_atom: ?*Atom = null,
173debug_pubtypes_atom: ?*Atom = null,
174
161pub const Segment = struct {175pub const Segment = struct {
162 alignment: u32,176 alignment: u32,
163 size: u32,177 size: u32,
...@@ -384,15 +398,16 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {...@@ -384,15 +398,16 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
384/// and symbols come from the object files instead.398/// and symbols come from the object files instead.
385pub fn initDebugSections(self: *Wasm) !void {399pub fn initDebugSections(self: *Wasm) !void {
386 if (self.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections400 if (self.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections
401 assert(self.debug_info_index == null);
387 // this will create an Atom and set the index for us.402 // this will create an Atom and set the index for us.
388 try self.createDebugSectionForIndex(&self.debug_info_index);403 self.debug_info_atom = try self.createDebugSectionForIndex(&self.debug_info_index, ".debug_info");
389 try self.createDebugSectionForIndex(&self.debug_line_index);404 self.debug_line_atom = try self.createDebugSectionForIndex(&self.debug_line_index, ".debug_line");
390 try self.createDebugSectionForIndex(&self.debug_loc_index);405 self.debug_loc_atom = try self.createDebugSectionForIndex(&self.debug_loc_index, ".debug_loc");
391 try self.createDebugSectionForIndex(&self.debug_abbrev_index);406 self.debug_abbrev_atom = try self.createDebugSectionForIndex(&self.debug_abbrev_index, ".debug_abbrev");
392 try self.createDebugSectionForIndex(&self.debug_ranges_index);407 self.debug_ranges_atom = try self.createDebugSectionForIndex(&self.debug_ranges_index, ".debug_ranges");
393 try self.createDebugSectionForIndex(&self.debug_str_index);408 self.debug_str_atom = try self.createDebugSectionForIndex(&self.debug_str_index, ".debug_str");
394 try self.createDebugSectionForIndex(&self.debug_pubnames_index);409 self.debug_pubnames_atom = try self.createDebugSectionForIndex(&self.debug_pubnames_index, ".debug_pubnames");
395 try self.createDebugSectionForIndex(&self.debug_pubtypes_index);410 self.debug_pubtypes_atom = try self.createDebugSectionForIndex(&self.debug_pubtypes_index, ".debug_pubtypes");
396}411}
397412
398fn parseInputFiles(self: *Wasm, files: []const []const u8) !void {413fn parseInputFiles(self: *Wasm, files: []const []const u8) !void {
...@@ -676,7 +691,7 @@ pub fn deinit(self: *Wasm) void {...@@ -676,7 +691,7 @@ pub fn deinit(self: *Wasm) void {
676 for (self.func_types.items) |*func_type| {691 for (self.func_types.items) |*func_type| {
677 func_type.deinit(gpa);692 func_type.deinit(gpa);
678 }693 }
679 for (self.segment_info.items) |segment_info| {694 for (self.segment_info.values()) |segment_info| {
680 gpa.free(segment_info.name);695 gpa.free(segment_info.name);
681 }696 }
682 for (self.objects.items) |*object| {697 for (self.objects.items) |*object| {
...@@ -1364,16 +1379,7 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {...@@ -1364,16 +1379,7 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
1364 const index = gop.value_ptr.*;1379 const index = gop.value_ptr.*;
1365 self.segments.items[index].size += atom.size;1380 self.segments.items[index].size += atom.size;
13661381
1367 // segment indexes can be off by 1 due to also containing a segment1382 symbol.index = @intCast(u32, self.segment_info.getIndex(index).?);
1368 // for the code section, so we must check if the existing segment
1369 // is larger than that of the code section, and substract the index by 1 in such case.
1370 var info_add = if (self.code_section_index) |idx| blk: {
1371 if (idx < index) break :blk @as(u32, 1);
1372 break :blk 0;
1373 } else @as(u32, 0);
1374 if (self.debug_info_index != null) info_add += 1;
1375 if (self.debug_line_index != null) info_add += 1;
1376 symbol.index = index - info_add;
1377 // segment info already exists, so free its memory1383 // segment info already exists, so free its memory
1378 self.base.allocator.free(segment_name);1384 self.base.allocator.free(segment_name);
1379 break :result index;1385 break :result index;
...@@ -1386,8 +1392,8 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {...@@ -1386,8 +1392,8 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
1386 });1392 });
1387 gop.value_ptr.* = index;1393 gop.value_ptr.* = index;
13881394
1389 const info_index = @intCast(u32, self.segment_info.items.len);1395 const info_index = @intCast(u32, self.segment_info.count());
1390 try self.segment_info.append(self.base.allocator, segment_info);1396 try self.segment_info.put(self.base.allocator, index, segment_info);
1391 symbol.index = info_index;1397 symbol.index = info_index;
1392 break :result index;1398 break :result index;
1393 }1399 }
...@@ -1397,18 +1403,54 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {...@@ -1397,18 +1403,54 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
1397 const segment: *Segment = &self.segments.items[final_index];1403 const segment: *Segment = &self.segments.items[final_index];
1398 segment.alignment = std.math.max(segment.alignment, atom.alignment);1404 segment.alignment = std.math.max(segment.alignment, atom.alignment);
13991405
1400 if (self.atoms.getPtr(final_index)) |last| {1406 try self.appendAtomAtIndex(final_index, atom);
1407}
1408
1409/// From a given index, append the given `Atom` at the back of the linked list.
1410/// Simply inserts it into the map of atoms when it doesn't exist yet.
1411pub fn appendAtomAtIndex(self: *Wasm, index: u32, atom: *Atom) !void {
1412 if (self.atoms.getPtr(index)) |last| {
1401 last.*.next = atom;1413 last.*.next = atom;
1402 atom.prev = last.*;1414 atom.prev = last.*;
1403 last.* = atom;1415 last.* = atom;
1404 } else {1416 } else {
1405 try self.atoms.putNoClobber(self.base.allocator, final_index, atom);1417 try self.atoms.putNoClobber(self.base.allocator, index, atom);
1406 }1418 }
1407}1419}
14081420
1421/// Allocates debug atoms into their respective debug sections
1422/// to merge them with maybe-existing debug atoms from object files.
1423fn allocateDebugAtoms(self: *Wasm) !void {
1424 if (self.dwarf == null) return;
1425
1426 const allocAtom = struct {
1427 fn f(bin: *Wasm, maybe_index: *?u32, atom: *Atom) !void {
1428 const index = maybe_index.* orelse idx: {
1429 const index = @intCast(u32, bin.segments.items.len);
1430 try bin.appendDummySegment();
1431 maybe_index.* = index;
1432 break :idx index;
1433 };
1434 atom.size = @intCast(u32, atom.code.items.len);
1435 bin.symbols.items[atom.sym_index].index = index;
1436 try bin.appendAtomAtIndex(index, atom);
1437 }
1438 }.f;
1439
1440 try allocAtom(self, &self.debug_info_index, self.debug_info_atom.?);
1441 try allocAtom(self, &self.debug_line_index, self.debug_line_atom.?);
1442 try allocAtom(self, &self.debug_loc_index, self.debug_loc_atom.?);
1443 try allocAtom(self, &self.debug_str_index, self.debug_str_atom.?);
1444 try allocAtom(self, &self.debug_ranges_index, self.debug_ranges_atom.?);
1445 try allocAtom(self, &self.debug_abbrev_index, self.debug_abbrev_atom.?);
1446 try allocAtom(self, &self.debug_pubnames_index, self.debug_pubnames_atom.?);
1447 try allocAtom(self, &self.debug_pubtypes_index, self.debug_pubtypes_atom.?);
1448}
1449
1409fn allocateAtoms(self: *Wasm) !void {1450fn allocateAtoms(self: *Wasm) !void {
1410 // first sort the data segments1451 // first sort the data segments
1411 try sortDataSegments(self);1452 try sortDataSegments(self);
1453 try allocateDebugAtoms(self);
14121454
1413 var it = self.atoms.iterator();1455 var it = self.atoms.iterator();
1414 while (it.next()) |entry| {1456 while (it.next()) |entry| {
...@@ -1426,7 +1468,7 @@ fn allocateAtoms(self: *Wasm) !void {...@@ -1426,7 +1468,7 @@ fn allocateAtoms(self: *Wasm) !void {
1426 atom.size,1468 atom.size,
1427 });1469 });
1428 offset += atom.size;1470 offset += atom.size;
1429 self.symbol_atom.putAssumeCapacity(atom.symbolLoc(), atom); // Update atom pointers1471 try self.symbol_atom.put(self.base.allocator, atom.symbolLoc(), atom); // Update atom pointers
1430 atom = atom.next orelse break;1472 atom = atom.next orelse break;
1431 }1473 }
1432 segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);1474 segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);
...@@ -1989,20 +2031,35 @@ fn populateErrorNameTable(self: *Wasm) !void {...@@ -1989,20 +2031,35 @@ fn populateErrorNameTable(self: *Wasm) !void {
1989/// From a given index variable, creates a new debug section.2031/// From a given index variable, creates a new debug section.
1990/// This initializes the index, appends a new segment,2032/// This initializes the index, appends a new segment,
1991/// and finally, creates a managed `Atom`.2033/// and finally, creates a managed `Atom`.
1992pub fn createDebugSectionForIndex(self: *Wasm, index: *?u32) !void {2034pub fn createDebugSectionForIndex(self: *Wasm, index: *?u32, name: []const u8) !*Atom {
1993 const new_index = @intCast(u32, self.segments.items.len);2035 const new_index = @intCast(u32, self.segments.items.len);
1994 index.* = new_index;2036 index.* = new_index;
1995 try self.appendDummySegment();2037 try self.appendDummySegment();
2038 // _ = index;
2039
2040 const sym_index = self.symbols_free_list.popOrNull() orelse idx: {
2041 const tmp_index = @intCast(u32, self.symbols.items.len);
2042 _ = try self.symbols.addOne(self.base.allocator);
2043 break :idx tmp_index;
2044 };
2045 self.symbols.items[sym_index] = .{
2046 .tag = .section,
2047 .name = try self.string_table.put(self.base.allocator, name),
2048 .index = 0,
2049 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
2050 };
19962051
1997 const atom = try self.base.allocator.create(Atom);2052 const atom = try self.base.allocator.create(Atom);
1998 atom.* = Atom.empty;2053 atom.* = Atom.empty;
1999 atom.alignment = 1; // debug sections are always 1-byte-aligned2054 atom.alignment = 1; // debug sections are always 1-byte-aligned
2055 atom.sym_index = sym_index;
2000 try self.managed_atoms.append(self.base.allocator, atom);2056 try self.managed_atoms.append(self.base.allocator, atom);
2001 try self.atoms.put(self.base.allocator, new_index, atom);2057 try self.symbol_atom.put(self.base.allocator, atom.symbolLoc(), atom);
2058 return atom;
2002}2059}
20032060
2004fn resetState(self: *Wasm) void {2061fn resetState(self: *Wasm) void {
2005 for (self.segment_info.items) |*segment_info| {2062 for (self.segment_info.values()) |segment_info| {
2006 self.base.allocator.free(segment_info.name);2063 self.base.allocator.free(segment_info.name);
2007 }2064 }
2008 if (self.base.options.module) |mod| {2065 if (self.base.options.module) |mod| {
...@@ -2029,6 +2086,12 @@ fn resetState(self: *Wasm) void {...@@ -2029,6 +2086,12 @@ fn resetState(self: *Wasm) void {
2029 self.code_section_index = null;2086 self.code_section_index = null;
2030 self.debug_info_index = null;2087 self.debug_info_index = null;
2031 self.debug_line_index = null;2088 self.debug_line_index = null;
2089 self.debug_loc_index = null;
2090 self.debug_str_index = null;
2091 self.debug_ranges_index = null;
2092 self.debug_abbrev_index = null;
2093 self.debug_pubnames_index = null;
2094 self.debug_pubtypes_index = null;
2032}2095}
20332096
2034pub fn flush(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {2097pub fn flush(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {
...@@ -2508,26 +2571,31 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2508,26 +2571,31 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2508 var debug_bytes = std.ArrayList(u8).init(self.base.allocator);2571 var debug_bytes = std.ArrayList(u8).init(self.base.allocator);
2509 defer debug_bytes.deinit();2572 defer debug_bytes.deinit();
25102573
2511 const debug_sections = .{2574 const DebugSection = struct {
2512 .{ ".debug_info", self.debug_info_index },2575 name: []const u8,
2513 .{ ".debug_pubtypes", self.debug_pubtypes_index },2576 index: ?u32,
2514 .{ ".debug_abbrev", self.debug_abbrev_index },2577 };
2515 .{ ".debug_line", self.debug_line_index },2578
2516 .{ ".debug_str", self.debug_str_index },2579 const debug_sections: []const DebugSection = &.{
2517 .{ ".debug_pubnames", self.debug_pubnames_index },2580 .{ .name = ".debug_info", .index = self.debug_info_index },
2518 .{ ".debug_loc", self.debug_loc_index },2581 .{ .name = ".debug_pubtypes", .index = self.debug_pubtypes_index },
2519 .{ ".debug_ranges", self.debug_ranges_index },2582 .{ .name = ".debug_abbrev", .index = self.debug_abbrev_index },
2583 .{ .name = ".debug_line", .index = self.debug_line_index },
2584 .{ .name = ".debug_str", .index = self.debug_str_index },
2585 .{ .name = ".debug_pubnames", .index = self.debug_pubnames_index },
2586 .{ .name = ".debug_loc", .index = self.debug_loc_index },
2587 .{ .name = ".debug_ranges", .index = self.debug_ranges_index },
2520 };2588 };
25212589
2522 inline for (debug_sections) |item| {2590 for (debug_sections) |item| {
2523 if (item[1]) |index| {2591 if (item.index) |index| {
2524 var atom = self.atoms.get(index).?.getFirst();2592 var atom = self.atoms.get(index).?.getFirst();
2525 while (true) {2593 while (true) {
2526 atom.resolveRelocs(self);2594 atom.resolveRelocs(self);
2527 try debug_bytes.appendSlice(atom.code.items);2595 try debug_bytes.appendSlice(atom.code.items);
2528 atom = atom.next orelse break;2596 atom = atom.next orelse break;
2529 }2597 }
2530 try emitDebugSection(file, debug_bytes.items, item[0]);2598 try emitDebugSection(file, debug_bytes.items, item.name);
2531 debug_bytes.clearRetainingCapacity();2599 debug_bytes.clearRetainingCapacity();
2532 }2600 }
2533 }2601 }
...@@ -3242,8 +3310,8 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {...@@ -3242,8 +3310,8 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {
3242 var payload = std.ArrayList(u8).init(arena);3310 var payload = std.ArrayList(u8).init(arena);
3243 const writer = payload.writer();3311 const writer = payload.writer();
3244 try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SEGMENT_INFO));3312 try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SEGMENT_INFO));
3245 try leb.writeULEB128(writer, @intCast(u32, self.segment_info.items.len));3313 try leb.writeULEB128(writer, @intCast(u32, self.segment_info.count()));
3246 for (self.segment_info.items) |segment_info| {3314 for (self.segment_info.values()) |segment_info| {
3247 log.debug("Emit segment: {s} align({d}) flags({b})", .{3315 log.debug("Emit segment: {s} align({d}) flags({b})", .{
3248 segment_info.name,3316 segment_info.name,
3249 @ctz(segment_info.alignment),3317 @ctz(segment_info.alignment),
src/link/Wasm/Atom.zig+1-1
...@@ -190,7 +190,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa...@@ -190,7 +190,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
190 const target_atom = wasm_bin.symbol_atom.get(target_loc).?;190 const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
191 const segment_info = if (target_atom.file) |object_index| blk: {191 const segment_info = if (target_atom.file) |object_index| blk: {
192 break :blk wasm_bin.objects.items[object_index].segment_info;192 break :blk wasm_bin.objects.items[object_index].segment_info;
193 } else wasm_bin.segment_info.items;193 } else wasm_bin.segment_info.values();
194 const segment_name = segment_info[symbol.index].outputName(merge_segment);194 const segment_name = segment_info[symbol.index].outputName(merge_segment);
195 const segment_index = wasm_bin.data_segments.get(segment_name).?;195 const segment_index = wasm_bin.data_segments.get(segment_name).?;
196 const segment = wasm_bin.segments.items[segment_index];196 const segment = wasm_bin.segments.items[segment_index];
src/link/Wasm/Object.zig+1-7
...@@ -953,13 +953,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin...@@ -953,13 +953,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
953 segment.alignment = std.math.max(segment.alignment, atom.alignment);953 segment.alignment = std.math.max(segment.alignment, atom.alignment);
954 }954 }
955955
956 if (wasm_bin.atoms.getPtr(final_index)) |last| {956 try wasm_bin.appendAtomAtIndex(final_index, atom);
957 last.*.next = atom;
958 atom.prev = last.*;
959 last.* = atom;
960 } else {
961 try wasm_bin.atoms.putNoClobber(gpa, final_index, atom);
962 }
963 log.debug("Parsed into atom: '{s}' at segment index {d}", .{ self.string_table.get(self.symtable[atom.sym_index].name), final_index });957 log.debug("Parsed into atom: '{s}' at segment index {d}", .{ self.string_table.get(self.symtable[atom.sym_index].name), final_index });
964 }958 }
965}959}