| ... | ... | @@ -67,6 +67,18 @@ code_section_index: ?u32 = null, |
| 67 | 67 | debug_info_index: ?u32 = null, |
| 68 | 68 | /// The index of the segment representing the custom '.debug_line' section. |
| 69 | 69 | debug_line_index: ?u32 = null, |
| 70 | /// The index of the segment representing the custom '.debug_loc' section. |
| 71 | debug_loc_index: ?u32 = null, |
| 72 | /// The index of the segment representing the custom '.debug_ranges' section. |
| 73 | debug_ranges_index: ?u32 = null, |
| 74 | /// The index of the segment representing the custom '.debug_pubnames' section. |
| 75 | debug_pubnames_index: ?u32 = null, |
| 76 | /// The index of the segment representing the custom '.debug_pubtypes' section. |
| 77 | debug_pubtypes_index: ?u32 = null, |
| 78 | /// The index of the segment representing the custom '.debug_pubtypes' section. |
| 79 | debug_str_index: ?u32 = null, |
| 80 | /// The index of the segment representing the custom '.debug_pubtypes' section. |
| 81 | debug_abbrev_index: ?u32 = null, |
| 70 | 82 | /// The count of imported functions. This number will be appended |
| 71 | 83 | /// to the function indexes as their index starts at the lowest non-extern function. |
| 72 | 84 | imported_functions_count: u32 = 0, |
| ... | ... | @@ -83,24 +95,15 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, types.Import) = .{}, |
| 83 | 95 | segments: std.ArrayListUnmanaged(Segment) = .{}, |
| 84 | 96 | /// Maps a data segment key (such as .rodata) to the index into `segments`. |
| 85 | 97 | data_segments: std.StringArrayHashMapUnmanaged(u32) = .{}, |
| 86 | | /// A list of `types.Segment` which provide meta data |
| 87 | | /// about a data symbol such as its name |
| 88 | | segment_info: std.ArrayListUnmanaged(types.Segment) = .{}, |
| 98 | /// A table of `types.Segment` which provide meta data |
| 99 | /// about a data symbol such as its name where the key is |
| 100 | /// the segment index, which can be found from `data_segments` |
| 101 | segment_info: std.AutoArrayHashMapUnmanaged(u32, types.Segment) = .{}, |
| 89 | 102 | /// Deduplicated string table for strings used by symbols, imports and exports. |
| 90 | 103 | string_table: StringTable = .{}, |
| 91 | 104 | /// Debug information for wasm |
| 92 | 105 | dwarf: ?Dwarf = null, |
| 93 | 106 | |
| 94 | | // *debug information* // |
| 95 | | /// Contains all bytes for the '.debug_info' section |
| 96 | | debug_info: std.ArrayListUnmanaged(u8) = .{}, |
| 97 | | /// Contains all bytes for the '.debug_line' section |
| 98 | | debug_line: std.ArrayListUnmanaged(u8) = .{}, |
| 99 | | /// Contains all bytes for the '.debug_abbrev' section |
| 100 | | debug_abbrev: std.ArrayListUnmanaged(u8) = .{}, |
| 101 | | /// Contains all bytes for the '.debug_ranges' section |
| 102 | | debug_aranges: std.ArrayListUnmanaged(u8) = .{}, |
| 103 | | |
| 104 | 107 | // Output sections |
| 105 | 108 | /// Output type section |
| 106 | 109 | func_types: std.ArrayListUnmanaged(wasm.Type) = .{}, |
| ... | ... | @@ -156,6 +159,19 @@ export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{}, |
| 156 | 159 | /// The actual table is populated during `flush`. |
| 157 | 160 | error_table_symbol: ?u32 = null, |
| 158 | 161 | |
| 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. |
| 166 | debug_info_atom: ?*Atom = null, |
| 167 | debug_line_atom: ?*Atom = null, |
| 168 | debug_loc_atom: ?*Atom = null, |
| 169 | debug_ranges_atom: ?*Atom = null, |
| 170 | debug_abbrev_atom: ?*Atom = null, |
| 171 | debug_str_atom: ?*Atom = null, |
| 172 | debug_pubnames_atom: ?*Atom = null, |
| 173 | debug_pubtypes_atom: ?*Atom = null, |
| 174 | |
| 159 | 175 | pub const Segment = struct { |
| 160 | 176 | alignment: u32, |
| 161 | 177 | size: u32, |
| ... | ... | @@ -209,6 +225,18 @@ pub const SymbolLoc = struct { |
| 209 | 225 | } |
| 210 | 226 | return wasm_bin.string_table.get(wasm_bin.symbols.items[self.index].name); |
| 211 | 227 | } |
| 228 | |
| 229 | /// From a given symbol location, returns the final location. |
| 230 | /// e.g. when a symbol was resolved and replaced by the symbol |
| 231 | /// in a different file, this will return said location. |
| 232 | /// If the symbol wasn't replaced by another, this will return |
| 233 | /// the given location itself. |
| 234 | pub fn finalLoc(self: SymbolLoc, wasm_bin: *const Wasm) SymbolLoc { |
| 235 | if (wasm_bin.discarded.get(self)) |new_loc| { |
| 236 | return new_loc.finalLoc(wasm_bin); |
| 237 | } |
| 238 | return self; |
| 239 | } |
| 212 | 240 | }; |
| 213 | 241 | |
| 214 | 242 | /// Generic string table that duplicates strings |
| ... | ... | @@ -335,6 +363,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 335 | 363 | }; |
| 336 | 364 | } |
| 337 | 365 | |
| 366 | try wasm_bin.initDebugSections(); |
| 338 | 367 | return wasm_bin; |
| 339 | 368 | } |
| 340 | 369 | |
| ... | ... | @@ -363,6 +392,24 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { |
| 363 | 392 | return self; |
| 364 | 393 | } |
| 365 | 394 | |
| 395 | /// Initializes symbols and atoms for the debug sections |
| 396 | /// Initialization is only done when compiling Zig code. |
| 397 | /// When Zig is invoked as a linker instead, the atoms |
| 398 | /// and symbols come from the object files instead. |
| 399 | pub fn initDebugSections(self: *Wasm) !void { |
| 400 | if (self.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections |
| 401 | assert(self.debug_info_index == null); |
| 402 | // this will create an Atom and set the index for us. |
| 403 | self.debug_info_atom = try self.createDebugSectionForIndex(&self.debug_info_index, ".debug_info"); |
| 404 | self.debug_line_atom = try self.createDebugSectionForIndex(&self.debug_line_index, ".debug_line"); |
| 405 | self.debug_loc_atom = try self.createDebugSectionForIndex(&self.debug_loc_index, ".debug_loc"); |
| 406 | self.debug_abbrev_atom = try self.createDebugSectionForIndex(&self.debug_abbrev_index, ".debug_abbrev"); |
| 407 | self.debug_ranges_atom = try self.createDebugSectionForIndex(&self.debug_ranges_index, ".debug_ranges"); |
| 408 | self.debug_str_atom = try self.createDebugSectionForIndex(&self.debug_str_index, ".debug_str"); |
| 409 | self.debug_pubnames_atom = try self.createDebugSectionForIndex(&self.debug_pubnames_index, ".debug_pubnames"); |
| 410 | self.debug_pubtypes_atom = try self.createDebugSectionForIndex(&self.debug_pubtypes_index, ".debug_pubtypes"); |
| 411 | } |
| 412 | |
| 366 | 413 | fn parseInputFiles(self: *Wasm, files: []const []const u8) !void { |
| 367 | 414 | for (files) |path| { |
| 368 | 415 | if (try self.parseObjectFile(path)) continue; |
| ... | ... | @@ -644,7 +691,7 @@ pub fn deinit(self: *Wasm) void { |
| 644 | 691 | for (self.func_types.items) |*func_type| { |
| 645 | 692 | func_type.deinit(gpa); |
| 646 | 693 | } |
| 647 | | for (self.segment_info.items) |segment_info| { |
| 694 | for (self.segment_info.values()) |segment_info| { |
| 648 | 695 | gpa.free(segment_info.name); |
| 649 | 696 | } |
| 650 | 697 | for (self.objects.items) |*object| { |
| ... | ... | @@ -692,11 +739,6 @@ pub fn deinit(self: *Wasm) void { |
| 692 | 739 | if (self.dwarf) |*dwarf| { |
| 693 | 740 | dwarf.deinit(); |
| 694 | 741 | } |
| 695 | | |
| 696 | | self.debug_info.deinit(gpa); |
| 697 | | self.debug_line.deinit(gpa); |
| 698 | | self.debug_abbrev.deinit(gpa); |
| 699 | | self.debug_aranges.deinit(gpa); |
| 700 | 742 | } |
| 701 | 743 | |
| 702 | 744 | pub fn allocateDeclIndexes(self: *Wasm, decl_index: Module.Decl.Index) !void { |
| ... | ... | @@ -1337,16 +1379,7 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 1337 | 1379 | const index = gop.value_ptr.*; |
| 1338 | 1380 | self.segments.items[index].size += atom.size; |
| 1339 | 1381 | |
| 1340 | | // segment indexes can be off by 1 due to also containing a segment |
| 1341 | | // for the code section, so we must check if the existing segment |
| 1342 | | // is larger than that of the code section, and substract the index by 1 in such case. |
| 1343 | | var info_add = if (self.code_section_index) |idx| blk: { |
| 1344 | | if (idx < index) break :blk @as(u32, 1); |
| 1345 | | break :blk 0; |
| 1346 | | } else @as(u32, 0); |
| 1347 | | if (self.debug_info_index != null) info_add += 1; |
| 1348 | | if (self.debug_line_index != null) info_add += 1; |
| 1349 | | symbol.index = index - info_add; |
| 1382 | symbol.index = @intCast(u32, self.segment_info.getIndex(index).?); |
| 1350 | 1383 | // segment info already exists, so free its memory |
| 1351 | 1384 | self.base.allocator.free(segment_name); |
| 1352 | 1385 | break :result index; |
| ... | ... | @@ -1359,8 +1392,8 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 1359 | 1392 | }); |
| 1360 | 1393 | gop.value_ptr.* = index; |
| 1361 | 1394 | |
| 1362 | | const info_index = @intCast(u32, self.segment_info.items.len); |
| 1363 | | try self.segment_info.append(self.base.allocator, segment_info); |
| 1395 | const info_index = @intCast(u32, self.segment_info.count()); |
| 1396 | try self.segment_info.put(self.base.allocator, index, segment_info); |
| 1364 | 1397 | symbol.index = info_index; |
| 1365 | 1398 | break :result index; |
| 1366 | 1399 | } |
| ... | ... | @@ -1370,18 +1403,54 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 1370 | 1403 | const segment: *Segment = &self.segments.items[final_index]; |
| 1371 | 1404 | segment.alignment = std.math.max(segment.alignment, atom.alignment); |
| 1372 | 1405 | |
| 1373 | | 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. |
| 1411 | pub fn appendAtomAtIndex(self: *Wasm, index: u32, atom: *Atom) !void { |
| 1412 | if (self.atoms.getPtr(index)) |last| { |
| 1374 | 1413 | last.*.next = atom; |
| 1375 | 1414 | atom.prev = last.*; |
| 1376 | 1415 | last.* = atom; |
| 1377 | 1416 | } else { |
| 1378 | | try self.atoms.putNoClobber(self.base.allocator, final_index, atom); |
| 1417 | try self.atoms.putNoClobber(self.base.allocator, index, atom); |
| 1379 | 1418 | } |
| 1380 | 1419 | } |
| 1381 | 1420 | |
| 1421 | /// Allocates debug atoms into their respective debug sections |
| 1422 | /// to merge them with maybe-existing debug atoms from object files. |
| 1423 | fn 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 | |
| 1382 | 1450 | fn allocateAtoms(self: *Wasm) !void { |
| 1383 | 1451 | // first sort the data segments |
| 1384 | 1452 | try sortDataSegments(self); |
| 1453 | try allocateDebugAtoms(self); |
| 1385 | 1454 | |
| 1386 | 1455 | var it = self.atoms.iterator(); |
| 1387 | 1456 | while (it.next()) |entry| { |
| ... | ... | @@ -1399,7 +1468,7 @@ fn allocateAtoms(self: *Wasm) !void { |
| 1399 | 1468 | atom.size, |
| 1400 | 1469 | }); |
| 1401 | 1470 | offset += atom.size; |
| 1402 | | self.symbol_atom.putAssumeCapacity(atom.symbolLoc(), atom); // Update atom pointers |
| 1471 | try self.symbol_atom.put(self.base.allocator, atom.symbolLoc(), atom); // Update atom pointers |
| 1403 | 1472 | atom = atom.next orelse break; |
| 1404 | 1473 | } |
| 1405 | 1474 | segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment); |
| ... | ... | @@ -1753,7 +1822,7 @@ fn setupMemory(self: *Wasm) !void { |
| 1753 | 1822 | /// From a given object's index and the index of the segment, returns the corresponding |
| 1754 | 1823 | /// index of the segment within the final data section. When the segment does not yet |
| 1755 | 1824 | /// exist, a new one will be initialized and appended. The new index will be returned in that case. |
| 1756 | | pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32) !u32 { |
| 1825 | pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32) !?u32 { |
| 1757 | 1826 | const object: Object = self.objects.items[object_index]; |
| 1758 | 1827 | const relocatable_data = object.relocatable_data[relocatable_index]; |
| 1759 | 1828 | const index = @intCast(u32, self.segments.items.len); |
| ... | ... | @@ -1765,27 +1834,83 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32 |
| 1765 | 1834 | const result = try self.data_segments.getOrPut(self.base.allocator, segment_info.outputName(merge_segment)); |
| 1766 | 1835 | if (!result.found_existing) { |
| 1767 | 1836 | result.value_ptr.* = index; |
| 1768 | | try self.segments.append(self.base.allocator, .{ |
| 1769 | | .alignment = 1, |
| 1770 | | .size = 0, |
| 1771 | | .offset = 0, |
| 1772 | | }); |
| 1837 | try self.appendDummySegment(); |
| 1773 | 1838 | return index; |
| 1774 | 1839 | } else return result.value_ptr.*; |
| 1775 | 1840 | }, |
| 1776 | 1841 | .code => return self.code_section_index orelse blk: { |
| 1777 | 1842 | self.code_section_index = index; |
| 1778 | | try self.segments.append(self.base.allocator, .{ |
| 1779 | | .alignment = 1, |
| 1780 | | .size = 0, |
| 1781 | | .offset = 0, |
| 1782 | | }); |
| 1843 | try self.appendDummySegment(); |
| 1783 | 1844 | break :blk index; |
| 1784 | 1845 | }, |
| 1785 | | .custom => return error.@"TODO: Custom section relocations for wasm", |
| 1846 | .debug => { |
| 1847 | const debug_name = object.getDebugName(relocatable_data); |
| 1848 | if (mem.eql(u8, debug_name, ".debug_info")) { |
| 1849 | return self.debug_info_index orelse blk: { |
| 1850 | self.debug_info_index = index; |
| 1851 | try self.appendDummySegment(); |
| 1852 | break :blk index; |
| 1853 | }; |
| 1854 | } else if (mem.eql(u8, debug_name, ".debug_line")) { |
| 1855 | return self.debug_line_index orelse blk: { |
| 1856 | self.debug_line_index = index; |
| 1857 | try self.appendDummySegment(); |
| 1858 | break :blk index; |
| 1859 | }; |
| 1860 | } else if (mem.eql(u8, debug_name, ".debug_loc")) { |
| 1861 | return self.debug_loc_index orelse blk: { |
| 1862 | self.debug_loc_index = index; |
| 1863 | try self.appendDummySegment(); |
| 1864 | break :blk index; |
| 1865 | }; |
| 1866 | } else if (mem.eql(u8, debug_name, ".debug_ranges")) { |
| 1867 | return self.debug_line_index orelse blk: { |
| 1868 | self.debug_ranges_index = index; |
| 1869 | try self.appendDummySegment(); |
| 1870 | break :blk index; |
| 1871 | }; |
| 1872 | } else if (mem.eql(u8, debug_name, ".debug_pubnames")) { |
| 1873 | return self.debug_pubnames_index orelse blk: { |
| 1874 | self.debug_pubnames_index = index; |
| 1875 | try self.appendDummySegment(); |
| 1876 | break :blk index; |
| 1877 | }; |
| 1878 | } else if (mem.eql(u8, debug_name, ".debug_pubtypes")) { |
| 1879 | return self.debug_pubtypes_index orelse blk: { |
| 1880 | self.debug_pubtypes_index = index; |
| 1881 | try self.appendDummySegment(); |
| 1882 | break :blk index; |
| 1883 | }; |
| 1884 | } else if (mem.eql(u8, debug_name, ".debug_abbrev")) { |
| 1885 | return self.debug_abbrev_index orelse blk: { |
| 1886 | self.debug_abbrev_index = index; |
| 1887 | try self.appendDummySegment(); |
| 1888 | break :blk index; |
| 1889 | }; |
| 1890 | } else if (mem.eql(u8, debug_name, ".debug_str")) { |
| 1891 | return self.debug_str_index orelse blk: { |
| 1892 | self.debug_str_index = index; |
| 1893 | try self.appendDummySegment(); |
| 1894 | break :blk index; |
| 1895 | }; |
| 1896 | } else { |
| 1897 | log.warn("found unknown debug section '{s}'", .{debug_name}); |
| 1898 | log.warn(" debug section will be skipped", .{}); |
| 1899 | return null; |
| 1900 | } |
| 1901 | }, |
| 1786 | 1902 | } |
| 1787 | 1903 | } |
| 1788 | 1904 | |
| 1905 | /// Appends a new segment with default field values |
| 1906 | fn appendDummySegment(self: *Wasm) !void { |
| 1907 | try self.segments.append(self.base.allocator, .{ |
| 1908 | .alignment = 1, |
| 1909 | .size = 0, |
| 1910 | .offset = 0, |
| 1911 | }); |
| 1912 | } |
| 1913 | |
| 1789 | 1914 | /// Returns the symbol index of the error name table. |
| 1790 | 1915 | /// |
| 1791 | 1916 | /// When the symbol does not yet exist, it will create a new one instead. |
| ... | ... | @@ -1903,50 +2028,52 @@ fn populateErrorNameTable(self: *Wasm) !void { |
| 1903 | 2028 | try self.parseAtom(names_atom, .{ .data = .read_only }); |
| 1904 | 2029 | } |
| 1905 | 2030 | |
| 1906 | | pub fn getDebugInfoIndex(self: *Wasm) !u32 { |
| 1907 | | assert(self.dwarf != null); |
| 1908 | | return self.debug_info_index orelse { |
| 1909 | | self.debug_info_index = @intCast(u32, self.segments.items.len); |
| 1910 | | const segment = try self.segments.addOne(self.base.allocator); |
| 1911 | | segment.* = .{ |
| 1912 | | .size = 0, |
| 1913 | | .offset = 0, |
| 1914 | | // debug sections always have alignment '1' |
| 1915 | | .alignment = 1, |
| 1916 | | }; |
| 1917 | | return self.debug_info_index.?; |
| 2031 | /// From a given index variable, creates a new debug section. |
| 2032 | /// This initializes the index, appends a new segment, |
| 2033 | /// and finally, creates a managed `Atom`. |
| 2034 | pub fn createDebugSectionForIndex(self: *Wasm, index: *?u32, name: []const u8) !*Atom { |
| 2035 | const new_index = @intCast(u32, self.segments.items.len); |
| 2036 | index.* = new_index; |
| 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; |
| 1918 | 2044 | }; |
| 1919 | | } |
| 1920 | | |
| 1921 | | pub fn getDebugLineIndex(self: *Wasm) !u32 { |
| 1922 | | assert(self.dwarf != null); |
| 1923 | | return self.debug_line_index orelse { |
| 1924 | | self.debug_line_index = @intCast(u32, self.segments.items.len); |
| 1925 | | const segment = try self.segments.addOne(self.base.allocator); |
| 1926 | | segment.* = .{ |
| 1927 | | .size = 0, |
| 1928 | | .offset = 0, |
| 1929 | | .alignment = 1, |
| 1930 | | }; |
| 1931 | | return self.debug_line_index.?; |
| 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), |
| 1932 | 2050 | }; |
| 2051 | |
| 2052 | const atom = try self.base.allocator.create(Atom); |
| 2053 | atom.* = Atom.empty; |
| 2054 | atom.alignment = 1; // debug sections are always 1-byte-aligned |
| 2055 | atom.sym_index = sym_index; |
| 2056 | try self.managed_atoms.append(self.base.allocator, atom); |
| 2057 | try self.symbol_atom.put(self.base.allocator, atom.symbolLoc(), atom); |
| 2058 | return atom; |
| 1933 | 2059 | } |
| 1934 | 2060 | |
| 1935 | 2061 | fn resetState(self: *Wasm) void { |
| 1936 | | for (self.segment_info.items) |*segment_info| { |
| 2062 | for (self.segment_info.values()) |segment_info| { |
| 1937 | 2063 | self.base.allocator.free(segment_info.name); |
| 1938 | 2064 | } |
| 1939 | | const mod = self.base.options.module.?; |
| 1940 | | var decl_it = self.decls.keyIterator(); |
| 1941 | | while (decl_it.next()) |decl_index_ptr| { |
| 1942 | | const decl = mod.declPtr(decl_index_ptr.*); |
| 1943 | | const atom = &decl.link.wasm; |
| 1944 | | atom.next = null; |
| 1945 | | atom.prev = null; |
| 2065 | if (self.base.options.module) |mod| { |
| 2066 | var decl_it = self.decls.keyIterator(); |
| 2067 | while (decl_it.next()) |decl_index_ptr| { |
| 2068 | const decl = mod.declPtr(decl_index_ptr.*); |
| 2069 | const atom = &decl.link.wasm; |
| 2070 | atom.next = null; |
| 2071 | atom.prev = null; |
| 1946 | 2072 | |
| 1947 | | for (atom.locals.items) |*local_atom| { |
| 1948 | | local_atom.next = null; |
| 1949 | | local_atom.prev = null; |
| 2073 | for (atom.locals.items) |*local_atom| { |
| 2074 | local_atom.next = null; |
| 2075 | local_atom.prev = null; |
| 2076 | } |
| 1950 | 2077 | } |
| 1951 | 2078 | } |
| 1952 | 2079 | self.functions.clearRetainingCapacity(); |
| ... | ... | @@ -1959,6 +2086,12 @@ fn resetState(self: *Wasm) void { |
| 1959 | 2086 | self.code_section_index = null; |
| 1960 | 2087 | self.debug_info_index = null; |
| 1961 | 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; |
| 1962 | 2095 | } |
| 1963 | 2096 | |
| 1964 | 2097 | pub fn flush(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| ... | ... | @@ -2036,29 +2169,34 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2036 | 2169 | defer self.resetState(); |
| 2037 | 2170 | try self.setupStart(); |
| 2038 | 2171 | try self.setupImports(); |
| 2039 | | const mod = self.base.options.module.?; |
| 2040 | | var decl_it = self.decls.keyIterator(); |
| 2041 | | while (decl_it.next()) |decl_index_ptr| { |
| 2042 | | const decl = mod.declPtr(decl_index_ptr.*); |
| 2043 | | if (decl.isExtern()) continue; |
| 2044 | | const atom = &decl.*.link.wasm; |
| 2045 | | if (decl.ty.zigTypeTag() == .Fn) { |
| 2046 | | try self.parseAtom(atom, .{ .function = decl.fn_link.wasm }); |
| 2047 | | } else if (decl.getVariable()) |variable| { |
| 2048 | | if (!variable.is_mutable) { |
| 2049 | | try self.parseAtom(atom, .{ .data = .read_only }); |
| 2050 | | } else if (variable.init.isUndefDeep()) { |
| 2051 | | try self.parseAtom(atom, .{ .data = .uninitialized }); |
| 2172 | if (self.base.options.module) |mod| { |
| 2173 | var decl_it = self.decls.keyIterator(); |
| 2174 | while (decl_it.next()) |decl_index_ptr| { |
| 2175 | const decl = mod.declPtr(decl_index_ptr.*); |
| 2176 | if (decl.isExtern()) continue; |
| 2177 | const atom = &decl.*.link.wasm; |
| 2178 | if (decl.ty.zigTypeTag() == .Fn) { |
| 2179 | try self.parseAtom(atom, .{ .function = decl.fn_link.wasm }); |
| 2180 | } else if (decl.getVariable()) |variable| { |
| 2181 | if (!variable.is_mutable) { |
| 2182 | try self.parseAtom(atom, .{ .data = .read_only }); |
| 2183 | } else if (variable.init.isUndefDeep()) { |
| 2184 | try self.parseAtom(atom, .{ .data = .uninitialized }); |
| 2185 | } else { |
| 2186 | try self.parseAtom(atom, .{ .data = .initialized }); |
| 2187 | } |
| 2052 | 2188 | } else { |
| 2053 | | try self.parseAtom(atom, .{ .data = .initialized }); |
| 2189 | try self.parseAtom(atom, .{ .data = .read_only }); |
| 2190 | } |
| 2191 | |
| 2192 | // also parse atoms for a decl's locals |
| 2193 | for (atom.locals.items) |*local_atom| { |
| 2194 | try self.parseAtom(local_atom, .{ .data = .read_only }); |
| 2054 | 2195 | } |
| 2055 | | } else { |
| 2056 | | try self.parseAtom(atom, .{ .data = .read_only }); |
| 2057 | 2196 | } |
| 2058 | 2197 | |
| 2059 | | // also parse atoms for a decl's locals |
| 2060 | | for (atom.locals.items) |*local_atom| { |
| 2061 | | try self.parseAtom(local_atom, .{ .data = .read_only }); |
| 2198 | if (self.dwarf) |*dwarf| { |
| 2199 | try dwarf.flushModule(&self.base, self.base.options.module.?); |
| 2062 | 2200 | } |
| 2063 | 2201 | } |
| 2064 | 2202 | |
| ... | ... | @@ -2066,9 +2204,6 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2066 | 2204 | try object.parseIntoAtoms(self.base.allocator, @intCast(u16, object_index), self); |
| 2067 | 2205 | } |
| 2068 | 2206 | |
| 2069 | | if (self.dwarf) |*dwarf| { |
| 2070 | | try dwarf.flushModule(&self.base, self.base.options.module.?); |
| 2071 | | } |
| 2072 | 2207 | try self.allocateAtoms(); |
| 2073 | 2208 | try self.setupMemory(); |
| 2074 | 2209 | self.mapFunctionTable(); |
| ... | ... | @@ -2424,19 +2559,44 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2424 | 2559 | } |
| 2425 | 2560 | } else if (!self.base.options.strip) { |
| 2426 | 2561 | if (self.dwarf) |*dwarf| { |
| 2427 | | if (self.debug_info_index != null) { |
| 2428 | | try dwarf.writeDbgAbbrev(&self.base); |
| 2429 | | // for debug info and ranges, the address is always 0, |
| 2430 | | // as locations are always offsets relative to 'code' section. |
| 2431 | | try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size); |
| 2432 | | try dwarf.writeDbgAranges(&self.base, 0, code_section_size); |
| 2433 | | try dwarf.writeDbgLineHeader(&self.base, mod); |
| 2434 | | |
| 2435 | | try emitDebugSection(file, self.debug_info.items, ".debug_info"); |
| 2436 | | try emitDebugSection(file, self.debug_aranges.items, ".debug_ranges"); |
| 2437 | | try emitDebugSection(file, self.debug_abbrev.items, ".debug_abbrev"); |
| 2438 | | try emitDebugSection(file, self.debug_line.items, ".debug_line"); |
| 2439 | | try emitDebugSection(file, dwarf.strtab.items, ".debug_str"); |
| 2562 | const mod = self.base.options.module.?; |
| 2563 | try dwarf.writeDbgAbbrev(&self.base); |
| 2564 | // for debug info and ranges, the address is always 0, |
| 2565 | // as locations are always offsets relative to 'code' section. |
| 2566 | try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size); |
| 2567 | try dwarf.writeDbgAranges(&self.base, 0, code_section_size); |
| 2568 | try dwarf.writeDbgLineHeader(&self.base, mod); |
| 2569 | } |
| 2570 | |
| 2571 | var debug_bytes = std.ArrayList(u8).init(self.base.allocator); |
| 2572 | defer debug_bytes.deinit(); |
| 2573 | |
| 2574 | const DebugSection = struct { |
| 2575 | name: []const u8, |
| 2576 | index: ?u32, |
| 2577 | }; |
| 2578 | |
| 2579 | const debug_sections: []const DebugSection = &.{ |
| 2580 | .{ .name = ".debug_info", .index = self.debug_info_index }, |
| 2581 | .{ .name = ".debug_pubtypes", .index = self.debug_pubtypes_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 }, |
| 2588 | }; |
| 2589 | |
| 2590 | for (debug_sections) |item| { |
| 2591 | if (item.index) |index| { |
| 2592 | var atom = self.atoms.get(index).?.getFirst(); |
| 2593 | while (true) { |
| 2594 | atom.resolveRelocs(self); |
| 2595 | try debug_bytes.appendSlice(atom.code.items); |
| 2596 | atom = atom.next orelse break; |
| 2597 | } |
| 2598 | try emitDebugSection(file, debug_bytes.items, item.name); |
| 2599 | debug_bytes.clearRetainingCapacity(); |
| 2440 | 2600 | } |
| 2441 | 2601 | } |
| 2442 | 2602 | try self.emitNameSection(file, arena); |
| ... | ... | @@ -2444,6 +2604,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2444 | 2604 | } |
| 2445 | 2605 | |
| 2446 | 2606 | fn emitDebugSection(file: fs.File, data: []const u8, name: []const u8) !void { |
| 2607 | if (data.len == 0) return; |
| 2447 | 2608 | const header_offset = try reserveCustomSectionHeader(file); |
| 2448 | 2609 | const writer = file.writer(); |
| 2449 | 2610 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| ... | ... | @@ -3149,8 +3310,8 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 3149 | 3310 | var payload = std.ArrayList(u8).init(arena); |
| 3150 | 3311 | const writer = payload.writer(); |
| 3151 | 3312 | try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SEGMENT_INFO)); |
| 3152 | | try leb.writeULEB128(writer, @intCast(u32, self.segment_info.items.len)); |
| 3153 | | for (self.segment_info.items) |segment_info| { |
| 3313 | try leb.writeULEB128(writer, @intCast(u32, self.segment_info.count())); |
| 3314 | for (self.segment_info.values()) |segment_info| { |
| 3154 | 3315 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ |
| 3155 | 3316 | segment_info.name, |
| 3156 | 3317 | @ctz(segment_info.alignment), |