| ... | @@ -1,32 +1,7 @@ | ... | @@ -1,32 +1,7 @@ |
| 1 | const Dwarf = @This(); | | |
| 2 | | | |
| 3 | const std = @import("std"); | | |
| 4 | const builtin = @import("builtin"); | | |
| 5 | const assert = std.debug.assert; | | |
| 6 | const fs = std.fs; | | |
| 7 | const leb128 = std.leb; | | |
| 8 | const log = std.log.scoped(.dwarf); | | |
| 9 | const mem = std.mem; | | |
| 10 | | | |
| 11 | const link = @import("../link.zig"); | | |
| 12 | const trace = @import("../tracy.zig").trace; | | |
| 13 | | | |
| 14 | const Allocator = mem.Allocator; | | |
| 15 | const DW = std.dwarf; | | |
| 16 | const File = link.File; | | |
| 17 | const LinkBlock = File.LinkBlock; | | |
| 18 | const LinkFn = File.LinkFn; | | |
| 19 | const LinkerLoad = @import("../codegen.zig").LinkerLoad; | | |
| 20 | const Module = @import("../Module.zig"); | | |
| 21 | const InternPool = @import("../InternPool.zig"); | | |
| 22 | const StringTable = @import("strtab.zig").StringTable; | | |
| 23 | const Type = @import("../type.zig").Type; | | |
| 24 | const Value = @import("../value.zig").Value; | | |
| 25 | | | |
| 26 | allocator: Allocator, | 1 | allocator: Allocator, |
| 27 | bin_file: *File, | 2 | bin_file: *File, |
| | 3 | format: Format, |
| 28 | ptr_width: PtrWidth, | 4 | ptr_width: PtrWidth, |
| 29 | target: std.Target, | | |
| 30 | | 5 | |
| 31 | /// A list of `Atom`s whose Line Number Programs have surplus capacity. | 6 | /// A list of `Atom`s whose Line Number Programs have surplus capacity. |
| 32 | /// This is the same concept as `Section.free_list` in Elf; see those doc comments. | 7 | /// This is the same concept as `Section.free_list` in Elf; see those doc comments. |
| ... | @@ -983,17 +958,17 @@ const min_nop_size = 2; | ... | @@ -983,17 +958,17 @@ const min_nop_size = 2; |
| 983 | /// actual_capacity + (actual_capacity / ideal_factor) | 958 | /// actual_capacity + (actual_capacity / ideal_factor) |
| 984 | const ideal_factor = 3; | 959 | const ideal_factor = 3; |
| 985 | | 960 | |
| 986 | pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf { | 961 | pub fn init(allocator: Allocator, bin_file: *File, format: Format) Dwarf { |
| 987 | const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { | 962 | const ptr_width: PtrWidth = switch (bin_file.options.target.ptrBitWidth()) { |
| 988 | 0...32 => .p32, | 963 | 0...32 => .p32, |
| 989 | 33...64 => .p64, | 964 | 33...64 => .p64, |
| 990 | else => unreachable, | 965 | else => unreachable, |
| 991 | }; | 966 | }; |
| 992 | return Dwarf{ | 967 | return .{ |
| 993 | .allocator = allocator, | 968 | .allocator = allocator, |
| 994 | .bin_file = bin_file, | 969 | .bin_file = bin_file, |
| | 970 | .format = format, |
| 995 | .ptr_width = ptr_width, | 971 | .ptr_width = ptr_width, |
| 996 | .target = target, | | |
| 997 | }; | 972 | }; |
| 998 | } | 973 | } |
| 999 | | 974 | |
| ... | @@ -1129,7 +1104,7 @@ pub fn commitDeclState( | ... | @@ -1129,7 +1104,7 @@ pub fn commitDeclState( |
| 1129 | const decl = mod.declPtr(decl_index); | 1104 | const decl = mod.declPtr(decl_index); |
| 1130 | const ip = &mod.intern_pool; | 1105 | const ip = &mod.intern_pool; |
| 1131 | | 1106 | |
| 1132 | const target_endian = self.target.cpu.arch.endian(); | 1107 | const target_endian = self.bin_file.options.target.cpu.arch.endian(); |
| 1133 | | 1108 | |
| 1134 | assert(decl.has_tv); | 1109 | assert(decl.has_tv); |
| 1135 | switch (decl.ty.zigTypeTag(mod)) { | 1110 | switch (decl.ty.zigTypeTag(mod)) { |
| ... | @@ -1788,8 +1763,6 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void { | ... | @@ -1788,8 +1763,6 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void { |
| 1788 | DW.AT.count, DW.FORM.udata, | 1763 | DW.AT.count, DW.FORM.udata, |
| 1789 | 0, | 1764 | 0, |
| 1790 | 0, // table sentinel | 1765 | 0, // table sentinel |
| 1791 | 0, | | |
| 1792 | 0, | | |
| 1793 | 0, // section sentinel | 1766 | 0, // section sentinel |
| 1794 | }; | 1767 | }; |
| 1795 | const abbrev_offset = 0; | 1768 | const abbrev_offset = 0; |
| ... | @@ -1839,12 +1812,10 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u | ... | @@ -1839,12 +1812,10 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u |
| 1839 | var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes); | 1812 | var di_buf = try std.ArrayList(u8).initCapacity(self.allocator, needed_bytes); |
| 1840 | defer di_buf.deinit(); | 1813 | defer di_buf.deinit(); |
| 1841 | | 1814 | |
| 1842 | const target_endian = self.target.cpu.arch.endian(); | 1815 | const target_endian = self.bin_file.options.target.cpu.arch.endian(); |
| 1843 | const init_len_size: usize = if (self.bin_file.tag == .macho) | 1816 | const init_len_size: usize = switch (self.format) { |
| 1844 | 4 | 1817 | .dwarf32 => 4, |
| 1845 | else switch (self.ptr_width) { | 1818 | .dwarf64 => 12, |
| 1846 | .p32 => @as(usize, 4), | | |
| 1847 | .p64 => 12, | | |
| 1848 | }; | 1819 | }; |
| 1849 | | 1820 | |
| 1850 | // initial length - length of the .debug_info contribution for this compilation unit, | 1821 | // initial length - length of the .debug_info contribution for this compilation unit, |
| ... | @@ -1852,33 +1823,17 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u | ... | @@ -1852,33 +1823,17 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u |
| 1852 | // We have to come back and write it later after we know the size. | 1823 | // We have to come back and write it later after we know the size. |
| 1853 | const after_init_len = di_buf.items.len + init_len_size; | 1824 | const after_init_len = di_buf.items.len + init_len_size; |
| 1854 | const dbg_info_end = self.getDebugInfoEnd().?; | 1825 | const dbg_info_end = self.getDebugInfoEnd().?; |
| 1855 | const init_len = dbg_info_end - after_init_len; | 1826 | const init_len = dbg_info_end - after_init_len + 1; |
| 1856 | if (self.bin_file.tag == .macho) { | 1827 | |
| 1857 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(init_len))); | 1828 | if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4); |
| 1858 | } else switch (self.ptr_width) { | 1829 | self.writeOffsetAssumeCapacity(&di_buf, init_len); |
| 1859 | .p32 => { | 1830 | |
| 1860 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(init_len)), target_endian); | | |
| 1861 | }, | | |
| 1862 | .p64 => { | | |
| 1863 | di_buf.appendNTimesAssumeCapacity(0xff, 4); | | |
| 1864 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian); | | |
| 1865 | }, | | |
| 1866 | } | | |
| 1867 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version | 1831 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version |
| 1868 | const abbrev_offset = self.abbrev_table_offset.?; | 1832 | const abbrev_offset = self.abbrev_table_offset.?; |
| 1869 | if (self.bin_file.tag == .macho) { | 1833 | |
| 1870 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(abbrev_offset))); | 1834 | self.writeOffsetAssumeCapacity(&di_buf, abbrev_offset); |
| 1871 | di_buf.appendAssumeCapacity(8); // address size | 1835 | di_buf.appendAssumeCapacity(self.ptrWidthBytes()); // address size |
| 1872 | } else switch (self.ptr_width) { | 1836 | |
| 1873 | .p32 => { | | |
| 1874 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(abbrev_offset)), target_endian); | | |
| 1875 | di_buf.appendAssumeCapacity(4); // address size | | |
| 1876 | }, | | |
| 1877 | .p64 => { | | |
| 1878 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), abbrev_offset, target_endian); | | |
| 1879 | di_buf.appendAssumeCapacity(8); // address size | | |
| 1880 | }, | | |
| 1881 | } | | |
| 1882 | // Write the form for the compile unit, which must match the abbrev table above. | 1837 | // Write the form for the compile unit, which must match the abbrev table above. |
| 1883 | const name_strp = try self.strtab.insert(self.allocator, module.root_mod.root_src_path); | 1838 | const name_strp = try self.strtab.insert(self.allocator, module.root_mod.root_src_path); |
| 1884 | var compile_unit_dir_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; | 1839 | var compile_unit_dir_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| ... | @@ -1887,21 +1842,13 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u | ... | @@ -1887,21 +1842,13 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u |
| 1887 | const producer_strp = try self.strtab.insert(self.allocator, link.producer_string); | 1842 | const producer_strp = try self.strtab.insert(self.allocator, link.producer_string); |
| 1888 | | 1843 | |
| 1889 | di_buf.appendAssumeCapacity(@intFromEnum(AbbrevKind.compile_unit)); | 1844 | di_buf.appendAssumeCapacity(@intFromEnum(AbbrevKind.compile_unit)); |
| 1890 | if (self.bin_file.tag == .macho) { | 1845 | self.writeOffsetAssumeCapacity(&di_buf, 0); // DW.AT.stmt_list, DW.FORM.sec_offset |
| 1891 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT.stmt_list, DW.FORM.sec_offset | 1846 | self.writeAddrAssumeCapacity(&di_buf, low_pc); |
| 1892 | mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), low_pc); | 1847 | self.writeAddrAssumeCapacity(&di_buf, high_pc); |
| 1893 | mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), high_pc); | 1848 | self.writeOffsetAssumeCapacity(&di_buf, name_strp); |
| 1894 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(name_strp))); | 1849 | self.writeOffsetAssumeCapacity(&di_buf, comp_dir_strp); |
| 1895 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(comp_dir_strp))); | 1850 | self.writeOffsetAssumeCapacity(&di_buf, producer_strp); |
| 1896 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(producer_strp))); | 1851 | |
| 1897 | } else { | | |
| 1898 | self.writeAddrAssumeCapacity(&di_buf, 0); // DW.AT.stmt_list, DW.FORM.sec_offset | | |
| 1899 | self.writeAddrAssumeCapacity(&di_buf, low_pc); | | |
| 1900 | self.writeAddrAssumeCapacity(&di_buf, high_pc); | | |
| 1901 | self.writeAddrAssumeCapacity(&di_buf, name_strp); | | |
| 1902 | self.writeAddrAssumeCapacity(&di_buf, comp_dir_strp); | | |
| 1903 | self.writeAddrAssumeCapacity(&di_buf, producer_strp); | | |
| 1904 | } | | |
| 1905 | // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: | 1852 | // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: |
| 1906 | // http://dwarfstd.org/ShowIssue.php?issue=171115.1 | 1853 | // http://dwarfstd.org/ShowIssue.php?issue=171115.1 |
| 1907 | // Until then we say it is C99. | 1854 | // Until then we say it is C99. |
| ... | @@ -1954,13 +1901,26 @@ fn resolveCompilationDir(module: *Module, buffer: *[std.fs.MAX_PATH_BYTES]u8) [] | ... | @@ -1954,13 +1901,26 @@ fn resolveCompilationDir(module: *Module, buffer: *[std.fs.MAX_PATH_BYTES]u8) [] |
| 1954 | } | 1901 | } |
| 1955 | | 1902 | |
| 1956 | fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void { | 1903 | fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void { |
| 1957 | const target_endian = self.target.cpu.arch.endian(); | 1904 | const target_endian = self.bin_file.options.target.cpu.arch.endian(); |
| 1958 | switch (self.ptr_width) { | 1905 | switch (self.ptr_width) { |
| 1959 | .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(addr)), target_endian), | 1906 | .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(addr)), target_endian), |
| 1960 | .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian), | 1907 | .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian), |
| 1961 | } | 1908 | } |
| 1962 | } | 1909 | } |
| 1963 | | 1910 | |
| | 1911 | fn writeOffsetAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), off: u64) void { |
| | 1912 | const target_endian = self.bin_file.options.target.cpu.arch.endian(); |
| | 1913 | switch (self.format) { |
| | 1914 | .dwarf32 => mem.writeInt( |
| | 1915 | u32, |
| | 1916 | buf.addManyAsArrayAssumeCapacity(4), |
| | 1917 | @as(u32, @intCast(off)), |
| | 1918 | target_endian, |
| | 1919 | ), |
| | 1920 | .dwarf64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), off, target_endian), |
| | 1921 | } |
| | 1922 | } |
| | 1923 | |
| 1964 | /// Writes to the file a buffer, prefixed and suffixed by the specified number of | 1924 | /// Writes to the file a buffer, prefixed and suffixed by the specified number of |
| 1965 | /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes | 1925 | /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes |
| 1966 | /// are less than 1044480 bytes (if this limit is ever reached, this function can be | 1926 | /// are less than 1044480 bytes (if this limit is ever reached, this function can be |
| ... | @@ -2176,13 +2136,7 @@ fn writeDbgInfoNopsToArrayList( | ... | @@ -2176,13 +2136,7 @@ fn writeDbgInfoNopsToArrayList( |
| 2176 | } | 2136 | } |
| 2177 | | 2137 | |
| 2178 | pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { | 2138 | pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { |
| 2179 | const target_endian = self.target.cpu.arch.endian(); | 2139 | const target_endian = self.bin_file.options.target.cpu.arch.endian(); |
| 2180 | const init_len_size: usize = if (self.bin_file.tag == .macho) | | |
| 2181 | 4 | | |
| 2182 | else switch (self.ptr_width) { | | |
| 2183 | .p32 => @as(usize, 4), | | |
| 2184 | .p64 => 12, | | |
| 2185 | }; | | |
| 2186 | const ptr_width_bytes = self.ptrWidthBytes(); | 2140 | const ptr_width_bytes = self.ptrWidthBytes(); |
| 2187 | | 2141 | |
| 2188 | // Enough for all the data without resizing. When support for more compilation units | 2142 | // Enough for all the data without resizing. When support for more compilation units |
| ... | @@ -2193,17 +2147,15 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { | ... | @@ -2193,17 +2147,15 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { |
| 2193 | // initial length - length of the .debug_aranges contribution for this compilation unit, | 2147 | // initial length - length of the .debug_aranges contribution for this compilation unit, |
| 2194 | // not including the initial length itself. | 2148 | // not including the initial length itself. |
| 2195 | // We have to come back and write it later after we know the size. | 2149 | // We have to come back and write it later after we know the size. |
| | 2150 | if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4); |
| 2196 | const init_len_index = di_buf.items.len; | 2151 | const init_len_index = di_buf.items.len; |
| 2197 | di_buf.items.len += init_len_size; | 2152 | self.writeOffsetAssumeCapacity(&di_buf, 0); |
| 2198 | const after_init_len = di_buf.items.len; | 2153 | const after_init_len = di_buf.items.len; |
| 2199 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version | 2154 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 2, target_endian); // version |
| | 2155 | |
| 2200 | // When more than one compilation unit is supported, this will be the offset to it. | 2156 | // When more than one compilation unit is supported, this will be the offset to it. |
| 2201 | // For now it is always at offset 0 in .debug_info. | 2157 | // For now it is always at offset 0 in .debug_info. |
| 2202 | if (self.bin_file.tag == .macho) { | 2158 | self.writeOffsetAssumeCapacity(&di_buf, 0); // .debug_info offset |
| 2203 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // __debug_info offset | | |
| 2204 | } else { | | |
| 2205 | self.writeAddrAssumeCapacity(&di_buf, 0); // .debug_info offset | | |
| 2206 | } | | |
| 2207 | di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size | 2159 | di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size |
| 2208 | di_buf.appendAssumeCapacity(0); // segment_selector_size | 2160 | di_buf.appendAssumeCapacity(0); // segment_selector_size |
| 2209 | | 2161 | |
| ... | @@ -2222,18 +2174,14 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { | ... | @@ -2222,18 +2174,14 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { |
| 2222 | | 2174 | |
| 2223 | // Go back and populate the initial length. | 2175 | // Go back and populate the initial length. |
| 2224 | const init_len = di_buf.items.len - after_init_len; | 2176 | const init_len = di_buf.items.len - after_init_len; |
| 2225 | if (self.bin_file.tag == .macho) { | 2177 | switch (self.format) { |
| 2226 | mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @as(u32, @intCast(init_len))); | 2178 | .dwarf32 => mem.writeInt( |
| 2227 | } else switch (self.ptr_width) { | 2179 | u32, |
| 2228 | .p32 => { | 2180 | di_buf.items[init_len_index..][0..4], |
| 2229 | mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @as(u32, @intCast(init_len)), target_endian); | 2181 | @as(u32, @intCast(init_len)), |
| 2230 | }, | 2182 | target_endian, |
| 2231 | .p64 => { | 2183 | ), |
| 2232 | // initial length - length of the .debug_aranges contribution for this compilation unit, | 2184 | .dwarf64 => mem.writeInt(u64, di_buf.items[init_len_index..][0..8], init_len, target_endian), |
| 2233 | // not including the initial length itself. | | |
| 2234 | di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff }; | | |
| 2235 | mem.writeInt(u64, di_buf.items[init_len_index + 4 ..][0..8], init_len, target_endian); | | |
| 2236 | }, | | |
| 2237 | } | 2185 | } |
| 2238 | | 2186 | |
| 2239 | const needed_size = @as(u32, @intCast(di_buf.items.len)); | 2187 | const needed_size = @as(u32, @intCast(di_buf.items.len)); |
| ... | @@ -2267,13 +2215,10 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { | ... | @@ -2267,13 +2215,10 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { |
| 2267 | pub fn writeDbgLineHeader(self: *Dwarf) !void { | 2215 | pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2268 | const gpa = self.allocator; | 2216 | const gpa = self.allocator; |
| 2269 | | 2217 | |
| 2270 | const ptr_width_bytes: u8 = self.ptrWidthBytes(); | 2218 | const target_endian = self.bin_file.options.target.cpu.arch.endian(); |
| 2271 | const target_endian = self.target.cpu.arch.endian(); | 2219 | const init_len_size: usize = switch (self.format) { |
| 2272 | const init_len_size: usize = if (self.bin_file.tag == .macho) | 2220 | .dwarf32 => 4, |
| 2273 | 4 | 2221 | .dwarf64 => 12, |
| 2274 | else switch (self.ptr_width) { | | |
| 2275 | .p32 => @as(usize, 4), | | |
| 2276 | .p64 => 12, | | |
| 2277 | }; | 2222 | }; |
| 2278 | | 2223 | |
| 2279 | const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return; | 2224 | const dbg_line_prg_off = self.getDebugLineProgramOff() orelse return; |
| ... | @@ -2291,25 +2236,8 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { | ... | @@ -2291,25 +2236,8 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2291 | var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes); | 2236 | var di_buf = try std.ArrayList(u8).initCapacity(gpa, needed_bytes); |
| 2292 | defer di_buf.deinit(); | 2237 | defer di_buf.deinit(); |
| 2293 | | 2238 | |
| 2294 | // initial length - length of the .debug_line contribution for this compilation unit, | 2239 | if (self.format == .dwarf64) di_buf.appendNTimesAssumeCapacity(0xff, 4); |
| 2295 | // not including the initial length itself. | 2240 | self.writeOffsetAssumeCapacity(&di_buf, 0); |
| 2296 | // We will backpatch this value later so just remember where we need to write it. | | |
| 2297 | const before_init_len = di_buf.items.len; | | |
| 2298 | | | |
| 2299 | switch (self.bin_file.tag) { | | |
| 2300 | .macho => { | | |
| 2301 | mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0)); | | |
| 2302 | }, | | |
| 2303 | else => switch (self.ptr_width) { | | |
| 2304 | .p32 => { | | |
| 2305 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @as(u32, 0), target_endian); | | |
| 2306 | }, | | |
| 2307 | .p64 => { | | |
| 2308 | di_buf.appendNTimesAssumeCapacity(0xff, 4); | | |
| 2309 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), @as(u64, 0), target_endian); | | |
| 2310 | }, | | |
| 2311 | }, | | |
| 2312 | } | | |
| 2313 | | 2241 | |
| 2314 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version | 2242 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version |
| 2315 | | 2243 | |
| ... | @@ -2318,12 +2246,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { | ... | @@ -2318,12 +2246,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2318 | // Therefore we rely on the NOP jump at the beginning of the Line Number Program for | 2246 | // Therefore we rely on the NOP jump at the beginning of the Line Number Program for |
| 2319 | // padding rather than this field. | 2247 | // padding rather than this field. |
| 2320 | const before_header_len = di_buf.items.len; | 2248 | const before_header_len = di_buf.items.len; |
| 2321 | | 2249 | self.writeOffsetAssumeCapacity(&di_buf, 0); // We will come back and write this. |
| 2322 | di_buf.items.len += switch (self.bin_file.tag) { // We will come back and write this. | | |
| 2323 | .macho => @sizeOf(u32), | | |
| 2324 | else => ptr_width_bytes, | | |
| 2325 | }; | | |
| 2326 | | | |
| 2327 | const after_header_len = di_buf.items.len; | 2250 | const after_header_len = di_buf.items.len; |
| 2328 | | 2251 | |
| 2329 | const opcode_base = DW.LNS.set_isa + 1; | 2252 | const opcode_base = DW.LNS.set_isa + 1; |
| ... | @@ -2360,7 +2283,11 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { | ... | @@ -2360,7 +2283,11 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2360 | | 2283 | |
| 2361 | for (paths.files, 0..) |file, i| { | 2284 | for (paths.files, 0..) |file, i| { |
| 2362 | const dir_index = paths.files_dirs_indexes[i]; | 2285 | const dir_index = paths.files_dirs_indexes[i]; |
| 2363 | log.debug("adding new file name at {d} of '{s}' referencing directory {d}", .{ i + 1, file, dir_index + 1 }); | 2286 | log.debug("adding new file name at {d} of '{s}' referencing directory {d}", .{ |
| | 2287 | i + 1, |
| | 2288 | file, |
| | 2289 | dir_index + 1, |
| | 2290 | }); |
| 2364 | di_buf.appendSliceAssumeCapacity(file); | 2291 | di_buf.appendSliceAssumeCapacity(file); |
| 2365 | di_buf.appendSliceAssumeCapacity(&[_]u8{ | 2292 | di_buf.appendSliceAssumeCapacity(&[_]u8{ |
| 2366 | 0, // null byte for the relative path name | 2293 | 0, // null byte for the relative path name |
| ... | @@ -2372,19 +2299,14 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { | ... | @@ -2372,19 +2299,14 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2372 | di_buf.appendAssumeCapacity(0); // file names sentinel | 2299 | di_buf.appendAssumeCapacity(0); // file names sentinel |
| 2373 | | 2300 | |
| 2374 | const header_len = di_buf.items.len - after_header_len; | 2301 | const header_len = di_buf.items.len - after_header_len; |
| 2375 | | 2302 | switch (self.format) { |
| 2376 | switch (self.bin_file.tag) { | 2303 | .dwarf32 => mem.writeInt( |
| 2377 | .macho => { | 2304 | u32, |
| 2378 | mem.writeIntLittle(u32, di_buf.items[before_header_len..][0..4], @as(u32, @intCast(header_len))); | 2305 | di_buf.items[before_header_len..][0..4], |
| 2379 | }, | 2306 | @as(u32, @intCast(header_len)), |
| 2380 | else => switch (self.ptr_width) { | 2307 | target_endian, |
| 2381 | .p32 => { | 2308 | ), |
| 2382 | mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @as(u32, @intCast(header_len)), target_endian); | 2309 | .dwarf64 => mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian), |
| 2383 | }, | | |
| 2384 | .p64 => { | | |
| 2385 | mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian); | | |
| 2386 | }, | | |
| 2387 | }, | | |
| 2388 | } | 2310 | } |
| 2389 | | 2311 | |
| 2390 | assert(needed_bytes == di_buf.items.len); | 2312 | assert(needed_bytes == di_buf.items.len); |
| ... | @@ -2452,18 +2374,13 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { | ... | @@ -2452,18 +2374,13 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void { |
| 2452 | } | 2374 | } |
| 2453 | | 2375 | |
| 2454 | // Backpatch actual length of the debug line program | 2376 | // Backpatch actual length of the debug line program |
| 2455 | const init_len = self.getDebugLineProgramEnd().? - before_init_len - init_len_size; | 2377 | const init_len = self.getDebugLineProgramEnd().? - init_len_size; |
| 2456 | switch (self.bin_file.tag) { | 2378 | switch (self.format) { |
| 2457 | .macho => { | 2379 | .dwarf32 => { |
| 2458 | mem.writeIntLittle(u32, di_buf.items[before_init_len..][0..4], @as(u32, @intCast(init_len))); | 2380 | mem.writeInt(u32, di_buf.items[0..4], @as(u32, @intCast(init_len)), target_endian); |
| 2459 | }, | 2381 | }, |
| 2460 | else => switch (self.ptr_width) { | 2382 | .dwarf64 => { |
| 2461 | .p32 => { | 2383 | mem.writeInt(u64, di_buf.items[4..][0..8], init_len, target_endian); |
| 2462 | mem.writeInt(u32, di_buf.items[before_init_len..][0..4], @as(u32, @intCast(init_len)), target_endian); | | |
| 2463 | }, | | |
| 2464 | .p64 => { | | |
| 2465 | mem.writeInt(u64, di_buf.items[before_init_len + 4 ..][0..8], init_len, target_endian); | | |
| 2466 | }, | | |
| 2467 | }, | 2384 | }, |
| 2468 | } | 2385 | } |
| 2469 | | 2386 | |
| ... | @@ -2500,7 +2417,7 @@ fn getDebugInfoOff(self: Dwarf) ?u32 { | ... | @@ -2500,7 +2417,7 @@ fn getDebugInfoOff(self: Dwarf) ?u32 { |
| 2500 | fn getDebugInfoEnd(self: Dwarf) ?u32 { | 2417 | fn getDebugInfoEnd(self: Dwarf) ?u32 { |
| 2501 | const last_index = self.di_atom_last_index orelse return null; | 2418 | const last_index = self.di_atom_last_index orelse return null; |
| 2502 | const last = self.getAtom(.di_atom, last_index); | 2419 | const last = self.getAtom(.di_atom, last_index); |
| 2503 | return last.off + last.len + 1; | 2420 | return last.off + last.len; |
| 2504 | } | 2421 | } |
| 2505 | | 2422 | |
| 2506 | fn getDebugLineProgramOff(self: Dwarf) ?u32 { | 2423 | fn getDebugLineProgramOff(self: Dwarf) ?u32 { |
| ... | @@ -2524,17 +2441,14 @@ fn ptrWidthBytes(self: Dwarf) u8 { | ... | @@ -2524,17 +2441,14 @@ fn ptrWidthBytes(self: Dwarf) u8 { |
| 2524 | } | 2441 | } |
| 2525 | | 2442 | |
| 2526 | fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 { | 2443 | fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 { |
| 2527 | var size = switch (self.bin_file.tag) { // length field | 2444 | var size: usize = switch (self.format) { // length field |
| 2528 | .macho => @sizeOf(u32), | 2445 | .dwarf32 => @as(usize, 4), |
| 2529 | else => switch (self.ptr_width) { | 2446 | .dwarf64 => 12, |
| 2530 | .p32 => @as(usize, @sizeOf(u32)), | | |
| 2531 | .p64 => @sizeOf(u32) + @sizeOf(u64), | | |
| 2532 | }, | | |
| 2533 | }; | 2447 | }; |
| 2534 | size += @sizeOf(u16); // version field | 2448 | size += @sizeOf(u16); // version field |
| 2535 | size += switch (self.bin_file.tag) { // offset to end-of-header | 2449 | size += switch (self.format) { // offset to end-of-header |
| 2536 | .macho => @sizeOf(u32), | 2450 | .dwarf32 => @as(usize, 4), |
| 2537 | else => self.ptrWidthBytes(), | 2451 | .dwarf64 => 8, |
| 2538 | }; | 2452 | }; |
| 2539 | size += 18; // opcodes | 2453 | size += 18; // opcodes |
| 2540 | | 2454 | |
| ... | @@ -2570,6 +2484,8 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { | ... | @@ -2570,6 +2484,8 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 2570 | } | 2484 | } |
| 2571 | | 2485 | |
| 2572 | pub fn flushModule(self: *Dwarf, module: *Module) !void { | 2486 | pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| | 2487 | const target = self.bin_file.options.target; |
| | 2488 | |
| 2573 | if (self.global_abbrev_relocs.items.len > 0) { | 2489 | if (self.global_abbrev_relocs.items.len > 0) { |
| 2574 | const gpa = self.allocator; | 2490 | const gpa = self.allocator; |
| 2575 | var arena_alloc = std.heap.ArenaAllocator.init(gpa); | 2491 | var arena_alloc = std.heap.ArenaAllocator.init(gpa); |
| ... | @@ -2581,7 +2497,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { | ... | @@ -2581,7 +2497,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2581 | module, | 2497 | module, |
| 2582 | Type.anyerror, | 2498 | Type.anyerror, |
| 2583 | module.global_error_set.keys(), | 2499 | module.global_error_set.keys(), |
| 2584 | self.target, | 2500 | target, |
| 2585 | &dbg_info_buffer, | 2501 | &dbg_info_buffer, |
| 2586 | ); | 2502 | ); |
| 2587 | | 2503 | |
| ... | @@ -2610,7 +2526,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { | ... | @@ -2610,7 +2526,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2610 | }; | 2526 | }; |
| 2611 | | 2527 | |
| 2612 | var buf: [@sizeOf(u32)]u8 = undefined; | 2528 | var buf: [@sizeOf(u32)]u8 = undefined; |
| 2613 | mem.writeInt(u32, &buf, self.getAtom(.di_atom, di_atom_index).off, self.target.cpu.arch.endian()); | 2529 | mem.writeInt(u32, &buf, self.getAtom(.di_atom, di_atom_index).off, target.cpu.arch.endian()); |
| 2614 | | 2530 | |
| 2615 | while (self.global_abbrev_relocs.popOrNull()) |reloc| { | 2531 | while (self.global_abbrev_relocs.popOrNull()) |reloc| { |
| 2616 | const atom = self.getAtom(.di_atom, reloc.atom_index); | 2532 | const atom = self.getAtom(.di_atom, reloc.atom_index); |
| ... | @@ -2670,21 +2586,18 @@ fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct { | ... | @@ -2670,21 +2586,18 @@ fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct { |
| 2670 | try files_dir_indexes.ensureTotalCapacity(self.di_files.count()); | 2586 | try files_dir_indexes.ensureTotalCapacity(self.di_files.count()); |
| 2671 | | 2587 | |
| 2672 | for (self.di_files.keys()) |dif| { | 2588 | for (self.di_files.keys()) |dif| { |
| 2673 | const dir_path = d: { | 2589 | const full_path = try dif.mod.root.joinString(arena, dif.sub_file_path); |
| 2674 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; | 2590 | const dir_path = std.fs.path.dirname(full_path) orelse "."; |
| 2675 | const dir_path = try dif.mod.root.joinString(arena, dif.mod.root.sub_path); | 2591 | const sub_file_path = std.fs.path.basename(full_path); |
| 2676 | const abs_dir_path = if (std.fs.path.isAbsolute(dir_path)) | 2592 | // TODO re-investigate if realpath is needed here |
| 2677 | dir_path | 2593 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 2678 | else | 2594 | const resolved = if (!std.fs.path.isAbsolute(dir_path)) |
| 2679 | std.os.realpath(dir_path, &buffer) catch dir_path; // If realpath fails, fallback to whatever dir_path was | 2595 | std.os.realpath(dir_path, &buffer) catch dir_path |
| 2680 | break :d try std.fs.path.join(arena, &.{ | 2596 | else |
| 2681 | abs_dir_path, std.fs.path.dirname(dif.sub_file_path) orelse "", | 2597 | dir_path; |
| 2682 | }); | | |
| 2683 | }; | | |
| 2684 | const sub_file_path = try arena.dupe(u8, std.fs.path.basename(dif.sub_file_path)); | | |
| 2685 | | 2598 | |
| 2686 | const dir_index: u28 = blk: { | 2599 | const dir_index: u28 = blk: { |
| 2687 | const dirs_gop = dirs.getOrPutAssumeCapacity(dir_path); | 2600 | const dirs_gop = dirs.getOrPutAssumeCapacity(try arena.dupe(u8, resolved)); |
| 2688 | break :blk @as(u28, @intCast(dirs_gop.index + 1)); | 2601 | break :blk @as(u28, @intCast(dirs_gop.index + 1)); |
| 2689 | }; | 2602 | }; |
| 2690 | | 2603 | |
| ... | @@ -2813,3 +2726,33 @@ fn getAtomPtr(self: *Dwarf, comptime kind: Kind, index: Atom.Index) *Atom { | ... | @@ -2813,3 +2726,33 @@ fn getAtomPtr(self: *Dwarf, comptime kind: Kind, index: Atom.Index) *Atom { |
| 2813 | .di_atom => &self.di_atoms.items[index], | 2726 | .di_atom => &self.di_atoms.items[index], |
| 2814 | }; | 2727 | }; |
| 2815 | } | 2728 | } |
| | 2729 | |
| | 2730 | pub const Format = enum { |
| | 2731 | dwarf32, |
| | 2732 | dwarf64, |
| | 2733 | }; |
| | 2734 | |
| | 2735 | const Dwarf = @This(); |
| | 2736 | |
| | 2737 | const std = @import("std"); |
| | 2738 | const builtin = @import("builtin"); |
| | 2739 | const assert = std.debug.assert; |
| | 2740 | const fs = std.fs; |
| | 2741 | const leb128 = std.leb; |
| | 2742 | const log = std.log.scoped(.dwarf); |
| | 2743 | const mem = std.mem; |
| | 2744 | |
| | 2745 | const link = @import("../link.zig"); |
| | 2746 | const trace = @import("../tracy.zig").trace; |
| | 2747 | |
| | 2748 | const Allocator = mem.Allocator; |
| | 2749 | const DW = std.dwarf; |
| | 2750 | const File = link.File; |
| | 2751 | const LinkBlock = File.LinkBlock; |
| | 2752 | const LinkFn = File.LinkFn; |
| | 2753 | const LinkerLoad = @import("../codegen.zig").LinkerLoad; |
| | 2754 | const Module = @import("../Module.zig"); |
| | 2755 | const InternPool = @import("../InternPool.zig"); |
| | 2756 | const StringTable = @import("strtab.zig").StringTable; |
| | 2757 | const Type = @import("../type.zig").Type; |
| | 2758 | const Value = @import("../value.zig").Value; |