authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-24 05:11:26+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-01-24 05:11:26+00:00
logf77e1b86225cd49c2d04dfa6ca4a7ede315dc0b1
treec30cddc29ae1f1162f3ec38fcaf89b94ecb4e6dd
parentd916954bee0f477bcada0693d4aa952197cf1eef
parent180db2bf23f05a02876d4567cac3b04842c11acb
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22578 from mlugg/stack-trace-tests-x86_64

tests: enable stack trace tests for x86_64-selfhosted

13 files changed, 200 insertions(+), 125 deletions(-)

lib/std/debug.zig+10-2
...@@ -732,11 +732,12 @@ pub const StackIterator = struct {...@@ -732,11 +732,12 @@ pub const StackIterator = struct {
732 // via DWARF before attempting to use the compact unwind info will produce incorrect results.732 // via DWARF before attempting to use the compact unwind info will produce incorrect results.
733 if (module.unwind_info) |unwind_info| {733 if (module.unwind_info) |unwind_info| {
734 if (SelfInfo.unwindFrameMachO(734 if (SelfInfo.unwindFrameMachO(
735 unwind_state.debug_info.allocator,
736 module.base_address,
735 &unwind_state.dwarf_context,737 &unwind_state.dwarf_context,
736 &it.ma,738 &it.ma,
737 unwind_info,739 unwind_info,
738 module.eh_frame,740 module.eh_frame,
739 module.base_address,
740 )) |return_address| {741 )) |return_address| {
741 return return_address;742 return return_address;
742 } else |err| {743 } else |err| {
...@@ -748,7 +749,14 @@ pub const StackIterator = struct {...@@ -748,7 +749,14 @@ pub const StackIterator = struct {
748 }749 }
749750
750 if (try module.getDwarfInfoForAddress(unwind_state.debug_info.allocator, unwind_state.dwarf_context.pc)) |di| {751 if (try module.getDwarfInfoForAddress(unwind_state.debug_info.allocator, unwind_state.dwarf_context.pc)) |di| {
751 return SelfInfo.unwindFrameDwarf(di, &unwind_state.dwarf_context, &it.ma, null);752 return SelfInfo.unwindFrameDwarf(
753 unwind_state.debug_info.allocator,
754 di,
755 module.base_address,
756 &unwind_state.dwarf_context,
757 &it.ma,
758 null,
759 );
752 } else return error.MissingDebugInfo;760 } else return error.MissingDebugInfo;
753 }761 }
754762
lib/std/debug/Dwarf.zig+14-4
...@@ -48,6 +48,8 @@ compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .empty,...@@ -48,6 +48,8 @@ compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .empty,
48/// Filled later by the initializer48/// Filled later by the initializer
49func_list: std.ArrayListUnmanaged(Func) = .empty,49func_list: std.ArrayListUnmanaged(Func) = .empty,
5050
51/// Starts out non-`null` if the `.eh_frame_hdr` section is present. May become `null` later if we
52/// find that `.eh_frame_hdr` is incomplete.
51eh_frame_hdr: ?ExceptionFrameHeader = null,53eh_frame_hdr: ?ExceptionFrameHeader = null,
52/// These lookup tables are only used if `eh_frame_hdr` is null54/// These lookup tables are only used if `eh_frame_hdr` is null
53cie_map: std.AutoArrayHashMapUnmanaged(u64, CommonInformationEntry) = .empty,55cie_map: std.AutoArrayHashMapUnmanaged(u64, CommonInformationEntry) = .empty,
...@@ -1754,10 +1756,12 @@ fn readDebugAddr(di: Dwarf, compile_unit: CompileUnit, index: u64) !u64 {...@@ -1754,10 +1756,12 @@ fn readDebugAddr(di: Dwarf, compile_unit: CompileUnit, index: u64) !u64 {
1754 };1756 };
1755}1757}
17561758
1757/// If .eh_frame_hdr is present, then only the header needs to be parsed.1759/// If `.eh_frame_hdr` is present, then only the header needs to be parsed. Otherwise, `.eh_frame`
1760/// and `.debug_frame` are scanned and a sorted list of FDEs is built for binary searching during
1761/// unwinding. Even if `.eh_frame_hdr` is used, we may find during unwinding that it's incomplete,
1762/// in which case we build the sorted list of FDEs at that point.
1758///1763///
1759/// Otherwise, .eh_frame and .debug_frame are scanned and a sorted list1764/// See also `scanCieFdeInfo`.
1760/// of FDEs is built for binary searching during unwinding.
1761pub fn scanAllUnwindInfo(di: *Dwarf, allocator: Allocator, base_address: usize) !void {1765pub fn scanAllUnwindInfo(di: *Dwarf, allocator: Allocator, base_address: usize) !void {
1762 if (di.section(.eh_frame_hdr)) |eh_frame_hdr| blk: {1766 if (di.section(.eh_frame_hdr)) |eh_frame_hdr| blk: {
1763 var fbr: FixedBufferReader = .{ .buf = eh_frame_hdr, .endian = native_endian };1767 var fbr: FixedBufferReader = .{ .buf = eh_frame_hdr, .endian = native_endian };
...@@ -1797,6 +1801,12 @@ pub fn scanAllUnwindInfo(di: *Dwarf, allocator: Allocator, base_address: usize)...@@ -1797,6 +1801,12 @@ pub fn scanAllUnwindInfo(di: *Dwarf, allocator: Allocator, base_address: usize)
1797 return;1801 return;
1798 }1802 }
17991803
1804 try di.scanCieFdeInfo(allocator, base_address);
1805}
1806
1807/// Scan `.eh_frame` and `.debug_frame` and build a sorted list of FDEs for binary searching during
1808/// unwinding.
1809pub fn scanCieFdeInfo(di: *Dwarf, allocator: Allocator, base_address: usize) !void {
1800 const frame_sections = [2]Section.Id{ .eh_frame, .debug_frame };1810 const frame_sections = [2]Section.Id{ .eh_frame, .debug_frame };
1801 for (frame_sections) |frame_section| {1811 for (frame_sections) |frame_section| {
1802 if (di.section(frame_section)) |section_data| {1812 if (di.section(frame_section)) |section_data| {
...@@ -2125,7 +2135,7 @@ pub const ElfModule = struct {...@@ -2125,7 +2135,7 @@ pub const ElfModule = struct {
2125 return self.dwarf.getSymbol(allocator, relocated_address);2135 return self.dwarf.getSymbol(allocator, relocated_address);
2126 }2136 }
21272137
2128 pub fn getDwarfInfoForAddress(self: *@This(), allocator: Allocator, address: usize) !?*const Dwarf {2138 pub fn getDwarfInfoForAddress(self: *@This(), allocator: Allocator, address: usize) !?*Dwarf {
2129 _ = allocator;2139 _ = allocator;
2130 _ = address;2140 _ = address;
2131 return &self.dwarf;2141 return &self.dwarf;
lib/std/debug/SelfInfo.zig+64-33
...@@ -707,7 +707,7 @@ pub const Module = switch (native_os) {...@@ -707,7 +707,7 @@ pub const Module = switch (native_os) {
707 }707 }
708 }708 }
709709
710 pub fn getDwarfInfoForAddress(self: *@This(), allocator: Allocator, address: usize) !?*const Dwarf {710 pub fn getDwarfInfoForAddress(self: *@This(), allocator: Allocator, address: usize) !?*Dwarf {
711 return if ((try self.getOFileInfoForAddress(allocator, address)).o_file_info) |o_file_info| &o_file_info.di else null;711 return if ((try self.getOFileInfoForAddress(allocator, address)).o_file_info) |o_file_info| &o_file_info.di else null;
712 }712 }
713 },713 },
...@@ -784,7 +784,7 @@ pub const Module = switch (native_os) {...@@ -784,7 +784,7 @@ pub const Module = switch (native_os) {
784 return .{};784 return .{};
785 }785 }
786786
787 pub fn getDwarfInfoForAddress(self: *@This(), allocator: Allocator, address: usize) !?*const Dwarf {787 pub fn getDwarfInfoForAddress(self: *@This(), allocator: Allocator, address: usize) !?*Dwarf {
788 _ = allocator;788 _ = allocator;
789 _ = address;789 _ = address;
790790
...@@ -808,7 +808,7 @@ pub const Module = switch (native_os) {...@@ -808,7 +808,7 @@ pub const Module = switch (native_os) {
808 return .{};808 return .{};
809 }809 }
810810
811 pub fn getDwarfInfoForAddress(self: *@This(), allocator: Allocator, address: usize) !?*const Dwarf {811 pub fn getDwarfInfoForAddress(self: *@This(), allocator: Allocator, address: usize) !?*Dwarf {
812 _ = self;812 _ = self;
813 _ = allocator;813 _ = allocator;
814 _ = address;814 _ = address;
...@@ -1156,11 +1156,12 @@ test machoSearchSymbols {...@@ -1156,11 +1156,12 @@ test machoSearchSymbols {
1156/// If the compact encoding can't encode a way to unwind a frame, it will1156/// If the compact encoding can't encode a way to unwind a frame, it will
1157/// defer unwinding to DWARF, in which case `.eh_frame` will be used if available.1157/// defer unwinding to DWARF, in which case `.eh_frame` will be used if available.
1158pub fn unwindFrameMachO(1158pub fn unwindFrameMachO(
1159 allocator: Allocator,
1160 base_address: usize,
1159 context: *UnwindContext,1161 context: *UnwindContext,
1160 ma: *std.debug.MemoryAccessor,1162 ma: *std.debug.MemoryAccessor,
1161 unwind_info: []const u8,1163 unwind_info: []const u8,
1162 eh_frame: ?[]const u8,1164 eh_frame: ?[]const u8,
1163 module_base_address: usize,
1164) !usize {1165) !usize {
1165 const header = std.mem.bytesAsValue(1166 const header = std.mem.bytesAsValue(
1166 macho.unwind_info_section_header,1167 macho.unwind_info_section_header,
...@@ -1172,7 +1173,7 @@ pub fn unwindFrameMachO(...@@ -1172,7 +1173,7 @@ pub fn unwindFrameMachO(
1172 );1173 );
1173 if (indices.len == 0) return error.MissingUnwindInfo;1174 if (indices.len == 0) return error.MissingUnwindInfo;
11741175
1175 const mapped_pc = context.pc - module_base_address;1176 const mapped_pc = context.pc - base_address;
1176 const second_level_index = blk: {1177 const second_level_index = blk: {
1177 var left: usize = 0;1178 var left: usize = 0;
1178 var len: usize = indices.len;1179 var len: usize = indices.len;
...@@ -1351,7 +1352,7 @@ pub fn unwindFrameMachO(...@@ -1351,7 +1352,7 @@ pub fn unwindFrameMachO(
1351 else stack_size: {1352 else stack_size: {
1352 // In .STACK_IND, the stack size is inferred from the subq instruction at the beginning of the function.1353 // In .STACK_IND, the stack size is inferred from the subq instruction at the beginning of the function.
1353 const sub_offset_addr =1354 const sub_offset_addr =
1354 module_base_address +1355 base_address +
1355 entry.function_offset +1356 entry.function_offset +
1356 encoding.value.x86_64.frameless.stack.indirect.sub_offset;1357 encoding.value.x86_64.frameless.stack.indirect.sub_offset;
1357 if (ma.load(usize, sub_offset_addr) == null) return error.InvalidUnwindInfo;1358 if (ma.load(usize, sub_offset_addr) == null) return error.InvalidUnwindInfo;
...@@ -1416,7 +1417,7 @@ pub fn unwindFrameMachO(...@@ -1416,7 +1417,7 @@ pub fn unwindFrameMachO(
1416 break :blk new_ip;1417 break :blk new_ip;
1417 },1418 },
1418 .DWARF => {1419 .DWARF => {
1419 return unwindFrameMachODwarf(context, ma, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.x86_64.dwarf));1420 return unwindFrameMachODwarf(allocator, base_address, context, ma, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.x86_64.dwarf));
1420 },1421 },
1421 },1422 },
1422 .aarch64, .aarch64_be => switch (encoding.mode.arm64) {1423 .aarch64, .aarch64_be => switch (encoding.mode.arm64) {
...@@ -1430,7 +1431,7 @@ pub fn unwindFrameMachO(...@@ -1430,7 +1431,7 @@ pub fn unwindFrameMachO(
1430 break :blk new_ip;1431 break :blk new_ip;
1431 },1432 },
1432 .DWARF => {1433 .DWARF => {
1433 return unwindFrameMachODwarf(context, ma, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.arm64.dwarf));1434 return unwindFrameMachODwarf(allocator, base_address, context, ma, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.arm64.dwarf));
1434 },1435 },
1435 .FRAME => blk: {1436 .FRAME => blk: {
1436 const fp = (try regValueNative(context.thread_context, fpRegNum(reg_context), reg_context)).*;1437 const fp = (try regValueNative(context.thread_context, fpRegNum(reg_context), reg_context)).*;
...@@ -1555,13 +1556,16 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize {...@@ -1555,13 +1556,16 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize {
15551556
1556/// Unwind a stack frame using DWARF unwinding info, updating the register context.1557/// Unwind a stack frame using DWARF unwinding info, updating the register context.
1557///1558///
1558/// If `.eh_frame_hdr` is available, it will be used to binary search for the FDE.1559/// If `.eh_frame_hdr` is available and complete, it will be used to binary search for the FDE.
1559/// Otherwise, a linear scan of `.eh_frame` and `.debug_frame` is done to find the FDE.1560/// Otherwise, a linear scan of `.eh_frame` and `.debug_frame` is done to find the FDE. The latter
1561/// may require lazily loading the data in those sections.
1560///1562///
1561/// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info1563/// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info
1562/// defers unwinding to DWARF. This is an offset into the `.eh_frame` section.1564/// defers unwinding to DWARF. This is an offset into the `.eh_frame` section.
1563pub fn unwindFrameDwarf(1565pub fn unwindFrameDwarf(
1564 di: *const Dwarf,1566 allocator: Allocator,
1567 di: *Dwarf,
1568 base_address: usize,
1565 context: *UnwindContext,1569 context: *UnwindContext,
1566 ma: *std.debug.MemoryAccessor,1570 ma: *std.debug.MemoryAccessor,
1567 explicit_fde_offset: ?usize,1571 explicit_fde_offset: ?usize,
...@@ -1570,10 +1574,7 @@ pub fn unwindFrameDwarf(...@@ -1570,10 +1574,7 @@ pub fn unwindFrameDwarf(
1570 if (context.pc == 0) return 0;1574 if (context.pc == 0) return 0;
15711575
1572 // Find the FDE and CIE1576 // Find the FDE and CIE
1573 var cie: Dwarf.CommonInformationEntry = undefined;1577 const cie, const fde = if (explicit_fde_offset) |fde_offset| blk: {
1574 var fde: Dwarf.FrameDescriptionEntry = undefined;
1575
1576 if (explicit_fde_offset) |fde_offset| {
1577 const dwarf_section: Dwarf.Section.Id = .eh_frame;1578 const dwarf_section: Dwarf.Section.Id = .eh_frame;
1578 const frame_section = di.section(dwarf_section) orelse return error.MissingFDE;1579 const frame_section = di.section(dwarf_section) orelse return error.MissingFDE;
1579 if (fde_offset >= frame_section.len) return error.MissingFDE;1580 if (fde_offset >= frame_section.len) return error.MissingFDE;
...@@ -1594,7 +1595,7 @@ pub fn unwindFrameDwarf(...@@ -1594,7 +1595,7 @@ pub fn unwindFrameDwarf(
1594 const cie_entry_header = try Dwarf.EntryHeader.read(&fbr, null, dwarf_section);1595 const cie_entry_header = try Dwarf.EntryHeader.read(&fbr, null, dwarf_section);
1595 if (cie_entry_header.type != .cie) return Dwarf.bad();1596 if (cie_entry_header.type != .cie) return Dwarf.bad();
15961597
1597 cie = try Dwarf.CommonInformationEntry.parse(1598 const cie = try Dwarf.CommonInformationEntry.parse(
1598 cie_entry_header.entry_bytes,1599 cie_entry_header.entry_bytes,
1599 0,1600 0,
1600 true,1601 true,
...@@ -1604,8 +1605,7 @@ pub fn unwindFrameDwarf(...@@ -1604,8 +1605,7 @@ pub fn unwindFrameDwarf(
1604 @sizeOf(usize),1605 @sizeOf(usize),
1605 native_endian,1606 native_endian,
1606 );1607 );
16071608 const fde = try Dwarf.FrameDescriptionEntry.parse(
1608 fde = try Dwarf.FrameDescriptionEntry.parse(
1609 fde_entry_header.entry_bytes,1609 fde_entry_header.entry_bytes,
1610 0,1610 0,
1611 true,1611 true,
...@@ -1613,17 +1613,44 @@ pub fn unwindFrameDwarf(...@@ -1613,17 +1613,44 @@ pub fn unwindFrameDwarf(
1613 @sizeOf(usize),1613 @sizeOf(usize),
1614 native_endian,1614 native_endian,
1615 );1615 );
1616 } else if (di.eh_frame_hdr) |header| {1616
1617 const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null;1617 break :blk .{ cie, fde };
1618 try header.findEntry(1618 } else blk: {
1619 ma,1619 // `.eh_frame_hdr` may be incomplete. We'll try it first, but if the lookup fails, we fall
1620 eh_frame_len,1620 // back to loading `.eh_frame`/`.debug_frame` and using those from that point on.
1621 @intFromPtr(di.section(.eh_frame_hdr).?.ptr),1621
1622 context.pc,1622 if (di.eh_frame_hdr) |header| hdr: {
1623 &cie,1623 const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null;
1624 &fde,1624
1625 );1625 var cie: Dwarf.CommonInformationEntry = undefined;
1626 } else {1626 var fde: Dwarf.FrameDescriptionEntry = undefined;
1627
1628 header.findEntry(
1629 ma,
1630 eh_frame_len,
1631 @intFromPtr(di.section(.eh_frame_hdr).?.ptr),
1632 context.pc,
1633 &cie,
1634 &fde,
1635 ) catch |err| switch (err) {
1636 error.InvalidDebugInfo => {
1637 // `.eh_frame_hdr` appears to be incomplete, so go ahead and populate `cie_map`
1638 // and `fde_list`, and fall back to the binary search logic below.
1639 try di.scanCieFdeInfo(allocator, base_address);
1640
1641 // Since `.eh_frame_hdr` is incomplete, we're very likely to get more lookup
1642 // failures using it, and we've just built a complete, sorted list of FDEs
1643 // anyway, so just stop using `.eh_frame_hdr` altogether.
1644 di.eh_frame_hdr = null;
1645
1646 break :hdr;
1647 },
1648 else => return err,
1649 };
1650
1651 break :blk .{ cie, fde };
1652 }
1653
1627 const index = std.sort.binarySearch(Dwarf.FrameDescriptionEntry, di.fde_list.items, context.pc, struct {1654 const index = std.sort.binarySearch(Dwarf.FrameDescriptionEntry, di.fde_list.items, context.pc, struct {
1628 pub fn compareFn(pc: usize, item: Dwarf.FrameDescriptionEntry) std.math.Order {1655 pub fn compareFn(pc: usize, item: Dwarf.FrameDescriptionEntry) std.math.Order {
1629 if (pc < item.pc_begin) return .lt;1656 if (pc < item.pc_begin) return .lt;
...@@ -1635,9 +1662,11 @@ pub fn unwindFrameDwarf(...@@ -1635,9 +1662,11 @@ pub fn unwindFrameDwarf(
1635 }1662 }
1636 }.compareFn);1663 }.compareFn);
16371664
1638 fde = if (index) |i| di.fde_list.items[i] else return error.MissingFDE;1665 const fde = if (index) |i| di.fde_list.items[i] else return error.MissingFDE;
1639 cie = di.cie_map.get(fde.cie_length_offset) orelse return error.MissingCIE;1666 const cie = di.cie_map.get(fde.cie_length_offset) orelse return error.MissingCIE;
1640 }1667
1668 break :blk .{ cie, fde };
1669 };
16411670
1642 var expression_context: Dwarf.expression.Context = .{1671 var expression_context: Dwarf.expression.Context = .{
1643 .format = cie.format,1672 .format = cie.format,
...@@ -1802,6 +1831,8 @@ pub fn supportsUnwinding(target: std.Target) bool {...@@ -1802,6 +1831,8 @@ pub fn supportsUnwinding(target: std.Target) bool {
1802}1831}
18031832
1804fn unwindFrameMachODwarf(1833fn unwindFrameMachODwarf(
1834 allocator: Allocator,
1835 base_address: usize,
1805 context: *UnwindContext,1836 context: *UnwindContext,
1806 ma: *std.debug.MemoryAccessor,1837 ma: *std.debug.MemoryAccessor,
1807 eh_frame: []const u8,1838 eh_frame: []const u8,
...@@ -1818,7 +1849,7 @@ fn unwindFrameMachODwarf(...@@ -1818,7 +1849,7 @@ fn unwindFrameMachODwarf(
1818 .owned = false,1849 .owned = false,
1819 };1850 };
18201851
1821 return unwindFrameDwarf(&di, context, ma, fde_offset);1852 return unwindFrameDwarf(allocator, &di, base_address, context, ma, fde_offset);
1822}1853}
18231854
1824/// This is a virtual machine that runs DWARF call frame instructions.1855/// This is a virtual machine that runs DWARF call frame instructions.
src/Compilation.zig+4-5
...@@ -1274,15 +1274,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1274,15 +1274,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1274 // The "any" values provided by resolved config only account for1274 // The "any" values provided by resolved config only account for
1275 // explicitly-provided settings. We now make them additionally account1275 // explicitly-provided settings. We now make them additionally account
1276 // for default setting resolution.1276 // for default setting resolution.
1277 const any_unwind_tables = switch (options.config.any_unwind_tables) {1277 const any_unwind_tables = options.config.any_unwind_tables or options.root_mod.unwind_tables != .none;
1278 .none => options.root_mod.unwind_tables,
1279 .sync, .@"async" => |uwt| uwt,
1280 };
1281 const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded;1278 const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded;
1282 const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread;1279 const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread;
1283 const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz;1280 const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz;
12841281
1285 const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables != .none;1282 const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables;
1286 const build_id = options.build_id orelse .none;1283 const build_id = options.build_id orelse .none;
12871284
1288 const link_libc = options.config.link_libc;1285 const link_libc = options.config.link_libc;
...@@ -6459,6 +6456,7 @@ fn buildOutputFromZig(...@@ -6459,6 +6456,7 @@ fn buildOutputFromZig(
6459 .root_optimize_mode = optimize_mode,6456 .root_optimize_mode = optimize_mode,
6460 .root_strip = strip,6457 .root_strip = strip,
6461 .link_libc = comp.config.link_libc,6458 .link_libc = comp.config.link_libc,
6459 .any_unwind_tables = comp.root_mod.unwind_tables != .none,
6462 });6460 });
64636461
6464 const root_mod = try Package.Module.create(arena, .{6462 const root_mod = try Package.Module.create(arena, .{
...@@ -6595,6 +6593,7 @@ pub fn build_crt_file(...@@ -6595,6 +6593,7 @@ pub fn build_crt_file(
6595 .root_optimize_mode = comp.compilerRtOptMode(),6593 .root_optimize_mode = comp.compilerRtOptMode(),
6596 .root_strip = comp.compilerRtStrip(),6594 .root_strip = comp.compilerRtStrip(),
6597 .link_libc = false,6595 .link_libc = false,
6596 .any_unwind_tables = options.unwind_tables != .none,
6598 .lto = switch (output_mode) {6597 .lto = switch (output_mode) {
6599 .Lib => comp.config.lto,6598 .Lib => comp.config.lto,
6600 .Obj, .Exe => .none,6599 .Obj, .Exe => .none,
src/Compilation/Config.zig+8-13
...@@ -12,14 +12,13 @@ link_libunwind: bool,...@@ -12,14 +12,13 @@ link_libunwind: bool,
12/// True if and only if the c_source_files field will have nonzero length when12/// True if and only if the c_source_files field will have nonzero length when
13/// calling Compilation.create.13/// calling Compilation.create.
14any_c_source_files: bool,14any_c_source_files: bool,
15/// This is not `.none` if any `Module` has `unwind_tables` set explicitly to a15/// This is `true` if any `Module` has `unwind_tables` set explicitly to a
16/// value other than `.none`. Until `Compilation.create()` is called, it is16/// value other than `.none`. Until `Compilation.create()` is called, it is
17/// possible for this to be `.none` while in fact all `Module` instances have17/// possible for this to be `false` while in fact all `Module` instances have
18/// `unwind_tables != .none` due to the default. After `Compilation.create()` is18/// `unwind_tables != .none` due to the default. After `Compilation.create()` is
19/// called, this will also take into account the default setting, making this19/// called, this will also take into account the default setting, making this
20/// value `.sync` or `.@"async"` if and only if any `Module` has20/// value `true` if and only if any `Module` has `unwind_tables != .none`.
21/// `unwind_tables != .none`.21any_unwind_tables: bool,
22any_unwind_tables: std.builtin.UnwindTables,
23/// This is true if any Module has single_threaded set explicitly to false. Until22/// This is true if any Module has single_threaded set explicitly to false. Until
24/// Compilation.create is called, it is possible for this to be false while in23/// Compilation.create is called, it is possible for this to be false while in
25/// fact all Module instances have single_threaded=false due to the default24/// fact all Module instances have single_threaded=false due to the default
...@@ -57,6 +56,7 @@ export_memory: bool,...@@ -57,6 +56,7 @@ export_memory: bool,
57shared_memory: bool,56shared_memory: bool,
58is_test: bool,57is_test: bool,
59debug_format: DebugFormat,58debug_format: DebugFormat,
59root_optimize_mode: std.builtin.OptimizeMode,
60root_strip: bool,60root_strip: bool,
61root_error_tracing: bool,61root_error_tracing: bool,
62dll_export_fns: bool,62dll_export_fns: bool,
...@@ -88,7 +88,7 @@ pub const Options = struct {...@@ -88,7 +88,7 @@ pub const Options = struct {
88 any_non_single_threaded: bool = false,88 any_non_single_threaded: bool = false,
89 any_sanitize_thread: bool = false,89 any_sanitize_thread: bool = false,
90 any_fuzz: bool = false,90 any_fuzz: bool = false,
91 any_unwind_tables: std.builtin.UnwindTables = .none,91 any_unwind_tables: bool = false,
92 any_dyn_libs: bool = false,92 any_dyn_libs: bool = false,
93 any_c_source_files: bool = false,93 any_c_source_files: bool = false,
94 any_non_stripped: bool = false,94 any_non_stripped: bool = false,
...@@ -359,12 +359,6 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -359,12 +359,6 @@ pub fn resolve(options: Options) ResolveError!Config {
359 break :b false;359 break :b false;
360 };360 };
361361
362 const any_unwind_tables = b: {
363 if (options.any_unwind_tables != .none) break :b options.any_unwind_tables;
364
365 break :b target_util.needUnwindTables(target, link_libunwind, options.any_sanitize_thread);
366 };
367
368 const link_mode = b: {362 const link_mode = b: {
369 const explicitly_exe_or_dyn_lib = switch (options.output_mode) {363 const explicitly_exe_or_dyn_lib = switch (options.output_mode) {
370 .Obj => false,364 .Obj => false,
...@@ -496,7 +490,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -496,7 +490,7 @@ pub fn resolve(options: Options) ResolveError!Config {
496 .link_libc = link_libc,490 .link_libc = link_libc,
497 .link_libcpp = link_libcpp,491 .link_libcpp = link_libcpp,
498 .link_libunwind = link_libunwind,492 .link_libunwind = link_libunwind,
499 .any_unwind_tables = any_unwind_tables,493 .any_unwind_tables = options.any_unwind_tables,
500 .any_c_source_files = options.any_c_source_files,494 .any_c_source_files = options.any_c_source_files,
501 .any_non_single_threaded = options.any_non_single_threaded,495 .any_non_single_threaded = options.any_non_single_threaded,
502 .any_error_tracing = any_error_tracing,496 .any_error_tracing = any_error_tracing,
...@@ -515,6 +509,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -515,6 +509,7 @@ pub fn resolve(options: Options) ResolveError!Config {
515 .use_lld = use_lld,509 .use_lld = use_lld,
516 .wasi_exec_model = wasi_exec_model,510 .wasi_exec_model = wasi_exec_model,
517 .debug_format = debug_format,511 .debug_format = debug_format,
512 .root_optimize_mode = root_optimize_mode,
518 .root_strip = root_strip,513 .root_strip = root_strip,
519 .dll_export_fns = dll_export_fns,514 .dll_export_fns = dll_export_fns,
520 .rdynamic = rdynamic,515 .rdynamic = rdynamic,
src/Package/Module.zig+13-5
...@@ -112,17 +112,14 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -112,17 +112,14 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
112 if (options.inherited.sanitize_thread == true) assert(options.global.any_sanitize_thread);112 if (options.inherited.sanitize_thread == true) assert(options.global.any_sanitize_thread);
113 if (options.inherited.fuzz == true) assert(options.global.any_fuzz);113 if (options.inherited.fuzz == true) assert(options.global.any_fuzz);
114 if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded);114 if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded);
115 if (options.inherited.unwind_tables) |uwt| if (uwt != .none) assert(options.global.any_unwind_tables != .none);115 if (options.inherited.unwind_tables) |uwt| if (uwt != .none) assert(options.global.any_unwind_tables);
116 if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing);116 if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing);
117117
118 const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target;118 const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target;
119 const target = resolved_target.result;119 const target = resolved_target.result;
120120
121 const optimize_mode = options.inherited.optimize_mode orelse121 const optimize_mode = options.inherited.optimize_mode orelse
122 if (options.parent) |p| p.optimize_mode else .Debug;122 if (options.parent) |p| p.optimize_mode else options.global.root_optimize_mode;
123
124 const unwind_tables = options.inherited.unwind_tables orelse
125 if (options.parent) |p| p.unwind_tables else options.global.any_unwind_tables;
126123
127 const strip = b: {124 const strip = b: {
128 if (options.inherited.strip) |x| break :b x;125 if (options.inherited.strip) |x| break :b x;
...@@ -220,6 +217,17 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -220,6 +217,17 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
220 break :b false;217 break :b false;
221 };218 };
222219
220 const unwind_tables = b: {
221 if (options.inherited.unwind_tables) |x| break :b x;
222 if (options.parent) |p| break :b p.unwind_tables;
223
224 break :b target_util.defaultUnwindTables(
225 target,
226 options.global.link_libunwind,
227 sanitize_thread or options.global.any_sanitize_thread,
228 );
229 };
230
223 const fuzz = b: {231 const fuzz = b: {
224 if (options.inherited.fuzz) |x| break :b x;232 if (options.inherited.fuzz) |x| break :b x;
225 if (options.parent) |p| break :b p.fuzz;233 if (options.parent) |p| break :b p.fuzz;
src/libcxx.zig+6-6
...@@ -397,6 +397,10 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -397,6 +397,10 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
397397
398 const optimize_mode = comp.compilerRtOptMode();398 const optimize_mode = comp.compilerRtOptMode();
399 const strip = comp.compilerRtStrip();399 const strip = comp.compilerRtStrip();
400 // See the `-fno-exceptions` logic for WASI.
401 // The old 32-bit x86 variant of SEH doesn't use tables.
402 const unwind_tables: std.builtin.UnwindTables =
403 if (target.os.tag == .wasi or (target.cpu.arch == .x86 and target.os.tag == .windows)) .none else .@"async";
400404
401 const config = Compilation.Config.resolve(.{405 const config = Compilation.Config.resolve(.{
402 .output_mode = output_mode,406 .output_mode = output_mode,
...@@ -408,6 +412,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -408,6 +412,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
408 .root_optimize_mode = optimize_mode,412 .root_optimize_mode = optimize_mode,
409 .root_strip = strip,413 .root_strip = strip,
410 .link_libc = true,414 .link_libc = true,
415 .any_unwind_tables = unwind_tables != .none,
411 .lto = comp.config.lto,416 .lto = comp.config.lto,
412 .any_sanitize_thread = comp.config.any_sanitize_thread,417 .any_sanitize_thread = comp.config.any_sanitize_thread,
413 }) catch |err| {418 }) catch |err| {
...@@ -438,12 +443,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -438,12 +443,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
438 .valgrind = false,443 .valgrind = false,
439 .optimize_mode = optimize_mode,444 .optimize_mode = optimize_mode,
440 .structured_cfg = comp.root_mod.structured_cfg,445 .structured_cfg = comp.root_mod.structured_cfg,
441 // See the `-fno-exceptions` logic for WASI.446 .unwind_tables = unwind_tables,
442 // The old 32-bit x86 variant of SEH doesn't use tables.
443 .unwind_tables = if (target.os.tag == .wasi or (target.cpu.arch == .x86 and target.os.tag == .windows))
444 .none
445 else
446 .@"async",
447 .pic = comp.root_mod.pic,447 .pic = comp.root_mod.pic,
448 },448 },
449 .global = config,449 .global = config,
src/libunwind.zig+5-2
...@@ -27,6 +27,9 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -27,6 +27,9 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
27 const arena = arena_allocator.allocator();27 const arena = arena_allocator.allocator();
2828
29 const output_mode = .Lib;29 const output_mode = .Lib;
30 const target = comp.root_mod.resolved_target.result;
31 const unwind_tables: std.builtin.UnwindTables =
32 if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async";
30 const config = Compilation.Config.resolve(.{33 const config = Compilation.Config.resolve(.{
31 .output_mode = .Lib,34 .output_mode = .Lib,
32 .resolved_target = comp.root_mod.resolved_target,35 .resolved_target = comp.root_mod.resolved_target,
...@@ -36,6 +39,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -36,6 +39,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
36 .root_optimize_mode = comp.compilerRtOptMode(),39 .root_optimize_mode = comp.compilerRtOptMode(),
37 .root_strip = comp.compilerRtStrip(),40 .root_strip = comp.compilerRtStrip(),
38 .link_libc = true,41 .link_libc = true,
42 .any_unwind_tables = unwind_tables != .none,
39 .lto = comp.config.lto,43 .lto = comp.config.lto,
40 }) catch |err| {44 }) catch |err| {
41 comp.setMiscFailure(45 comp.setMiscFailure(
...@@ -45,7 +49,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -45,7 +49,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
45 );49 );
46 return error.SubCompilationFailed;50 return error.SubCompilationFailed;
47 };51 };
48 const target = comp.root_mod.resolved_target.result;
49 const root_mod = Module.create(arena, .{52 const root_mod = Module.create(arena, .{
50 .global_cache_directory = comp.global_cache_directory,53 .global_cache_directory = comp.global_cache_directory,
51 .paths = .{54 .paths = .{
...@@ -65,7 +68,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -65,7 +68,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
65 .sanitize_thread = false,68 .sanitize_thread = false,
66 // necessary so that libunwind can unwind through its own stack frames69 // necessary so that libunwind can unwind through its own stack frames
67 // The old 32-bit x86 variant of SEH doesn't use tables.70 // The old 32-bit x86 variant of SEH doesn't use tables.
68 .unwind_tables = if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async",71 .unwind_tables = unwind_tables,
69 .pic = if (target_util.supports_fpic(target)) true else null,72 .pic = if (target_util.supports_fpic(target)) true else null,
70 .optimize_mode = comp.compilerRtOptMode(),73 .optimize_mode = comp.compilerRtOptMode(),
71 },74 },
src/main.zig+5-12
...@@ -575,6 +575,7 @@ const usage_build_generic =...@@ -575,6 +575,7 @@ const usage_build_generic =
575 \\ 0x[hexstring] Maximum 32 bytes575 \\ 0x[hexstring] Maximum 32 bytes
576 \\ none (default) Disable build-id576 \\ none (default) Disable build-id
577 \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker577 \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker
578 \\ --no-eh-frame-hdr Disable C++ exception handling by passing --no-eh-frame-hdr to linker
578 \\ --emit-relocs Enable output of relocation sections for post build tools579 \\ --emit-relocs Enable output of relocation sections for post build tools
579 \\ -z [arg] Set linker extension flags580 \\ -z [arg] Set linker extension flags
580 \\ nodelete Indicate that the object cannot be deleted from a process581 \\ nodelete Indicate that the object cannot be deleted from a process
...@@ -1582,6 +1583,8 @@ fn buildOutputType(...@@ -1582,6 +1583,8 @@ fn buildOutputType(
1582 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1583 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
1583 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {1584 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
1584 link_eh_frame_hdr = true;1585 link_eh_frame_hdr = true;
1586 } else if (mem.eql(u8, arg, "--no-eh-frame-hdr")) {
1587 link_eh_frame_hdr = false;
1585 } else if (mem.eql(u8, arg, "--dynamicbase")) {1588 } else if (mem.eql(u8, arg, "--dynamicbase")) {
1586 linker_dynamicbase = true;1589 linker_dynamicbase = true;
1587 } else if (mem.eql(u8, arg, "--no-dynamicbase")) {1590 } else if (mem.eql(u8, arg, "--no-dynamicbase")) {
...@@ -2846,12 +2849,7 @@ fn buildOutputType(...@@ -2846,12 +2849,7 @@ fn buildOutputType(
2846 create_module.opts.any_fuzz = true;2849 create_module.opts.any_fuzz = true;
2847 if (mod_opts.unwind_tables) |uwt| switch (uwt) {2850 if (mod_opts.unwind_tables) |uwt| switch (uwt) {
2848 .none => {},2851 .none => {},
2849 .sync => if (create_module.opts.any_unwind_tables == .none) {2852 .sync, .@"async" => create_module.opts.any_unwind_tables = true,
2850 create_module.opts.any_unwind_tables = .sync;
2851 },
2852 .@"async" => {
2853 create_module.opts.any_unwind_tables = .@"async";
2854 },
2855 };2853 };
2856 if (mod_opts.strip == false)2854 if (mod_opts.strip == false)
2857 create_module.opts.any_non_stripped = true;2855 create_module.opts.any_non_stripped = true;
...@@ -7563,12 +7561,7 @@ fn handleModArg(...@@ -7563,12 +7561,7 @@ fn handleModArg(
7563 create_module.opts.any_fuzz = true;7561 create_module.opts.any_fuzz = true;
7564 if (mod_opts.unwind_tables) |uwt| switch (uwt) {7562 if (mod_opts.unwind_tables) |uwt| switch (uwt) {
7565 .none => {},7563 .none => {},
7566 .sync => if (create_module.opts.any_unwind_tables == .none) {7564 .sync, .@"async" => create_module.opts.any_unwind_tables = true,
7567 create_module.opts.any_unwind_tables = .sync;
7568 },
7569 .@"async" => {
7570 create_module.opts.any_unwind_tables = .@"async";
7571 },
7572 };7565 };
7573 if (mod_opts.strip == false)7566 if (mod_opts.strip == false)
7574 create_module.opts.any_non_stripped = true;7567 create_module.opts.any_non_stripped = true;
src/target.zig+1-1
...@@ -407,7 +407,7 @@ pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool {...@@ -407,7 +407,7 @@ pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool {
407 };407 };
408}408}
409409
410pub fn needUnwindTables(target: std.Target, libunwind: bool, libtsan: bool) std.builtin.UnwindTables {410pub fn defaultUnwindTables(target: std.Target, libunwind: bool, libtsan: bool) std.builtin.UnwindTables {
411 if (target.os.tag == .windows) {411 if (target.os.tag == .windows) {
412 // The old 32-bit x86 variant of SEH doesn't use tables.412 // The old 32-bit x86 variant of SEH doesn't use tables.
413 return if (target.cpu.arch != .x86) .@"async" else .none;413 return if (target.cpu.arch != .x86) .@"async" else .none;
test/src/StackTrace.zig+25-6
...@@ -21,17 +21,34 @@ const Config = struct {...@@ -21,17 +21,34 @@ const Config = struct {
21};21};
2222
23pub fn addCase(self: *StackTrace, config: Config) void {23pub fn addCase(self: *StackTrace, config: Config) void {
24 self.addCaseInner(config, true);
25 if (shouldTestNonLlvm(self.b.graph.host.result)) {
26 self.addCaseInner(config, false);
27 }
28}
29
30fn addCaseInner(self: *StackTrace, config: Config, use_llvm: bool) void {
24 if (config.Debug) |per_mode|31 if (config.Debug) |per_mode|
25 self.addExpect(config.name, config.source, .Debug, per_mode);32 self.addExpect(config.name, config.source, .Debug, use_llvm, per_mode);
2633
27 if (config.ReleaseSmall) |per_mode|34 if (config.ReleaseSmall) |per_mode|
28 self.addExpect(config.name, config.source, .ReleaseSmall, per_mode);35 self.addExpect(config.name, config.source, .ReleaseSmall, use_llvm, per_mode);
2936
30 if (config.ReleaseFast) |per_mode|37 if (config.ReleaseFast) |per_mode|
31 self.addExpect(config.name, config.source, .ReleaseFast, per_mode);38 self.addExpect(config.name, config.source, .ReleaseFast, use_llvm, per_mode);
3239
33 if (config.ReleaseSafe) |per_mode|40 if (config.ReleaseSafe) |per_mode|
34 self.addExpect(config.name, config.source, .ReleaseSafe, per_mode);41 self.addExpect(config.name, config.source, .ReleaseSafe, use_llvm, per_mode);
42}
43
44fn shouldTestNonLlvm(target: std.Target) bool {
45 return switch (target.cpu.arch) {
46 .x86_64 => switch (target.ofmt) {
47 .elf => true,
48 else => false,
49 },
50 else => false,
51 };
35}52}
3653
37fn addExpect(54fn addExpect(
...@@ -39,13 +56,14 @@ fn addExpect(...@@ -39,13 +56,14 @@ fn addExpect(
39 name: []const u8,56 name: []const u8,
40 source: []const u8,57 source: []const u8,
41 optimize_mode: OptimizeMode,58 optimize_mode: OptimizeMode,
59 use_llvm: bool,
42 mode_config: Config.PerMode,60 mode_config: Config.PerMode,
43) void {61) void {
44 for (mode_config.exclude_os) |tag| if (tag == builtin.os.tag) return;62 for (mode_config.exclude_os) |tag| if (tag == builtin.os.tag) return;
4563
46 const b = self.b;64 const b = self.b;
47 const annotated_case_name = b.fmt("check {s} ({s})", .{65 const annotated_case_name = b.fmt("check {s} ({s} {s})", .{
48 name, @tagName(optimize_mode),66 name, @tagName(optimize_mode), if (use_llvm) "llvm" else "selfhosted",
49 });67 });
50 for (self.test_filters) |test_filter| {68 for (self.test_filters) |test_filter| {
51 if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;69 if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
...@@ -61,6 +79,7 @@ fn addExpect(...@@ -61,6 +79,7 @@ fn addExpect(
61 .target = b.graph.host,79 .target = b.graph.host,
62 .error_tracing = mode_config.error_tracing,80 .error_tracing = mode_config.error_tracing,
63 }),81 }),
82 .use_llvm = use_llvm,
64 });83 });
6584
66 const run = b.addRunArtifact(exe);85 const run = b.addRunArtifact(exe);
test/src/check-stack-trace.zig+15-6
...@@ -58,14 +58,23 @@ pub fn main() !void {...@@ -58,14 +58,23 @@ pub fn main() !void {
58 try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);58 try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);
59 try buf.appendSlice(" [address]");59 try buf.appendSlice(" [address]");
60 if (optimize_mode == .Debug) {60 if (optimize_mode == .Debug) {
61 // On certain platforms (windows) or possibly depending on how we choose to link main61 try buf.appendSlice(line[marks[3] .. marks[4] + delims[4].len]);
62 // the object file extension may be present so we simply strip any extension.62
63 if (mem.indexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| {63 const file_name = line[marks[4] + delims[4].len .. marks[5]];
64 try buf.appendSlice(line[marks[3] .. marks[4] + idot]);64 // The LLVM backend currently uses the object file name in the debug info here.
65 try buf.appendSlice(line[marks[5]..]);65 // This actually violates the DWARF specification (DWARF5 § 3.1.1, lines 24-27).
66 // The self-hosted backend uses the root Zig source file of the module (in compilance with the spec).
67 if (std.mem.eql(u8, file_name, "test") or
68 std.mem.eql(u8, file_name, "test.exe.obj") or
69 std.mem.endsWith(u8, file_name, ".zig"))
70 {
71 try buf.appendSlice("[main_file]");
66 } else {72 } else {
67 try buf.appendSlice(line[marks[3]..]);73 // Something unexpected; include it verbatim.
74 try buf.appendSlice(file_name);
68 }75 }
76
77 try buf.appendSlice(line[marks[5]..]);
69 } else {78 } else {
70 try buf.appendSlice(line[marks[3] .. marks[3] + delims[3].len]);79 try buf.appendSlice(line[marks[3] .. marks[3] + delims[3].len]);
71 try buf.appendSlice("[function]");80 try buf.appendSlice("[function]");
test/stack_traces.zig+30-30
...@@ -13,7 +13,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -13,7 +13,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
13 .Debug = .{13 .Debug = .{
14 .expect =14 .expect =
15 \\error: TheSkyIsFalling15 \\error: TheSkyIsFalling
16 \\source.zig:2:5: [address] in main (test)16 \\source.zig:2:5: [address] in main ([main_file])
17 \\ return error.TheSkyIsFalling;17 \\ return error.TheSkyIsFalling;
18 \\ ^18 \\ ^
19 \\19 \\
...@@ -61,10 +61,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -61,10 +61,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
61 .Debug = .{61 .Debug = .{
62 .expect =62 .expect =
63 \\error: TheSkyIsFalling63 \\error: TheSkyIsFalling
64 \\source.zig:2:5: [address] in foo (test)64 \\source.zig:2:5: [address] in foo ([main_file])
65 \\ return error.TheSkyIsFalling;65 \\ return error.TheSkyIsFalling;
66 \\ ^66 \\ ^
67 \\source.zig:6:5: [address] in main (test)67 \\source.zig:6:5: [address] in main ([main_file])
68 \\ try foo();68 \\ try foo();
69 \\ ^69 \\ ^
70 \\70 \\
...@@ -120,7 +120,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -120,7 +120,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
120 .Debug = .{120 .Debug = .{
121 .expect =121 .expect =
122 \\error: UnrelatedError122 \\error: UnrelatedError
123 \\source.zig:13:5: [address] in main (test)123 \\source.zig:13:5: [address] in main ([main_file])
124 \\ return error.UnrelatedError;124 \\ return error.UnrelatedError;
125 \\ ^125 \\ ^
126 \\126 \\
...@@ -172,7 +172,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -172,7 +172,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
172 .Debug = .{172 .Debug = .{
173 .expect =173 .expect =
174 \\error: UnrelatedError174 \\error: UnrelatedError
175 \\source.zig:10:5: [address] in main (test)175 \\source.zig:10:5: [address] in main ([main_file])
176 \\ return error.UnrelatedError;176 \\ return error.UnrelatedError;
177 \\ ^177 \\ ^
178 \\178 \\
...@@ -224,10 +224,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -224,10 +224,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
224 .Debug = .{224 .Debug = .{
225 .expect =225 .expect =
226 \\error: TheSkyIsFalling226 \\error: TheSkyIsFalling
227 \\source.zig:2:5: [address] in foo (test)227 \\source.zig:2:5: [address] in foo ([main_file])
228 \\ return error.TheSkyIsFalling;228 \\ return error.TheSkyIsFalling;
229 \\ ^229 \\ ^
230 \\source.zig:10:5: [address] in main (test)230 \\source.zig:10:5: [address] in main ([main_file])
231 \\ try foo();231 \\ try foo();
232 \\ ^232 \\ ^
233 \\233 \\
...@@ -284,7 +284,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -284,7 +284,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
284 .Debug = .{284 .Debug = .{
285 .expect =285 .expect =
286 \\error: BadTime286 \\error: BadTime
287 \\source.zig:12:5: [address] in main (test)287 \\source.zig:12:5: [address] in main ([main_file])
288 \\ return error.BadTime;288 \\ return error.BadTime;
289 \\ ^289 \\ ^
290 \\290 \\
...@@ -332,10 +332,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -332,10 +332,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
332 .Debug = .{332 .Debug = .{
333 .expect =333 .expect =
334 \\error: AndMyCarIsOutOfGas334 \\error: AndMyCarIsOutOfGas
335 \\source.zig:2:5: [address] in foo (test)335 \\source.zig:2:5: [address] in foo ([main_file])
336 \\ return error.TheSkyIsFalling;336 \\ return error.TheSkyIsFalling;
337 \\ ^337 \\ ^
338 \\source.zig:6:5: [address] in main (test)338 \\source.zig:6:5: [address] in main ([main_file])
339 \\ return foo() catch error.AndMyCarIsOutOfGas;339 \\ return foo() catch error.AndMyCarIsOutOfGas;
340 \\ ^340 \\ ^
341 \\341 \\
...@@ -391,7 +391,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -391,7 +391,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
391 .Debug = .{391 .Debug = .{
392 .expect =392 .expect =
393 \\error: SomethingUnrelatedWentWrong393 \\error: SomethingUnrelatedWentWrong
394 \\source.zig:11:5: [address] in main (test)394 \\source.zig:11:5: [address] in main ([main_file])
395 \\ return error.SomethingUnrelatedWentWrong;395 \\ return error.SomethingUnrelatedWentWrong;
396 \\ ^396 \\ ^
397 \\397 \\
...@@ -456,13 +456,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -456,13 +456,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
456 .Debug = .{456 .Debug = .{
457 .expect =457 .expect =
458 \\error: StillUnresolved458 \\error: StillUnresolved
459 \\source.zig:1:18: [address] in foo (test)459 \\source.zig:1:18: [address] in foo ([main_file])
460 \\fn foo() !void { return error.TheSkyIsFalling; }460 \\fn foo() !void { return error.TheSkyIsFalling; }
461 \\ ^461 \\ ^
462 \\source.zig:2:18: [address] in bar (test)462 \\source.zig:2:18: [address] in bar ([main_file])
463 \\fn bar() !void { return error.InternalError; }463 \\fn bar() !void { return error.InternalError; }
464 \\ ^464 \\ ^
465 \\source.zig:23:5: [address] in main (test)465 \\source.zig:23:5: [address] in main ([main_file])
466 \\ return error.StillUnresolved;466 \\ return error.StillUnresolved;
467 \\ ^467 \\ ^
468 \\468 \\
...@@ -527,13 +527,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -527,13 +527,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
527 .Debug = .{527 .Debug = .{
528 .expect =528 .expect =
529 \\error: TestExpectedError529 \\error: TestExpectedError
530 \\source.zig:9:18: [address] in foo (test)530 \\source.zig:9:18: [address] in foo ([main_file])
531 \\fn foo() !void { return error.Foo; }531 \\fn foo() !void { return error.Foo; }
532 \\ ^532 \\ ^
533 \\source.zig:5:5: [address] in expectError (test)533 \\source.zig:5:5: [address] in expectError ([main_file])
534 \\ return error.TestExpectedError;534 \\ return error.TestExpectedError;
535 \\ ^535 \\ ^
536 \\source.zig:17:5: [address] in main (test)536 \\source.zig:17:5: [address] in main ([main_file])
537 \\ try expectError(error.Bar, foo());537 \\ try expectError(error.Bar, foo());
538 \\ ^538 \\ ^
539 \\539 \\
...@@ -592,13 +592,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -592,13 +592,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
592 .Debug = .{592 .Debug = .{
593 .expect =593 .expect =
594 \\error: AndMyCarIsOutOfGas594 \\error: AndMyCarIsOutOfGas
595 \\source.zig:2:5: [address] in foo (test)595 \\source.zig:2:5: [address] in foo ([main_file])
596 \\ return error.TheSkyIsFalling;596 \\ return error.TheSkyIsFalling;
597 \\ ^597 \\ ^
598 \\source.zig:6:5: [address] in bar (test)598 \\source.zig:6:5: [address] in bar ([main_file])
599 \\ return error.AndMyCarIsOutOfGas;599 \\ return error.AndMyCarIsOutOfGas;
600 \\ ^600 \\ ^
601 \\source.zig:11:9: [address] in main (test)601 \\source.zig:11:9: [address] in main ([main_file])
602 \\ try bar();602 \\ try bar();
603 \\ ^603 \\ ^
604 \\604 \\
...@@ -657,13 +657,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -657,13 +657,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
657 .Debug = .{657 .Debug = .{
658 .expect =658 .expect =
659 \\error: AndMyCarIsOutOfGas659 \\error: AndMyCarIsOutOfGas
660 \\source.zig:2:5: [address] in foo (test)660 \\source.zig:2:5: [address] in foo ([main_file])
661 \\ return error.TheSkyIsFalling;661 \\ return error.TheSkyIsFalling;
662 \\ ^662 \\ ^
663 \\source.zig:6:5: [address] in bar (test)663 \\source.zig:6:5: [address] in bar ([main_file])
664 \\ return error.AndMyCarIsOutOfGas;664 \\ return error.AndMyCarIsOutOfGas;
665 \\ ^665 \\ ^
666 \\source.zig:11:9: [address] in main (test)666 \\source.zig:11:9: [address] in main ([main_file])
667 \\ try bar();667 \\ try bar();
668 \\ ^668 \\ ^
669 \\669 \\
...@@ -724,16 +724,16 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -724,16 +724,16 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
724 .Debug = .{724 .Debug = .{
725 .expect =725 .expect =
726 \\error: TheSkyIsFalling726 \\error: TheSkyIsFalling
727 \\source.zig:10:5: [address] in make_error (test)727 \\source.zig:10:5: [address] in make_error ([main_file])
728 \\ return error.TheSkyIsFalling;728 \\ return error.TheSkyIsFalling;
729 \\ ^729 \\ ^
730 \\source.zig:6:5: [address] in bar (test)730 \\source.zig:6:5: [address] in bar ([main_file])
731 \\ return make_error();731 \\ return make_error();
732 \\ ^732 \\ ^
733 \\source.zig:2:5: [address] in foo (test)733 \\source.zig:2:5: [address] in foo ([main_file])
734 \\ try bar();734 \\ try bar();
735 \\ ^735 \\ ^
736 \\source.zig:14:5: [address] in main (test)736 \\source.zig:14:5: [address] in main ([main_file])
737 \\ try foo();737 \\ try foo();
738 \\ ^738 \\ ^
739 \\739 \\
...@@ -797,10 +797,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -797,10 +797,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
797 .windows, // TODO intermittent failures797 .windows, // TODO intermittent failures
798 },798 },
799 .expect =799 .expect =
800 \\source.zig:7:8: [address] in foo (test)800 \\source.zig:7:8: [address] in foo ([main_file])
801 \\ bar();801 \\ bar();
802 \\ ^802 \\ ^
803 \\source.zig:10:8: [address] in main (test)803 \\source.zig:10:8: [address] in main ([main_file])
804 \\ foo();804 \\ foo();
805 \\ ^805 \\ ^
806 \\806 \\
...@@ -829,7 +829,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -829,7 +829,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
829 .Debug = .{829 .Debug = .{
830 .expect =830 .expect =
831 \\error: TheSkyIsFalling831 \\error: TheSkyIsFalling
832 \\source.zig:3:5: [address] in main (test)832 \\source.zig:3:5: [address] in main ([main_file])
833 \\ return error.TheSkyIsFalling;833 \\ return error.TheSkyIsFalling;
834 \\ ^834 \\ ^
835 \\835 \\