authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-21 16:14:40+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-21 16:14:40+02:00
log809e7aa4fc0e613752f8c7a4319ac4157089ea84
tree52b38d59672519e0901e65d487d1013335ed7348
parent3d6e63337164b42fec4df55687071be38d33dce9
parentf4f5e9edd69d3ca8f4d523ca6949487721a4e166
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17638 from ziglang/elf-dwarf-fixes

dwarf: decouple DWARF formats from target pointer size + misc fixes

4 files changed, 133 insertions(+), 190 deletions(-)

src/link/Dwarf.zig+130-187
...@@ -1,32 +1,7 @@...@@ -1,32 +1,7 @@
1const Dwarf = @This();
2
3const std = @import("std");
4const builtin = @import("builtin");
5const assert = std.debug.assert;
6const fs = std.fs;
7const leb128 = std.leb;
8const log = std.log.scoped(.dwarf);
9const mem = std.mem;
10
11const link = @import("../link.zig");
12const trace = @import("../tracy.zig").trace;
13
14const Allocator = mem.Allocator;
15const DW = std.dwarf;
16const File = link.File;
17const LinkBlock = File.LinkBlock;
18const LinkFn = File.LinkFn;
19const LinkerLoad = @import("../codegen.zig").LinkerLoad;
20const Module = @import("../Module.zig");
21const InternPool = @import("../InternPool.zig");
22const StringTable = @import("strtab.zig").StringTable;
23const Type = @import("../type.zig").Type;
24const Value = @import("../value.zig").Value;
25
26allocator: Allocator,1allocator: Allocator,
27bin_file: *File,2bin_file: *File,
3format: Format,
28ptr_width: PtrWidth,4ptr_width: PtrWidth,
29target: std.Target,
305
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)
984const ideal_factor = 3;959const ideal_factor = 3;
985960
986pub fn init(allocator: Allocator, bin_file: *File, target: std.Target) Dwarf {961pub 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}
999974
...@@ -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;
11311106
1132 const target_endian = self.target.cpu.arch.endian();1107 const target_endian = self.bin_file.options.target.cpu.arch.endian();
11331108
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 sentinel1765 0, // table sentinel
1791 0,
1792 0,
1793 0, // section sentinel1766 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();
18411814
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 41817 .dwarf32 => 4,
1845 else switch (self.ptr_width) {1818 .dwarf64 => 12,
1846 .p32 => @as(usize, 4),
1847 .p64 => 12,
1848 };1819 };
18491820
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 version1831 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 size1835 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);
18881843
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_offset1846 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.11853 // 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}
19551902
1956fn writeAddrAssumeCapacity(self: *Dwarf, buf: *std.ArrayList(u8), addr: u64) void {1903fn 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}
19631910
1911fn 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 of1924/// 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 bytes1925/// 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 be1926/// 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}
21772137
2178pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {2138pub 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();
21872141
2188 // Enough for all the data without resizing. When support for more compilation units2142 // 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); // version2154 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_size2159 di_buf.appendAssumeCapacity(ptr_width_bytes); // address_size
2208 di_buf.appendAssumeCapacity(0); // segment_selector_size2160 di_buf.appendAssumeCapacity(0); // segment_selector_size
22092161
...@@ -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 {
22222174
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 }
22382186
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 {
2267pub fn writeDbgLineHeader(self: *Dwarf) !void {2215pub fn writeDbgLineHeader(self: *Dwarf) !void {
2268 const gpa = self.allocator;2216 const gpa = self.allocator;
22692217
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 42221 .dwarf64 => 12,
2274 else switch (self.ptr_width) {
2275 .p32 => @as(usize, 4),
2276 .p64 => 12,
2277 };2222 };
22782223
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();
22932238
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 }
23132241
2314 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version2242 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // version
23152243
...@@ -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 for2246 // 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;
23212249 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;
23282251
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 {
23602283
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 name2293 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 sentinel2299 di_buf.appendAssumeCapacity(0); // file names sentinel
23732300
2374 const header_len = di_buf.items.len - after_header_len;2301 const header_len = di_buf.items.len - after_header_len;
23752302 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 }
23892311
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 }
24532375
2454 // Backpatch actual length of the debug line program2376 // 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 }
24692386
...@@ -2500,7 +2417,7 @@ fn getDebugInfoOff(self: Dwarf) ?u32 {...@@ -2500,7 +2417,7 @@ fn getDebugInfoOff(self: Dwarf) ?u32 {
2500fn getDebugInfoEnd(self: Dwarf) ?u32 {2417fn 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}
25052422
2506fn getDebugLineProgramOff(self: Dwarf) ?u32 {2423fn getDebugLineProgramOff(self: Dwarf) ?u32 {
...@@ -2524,17 +2441,14 @@ fn ptrWidthBytes(self: Dwarf) u8 {...@@ -2524,17 +2441,14 @@ fn ptrWidthBytes(self: Dwarf) u8 {
2524}2441}
25252442
2526fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 {2443fn dbgLineNeededHeaderBytes(self: Dwarf, dirs: []const []const u8, files: []const []const u8) u32 {
2527 var size = switch (self.bin_file.tag) { // length field2444 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 field2448 size += @sizeOf(u16); // version field
2535 size += switch (self.bin_file.tag) { // offset to end-of-header2449 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; // opcodes2453 size += 18; // opcodes
25402454
...@@ -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}
25712485
2572pub fn flushModule(self: *Dwarf, module: *Module) !void {2486pub 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 );
25872503
...@@ -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 };
26112527
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());
26142530
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());
26712587
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_path2593 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
2678 else2594 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 was2595 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));
26852598
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 };
26902603
...@@ -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
2730pub const Format = enum {
2731 dwarf32,
2732 dwarf64,
2733};
2734
2735const Dwarf = @This();
2736
2737const std = @import("std");
2738const builtin = @import("builtin");
2739const assert = std.debug.assert;
2740const fs = std.fs;
2741const leb128 = std.leb;
2742const log = std.log.scoped(.dwarf);
2743const mem = std.mem;
2744
2745const link = @import("../link.zig");
2746const trace = @import("../tracy.zig").trace;
2747
2748const Allocator = mem.Allocator;
2749const DW = std.dwarf;
2750const File = link.File;
2751const LinkBlock = File.LinkBlock;
2752const LinkFn = File.LinkFn;
2753const LinkerLoad = @import("../codegen.zig").LinkerLoad;
2754const Module = @import("../Module.zig");
2755const InternPool = @import("../InternPool.zig");
2756const StringTable = @import("strtab.zig").StringTable;
2757const Type = @import("../type.zig").Type;
2758const Value = @import("../value.zig").Value;
src/link/Elf.zig+1-1
...@@ -310,7 +310,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -310,7 +310,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
310310
311 if (options.module != null and !options.use_llvm) {311 if (options.module != null and !options.use_llvm) {
312 if (!options.strip) {312 if (!options.strip) {
313 self.dwarf = Dwarf.init(allocator, &self.base, options.target);313 self.dwarf = Dwarf.init(allocator, &self.base, .dwarf32);
314 }314 }
315315
316 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));316 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));
src/link/MachO.zig+1-1
...@@ -206,7 +206,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {...@@ -206,7 +206,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
206206
207 self.d_sym = .{207 self.d_sym = .{
208 .allocator = allocator,208 .allocator = allocator,
209 .dwarf = link.File.Dwarf.init(allocator, &self.base, options.target),209 .dwarf = link.File.Dwarf.init(allocator, &self.base, .dwarf32),
210 .file = d_sym_file,210 .file = d_sym_file,
211 };211 };
212 }212 }
src/link/Wasm.zig+1-1
...@@ -507,7 +507,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -507,7 +507,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
507 }507 }
508508
509 // if (!options.strip and options.module != null) {509 // if (!options.strip and options.module != null) {
510 // wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, options.target);510 // wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, .dwarf32);
511 // try wasm_bin.initDebugSections();511 // try wasm_bin.initDebugSections();
512 // }512 // }
513513