From 22f9592dc7db869b2a618a72560fd0cf25b62d42 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Fri, 20 Mar 2026 17:51:34 -0700 Subject: [PATCH 01/29] First pass at reading inline info from PDBs --- lib/std/debug.zig | 67 +++-- lib/std/debug/Pdb.zig | 467 ++++++++++++++++++++++++++++- lib/std/debug/SelfInfo/Elf.zig | 40 ++- lib/std/debug/SelfInfo/Windows.zig | 197 +++++++++--- lib/std/pdb.zig | 152 +++++++++- 5 files changed, 825 insertions(+), 98 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 3e05aa49d79ed4abab6a23fbcaa8433c12702f30..78e1b8df23ae775503e655e5901460dd4601f6d1 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -39,8 +39,8 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// pub const init: SelfInfo; /// pub fn deinit(si: *SelfInfo, io: Io) void; /// -/// /// Returns the symbol and source location of the instruction at `address`. -/// pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) SelfInfoError!Symbol; +/// /// Returns an iterator over the symbols and source locations of the instruction at `address`. +/// pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SelfInfo.SymbolIterator; /// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`. /// pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const u8; /// pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) SelfInfoError!usize; @@ -61,6 +61,11 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// /// Only required if `can_unwind == true`. Unwinds a single stack frame, returning the frame's /// /// return address, or 0 if the end of the stack has been reached. /// pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) SelfInfoError!usize; +/// /// Iterates symbols found at an address. +/// pub const SymbolIterator = struct { +/// pub fn deinit(Self: *SymbolIterator, io: Io) void; +/// pub fn next(self: *SymbolIterator) ?SelfInfoError!Symbol; +/// }; /// ``` pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo")) root.debug.SelfInfo @@ -1107,33 +1112,37 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { } fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: usize) Writer.Error!void { - const symbol: Symbol = debug_info.getSymbol(io, address) catch |err| switch (err) { - error.MissingDebugInfo, - error.UnsupportedDebugInfo, - error.InvalidDebugInfo, - => .unknown, - error.ReadFailed, error.Unexpected, error.Canceled => s: { - t.setColor(.dim) catch {}; - try t.writer.print("Failed to read debug info from filesystem, trace may be incomplete\n\n", .{}); - t.setColor(.reset) catch {}; - break :s .unknown; - }, - error.OutOfMemory => s: { - t.setColor(.dim) catch {}; - try t.writer.print("Ran out of memory loading debug info, trace may be incomplete\n\n", .{}); - t.setColor(.reset) catch {}; - break :s .unknown; - }, - }; - defer if (symbol.source_location) |sl| getDebugInfoAllocator().free(sl.file_name); - return printLineInfo( - io, - t, - symbol.source_location, - address, - symbol.name orelse "???", - symbol.compile_unit_name orelse debug_info.getModuleName(io, address) catch "???", - ); + var symbols: SelfInfo.SymbolIterator = debug_info.getSymbols(io, address); + defer symbols.deinit(io); + while (symbols.next()) |curr| { + const symbol: Symbol = curr catch |err| switch (err) { + error.MissingDebugInfo, + error.UnsupportedDebugInfo, + error.InvalidDebugInfo, + => .unknown, + error.ReadFailed, error.Unexpected, error.Canceled => s: { + t.setColor(.dim) catch {}; + try t.writer.print("Failed to read debug info from filesystem, trace may be incomplete\n\n", .{}); + t.setColor(.reset) catch {}; + break :s .unknown; + }, + error.OutOfMemory => s: { + t.setColor(.dim) catch {}; + try t.writer.print("Ran out of memory loading debug info, trace may be incomplete\n\n", .{}); + t.setColor(.reset) catch {}; + break :s .unknown; + }, + }; + defer if (symbol.source_location) |sl| getDebugInfoAllocator().free(sl.file_name); + try printLineInfo( + io, + t, + symbol.source_location, + address, + symbol.name orelse "???", + symbol.compile_unit_name orelse debug_info.getModuleName(io, address) catch "???", + ); + } } fn printLineInfo( io: Io, diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index 3ecfd1b3637713954751dd2bf4835819683bd88a..1e848121ed3032eb78fc6dff866a320e346d1e9d 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const File = std.Io.File; +const Io = std.Io; +const File = Io.File; const Allocator = std.mem.Allocator; const pdb = std.pdb; const assert = std.debug.assert; @@ -10,7 +11,7 @@ file_reader: *File.Reader, msf: Msf, allocator: Allocator, string_table: ?*MsfStream, -dbi: ?*MsfStream, +ipi: ?[]u8, modules: []Module, sect_contribs: []pdb.SectionContribEntry, guid: [16]u8, @@ -41,7 +42,7 @@ pub fn init(gpa: Allocator, file_reader: *File.Reader) !Pdb { .file_reader = file_reader, .allocator = gpa, .string_table = null, - .dbi = null, + .ipi = null, .msf = try Msf.init(gpa, file_reader), .modules = &.{}, .sect_contribs = &.{}, @@ -53,6 +54,7 @@ pub fn init(gpa: Allocator, file_reader: *File.Reader) !Pdb { pub fn deinit(self: *Pdb) void { const gpa = self.allocator; self.msf.deinit(gpa); + if (self.ipi) |ipi| gpa.free(ipi); for (self.modules) |*module| { module.deinit(gpa); } @@ -67,7 +69,7 @@ pub fn parseDbiStream(self: *Pdb) !void { const gpa = self.allocator; const reader = &stream.interface; - const header = try reader.takeStruct(std.pdb.DbiStreamHeader, .little); + const header = try reader.takeStruct(pdb.DbiStreamHeader, .little); if (header.version_header != 19990903) // V70, only value observed by LLVM team return error.UnknownPDBVersion; // if (header.Age != age) @@ -85,14 +87,14 @@ pub fn parseDbiStream(self: *Pdb) !void { const mod_info = try reader.takeStruct(pdb.ModInfo, .little); var this_record_len: usize = @sizeOf(pdb.ModInfo); - var module_name: std.Io.Writer.Allocating = .init(gpa); + var module_name: Io.Writer.Allocating = .init(gpa); defer module_name.deinit(); this_record_len += try reader.streamDelimiterLimit(&module_name.writer, 0, .limited(1024)); assert(reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API reader.toss(1); this_record_len += 1; - var obj_file_name: std.Io.Writer.Allocating = .init(gpa); + var obj_file_name: Io.Writer.Allocating = .init(gpa); defer obj_file_name.deinit(); this_record_len += try reader.streamDelimiterLimit(&obj_file_name.writer, 0, .limited(1024)); assert(reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API @@ -128,7 +130,7 @@ pub fn parseDbiStream(self: *Pdb) !void { var sect_cont_offset: usize = 0; if (section_contrib_size != 0) { - const version = reader.takeEnum(std.pdb.SectionContrSubstreamVersion, .little) catch |err| switch (err) { + const version = reader.takeEnum(pdb.SectionContrSubstreamVersion, .little) catch |err| switch (err) { error.InvalidEnumTag, error.EndOfStream => return error.InvalidDebugInfo, error.ReadFailed => return error.ReadFailed, }; @@ -148,6 +150,15 @@ pub fn parseDbiStream(self: *Pdb) !void { self.sect_contribs = try sect_contribs.toOwnedSlice(); } +pub fn parseIpiStream(self: *Pdb) !void { + const gpa = self.allocator; + const stream = self.getStream(.ipi) orelse return; + const header = try stream.interface.peekStruct(pdb.IpiStreamHeader, .little); + if (header.version != .v80) // only value observed by LLVM team + return error.UnknownPDBVersion; + self.ipi = try stream.interface.readAlloc(gpa, @sizeOf(pdb.IpiStreamHeader) + header.type_record_bytes); +} + pub fn parseInfoStream(self: *Pdb) !void { var stream = self.getStream(pdb.StreamType.pdb) orelse return error.InvalidDebugInfo; const reader = &stream.interface; @@ -212,8 +223,9 @@ pub fn parseInfoStream(self: *Pdb) !void { return error.MissingDebugInfo; } -pub fn getSymbolName(self: *Pdb, module: *Module, address: u64) ?[]const u8 { +pub fn getProcSym(self: *Pdb, module: *Module, address: u64) ?*align(1) pdb.ProcSym { _ = self; + std.debug.assert(module.populated); var symbol_i: usize = 0; @@ -223,9 +235,9 @@ pub fn getSymbolName(self: *Pdb, module: *Module, address: u64) ?[]const u8 { return null; switch (prefix.record_kind) { .lproc32, .gproc32 => { - const proc_sym: *align(1) pdb.ProcSym = @ptrCast(&module.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]); + const proc_sym: *align(1) pdb.ProcSym = @ptrCast(prefix); if (address >= proc_sym.code_offset and address < proc_sym.code_offset + proc_sym.code_size) { - return std.mem.sliceTo(@as([*:0]u8, @ptrCast(&proc_sym.name[0])), 0); + return proc_sym; } }, else => {}, @@ -236,6 +248,433 @@ pub fn getSymbolName(self: *Pdb, module: *Module, address: u64) ?[]const u8 { return null; } +pub const InlineSiteSymIterator = struct { + module_index: usize, + offset: usize, + end: usize, + + pub const empty: InlineSiteSymIterator = .{ + .module_index = 0, + .offset = 0, + .end = 0, + }; + + pub fn next(iter: *InlineSiteSymIterator, module: *Module) ?*align(1) pdb.InlineSiteSym { + while (iter.offset < iter.end) { + const inline_prefix: *align(1) pdb.RecordPrefix = @ptrCast(&module.symbols[iter.offset]); + if (inline_prefix.record_len < 2) + return null; + const end = iter.offset + inline_prefix.record_len + @sizeOf(u16); + defer iter.offset = end; + switch (inline_prefix.record_kind) { + // Skip nested procedures + .lproc32, + .lproc32_st, + .gproc32, + .gproc32_st, + .lproc32_id, + .gproc32_id, + .lproc32_dpc, + .lproc32_dpc_id, + => { + const skip: *align(1) pdb.ProcSym = @ptrCast(inline_prefix); + iter.offset = skip.end; + }, + .inlinesite, + .inlinesite2, + => return @ptrCast(inline_prefix), + else => {} + } + } + + return null; + } +}; + +pub const BinaryAnnotation = union(enum) { + code_offset: u32, + change_code_offset_base: u32, + change_code_offset: u32, + change_code_length: u32, + change_file: u32, + change_line_offset: i32, + change_line_end_delta: u32, + change_range_kind: RangeKind, + change_column_start: u32, + change_column_end_delta: i32, + change_code_offset_and_line_offset: struct { code_delta: u32, line_delta: i32 }, + change_code_length_and_code_offset: struct { length: u32, delta: u32 }, + change_column_end: u32, + + pub const RangeKind = enum(u32) { expression = 0, statement = 1 }; + + /// A virtual machine that processed binary annotations. + pub const RangeIterator = struct { + annotations: Iterator, + curr: PartialRange, + /// The previous range is tracked as the code length is sometimes implied by the subsequent + /// range. + prev: ?PartialRange, + + const PartialRange = struct { + line_offset: u32, + file_offset: u32, + code_offset: u32, + code_length: ?u32, + }; + + pub fn init(annotations: Iterator) RangeIterator { + return .{ + .annotations = annotations, + .curr = .{ + .line_offset = 0, + .file_offset = 0, + .code_offset = 0, + .code_length = null, + }, + .prev = null, + }; + } + + pub const Range = struct { + line_offset: u32, + file_offset: u32, + code_offset: u32, + code_length: u32, + + pub fn contains(self: Range, offset_in_func: usize) bool { + return self.code_offset <= offset_in_func and + offset_in_func < self.code_offset + self.code_length; + } + }; + + pub fn next(self: *RangeIterator) error{InvalidDebugInfo}!?Range { + while (try self.annotations.next()) |annotation| { + switch (annotation) { + .change_code_offset => |delta| { + self.curr.code_offset += delta; + }, + .change_code_length => |length| { + if (self.prev) |*prev| prev.code_length = prev.code_length orelse length; + self.curr.code_offset += length; + }, + .change_file => @panic("unimplemented"), + // LLVM never emits this opcode, but it's clear enough how to interpret it so we may as + // well in case they use it in the future + .change_code_length_and_code_offset => |info| { + self.curr.code_length = info.length; + self.curr.code_offset += info.delta; + }, + .change_line_offset => |delta| { + self.curr.line_offset +%= @bitCast(delta); + }, + .change_code_offset_and_line_offset => |info| { + self.curr.code_offset += info.code_delta; + self.curr.line_offset +%= @bitCast(info.line_delta); + }, + + // Not emitted by LLVM at the time of writing, but if we get it from elsewhere it should + // be safe to ignore since we don't use this info. Theoretically we could use column + // info if it was present, but it's not easy to test since LLVM doesn't output it. + .change_line_end_delta, + .change_column_start, + .change_column_end_delta, + .change_column_end, + => {}, + + // Not emitted by LLVM at the time of writing. Various sources conflict on how these + // instructions should be interpreted, so we make no attempt to handle them. + .code_offset, + .change_code_offset_base, + .change_range_kind, + => @panic("unimplemented"), + } + + switch (annotation) { + .change_code_offset, + .change_code_offset_and_line_offset, + .change_code_length_and_code_offset, + => {}, + else => continue, + } + + if (self.prev) |*prev| { + if (prev.code_length == null) { + prev.code_length = self.curr.code_offset - prev.code_offset; + } + } + + defer self.prev = .{ + .code_offset = self.curr.code_offset, + .code_length = self.curr.code_length, + .line_offset = self.curr.line_offset, + .file_offset = self.curr.file_offset, + }; + const prev = self.prev orelse continue; + const prev_code_length = prev.code_length orelse continue; + return .{ + .code_offset = prev.code_offset, + .code_length = prev_code_length, + .line_offset = prev.line_offset, + .file_offset = prev.file_offset, + }; + } + + const prev = self.prev orelse return null; + defer self.prev = null; + const prev_code_length = prev.code_length orelse return null; + return .{ + .code_offset = prev.code_offset, + .code_length = prev_code_length, + .line_offset = prev.line_offset, + .file_offset = prev.file_offset, + }; + } + }; + + pub const Iterator = struct { + reader: Io.Reader, + + pub fn next(self: *Iterator) error{InvalidDebugInfo}!?BinaryAnnotation { + return take(&self.reader) catch |err| switch (err) { + error.ReadFailed => return error.InvalidDebugInfo, + error.EndOfStream => return null, + }; + } + }; + + pub fn take(reader: *Io.Reader) Io.Reader.Error!BinaryAnnotation { + const op = std.enums.fromInt( + pdb.BinaryAnnotationOpcode, + try takePackedU32(reader), + ) orelse return error.ReadFailed; + switch (op) { + .invalid => return error.EndOfStream, + .code_offset => return .{ + .code_offset = try expect(takePackedU32(reader)), + }, + .change_code_offset_base => return .{ + .change_code_offset_base = try expect(takePackedU32(reader)), + }, + .change_code_offset => return .{ + .change_code_offset = try expect(takePackedU32(reader)), + }, + .change_code_length => return .{ + .change_code_length = try expect(takePackedU32(reader)), + }, + .change_file => return .{ + .change_file = try expect(takePackedU32(reader)), + }, + .change_line_offset => return .{ + .change_line_offset = try expect(takePackedI32(reader)), + }, + .change_line_end_delta => return .{ + .change_line_end_delta = try expect(takePackedU32(reader)), + }, + .change_range_kind => return .{ + .change_range_kind = std.enums.fromInt( + RangeKind, + try expect(takePackedU32(reader)), + ) orelse return error.ReadFailed, + }, + .change_column_start => return .{ + .change_column_start = try expect(takePackedU32(reader)), + }, + .change_column_end_delta => return .{ + .change_column_end_delta = try expect(takePackedI32(reader)), + }, + .change_code_offset_and_line_offset => { + const EncodedArgs = packed struct(u32) { + code_delta: u4, + encoded_line_delta: u28, + }; + const args: EncodedArgs = @bitCast(try expect(takePackedU32(reader))); + return .{ + .change_code_offset_and_line_offset = .{ + .code_delta = args.code_delta, + .line_delta = decodeI32(args.encoded_line_delta), + }, + }; + }, + .change_code_length_and_code_offset => return .{ + .change_code_length_and_code_offset = .{ + .length = try expect(takePackedU32(reader)), + .delta = try expect(takePackedU32(reader)), + }, + }, + .change_column_end => return .{ + .change_column_end = try expect(takePackedU32(reader)), + }, + } + } + + // Adapated from: + // https://github.com/microsoft/microsoft-pdb/blob/805655a28bd8198004be2ac27e6e0290121a5e89/include/cvinfo.h#L4942 + pub fn takePackedU32(reader: *Io.Reader) Io.Reader.Error!u32 { + const b0: u32 = try reader.takeByte(); + if (b0 & 0x80 == 0x00) return b0; + + const b1: u32 = try reader.takeByte(); + if (b0 & 0xC0 == 0x80) return ((b0 & 0x3F) << 8) | b1; + + const b2: u32 = try reader.takeByte(); + const b3: u32 = try reader.takeByte(); + if (b0 & 0xE0 == 0xC0) return ((b0 & 0x1f) << 24) | (b1 << 16) | (b2 << 8) | b3; + + return error.ReadFailed; + } + + pub fn takePackedI32(reader: *Io.Reader) Io.Reader.Error!i32 { + return decodeI32(try takePackedU32(reader)); + } + + pub fn decodeI32(u: u32) i32 { + const i: i32 = @bitCast(u); + if (i & 1 != 0) { + return -(i >> 1); + } else { + return i >> 1; + } + } + + fn expect(value: anytype) error { ReadFailed }!@typeInfo(@TypeOf(value)).error_union.payload { + comptime assert(@typeInfo(@TypeOf(value)).error_union.error_set == Io.Reader.Error); + return value catch error.ReadFailed; + } +}; + +pub fn findInlineeName(self: *const Pdb, inlinee: u32) ?[]const u8 { + var reader: Io.Reader = .fixed(self.ipi orelse return null); + const header = reader.takeStructPointer(pdb.IpiStreamHeader) catch return null; + for (header.type_index_begin..header.type_index_end) |type_index| { + const prefix = reader.takeStructPointer(pdb.LfRecordPrefix) catch return null; + reader.discardAll(prefix.len - @sizeOf(@FieldType(pdb.LfRecordPrefix, "len"))) catch return null; + + if (type_index == inlinee) { + switch (prefix.kind) { + .func_id => { + const func: *align(1) pdb.LfFuncId = @ptrCast(prefix); + return std.mem.sliceTo(@as([*:0]const u8, @ptrCast(&func.name[0])), 0); + }, + .mfunc_id => { + const func: *align(1) pdb.LfMFuncId = @ptrCast(prefix); + return std.mem.sliceTo(@as([*:0]const u8, @ptrCast(&func.name[0])), 0); + }, + else => return null, + } + } + } + return null; +} + +pub fn getInlinees(self: *Pdb, module: *Module, proc_sym: *align(1) const pdb.ProcSym) InlineSiteSymIterator { + const module_index = module - self.modules.ptr; + const offset = @intFromPtr(proc_sym) - + @intFromPtr(module.symbols.ptr) + + proc_sym.record_len + + @sizeOf(@FieldType(pdb.ProcSym, "record_len")); + return .{ + .module_index = module_index, + .offset = offset, + .end = proc_sym.end, + }; +} + +pub fn getBinaryAnnotations(self: *Pdb, site: *align(1) const pdb.InlineSiteSym) BinaryAnnotation.Iterator { + _ = self; + var start: usize = @intFromPtr(site) + @sizeOf(pdb.InlineSiteSym); + var end = start + site.record_len + @sizeOf(@FieldType(pdb.InlineSiteSym, "record_len")) - @sizeOf(pdb.InlineSiteSym); + switch (site.record_kind) { + .inlinesite => {}, + .inlinesite2 => start += @sizeOf(pdb.InlineSiteSym2) - @sizeOf(pdb.InlineSiteSym), + else => end = start, + } + const ptr: [*]const u8 = @ptrFromInt(start); + const slice = ptr[0..end - start]; + return .{ .reader = Io.Reader.fixed(slice) }; +} + +pub fn calculateOffset( + self: *Pdb, + site: *align(1) const pdb.InlineSiteSym, + loc: std.debug.SourceLocation, + offset_in_func: usize, +) error{InvalidDebugInfo, MissingDebugInfo, ReadFailed}!?std.debug.SourceLocation { + var ranges: BinaryAnnotation.RangeIterator = .init(self.getBinaryAnnotations(site)); + while (try ranges.next()) |range| { + if (range.contains(offset_in_func)) { + var result: std.debug.SourceLocation = loc; + result.line += range.line_offset; + return result; + } + } + return null; +} + +pub fn getSymbolName(self: *Pdb, proc_sym: *align(1) const pdb.ProcSym) []const u8 { + _ = self; + return std.mem.sliceTo(@as([*:0]const u8, @ptrCast(&proc_sym.name[0])), 0); +} + +pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceLocation { + const gpa = self.allocator; + var sect_offset: usize = 0; + var skip_len: usize = undefined; + while (sect_offset < mod.subsect_info.len) : (sect_offset += skip_len) { + const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&mod.subsect_info[sect_offset]); + skip_len = subsect_hdr.length; + sect_offset += @sizeOf(pdb.DebugSubsectionHeader); + + if (subsect_hdr.kind == .inlinee_lines) { + var offset = sect_offset; + const signature: *const align(1) pdb.InlineeSourceLineSignature = @ptrCast(&mod.subsect_info[offset]); + offset += @sizeOf(pdb.InlineeSourceLineSignature); + + const has_extra_files = switch (signature.*) { + .normal => false, + .ex => true, + else => continue, + }; + + while (offset < sect_offset + subsect_hdr.length) { + const entry: *const align(1) pdb.InlineeSourceLine = @ptrCast(&mod.subsect_info[offset]); + offset += @sizeOf(pdb.InlineeSourceLine); + + if (has_extra_files) { + const file_count: *const align(1) u32 = @ptrCast(&mod.subsect_info[offset]); + offset += @sizeOf(u32); + offset += file_count.* * @sizeOf(u32); + } + + if (entry.inlinee == inlinee) { + const source_file_name = s: { + const checksum_offset = mod.checksum_offset orelse return error.MissingDebugInfo; + const subsect_index = checksum_offset + entry.file_id; + const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&mod.subsect_info[subsect_index]); + const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; + try self.string_table.?.seekTo(strtab_offset); + const string_reader = &self.string_table.?.interface; + var source_file_name: Io.Writer.Allocating = .init(gpa); + defer source_file_name.deinit(); + _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); + assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API + string_reader.toss(1); + break :s try source_file_name.toOwnedSlice(); + }; + errdefer gpa.free(source_file_name); + + return .{ + .line = entry.source_line_num, + .column = 0, + .file_name = source_file_name, + }; + } + } + } + } + return error.MissingDebugInfo; +} + pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.SourceLocation { std.debug.assert(module.populated); const subsect_info = module.subsect_info; @@ -296,7 +735,7 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S try self.string_table.?.seekTo(strtab_offset); const source_file_name = s: { const string_reader = &self.string_table.?.interface; - var source_file_name: std.Io.Writer.Allocating = .init(gpa); + var source_file_name: Io.Writer.Allocating = .init(gpa); defer source_file_name.deinit(); _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API @@ -497,7 +936,7 @@ const MsfStream = struct { next_read_pos: u64, blocks: []u32, block_size: u32, - interface: std.Io.Reader, + interface: Io.Reader, err: ?Error, const Error = File.Reader.SeekError; @@ -527,7 +966,7 @@ const MsfStream = struct { }; } - fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { + fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize { const ms: *MsfStream = @alignCast(@fieldParentPtr("interface", r)); var block_id: usize = @intCast(ms.next_read_pos / ms.block_size); @@ -595,7 +1034,7 @@ const MsfStream = struct { } }; -fn readSparseBitVector(reader: *std.Io.Reader, allocator: Allocator) ![]u32 { +fn readSparseBitVector(reader: *Io.Reader, allocator: Allocator) ![]u32 { const num_words = try reader.takeInt(u32, .little); var list = std.array_list.Managed(u32).init(allocator); errdefer list.deinit(); diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 263f292e9964f32cd16edd1c1519ccdd354d076e..7955dd32c6277d8f66044d94f9eaa832f66d79aa 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -30,51 +30,67 @@ pub fn deinit(si: *SelfInfo, io: Io) void { if (si.unwind_cache) |cache| gpa.free(cache); } -pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol { +pub const SymbolIterator = struct { + curr: ?Error!std.debug.Symbol, + + pub fn deinit(self: *SymbolIterator, _: Io) void { + self.* = undefined; + } + + pub fn next(self: *SymbolIterator) ?Error!std.debug.Symbol { + const result = self.curr; + self.curr = null; + return result; + } +}; + +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { const gpa = std.debug.getDebugInfoAllocator(); - const module = try si.findModule(gpa, io, address, .exclusive); + const module = si.findModule(gpa, io, address, .exclusive) catch |err| return .{ .curr = err }; defer si.rwlock.unlock(io); const vaddr = address - module.load_offset; - const loaded_elf = try module.getLoadedElf(gpa, io); + const loaded_elf = module.getLoadedElf(gpa, io) catch |err| return .{ .curr = err }; if (loaded_elf.file.dwarf) |*dwarf| { if (!loaded_elf.scanned_dwarf) { dwarf.open(gpa, native_endian) catch |err| switch (err) { error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory, - => |e| return e, + => |e| return .{ .curr = e }, error.EndOfStream, error.Overflow, error.ReadFailed, error.StreamTooLong, - => return error.InvalidDebugInfo, + => return .{ .curr = error.InvalidDebugInfo }, }; loaded_elf.scanned_dwarf = true; } if (dwarf.getSymbol(gpa, native_endian, vaddr)) |sym| { - return sym; + return .{ .curr = sym }; } else |err| switch (err) { error.MissingDebugInfo => {}, error.InvalidDebugInfo, error.OutOfMemory, - => |e| return e, + => |e| return .{ .curr = e }, error.ReadFailed, error.EndOfStream, error.Overflow, error.StreamTooLong, - => return error.InvalidDebugInfo, + => return .{ .curr = error.InvalidDebugInfo }, } } // When DWARF is unavailable, fall back to searching the symtab. - return loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { - error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo, - error.BadSymtab => return error.InvalidDebugInfo, - error.OutOfMemory => |e| return e, + const symbol = loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { + error.NoSymtab, error.NoStrtab => return .{ .curr = error.MissingDebugInfo }, + error.BadSymtab => return .{ .curr = error.InvalidDebugInfo }, + error.OutOfMemory => |e| return .{ .curr = e }, }; + + return .{ .curr = symbol }; } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { const gpa = std.debug.getDebugInfoAllocator(); diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index c7323c722ae1a0a7ad493aa4eca5413920ede808..f75fee09d0e26daf07065d9c331f6ee25d2f4a61 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -1,10 +1,10 @@ -mutex: Io.Mutex, +lock: Io.RwLock, ntdll_handle: ?if (load_dll_notification_procs) *anyopaque else noreturn, notification_cookie: ?LDR.DLL_NOTIFICATION.COOKIE, modules: std.ArrayList(Module), pub const init: SelfInfo = .{ - .mutex = .init, + .lock = .init, .ntdll_handle = null, .notification_cookie = null, .modules = .empty, @@ -25,18 +25,117 @@ pub fn deinit(si: *SelfInfo, io: Io) void { si.modules.deinit(gpa); } -pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol { +pub const SymbolIterator = struct { + err: Error!void = {}, + lock: ?*Io.RwLock, + module: *Module, + symbols: Module.DebugInfo.Symbols, + + pub fn deinit(self: *SymbolIterator, io: Io) void { + if (self.lock) |lock| lock.unlockShared(io); + self.* = undefined; + } + + fn failing(err: Error) SymbolIterator { + return .{ + .err = err, + .lock = null, + .module = undefined, + .symbols = .none, + }; + } + + pub fn next(self: *SymbolIterator) ?Error!std.debug.Symbol { + // Check for errors + self.err catch |err| { + self.err = {}; + self.symbols = .none; + return err; + }; + + // Return the next symbol for the debug info type + switch (self.symbols) { + .pdb => |*info| { + // The failure cases are unreachable because we only set the pdb field if these are + // set + const di = if (self.module.di.?) |*di| di else |_| unreachable; + const pdb = if (di.pdb) |*pdb| pdb else unreachable; + + // Get the next inlinee if it exists + if (info.inlinees.next(info.module)) |site| { + if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| { + if (info.proc_sym) |proc_sym| { + const offset_in_func = info.addr - proc_sym.code_offset; + if (try pdb.calculateOffset(site, loc, offset_in_func)) |offset| { + return .{ + .name = pdb.findInlineeName(site.inlinee), + .compile_unit_name = null, + .source_location = offset, + }; + } + } + } + } + + // Return the main symbol and end the iterator + defer self.symbols = .none; + return .{ + .name = if (info.proc_sym) |proc_sym| + pdb.getSymbolName(proc_sym) + else + null, + .compile_unit_name = fs.path.basename(info.module.obj_file_name), + .source_location = pdb.getLineNumberInfo( + info.module, + info.addr, + ) catch null, + }; + }, + .dwarf => |info| { + // The failure cases are unreachable because we only set the dwarf field if these + // are set + const di = if (self.module.di.?) |*di| di else |_| unreachable; + const dwarf = if (di.dwarf) |*dwarf| dwarf else unreachable; + + // Return the main symbol and then return the iterator + defer self.symbols = .none; + const gpa = std.debug.getDebugInfoAllocator(); + return dwarf.getSymbol(gpa, native_endian, info.addr) catch |err| switch (err) { + error.MissingDebugInfo => return null, + + error.InvalidDebugInfo, + error.OutOfMemory, + => |e| return e, + + error.ReadFailed, + error.EndOfStream, + error.Overflow, + error.StreamTooLong, + => return error.InvalidDebugInfo, + }; + }, + .none => return null, + } + } +}; + +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { const gpa = std.debug.getDebugInfoAllocator(); - try si.mutex.lock(io); - defer si.mutex.unlock(io); - const module = try si.findModule(gpa, address); - const di = try module.getDebugInfo(gpa, io); - return di.getSymbol(gpa, address - @intFromPtr(module.entry.DllBase)); + si.lock.lockShared(io) catch |err| return .failing(err); + errdefer si.lock.unlockShared(io); + const module = si.findModule(gpa, address) catch |err| return .failing(err); + const di = module.getDebugInfo(gpa, io) catch |err| return .failing(err); + const symbols = di.getSymbols(address - @intFromPtr(module.entry.DllBase)) catch |err| return .failing(err); + return .{ + .lock = &si.lock, + .module = module, + .symbols = symbols, + }; } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { const gpa = std.debug.getDebugInfoAllocator(); - try si.mutex.lock(io); - defer si.mutex.unlock(io); + try si.lock.lockShared(io); + defer si.lock.unlockShared(io); const module = try si.findModule(gpa, address); return module.name orelse { const name = try std.unicode.wtf16LeToWtf8Alloc(gpa, module.entry.BaseDllName.slice()); @@ -46,8 +145,8 @@ pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { } pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize { const gpa = std.debug.getDebugInfoAllocator(); - try si.mutex.lock(io); - defer si.mutex.unlock(io); + try si.lock.lockShared(io); + defer si.lock.unlockShared(io); const module = try si.findModule(gpa, address); return module.base_address; } @@ -240,7 +339,19 @@ const Module = struct { arena.deinit(); } - fn getSymbol(di: *DebugInfo, gpa: Allocator, vaddr: usize) Error!std.debug.Symbol { + pub const Symbols = union(enum) { + pdb: struct { + module: *Pdb.Module, + proc_sym: ?*align(1) const std.pdb.ProcSym, + addr: usize, + inlinees: Pdb.InlineSiteSymIterator, + }, + dwarf: struct { + addr: usize, + }, + none: void, + }; + fn getSymbols(di: *DebugInfo, vaddr: usize) Error!Symbols { pdb: { const pdb = &(di.pdb orelse break :pdb); var coff_section: *align(1) const coff.SectionHeader = undefined; @@ -270,32 +381,30 @@ const Module = struct { } orelse { return error.InvalidDebugInfo; // bad module index }; - return .{ - .name = pdb.getSymbolName(module, vaddr - coff_section.virtual_address), - .compile_unit_name = fs.path.basename(module.obj_file_name), - .source_location = pdb.getLineNumberInfo( - module, - vaddr - coff_section.virtual_address, - ) catch null, - }; + + const addr = vaddr - coff_section.virtual_address; + const proc_sym = pdb.getProcSym(module, addr); + const inlinees: Pdb.InlineSiteSymIterator = if (proc_sym) |sym| + pdb.getInlinees(module, sym) + else + .empty; + return .{ .pdb = .{ + .module = module, + .proc_sym = proc_sym, + .addr = addr, + .inlinees = inlinees, + } }; } + + // Dwarf dwarf: { - const dwarf = &(di.dwarf orelse break :dwarf); - const dwarf_address = vaddr + di.coff_image_base; - return dwarf.getSymbol(gpa, native_endian, dwarf_address) catch |err| switch (err) { - error.MissingDebugInfo => break :dwarf, - - error.InvalidDebugInfo, - error.OutOfMemory, - => |e| return e, - - error.ReadFailed, - error.EndOfStream, - error.Overflow, - error.StreamTooLong, - => return error.InvalidDebugInfo, - }; + if (di.dwarf == null) break :dwarf; + const addr = vaddr + di.coff_image_base; + return .{ .dwarf = .{ + .addr = addr, + } }; } + return error.MissingDebugInfo; } }; @@ -505,6 +614,16 @@ const Module = struct { error.ReadFailed, => |e| return e, }; + pdb.parseIpiStream() catch |err| switch (err) { + error.UnknownPDBVersion => return error.UnsupportedDebugInfo, + + error.EndOfStream, + => return error.InvalidDebugInfo, + + error.OutOfMemory, + error.ReadFailed, + => |e| return e, + }; if (!std.mem.eql(u8, &coff_obj.guid, &pdb.guid) or coff_obj.age != pdb.age) return error.InvalidDebugInfo; @@ -531,7 +650,7 @@ const Module = struct { } }; -/// Assumes we already hold `si.mutex`. +/// Assumes we already hold `si.lock`. fn findModule(si: *SelfInfo, gpa: Allocator, address: usize) error{ MissingDebugInfo, OutOfMemory, Unexpected }!*Module { for (si.modules.items) |*mod| { const base = @intFromPtr(mod.entry.DllBase); @@ -601,8 +720,8 @@ fn dllNotification( .LOADED => {}, .UNLOADED => { const io = std.Options.debug_io; - si.mutex.lockUncancelable(io); - defer si.mutex.unlock(io); + si.lock.lockUncancelable(io); + defer si.lock.unlock(io); for (si.modules.items, 0..) |*mod, mod_index| { if (mod.entry.DllBase != data.Unloaded.DllBase) continue; mod.deinit(std.debug.getDebugInfoAllocator(), io); diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig index 094537972b3c7e7e560019f56178631f52663312..bff15d89de61342d6efc3a38e068764a52211a52 100644 --- a/lib/std/pdb.zig +++ b/lib/std/pdb.zig @@ -314,11 +314,9 @@ pub const SymbolKind = enum(u16) { pub const TypeIndex = u32; -// TODO According to this header: -// https://github.com/microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3722 -// we should define RecordPrefix as part of the ProcSym structure. -// This might be important when we start generating PDB in self-hosted with our own PE linker. pub const ProcSym = extern struct { + record_len: u16, + record_kind: SymbolKind, parent: u32, end: u32, next: u32, @@ -508,3 +506,149 @@ pub const SuperBlock = extern struct { // implement it so we're kind of safe making this assumption for now. block_map_addr: u32, }; + +pub const IpiStreamVersion = enum(u32) { + v40 = 19950410, + v41 = 19951122, + v50 = 19961031, + v70 = 19990903, + v80 = 20040203, + _, +}; + +pub const IpiStreamHeader = extern struct { + version: IpiStreamVersion, + header_size: u32, + type_index_begin: u32, + type_index_end: u32, + type_record_bytes: u32, + hash_stream_index: u16, + hash_aux_stream_index: u16, + hash_key_size: u32, + num_hash_buckets: u32, + hash_value_buffer_offset: i32, + hash_value_buffer_length: u32, + index_offset_buffer_offset: i32, + index_offset_buffer_length: u32, + hash_adj_buffer_offset: i32, + hash_adj_buffer_length: u32, +}; + +pub const LfRecordPrefix = extern struct { + len: u16, + kind: LfRecordKind, +}; + +pub const LfRecordKind = enum(u16) { + pointer = 0x1002, + modifier = 0x1001, + procedure = 0x1008, + mfunction = 0x1009, + label = 0x000e, + arglist = 0x1201, + fieldlist = 0x1203, + array = 0x1503, + class = 0x1504, + structure = 0x1505, + interface = 0x1519, + @"union" = 0x1506, + @"enum" = 0x1507, + typeserver2 = 0x1515, + vftable = 0x151d, + vtshape = 0x000a, + bitfield = 0x1205, + func_id = 0x1601, + mfunc_id = 0x1602, + buildinfo = 0x1603, + substr_list = 0x1604, + string_id = 0x1605, + udt_src_line = 0x1606, + udt_mod_src_line = 0x1607, + methodlist = 0x1206, + precomp = 0x1509, + endprecomp = 0x0014, + bclass = 0x1400, + binterface = 0x151a, + vbclass = 0x1401, + ivbclass = 0x1402, + vfunctab = 0x1409, + stmember = 0x150e, + method = 0x150f, + member = 0x150d, + nesttype = 0x1510, + onemethod = 0x1511, + enumerate = 0x1502, + index = 0x1404, + pad0 = 0xf0, + _, +}; + +pub const LfFuncId = extern struct { + len: u16, + kind: LfRecordKind, + scope_id: u32, + type: u32, + name: [1]u8, // null-terminated +}; + +pub const LfMFuncId = extern struct { + len: u16, + kind: LfRecordKind, + parent_type: u32, + type: u32, + name: [1]u8, // null-terminated +}; + +pub const InlineSiteSym = extern struct { + record_len: u16, + record_kind: SymbolKind, + parent: u32, + end: u32, + inlinee: u32, +}; + +pub const InlineSiteSym2 = extern struct { + record_len: u16, + record_kind: SymbolKind, + parent: u32, + end: u32, + inlinee: u32, + invocations: u32, +}; + +pub const InlineeSourceLineSignature = enum(u32) { + normal = 0, + ex = 1, + _ +}; + +pub const InlineeSourceLine = extern struct { + inlinee: u32, + file_id: u32, + source_line_num: u32, +}; + +pub const InlineeSourceLineEx = extern struct { + inlinee: u32, + file_id: u32, + source_line_num: u32, + count_of_extra_files: u32, +}; + +pub const BinaryAnnotationOpcode = enum(u8) { + invalid = 0, + code_offset = 1, + change_code_offset_base = 2, + change_code_offset = 3, + change_code_length = 4, + change_file = 5, + change_line_offset = 6, + change_line_end_delta = 7, + change_range_kind = 8, + change_column_start = 9, + change_column_end_delta = 10, + change_code_offset_and_line_offset = 11, + change_code_length_and_code_offset = 12, + change_column_end = 13, +}; + -- 2.54.0 From 156f54d8f0165fb772d538382a6c3248e2ee30be Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 6 Apr 2026 13:01:27 -0700 Subject: [PATCH 02/29] Adds includes_inlined_frames option to builtin.StackTrace This will be relevant once #31605 is merged. In general, stack traces do *not* contain unique addresses for inlined frames, but for error return traces, they will after the above PR. This bool indicates that code printing the trace should not try to resolve inline frames since they're explicitly encoded into the instruction addresses. This is set as state on stack trace rather than passed into the formatting methods as an argument, as it's not really a formatting option--whether or not it's correct to resolve inlines is decided at the time of capture! --- lib/std/builtin.zig | 3 +++ lib/std/debug.zig | 42 ++++++++++++++++++++++++++------ lib/std/heap/debug_allocator.zig | 2 ++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 00ae6199d1d9cdf96e8202a29b3f0b7385b5d387..addfa166b3bc8043e1ac45a55373d40fcf237b75 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -11,6 +11,9 @@ pub const assembly = @import("builtin/assembly.zig"); pub const StackTrace = struct { index: usize, instruction_addresses: []usize, + /// Set to true if inlined frames are given their own entries in `instruction_addresses`, + /// otherwise set to false. + includes_inlined_frames: bool, }; /// This data structure is used by the Zig language code generation and diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 78e1b8df23ae775503e655e5901460dd4601f6d1..a7c2c68d0e0baedc7a91688dc5c6c750828a7069 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -626,7 +626,11 @@ pub const StackUnwindOptions = struct { /// /// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it. pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace { - const empty_trace: StackTrace = .{ .index = 0, .instruction_addresses = &.{} }; + const empty_trace: StackTrace = .{ + .index = 0, + .instruction_addresses = &.{}, + .includes_inlined_frames = false, + }; if (!std.options.allow_stack_tracing) return empty_trace; var it: StackIterator = .init(options.context); defer it.deinit(); @@ -661,6 +665,7 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: return .{ .index = index, .instruction_addresses = addr_buf[0..index], + .includes_inlined_frames = false, }; } /// Write the current stack trace to `writer`, annotated with source locations. @@ -745,7 +750,10 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin } // `ret_addr` is the return address, which is *after* the function call. // Subtract 1 to get an address *in* the function call for a better source location. - try printSourceAtAddress(io, di, t, ret_addr -| StackIterator.ra_call_offset); + try printSourceAtAddress(io, di, t, .{ + .address = ret_addr -| StackIterator.ra_call_offset, + .print_inlines = true, + }); printed_any_frame = true; }, }; @@ -805,7 +813,10 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void for (st.instruction_addresses[0..captured_frames]) |ret_addr| { // `ret_addr` is the return address, which is *after* the function call. // Subtract 1 to get an address *in* the function call for a better source location. - try printSourceAtAddress(io, di, t, ret_addr -| StackIterator.ra_call_offset); + try printSourceAtAddress(io, di, t, .{ + .address = ret_addr -| StackIterator.ra_call_offset, + .print_inlines = !st.includes_inlined_frames, + }); } if (n_frames > captured_frames) { t.setColor(.bold) catch {}; @@ -1111,8 +1122,18 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { return ptr; } -fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: usize) Writer.Error!void { - var symbols: SelfInfo.SymbolIterator = debug_info.getSymbols(io, address); +const PrintSourceAddressOptions = struct { + address: usize, + print_inlines: bool, +}; + +fn printSourceAtAddress( + io: Io, + debug_info: *SelfInfo, + t: Io.Terminal, + options: PrintSourceAddressOptions, +) Writer.Error!void { + var symbols: SelfInfo.SymbolIterator = debug_info.getSymbols(io, options.address); defer symbols.deinit(io); while (symbols.next()) |curr| { const symbol: Symbol = curr catch |err| switch (err) { @@ -1138,10 +1159,11 @@ fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: io, t, symbol.source_location, - address, + options.address, symbol.name orelse "???", - symbol.compile_unit_name orelse debug_info.getModuleName(io, address) catch "???", + symbol.compile_unit_name orelse debug_info.getModuleName(io, options.address) catch "???", ); + if (!options.print_inlines) break; } } fn printLineInfo( @@ -1608,7 +1630,10 @@ test "manage resources correctly" { var di: SelfInfo = .init; defer di.deinit(io); const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color }; - try printSourceAtAddress(io, &di, t, S.showMyTrace()); + try printSourceAtAddress(io, &di, t, .{ + .address = S.showMyTrace(), + .inlines = true, + }); } /// This API helps you track where a value originated and where it was mutated, @@ -1679,6 +1704,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize const stack_trace: StackTrace = .{ .index = frames.len, .instruction_addresses = frames, + .includes_inlined_frames = false, }; writeStackTrace(&stack_trace, stderr) catch return; } diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index d6f2bf179653582d1d0d02faa1236e38e7fa5ab0..987bb4e6eaaca055953b8f2a4149b08b052db1b1 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -239,6 +239,7 @@ pub fn DebugAllocator(comptime config: Config) type { return .{ .instruction_addresses = stack_addresses, .index = len, + .includes_inlined_frames = false, }; } @@ -341,6 +342,7 @@ pub fn DebugAllocator(comptime config: Config) type { return .{ .instruction_addresses = stack_addresses, .index = len, + .includes_inlined_frames = false, }; } -- 2.54.0 From 5c6885be53b0e7d791f13dee32cb945b3f8f0d7d Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 6 Apr 2026 15:22:45 -0700 Subject: [PATCH 03/29] Fixes bug that would stop iterating inline site syms early This fix reveals another bug--we need to display the inline site syms in the reverse of the encoded order. The parent/child relationships are actually encoded on the inline sites, but it's likely a bit fragile to try to trace those, and also more complex. As long as there aren't multiple matches this is fine, and if there are, tracing the parent/child chain won't work anyway. --- lib/std/debug/SelfInfo/Windows.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index f75fee09d0e26daf07065d9c331f6ee25d2f4a61..260e012c1e65261dc4c8a88907108620030228d1 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -62,7 +62,8 @@ pub const SymbolIterator = struct { const pdb = if (di.pdb) |*pdb| pdb else unreachable; // Get the next inlinee if it exists - if (info.inlinees.next(info.module)) |site| { + while (info.inlinees.next(info.module)) |site| { + const parent: *align(1) const std.pdb.RecordPrefix = @ptrCast(&info.module.symbols[site.parent - @sizeOf(u16) * 2]); if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| { if (info.proc_sym) |proc_sym| { const offset_in_func = info.addr - proc_sym.code_offset; -- 2.54.0 From 781bab193b3ea026d2bd6adf8150bb6510205766 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Tue, 7 Apr 2026 13:39:35 -0700 Subject: [PATCH 04/29] Iterates inline sites in the correct order --- lib/std/debug/Pdb.zig | 6 -- lib/std/debug/SelfInfo/Windows.zig | 157 ++++++++++++++++------------- 2 files changed, 88 insertions(+), 75 deletions(-) diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index 1e848121ed3032eb78fc6dff866a320e346d1e9d..117a7a992c0e09b99faaa6ab1dbed0e36a91cab1 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -253,12 +253,6 @@ pub const InlineSiteSymIterator = struct { offset: usize, end: usize, - pub const empty: InlineSiteSymIterator = .{ - .module_index = 0, - .offset = 0, - .end = 0, - }; - pub fn next(iter: *InlineSiteSymIterator, module: *Module) ?*align(1) pdb.InlineSiteSym { while (iter.offset < iter.end) { const inline_prefix: *align(1) pdb.RecordPrefix = @ptrCast(&module.symbols[iter.offset]); diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index 260e012c1e65261dc4c8a88907108620030228d1..65db9fd9a1be9129446379db1b83413e0902b23f 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -33,6 +33,7 @@ pub const SymbolIterator = struct { pub fn deinit(self: *SymbolIterator, io: Io) void { if (self.lock) |lock| lock.unlockShared(io); + self.symbols.deinit(); self.* = undefined; } @@ -62,11 +63,10 @@ pub const SymbolIterator = struct { const pdb = if (di.pdb) |*pdb| pdb else unreachable; // Get the next inlinee if it exists - while (info.inlinees.next(info.module)) |site| { - const parent: *align(1) const std.pdb.RecordPrefix = @ptrCast(&info.module.symbols[site.parent - @sizeOf(u16) * 2]); - if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| { - if (info.proc_sym) |proc_sym| { - const offset_in_func = info.addr - proc_sym.code_offset; + if (info.proc) |proc| { + while (info.inline_sites.pop()) |site| { + if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| { + const offset_in_func = info.addr - proc.code_offset; if (try pdb.calculateOffset(site, loc, offset_in_func)) |offset| { return .{ .name = pdb.findInlineeName(site.inlinee), @@ -81,15 +81,9 @@ pub const SymbolIterator = struct { // Return the main symbol and end the iterator defer self.symbols = .none; return .{ - .name = if (info.proc_sym) |proc_sym| - pdb.getSymbolName(proc_sym) - else - null, + .name = if (info.proc) |proc| pdb.getSymbolName(proc) else null, .compile_unit_name = fs.path.basename(info.module.obj_file_name), - .source_location = pdb.getLineNumberInfo( - info.module, - info.addr, - ) catch null, + .source_location = pdb.getLineNumberInfo(info.module, info.addr) catch null, }; }, .dwarf => |info| { @@ -126,7 +120,9 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { errdefer si.lock.unlockShared(io); const module = si.findModule(gpa, address) catch |err| return .failing(err); const di = module.getDebugInfo(gpa, io) catch |err| return .failing(err); - const symbols = di.getSymbols(address - @intFromPtr(module.entry.DllBase)) catch |err| return .failing(err); + const symbols = Module.DebugInfo.Symbols.init(di, address - @intFromPtr(module.entry.DllBase)) + catch |err| return .failing(err); + errdefer comptime unreachable; return .{ .lock = &si.lock, .module = module, @@ -343,71 +339,94 @@ const Module = struct { pub const Symbols = union(enum) { pdb: struct { module: *Pdb.Module, - proc_sym: ?*align(1) const std.pdb.ProcSym, - addr: usize, - inlinees: Pdb.InlineSiteSymIterator, - }, - dwarf: struct { + proc: ?*align(1) const std.pdb.ProcSym, addr: usize, + /// Inline sites are stored in the pdb in reverse order, so we build up a list of up + /// front so that our iterator can return them in the correct order without doing an + /// n^2 search. We don't try to filter inline sites based on address until the user + /// calls `next` as this requires parsing binary annotations, and this is work we + /// may be able to elide if the caller chooses to early out before finishing + /// iteration, e.g. because they only wanted the topmost call. + inline_sites: std.ArrayList(*align(1) const std.pdb.InlineSiteSym), }, + dwarf: struct { addr: usize }, none: void, - }; - fn getSymbols(di: *DebugInfo, vaddr: usize) Error!Symbols { - pdb: { - const pdb = &(di.pdb orelse break :pdb); - var coff_section: *align(1) const coff.SectionHeader = undefined; - const mod_index = for (pdb.sect_contribs) |sect_contrib| { - if (sect_contrib.section > di.coff_section_headers.len) continue; - // Remember that SectionContribEntry.Section is 1-based. - coff_section = &di.coff_section_headers[sect_contrib.section - 1]; - - const vaddr_start = coff_section.virtual_address + sect_contrib.offset; - const vaddr_end = vaddr_start + sect_contrib.size; - if (vaddr >= vaddr_start and vaddr < vaddr_end) { - break sect_contrib.module_index; + + fn init(di: *DebugInfo, vaddr: usize) Error!Symbols { + const gpa = std.debug.getDebugInfoAllocator(); + + pdb: { + const pdb = &(di.pdb orelse break :pdb); + var coff_section: *align(1) const coff.SectionHeader = undefined; + const mod_index = for (pdb.sect_contribs) |sect_contrib| { + if (sect_contrib.section > di.coff_section_headers.len) continue; + // Remember that SectionContribEntry.Section is 1-based. + coff_section = &di.coff_section_headers[sect_contrib.section - 1]; + + const vaddr_start = coff_section.virtual_address + sect_contrib.offset; + const vaddr_end = vaddr_start + sect_contrib.size; + if (vaddr >= vaddr_start and vaddr < vaddr_end) { + break sect_contrib.module_index; + } + } else { + // we have no information to add to the address + break :pdb; + }; + const module = pdb.getModule(mod_index) catch |err| switch (err) { + error.InvalidDebugInfo, + error.MissingDebugInfo, + error.OutOfMemory, + => |e| return e, + + error.ReadFailed, + error.EndOfStream, + => return error.InvalidDebugInfo, + } orelse { + return error.InvalidDebugInfo; // bad module index + }; + + const addr = vaddr - coff_section.virtual_address; + const maybe_proc = pdb.getProcSym(module, addr); + + var inline_sites: std.ArrayList(*align(1) const std.pdb.InlineSiteSym) = .empty; + if (maybe_proc) |proc| { + var iter = pdb.getInlinees(module, proc); + while (iter.next(module)) |inline_site| { + try inline_sites.append(gpa, inline_site); + } } - } else { - // we have no information to add to the address - break :pdb; - }; - const module = pdb.getModule(mod_index) catch |err| switch (err) { - error.InvalidDebugInfo, - error.MissingDebugInfo, - error.OutOfMemory, - => |e| return e, - error.ReadFailed, - error.EndOfStream, - => return error.InvalidDebugInfo, - } orelse { - return error.InvalidDebugInfo; // bad module index - }; + return .{ .pdb = .{ + .module = module, + .proc = maybe_proc, + .addr = addr, + .inline_sites = inline_sites, + } }; + } - const addr = vaddr - coff_section.virtual_address; - const proc_sym = pdb.getProcSym(module, addr); - const inlinees: Pdb.InlineSiteSymIterator = if (proc_sym) |sym| - pdb.getInlinees(module, sym) - else - .empty; - return .{ .pdb = .{ - .module = module, - .proc_sym = proc_sym, - .addr = addr, - .inlinees = inlinees, - } }; + // Dwarf + dwarf: { + if (di.dwarf == null) break :dwarf; + const addr = vaddr + di.coff_image_base; + return .{ .dwarf = .{ + .addr = addr, + } }; + } + + return error.MissingDebugInfo; } - // Dwarf - dwarf: { - if (di.dwarf == null) break :dwarf; - const addr = vaddr + di.coff_image_base; - return .{ .dwarf = .{ - .addr = addr, - } }; + fn deinit(self: *Symbols) void { + switch (self.*) { + .pdb => |*info| { + const gpa = std.debug.getDebugInfoAllocator(); + info.inline_sites.deinit(gpa); + }, + .dwarf, .none => {}, + } } + }; - return error.MissingDebugInfo; - } }; fn deinit(module: *Module, gpa: Allocator, io: Io) void { -- 2.54.0 From a1a8dd1b40d2f42e9df6fee053c2cb737e0753f7 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Tue, 7 Apr 2026 13:51:35 -0700 Subject: [PATCH 05/29] Filters out duplicate sites, outputs compile unit name --- lib/std/debug/SelfInfo/Windows.zig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index 65db9fd9a1be9129446379db1b83413e0902b23f..29114035dfb29d09854155f8e4cfce14965cb7df 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -68,9 +68,18 @@ pub const SymbolIterator = struct { if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| { const offset_in_func = info.addr - proc.code_offset; if (try pdb.calculateOffset(site, loc, offset_in_func)) |offset| { + // If we've found a match, filter out any duplicate sites that + // follow. Tools like llvm-addr2line output duplicate sites in the + // same cases as us, implying that they exist in the underlying + // data and are not indicative of a parser bug. + while (info.inline_sites.getLastOrNull()) |top| { + if (top.inlinee != site.inlinee) break; + _ = info.inline_sites.pop(); + } + return .{ .name = pdb.findInlineeName(site.inlinee), - .compile_unit_name = null, + .compile_unit_name = fs.path.basename(info.module.obj_file_name), .source_location = offset, }; } -- 2.54.0 From 7ec2f2b27d72c46b6d2e0b68f8f91aaf61c2263e Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Tue, 7 Apr 2026 15:57:58 -0700 Subject: [PATCH 06/29] Cleans up, implements handling for the change file binary annotation --- lib/std/debug/Pdb.zig | 120 +++++++++++++++-------------- lib/std/debug/SelfInfo/Windows.zig | 44 +++++++---- 2 files changed, 89 insertions(+), 75 deletions(-) diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index 117a7a992c0e09b99faaa6ab1dbed0e36a91cab1..4405bea39711fba705ce327c8cb09bb34d79671e 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -312,7 +312,7 @@ pub const BinaryAnnotation = union(enum) { const PartialRange = struct { line_offset: u32, - file_offset: u32, + file_id: ?u32, code_offset: u32, code_length: ?u32, }; @@ -322,7 +322,7 @@ pub const BinaryAnnotation = union(enum) { .annotations = annotations, .curr = .{ .line_offset = 0, - .file_offset = 0, + .file_id = null, .code_offset = 0, .code_length = null, }, @@ -332,7 +332,7 @@ pub const BinaryAnnotation = union(enum) { pub const Range = struct { line_offset: u32, - file_offset: u32, + file_id: ?u32, code_offset: u32, code_length: u32, @@ -352,7 +352,11 @@ pub const BinaryAnnotation = union(enum) { if (self.prev) |*prev| prev.code_length = prev.code_length orelse length; self.curr.code_offset += length; }, - .change_file => @panic("unimplemented"), + // LLVM has code to emit these, but I wasn't able to figure out how trigger it + // so this logic is untested. + .change_file => |file_id| { + self.curr.file_id = file_id; + }, // LLVM never emits this opcode, but it's clear enough how to interpret it so we may as // well in case they use it in the future .change_code_length_and_code_offset => |info| { @@ -402,7 +406,7 @@ pub const BinaryAnnotation = union(enum) { .code_offset = self.curr.code_offset, .code_length = self.curr.code_length, .line_offset = self.curr.line_offset, - .file_offset = self.curr.file_offset, + .file_id = self.curr.file_id, }; const prev = self.prev orelse continue; const prev_code_length = prev.code_length orelse continue; @@ -410,7 +414,7 @@ pub const BinaryAnnotation = union(enum) { .code_offset = prev.code_offset, .code_length = prev_code_length, .line_offset = prev.line_offset, - .file_offset = prev.file_offset, + .file_id = prev.file_id, }; } @@ -421,7 +425,7 @@ pub const BinaryAnnotation = union(enum) { .code_offset = prev.code_offset, .code_length = prev_code_length, .line_offset = prev.line_offset, - .file_offset = prev.file_offset, + .file_id = prev.file_id, }; } }; @@ -588,30 +592,62 @@ pub fn getBinaryAnnotations(self: *Pdb, site: *align(1) const pdb.InlineSiteSym) return .{ .reader = Io.Reader.fixed(slice) }; } -pub fn calculateOffset( +pub fn getInlineSiteSourceLocation( self: *Pdb, + mod: *Module, site: *align(1) const pdb.InlineSiteSym, - loc: std.debug.SourceLocation, + inlinee_src_line: *align(1) const pdb.InlineeSourceLine, offset_in_func: usize, -) error{InvalidDebugInfo, MissingDebugInfo, ReadFailed}!?std.debug.SourceLocation { +) !?std.debug.SourceLocation { var ranges: BinaryAnnotation.RangeIterator = .init(self.getBinaryAnnotations(site)); while (try ranges.next()) |range| { - if (range.contains(offset_in_func)) { - var result: std.debug.SourceLocation = loc; - result.line += range.line_offset; - return result; - } + if (!range.contains(offset_in_func)) continue; + + const file_id = range.file_id orelse inlinee_src_line.file_id; + const file_name = try self.getFileName(mod, file_id); + errdefer self.allocator.free(file_name); + + return .{ + .line = inlinee_src_line.source_line_num + range.line_offset, + // LLVM doesn't currently emit column information for inlined calls in PDBs. + .column = 0, + .file_name = file_name, + }; } return null; } +pub fn getFileName(self: *Pdb, mod: *Module, file_id: u32) ![]const u8 { + const checksum_offset = mod.checksum_offset orelse return error.MissingDebugInfo; + const subsect_index = checksum_offset + file_id; + const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&mod.subsect_info[subsect_index]); + const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; + self.string_table.?.seekTo(strtab_offset) catch return error.InvalidDebugInfo; + const string_reader = &self.string_table.?.interface; + var source_file_name: Io.Writer.Allocating = .init(self.allocator); + defer source_file_name.deinit(); + _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); + assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API + string_reader.toss(1); + return try source_file_name.toOwnedSlice(); +} + pub fn getSymbolName(self: *Pdb, proc_sym: *align(1) const pdb.ProcSym) []const u8 { _ = self; return std.mem.sliceTo(@as([*:0]const u8, @ptrCast(&proc_sym.name[0])), 0); } -pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceLocation { - const gpa = self.allocator; +pub const InlineeSourceLine = struct { + signature: pdb.InlineeSourceLineSignature, + info: *align(1) const pdb.InlineeSourceLine, +}; + +pub fn getInlineeSourceLine( + self: *Pdb, + mod: *Module, + inlinee: u32, +) ?InlineeSourceLine { + _ = self; var sect_offset: usize = 0; var skip_len: usize = undefined; while (sect_offset < mod.subsect_info.len) : (sect_offset += skip_len) { @@ -631,7 +667,7 @@ pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceL }; while (offset < sect_offset + subsect_hdr.length) { - const entry: *const align(1) pdb.InlineeSourceLine = @ptrCast(&mod.subsect_info[offset]); + const inlinee_src_line: *const align(1) pdb.InlineeSourceLine = @ptrCast(&mod.subsect_info[offset]); offset += @sizeOf(pdb.InlineeSourceLine); if (has_extra_files) { @@ -640,33 +676,14 @@ pub fn getInlineeInfo(self: *Pdb, mod: *Module, inlinee: u32) !std.debug.SourceL offset += file_count.* * @sizeOf(u32); } - if (entry.inlinee == inlinee) { - const source_file_name = s: { - const checksum_offset = mod.checksum_offset orelse return error.MissingDebugInfo; - const subsect_index = checksum_offset + entry.file_id; - const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&mod.subsect_info[subsect_index]); - const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; - try self.string_table.?.seekTo(strtab_offset); - const string_reader = &self.string_table.?.interface; - var source_file_name: Io.Writer.Allocating = .init(gpa); - defer source_file_name.deinit(); - _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); - assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API - string_reader.toss(1); - break :s try source_file_name.toOwnedSlice(); - }; - errdefer gpa.free(source_file_name); - - return .{ - .line = entry.source_line_num, - .column = 0, - .file_name = source_file_name, - }; - } + if (inlinee_src_line.inlinee == inlinee) return .{ + .signature = signature.*, + .info = inlinee_src_line, + }; } } } - return error.MissingDebugInfo; + return null; } pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.SourceLocation { @@ -676,7 +693,6 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S var sect_offset: usize = 0; var skip_len: usize = undefined; - const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo; while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&subsect_info[sect_offset]); skip_len = subsect_hdr.length; @@ -723,20 +739,8 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S // line_i == 0 would mean that no matching pdb.LineNumberEntry was found. if (line_i > 0) { - const subsect_index = checksum_offset + block_hdr.name_index; - const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&module.subsect_info[subsect_index]); - const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; - try self.string_table.?.seekTo(strtab_offset); - const source_file_name = s: { - const string_reader = &self.string_table.?.interface; - var source_file_name: Io.Writer.Allocating = .init(gpa); - defer source_file_name.deinit(); - _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); - assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API - string_reader.toss(1); - break :s try source_file_name.toOwnedSlice(); - }; - errdefer gpa.free(source_file_name); + const file_name = try self.getFileName(module, block_hdr.name_index); + errdefer gpa.free(file_name); const line_entry_idx = line_i - 1; @@ -751,7 +755,7 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S const line_num_entry: *align(1) pdb.LineNumberEntry = @ptrCast(&subsect_info[found_line_index]); return .{ - .file_name = source_file_name, + .file_name = file_name, .line = line_num_entry.flags.start, .column = column, }; diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index 29114035dfb29d09854155f8e4cfce14965cb7df..ccf7263461284931eebd6f3646b684ae3d7328c1 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -64,26 +64,36 @@ pub const SymbolIterator = struct { // Get the next inlinee if it exists if (info.proc) |proc| { + const offset_in_func = info.addr - proc.code_offset; while (info.inline_sites.pop()) |site| { - if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| { - const offset_in_func = info.addr - proc.code_offset; - if (try pdb.calculateOffset(site, loc, offset_in_func)) |offset| { - // If we've found a match, filter out any duplicate sites that - // follow. Tools like llvm-addr2line output duplicate sites in the - // same cases as us, implying that they exist in the underlying - // data and are not indicative of a parser bug. - while (info.inline_sites.getLastOrNull()) |top| { - if (top.inlinee != site.inlinee) break; - _ = info.inline_sites.pop(); - } + // If our address points into this site, get the source location it points + // at + const inlinee_src_line = pdb.getInlineeSourceLine( + info.module, + site.inlinee, + ) orelse continue; + const maybe_loc = pdb.getInlineSiteSourceLocation( + info.module, + site, + inlinee_src_line.info, + offset_in_func, + ) catch continue; + const loc = maybe_loc orelse continue; - return .{ - .name = pdb.findInlineeName(site.inlinee), - .compile_unit_name = fs.path.basename(info.module.obj_file_name), - .source_location = offset, - }; - } + // If we've found a match, filter out any duplicates that might follow. + // Tools like llvm-addr2line output duplicate sites in the same cases as us, + // implying that they exist in the underlying data and are not indicative of + // a parser bug. + while (info.inline_sites.getLastOrNull()) |top| { + if (top.inlinee != site.inlinee) break; + _ = info.inline_sites.pop(); } + + return .{ + .name = pdb.findInlineeName(site.inlinee), + .compile_unit_name = fs.path.basename(info.module.obj_file_name), + .source_location = loc, + }; } } -- 2.54.0 From 094e841f09feebaf28a269650b053e0639783440 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Tue, 7 Apr 2026 16:01:14 -0700 Subject: [PATCH 07/29] Don't print column if column info is missing --- lib/std/debug.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index a7c2c68d0e0baedc7a91688dc5c6c750828a7069..ef9b2c2b6cc71e3e763a334d9d1679d653f3e333 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1178,7 +1178,11 @@ fn printLineInfo( t.setColor(.bold) catch {}; if (source_location) |*sl| { - try writer.print("{s}:{d}:{d}", .{ sl.file_name, sl.line, sl.column }); + if (sl.column == 0) { + try writer.print("{s}:{d}", .{ sl.file_name, sl.line }); + } else { + try writer.print("{s}:{d}:{d}", .{ sl.file_name, sl.line, sl.column }); + } } else { try writer.writeAll("???:?:?"); } -- 2.54.0 From fa26ab6fa36a5f8d2a6cf11063d42519854d008c Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Tue, 7 Apr 2026 16:24:48 -0700 Subject: [PATCH 08/29] Cleans up handling of signed line deltas --- lib/std/debug/Pdb.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index 4405bea39711fba705ce327c8cb09bb34d79671e..e7016d50180ed5793480874aebd9dd45cb3872a7 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -311,7 +311,7 @@ pub const BinaryAnnotation = union(enum) { prev: ?PartialRange, const PartialRange = struct { - line_offset: u32, + line_offset: i32, file_id: ?u32, code_offset: u32, code_length: ?u32, @@ -331,7 +331,7 @@ pub const BinaryAnnotation = union(enum) { } pub const Range = struct { - line_offset: u32, + line_offset: i32, file_id: ?u32, code_offset: u32, code_length: u32, @@ -364,11 +364,11 @@ pub const BinaryAnnotation = union(enum) { self.curr.code_offset += info.delta; }, .change_line_offset => |delta| { - self.curr.line_offset +%= @bitCast(delta); + self.curr.line_offset += delta; }, .change_code_offset_and_line_offset => |info| { self.curr.code_offset += info.code_delta; - self.curr.line_offset +%= @bitCast(info.line_delta); + self.curr.line_offset += info.line_delta; }, // Not emitted by LLVM at the time of writing, but if we get it from elsewhere it should @@ -608,7 +608,7 @@ pub fn getInlineSiteSourceLocation( errdefer self.allocator.free(file_name); return .{ - .line = inlinee_src_line.source_line_num + range.line_offset, + .line = inlinee_src_line.source_line_num +% @as(u32, @bitCast(range.line_offset)), // LLVM doesn't currently emit column information for inlined calls in PDBs. .column = 0, .file_name = file_name, -- 2.54.0 From cc15c8ae7e0b8d994e818f8275bf73617edefe68 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Tue, 7 Apr 2026 16:35:10 -0700 Subject: [PATCH 09/29] Cleans up binary annotation opcodes that we don't handle --- lib/std/debug/Pdb.zig | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index e7016d50180ed5793480874aebd9dd45cb3872a7..198e81534628967a923f3e9ef558be8a6f0e6178 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -357,8 +357,8 @@ pub const BinaryAnnotation = union(enum) { .change_file => |file_id| { self.curr.file_id = file_id; }, - // LLVM never emits this opcode, but it's clear enough how to interpret it so we may as - // well in case they use it in the future + // LLVM never emits this opcode, but it's clear enough how to interpret it so we + // may as well in case they use it in the future .change_code_length_and_code_offset => |info| { self.curr.code_length = info.length; self.curr.code_offset += info.delta; @@ -371,21 +371,24 @@ pub const BinaryAnnotation = union(enum) { self.curr.line_offset += info.line_delta; }, - // Not emitted by LLVM at the time of writing, but if we get it from elsewhere it should - // be safe to ignore since we don't use this info. Theoretically we could use column - // info if it was present, but it's not easy to test since LLVM doesn't output it. + // Not emitted by LLVM at the time of writing, and we don't want to add support + // without a test csae. Safe to ignore since we don't use this info right now. .change_line_end_delta, .change_column_start, .change_column_end_delta, .change_column_end, => {}, - // Not emitted by LLVM at the time of writing. Various sources conflict on how these - // instructions should be interpreted, so we make no attempt to handle them. + // Not emitted by LLVM at the time of writing. Various sources conflict on how + // these opcodes should be interpreted, so we make no attempt to handle them. .code_offset, .change_code_offset_base, .change_range_kind, - => @panic("unimplemented"), + => { + self.annotations = .empty; + self.prev = null; + return null; + }, } switch (annotation) { @@ -433,6 +436,8 @@ pub const BinaryAnnotation = union(enum) { pub const Iterator = struct { reader: Io.Reader, + pub const empty: Iterator = .{ .reader = .ending_instance }; + pub fn next(self: *Iterator) error{InvalidDebugInfo}!?BinaryAnnotation { return take(&self.reader) catch |err| switch (err) { error.ReadFailed => return error.InvalidDebugInfo, -- 2.54.0 From 94ff38af87e9784fc78ad3186553c953860659c4 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Wed, 8 Apr 2026 13:49:44 -0700 Subject: [PATCH 10/29] Separates error return traces from stack traces Doesn't commit the changes to stage1, we can generate those at the end once we're not making any more changes to it to avoid wasting storage. --- doc/langref.html.in | 2 +- lib/build-web/main.zig | 2 +- lib/docs/wasm/main.zig | 2 +- lib/std/Build/Step.zig | 2 +- lib/std/builtin.zig | 5 +- lib/std/debug.zig | 51 +++++++++++++------ lib/std/heap/debug_allocator.zig | 6 +-- lib/std/start.zig | 2 +- lib/std/testing/FailingAllocator.zig | 2 +- src/Sema.zig | 45 ++++++++-------- src/Zcu.zig | 4 +- src/codegen/llvm.zig | 2 +- .../panic_has_source_location.zig | 2 +- test/cases/disable_stack_tracing.zig | 2 +- test/cases/safety/@alignCast misaligned.zig | 2 +- .../@enumFromInt - no matching tag value.zig | 2 +- ...numFromInt truncated bits - exhaustive.zig | 2 +- ...FromInt truncated bits - nonexhaustive.zig | 2 +- ...rCast error not present in destination.zig | 2 +- ...ast error union casted to disjoint set.zig | 2 +- test/cases/safety/@intCast to u0.zig | 2 +- ...at cannot fit - boundary case - i0 max.zig | 2 +- ...at cannot fit - boundary case - i0 min.zig | 2 +- ...annot fit - boundary case - signed max.zig | 2 +- ...annot fit - boundary case - signed min.zig | 2 +- ...at cannot fit - boundary case - u0 max.zig | 2 +- ...at cannot fit - boundary case - u0 min.zig | 2 +- ...not fit - boundary case - unsigned max.zig | 2 +- ...not fit - boundary case - unsigned min.zig | 2 +- ...annot fit - boundary case - vector max.zig | 2 +- ...annot fit - boundary case - vector min.zig | 2 +- ...oat cannot fit - negative out of range.zig | 2 +- ...loat cannot fit - negative to unsigned.zig | 2 +- ...oat cannot fit - positive out of range.zig | 2 +- ...o to non-optional byte-aligned pointer.zig | 2 +- ...t address zero to non-optional pointer.zig | 2 +- .../@ptrFromInt with misaligned address.zig | 2 +- .../@tagName on corrupted enum value.zig | 2 +- .../@tagName on corrupted union value.zig | 2 +- .../array slice sentinel mismatch vector.zig | 2 +- .../safety/array slice sentinel mismatch.zig | 2 +- test/cases/safety/bad union field access.zig | 2 +- test/cases/safety/calling panic.zig | 2 +- ...ast []u8 to bigger slice of wrong size.zig | 2 +- ...er to global error and no code matches.zig | 2 +- ...mpty slice with sentinel out of bounds.zig | 2 +- .../exact division failure - vectors.zig | 2 +- test/cases/safety/exact division failure.zig | 2 +- test/cases/safety/for_len_mismatch.zig | 2 +- test/cases/safety/for_len_mismatch_three.zig | 2 +- .../ignored expression integer overflow.zig | 2 +- .../safety/integer addition overflow.zig | 2 +- .../integer division by zero - vectors.zig | 2 +- .../cases/safety/integer division by zero.zig | 2 +- .../integer multiplication overflow.zig | 2 +- .../safety/integer negation overflow.zig | 2 +- .../safety/integer subtraction overflow.zig | 2 +- test/cases/safety/memcpy_alias.zig | 2 +- test/cases/safety/memcpy_len_mismatch.zig | 2 +- test/cases/safety/memmove_len_mismatch.zig | 2 +- .../safety/memset_array_undefined_bytes.zig | 2 +- .../safety/memset_array_undefined_large.zig | 2 +- .../safety/memset_slice_undefined_bytes.zig | 2 +- .../safety/memset_slice_undefined_large.zig | 2 +- test/cases/safety/modrem by zero.zig | 2 +- test/cases/safety/modulus by zero.zig | 2 +- test/cases/safety/noreturn returned.zig | 2 +- .../optional unwrap operator on C pointer.zig | 2 +- ...tional unwrap operator on null pointer.zig | 2 +- .../cases/safety/optional_empty_error_set.zig | 2 +- .../out of bounds array slice by length.zig | 2 +- .../safety/out of bounds slice access.zig | 2 +- ...r casting null to non-optional pointer.zig | 2 +- ...inter casting to null function pointer.zig | 2 +- .../pointer slice sentinel mismatch.zig | 2 +- .../safety/remainder division by zero.zig | 2 +- .../safety/shift left by huge amount.zig | 2 +- .../safety/shift right by huge amount.zig | 2 +- ...ed integer division overflow - vectors.zig | 2 +- .../signed integer division overflow.zig | 2 +- ...in cast to unsigned integer - widening.zig | 2 +- ...ot fitting in cast to unsigned integer.zig | 2 +- .../safety/signed shift left overflow.zig | 2 +- .../safety/signed shift right overflow.zig | 2 +- .../safety/signed-unsigned vector cast.zig | 2 +- ...ice by length sentinel mismatch on lhs.zig | 2 +- ...ice by length sentinel mismatch on rhs.zig | 2 +- .../slice sentinel mismatch - floats.zig | 2 +- ... sentinel mismatch - optional pointers.zig | 2 +- .../safety/slice slice sentinel mismatch.zig | 2 +- ...ice start index greater than end index.zig | 2 +- ...h sentinel out of bounds - runtime len.zig | 2 +- .../slice with sentinel out of bounds.zig | 2 +- test/cases/safety/slice_cast_change_len_0.zig | 2 +- test/cases/safety/slice_cast_change_len_1.zig | 2 +- test/cases/safety/slice_cast_change_len_2.zig | 2 +- .../slicing null C pointer - runtime len.zig | 2 +- test/cases/safety/slicing null C pointer.zig | 2 +- ...else on corrupt enum value - one prong.zig | 2 +- ...tch else on corrupt enum value - union.zig | 2 +- .../switch else on corrupt enum value.zig | 2 +- .../safety/switch on corrupted enum value.zig | 2 +- .../switch on corrupted union value.zig | 2 +- test/cases/safety/truncating vector cast.zig | 2 +- test/cases/safety/unreachable.zig | 2 +- ...ast to signed integer - same bit count.zig | 2 +- .../safety/unsigned shift left overflow.zig | 2 +- .../safety/unsigned shift right overflow.zig | 2 +- .../safety/unsigned-signed vector cast.zig | 2 +- test/cases/safety/unwrap error switch.zig | 2 +- test/cases/safety/unwrap error.zig | 2 +- ...e does not fit in shortening cast - u0.zig | 2 +- .../value does not fit in shortening cast.zig | 2 +- .../vector integer addition overflow.zig | 2 +- ...vector integer multiplication overflow.zig | 2 +- .../vector integer negation overflow.zig | 2 +- .../vector integer subtraction overflow.zig | 2 +- test/cases/safety/zero casted to error.zig | 2 +- test/cases/tail_call_noreturn.zig | 4 +- test/stack_traces.zig | 18 +++---- test/standalone/compile_asm/main.zig | 2 +- test/standalone/issue_339/test.zig | 2 +- test/tests.zig | 2 +- 123 files changed, 190 insertions(+), 175 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 9f32e05896e3eccf237f6388b79198f65c90a0b8..0d2564a23935821462732926d5fb647233f09b2e 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4900,7 +4900,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val {#header_close#} {#header_open|@errorReturnTrace#} -
{#syntax#}@errorReturnTrace() ?*builtin.StackTrace{#endsyntax#}
+
{#syntax#}@errorReturnTrace() ?*builtin.ErrorReturnTrace{#endsyntax#}

If the binary is built with error return tracing, and this function is invoked in a function that calls a function with an error or error union return type, returns a diff --git a/lib/build-web/main.zig b/lib/build-web/main.zig index e71c47707b2a5fa6f93df8398ccf7778c1a81b9d..5899e5626563f9d82721569479e38e81abfada4f 100644 --- a/lib/build-web/main.zig +++ b/lib/build-web/main.zig @@ -40,7 +40,7 @@ pub const std_options: std.Options = .{ .logFn = logFn, }; -pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noreturn { +pub fn panic(msg: []const u8, st: ?*std.debug.StackTrace, addr: ?usize) noreturn { _ = st; _ = addr; log.err("panic: {s}", .{msg}); diff --git a/lib/docs/wasm/main.zig b/lib/docs/wasm/main.zig index bee3e4acbcc370261f3b137d40584ea2ad2f8065..dadc6a34926debd48caa1de9500c818ce329b38f 100644 --- a/lib/docs/wasm/main.zig +++ b/lib/docs/wasm/main.zig @@ -33,7 +33,7 @@ pub const std_options: std.Options = .{ //.log_level = .debug, }; -pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noreturn { +pub fn panic(msg: []const u8, st: ?*std.debug.StackTrace, addr: ?usize) noreturn { _ = st; _ = addr; log.err("panic: {s}", .{msg}); diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index 9df1b9d0383db5fa8cdc582d6c7bc6e466132781..5d86a0d018d636424ae252c2068ea82ac7cde723 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -67,7 +67,7 @@ test_results: TestResults, /// The return address associated with creation of this step that can be useful /// to print along with debugging messages. -debug_stack_trace: std.builtin.StackTrace, +debug_stack_trace: std.debug.StackTrace, pub const TestResults = struct { /// The total number of tests in the step. Every test has a "status" from the following: diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index addfa166b3bc8043e1ac45a55373d40fcf237b75..04959733c1b6adb7f8b71bccff2a1fad43e85b5c 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -8,12 +8,9 @@ pub const assembly = @import("builtin/assembly.zig"); /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const StackTrace = struct { +pub const ErrorReturnTrace = struct { index: usize, instruction_addresses: []usize, - /// Set to true if inlined frames are given their own entries in `instruction_addresses`, - /// otherwise set to false. - includes_inlined_frames: bool, }; /// This data structure is used by the Zig language code generation and diff --git a/lib/std/debug.zig b/lib/std/debug.zig index ef9b2c2b6cc71e3e763a334d9d1679d653f3e333..c10cdf949ec5c1d893e63447c112055f7e55964b 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -13,7 +13,6 @@ const windows = std.os.windows; const builtin = @import("builtin"); const native_arch = builtin.cpu.arch; const native_os = builtin.os.tag; -const StackTrace = std.builtin.StackTrace; const root = @import("root"); @@ -568,7 +567,7 @@ pub fn defaultPanic(msg: []const u8, first_trace_addr: ?usize) noreturn { if (@errorReturnTrace()) |t| if (t.index > 0) { writer.writeAll("error return context:\n") catch break :trace; - writeStackTrace(t, stderr) catch break :trace; + writeErrorReturnTrace(t, stderr) catch break :trace; writer.writeAll("\nstack trace:\n") catch break :trace; }; writeCurrentStackTrace(.{ @@ -607,6 +606,13 @@ fn waitForOtherThreadToFinishPanicking() void { } } +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const StackTrace = struct { + index: usize, + instruction_addresses: []usize, +}; + pub const StackUnwindOptions = struct { /// If not `null`, we will ignore all frames up until this return address. This is typically /// used to omit intermediate handling code (for instance, a panic handler and its machinery) @@ -629,7 +635,6 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: const empty_trace: StackTrace = .{ .index = 0, .instruction_addresses = &.{}, - .includes_inlined_frames = false, }; if (!std.options.allow_stack_tracing) return empty_trace; var it: StackIterator = .init(options.context); @@ -665,7 +670,6 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: return .{ .index = index, .instruction_addresses = addr_buf[0..index], - .includes_inlined_frames = false, }; } /// Write the current stack trace to `writer`, annotated with source locations. @@ -752,7 +756,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin // Subtract 1 to get an address *in* the function call for a better source location. try printSourceAtAddress(io, di, t, .{ .address = ret_addr -| StackIterator.ra_call_offset, - .print_inlines = true, + .resolve_inline_callers = true, }); printed_any_frame = true; }, @@ -786,8 +790,17 @@ pub const FormatStackTrace = struct { } }; +/// Write a previously captured error return trace to `writer`, annotated with source locations. +pub fn writeErrorReturnTrace(st: *const std.builtin.ErrorReturnTrace, t: Io.Terminal) Writer.Error!void { + try writeTrace(st, t, false); +} + /// Write a previously captured stack trace to `writer`, annotated with source locations. -pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void { +pub fn writeStackTrace(et: *const StackTrace, t: Io.Terminal) Writer.Error!void { + try writeTrace(et, t, true); +} + +fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writer.Error!void { const writer = t.writer; if (!std.options.allow_stack_tracing) { t.setColor(.dim) catch {}; @@ -796,9 +809,9 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void return; } - // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if - // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. - const n_frames = st.index; + // Fetch `trace.index` straight away. Aside from avoiding redundant loads, this prevents issues if + // `trace` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. + const n_frames = trace.index; if (n_frames == 0) return writer.writeAll("(empty stack trace)\n"); const di = getSelfDebugInfo() catch |err| switch (err) { error.UnsupportedTarget => { @@ -809,13 +822,13 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void }, }; const io = std.Options.debug_io; - const captured_frames = @min(n_frames, st.instruction_addresses.len); - for (st.instruction_addresses[0..captured_frames]) |ret_addr| { + const captured_frames = @min(n_frames, trace.instruction_addresses.len); + for (trace.instruction_addresses[0..captured_frames]) |ret_addr| { // `ret_addr` is the return address, which is *after* the function call. // Subtract 1 to get an address *in* the function call for a better source location. try printSourceAtAddress(io, di, t, .{ .address = ret_addr -| StackIterator.ra_call_offset, - .print_inlines = !st.includes_inlined_frames, + .resolve_inline_callers = resolve_inline_callers, }); } if (n_frames > captured_frames) { @@ -833,6 +846,15 @@ pub fn dumpStackTrace(st: *const StackTrace) void { }; } +/// A thin wrapper around `writeErrorReturnTrace` which writes to stderr and ignores write errors. +pub fn dumpErrorReturnTrace(et: *const std.builtin.ErrorReturnTrace) void { + const stderr = lockStderr(&.{}).terminal(); + defer unlockStderr(); + writeErrorReturnTrace(et, stderr) catch |err| switch (err) { + error.WriteFailed => {}, + }; +} + const StackIterator = union(enum) { /// We will first report the current PC of this `CpuContextPtr`, then we will switch to a /// different strategy to actually unwind. @@ -1124,7 +1146,7 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { const PrintSourceAddressOptions = struct { address: usize, - print_inlines: bool, + resolve_inline_callers: bool, }; fn printSourceAtAddress( @@ -1163,7 +1185,7 @@ fn printSourceAtAddress( symbol.name orelse "???", symbol.compile_unit_name orelse debug_info.getModuleName(io, options.address) catch "???", ); - if (!options.print_inlines) break; + if (!options.resolve_inline_callers) break; } } fn printLineInfo( @@ -1708,7 +1730,6 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize const stack_trace: StackTrace = .{ .index = frames.len, .instruction_addresses = frames, - .includes_inlined_frames = false, }; writeStackTrace(&stack_trace, stderr) catch return; } diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index 987bb4e6eaaca055953b8f2a4149b08b052db1b1..f49fc9493d408c0ea52eaae556a3ec3cc1b04b52 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -81,7 +81,7 @@ //! Resizing and remapping are forwarded directly to the backing allocator, //! except where such operations would change the category from large to small. const builtin = @import("builtin"); -const StackTrace = std.builtin.StackTrace; +const StackTrace = std.debug.StackTrace; const std = @import("std"); const log = std.log.scoped(.DebugAllocator); @@ -229,7 +229,7 @@ pub fn DebugAllocator(comptime config: Config) type { std.debug.dumpStackTrace(self.getStackTrace(trace_kind)); } - fn getStackTrace(self: *LargeAlloc, trace_kind: TraceKind) std.builtin.StackTrace { + fn getStackTrace(self: *LargeAlloc, trace_kind: TraceKind) std.debug.StackTrace { assert(@intFromEnum(trace_kind) < trace_n); const stack_addresses = &self.stack_addresses[@intFromEnum(trace_kind)]; var len: usize = 0; @@ -239,7 +239,6 @@ pub fn DebugAllocator(comptime config: Config) type { return .{ .instruction_addresses = stack_addresses, .index = len, - .includes_inlined_frames = false, }; } @@ -342,7 +341,6 @@ pub fn DebugAllocator(comptime config: Config) type { return .{ .instruction_addresses = stack_addresses, .index = len, - .includes_inlined_frames = false, }; } diff --git a/lib/std/start.zig b/lib/std/start.zig index 29c76fdfadc55af1493546bc4b5fba7ef8dc2b76..01b33ba5f146d79ae8ba5a5ba0b7052d64b084cd 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -761,7 +761,7 @@ inline fn wrapMain(result: anytype) u8 { std.log.err("{t}", .{err}); switch (native_os) { .freestanding, .other => {}, - else => if (@errorReturnTrace()) |trace| std.debug.dumpStackTrace(trace), + else => if (@errorReturnTrace()) |trace| std.debug.dumpErrorReturnTrace(trace), } return 1; }; diff --git a/lib/std/testing/FailingAllocator.zig b/lib/std/testing/FailingAllocator.zig index 6476725a2f70106602afc735e2d7bd368f850bea..bcd88567106dca6804b32b85ec32ac58319106fb 100644 --- a/lib/std/testing/FailingAllocator.zig +++ b/lib/std/testing/FailingAllocator.zig @@ -131,7 +131,7 @@ fn free( } /// Only valid once `has_induced_failure == true` -pub fn getStackTrace(self: *FailingAllocator) std.builtin.StackTrace { +pub fn getStackTrace(self: *FailingAllocator) std.debug.StackTrace { std.debug.assert(self.has_induced_failure); var len: usize = 0; while (len < self.stack_addresses.len and self.stack_addresses[len] != 0) { diff --git a/src/Sema.zig b/src/Sema.zig index 4702241a71aba52188f51cd1605131785673f95d..1767e058e0d627e663a41236a69bdc6d7f3c3a22 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2252,9 +2252,8 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) }); const addrs_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(addr_arr_ty)); - // var st: StackTrace = undefined; - const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); - const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(stack_trace_ty)); + const error_return_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .ErrorReturnTrace); + const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(error_return_trace_ty)); // st.instruction_addresses = &addrs; const instruction_addresses_field_name = try ip.getOrPutString(gpa, io, pt.tid, "instruction_addresses", .no_embedded_nulls); @@ -6166,10 +6165,10 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref if (!block.ownerModule().error_tracing) return .none; - const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); + const error_return_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .ErrorReturnTrace); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); - const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { - error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"), + const field_index = sema.structFieldIndex(block, error_return_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { + error.AnalysisFail => @panic("std.builtin.ErrorReturnTrace is corrupt"), error.ComptimeReturn, error.ComptimeBreak => unreachable, error.OutOfMemory, error.Canceled => |e| return e, }; @@ -6177,7 +6176,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref return try block.addInst(.{ .tag = .save_err_return_trace_index, .data = .{ .ty_pl = .{ - .ty = Air.internedToRef(stack_trace_ty.toIntern()), + .ty = Air.internedToRef(error_return_trace_ty.toIntern()), .payload = @intCast(field_index), } }, }); @@ -6209,11 +6208,11 @@ fn popErrorReturnTrace( // AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or // the result is comptime-known to be a non-error. Either way, pop unconditionally. - const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace); - const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); - const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); + const error_return_trace_ty = try sema.getBuiltinType(src, .ErrorReturnTrace); + const ptr_error_return_trace_ty = try pt.singleMutPtrType(error_return_trace_ty); + const err_return_trace = try block.addTy(.err_return_trace, ptr_error_return_trace_ty); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); - const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty); + const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, error_return_trace_ty); try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); } else if (is_non_error == null) { // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need @@ -6234,11 +6233,11 @@ fn popErrorReturnTrace( defer then_block.instructions.deinit(gpa); // If non-error, then pop the error return trace by restoring the index. - const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace); - const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); - const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); + const error_return_trace_ty = try sema.getBuiltinType(src, .ErrorReturnTrace); + const ptr_error_return_trace_ty = try pt.singleMutPtrType(error_return_trace_ty); + const err_return_trace = try then_block.addTy(.err_return_trace, ptr_error_return_trace_ty); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); - const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty); + const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, error_return_trace_ty); try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); _ = try then_block.addBr(cond_block_inst, .void_value); @@ -6373,15 +6372,15 @@ fn zirCall( // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only // need to clean-up our own trace if we were passed to a non-error-handling expression. if (input_is_error or (pop_error_return_trace and return_ty.isError(zcu))) { - const stack_trace_ty = try sema.getBuiltinType(call_src, .StackTrace); + const error_return_trace_ty = try sema.getBuiltinType(call_src, .ErrorReturnTrace); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); - const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); + const field_index = try sema.structFieldIndex(block, error_return_trace_ty, field_name, call_src); // Insert a save instruction before the arg resolution + call instructions we just generated const save_inst = try block.insertInst(block_index, .{ .tag = .save_err_return_trace_index, .data = .{ .ty_pl = .{ - .ty = Air.internedToRef(stack_trace_ty.toIntern()), + .ty = Air.internedToRef(error_return_trace_ty.toIntern()), .payload = @intCast(field_index), } }, }); @@ -19529,13 +19528,13 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); - const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); - const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern()); + const error_return_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .ErrorReturnTrace); + const ptr_error_return_trace_ty = try pt.singleMutPtrType(error_return_trace_ty); + const opt_ptr_error_return_trace_ty = try pt.optionalType(ptr_error_return_trace_ty.toIntern()); switch (sema.owner.unwrap()) { .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) { - return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); + return block.addTy(.err_return_trace, opt_ptr_error_return_trace_ty); }, .@"comptime", @@ -19547,7 +19546,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { => {}, } return Air.internedToRef(try pt.intern(.{ .opt = .{ - .ty = opt_ptr_stack_trace_ty.toIntern(), + .ty = opt_ptr_error_return_trace_ty.toIntern(), .val = .none, } })); } diff --git a/src/Zcu.zig b/src/Zcu.zig index 88258b236acf77c69a5b3e97b2d9e20ebc346c04..9b56b68c69f06cbfc1b4af238c3fdd5a389c025e 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -434,7 +434,7 @@ pub const BuiltinDecl = enum { AddressSpace, CallingConvention, returnError, - StackTrace, + ErrorReturnTrace, SourceLocation, CallModifier, AtomicOrder, @@ -512,7 +512,7 @@ pub const BuiltinDecl = enum { return switch (decl) { .returnError => .func, - .StackTrace, + .ErrorReturnTrace, .CallingConvention, .SourceLocation, .Signedness, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 1ba3b272da797e44061a16136a8269fb3c61b195..b138c852621e81bad93f3c462efb52d02db71a08 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3374,7 +3374,7 @@ pub const Object = struct { } if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) { - // First parameter is a pointer to `std.builtin.StackTrace`. + // First parameter is a pointer to `std.builtin.ErrorReturnTrace`. const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(.generic, target)); try llvm_params.append(o.gpa, llvm_ptr_ty); } diff --git a/test/cases/compile_errors/panic_has_source_location.zig b/test/cases/compile_errors/panic_has_source_location.zig index a04d89c3ee3a9dd134fbe037a9ead08f59cd1edf..2db115ebf66d39a7c27e44d3d9b404af2ca20174 100644 --- a/test/cases/compile_errors/panic_has_source_location.zig +++ b/test/cases/compile_errors/panic_has_source_location.zig @@ -6,7 +6,7 @@ export fn foo() void { @panic("oh no"); } -pub fn panic(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(_: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { @compileError("panic"); } diff --git a/test/cases/disable_stack_tracing.zig b/test/cases/disable_stack_tracing.zig index 36620130c9a6fb6089e222b0bf7d0a5d7f5f179a..a1659f2bd46fa0428d59c117e47c1f15dfebc62d 100644 --- a/test/cases/disable_stack_tracing.zig +++ b/test/cases/disable_stack_tracing.zig @@ -13,7 +13,7 @@ pub fn main() !void { try stdout.interface.flush(); } -fn foo(w: *std.Io.Writer, st_buf: []usize) !std.builtin.StackTrace { +fn foo(w: *std.Io.Writer, st_buf: []usize) !std.debug.StackTrace { try std.debug.writeCurrentStackTrace(.{}, .{ .writer = w, .mode = .no_color }); return std.debug.captureCurrentStackTrace(.{}, st_buf); } diff --git a/test/cases/safety/@alignCast misaligned.zig b/test/cases/safety/@alignCast misaligned.zig index f5e0dc87a7923dde14215dc4383477ee24830775..92b2badb5a056e9ef05e77b4098cd05ff8f50efa 100644 --- a/test/cases/safety/@alignCast misaligned.zig +++ b/test/cases/safety/@alignCast misaligned.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "incorrect alignment")) { std.process.exit(0); diff --git a/test/cases/safety/@enumFromInt - no matching tag value.zig b/test/cases/safety/@enumFromInt - no matching tag value.zig index 35d23b2be7543f1f4f92e84408e5ea7491e34a7f..e9bb3a2abc0ccdb69c1709580c3b5ea673d02354 100644 --- a/test/cases/safety/@enumFromInt - no matching tag value.zig +++ b/test/cases/safety/@enumFromInt - no matching tag value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); diff --git a/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig b/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig index 4edbfae996280f074e9600f65e5c5aae5b646882..f93677cf7e01a6888a6f7165498df060a0594210 100644 --- a/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig +++ b/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); } diff --git a/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig b/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig index 16e4699478c5f0448211fbe855a1eecadab0fd6e..f7bcd690634919b703dfa5958f2833609f672c26 100644 --- a/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig +++ b/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); } diff --git a/test/cases/safety/@errorCast error not present in destination.zig b/test/cases/safety/@errorCast error not present in destination.zig index bb8379042b279d385b91d12db0328fdd595c2a5e..b7a7b2ae2ab531be8644d9de6702fb002c8a5655 100644 --- a/test/cases/safety/@errorCast error not present in destination.zig +++ b/test/cases/safety/@errorCast error not present in destination.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid error code")) { std.process.exit(0); diff --git a/test/cases/safety/@errorCast error union casted to disjoint set.zig b/test/cases/safety/@errorCast error union casted to disjoint set.zig index 267c136e9e8b139c9bdc78c9aa1daa17ded5871d..a8b0b8dcfaa846df7b6fb1b374597ac794c1e753 100644 --- a/test/cases/safety/@errorCast error union casted to disjoint set.zig +++ b/test/cases/safety/@errorCast error union casted to disjoint set.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid error code")) { std.process.exit(0); diff --git a/test/cases/safety/@intCast to u0.zig b/test/cases/safety/@intCast to u0.zig index 180ee78512fccc28ba1b33ef2b78e0570f0044cb..0649df2fb1bb37b22684b2a5c8b8bb8b92c55ba4 100644 --- a/test/cases/safety/@intCast to u0.zig +++ b/test/cases/safety/@intCast to u0.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig index dd5c62e07cc10c5f317c60eb96ff6603fd6297d2..2b3a9c35562e7553c2e1f809128957bed00c8863 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig index 0b0fab15d9ca8ec6abbdb1b85c86bde0b4f2dd4b..65a3d904c27770d438061333a51687ff077553ac 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig index 8c42449a87a8b8c6a1d5dc28763864b34f6fca4d..fda0fbd8c184bb951ed3c8fae3c6653b3006c312 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig index 49cee6a78613742cb8ac22dc7110ec906d207f7d..847a65e3aee059bf156684526483a3fd8e42bfbc 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig index 0a786bff7baaced248118379e0fc586b6ee8932b..748d89e12a1e8bbd4ed5283a6c205b8e2cea2bb5 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig index 07f5ff3e42b1cf2ee315c84d1f889c8510a1bd4a..ab43e1d9e8e1895c7916941dfd380cf93f2077ea 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig index e54bc221da96a0562862c01b81106bf97f8ab2bf..f28cc6de0c2110a22d6a846e5edcbdc9b8ba40bd 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig index 90bbb696e274792bbc0be62939124096410e8dc1..af03ad840a26d288a3ec60cd12dc79adc9fd0df4 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig index 77b1ef5a14fe37276ba85d468acb196240932881..f2b25df616080eb1bcdda4152ae3a0810e3cf669 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig index 095298e6facfca3d405da16b71e7a6967f69af3e..8e5208a882d20bba75b445c637cfc44544eb303c 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig b/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig index b67604541cec32e182f68c5d447f9b4cdf040e54..95e077c774fa83ffd13485319f8ed91e6ddf8678 100644 --- a/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig +++ b/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig b/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig index f6e6f4662cf7c37d1683a5deb60ff9a679ac3c3d..74cb95297a24aaead6bb48fb0bed5de39eed3de9 100644 --- a/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig +++ b/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig b/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig index 594cedf8ed0d31ebf0d4bf21271daffc009670cc..faba3ffa639b2c5bf9efb3e987cd78fcb229ecf0 100644 --- a/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig +++ b/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig b/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig index 16630b6f6a7dc374e998a4359b9e761c23659bf3..ce9aa416493935048a5bb8e46882f0d1d04b5e20 100644 --- a/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig +++ b/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "cast causes pointer to be null")) { std.process.exit(0); diff --git a/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig b/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig index 21cfda643470e04be687f796323fc30cf2101d59..3b162c85e4b50cc162e1ac99ba13be798b3e38f1 100644 --- a/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig +++ b/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "cast causes pointer to be null")) { std.process.exit(0); diff --git a/test/cases/safety/@ptrFromInt with misaligned address.zig b/test/cases/safety/@ptrFromInt with misaligned address.zig index 81e2ffb91ef238d758deb6ff7a7184579219f8e5..7f2e527c1f498864355a035f64b2e0c249f644fd 100644 --- a/test/cases/safety/@ptrFromInt with misaligned address.zig +++ b/test/cases/safety/@ptrFromInt with misaligned address.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "incorrect alignment")) { std.process.exit(0); diff --git a/test/cases/safety/@tagName on corrupted enum value.zig b/test/cases/safety/@tagName on corrupted enum value.zig index faf8103880cdc478d1dd2aef8e8311c554bd054f..e1e9f6bb261b6f835778b78c972a34fcf48cc0d2 100644 --- a/test/cases/safety/@tagName on corrupted enum value.zig +++ b/test/cases/safety/@tagName on corrupted enum value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); diff --git a/test/cases/safety/@tagName on corrupted union value.zig b/test/cases/safety/@tagName on corrupted union value.zig index 73e62a60b8ffcc3e0e6250c45dbd5a8d1030cac3..01d1e7f882732be6c1b4bf900169c173719d8e24 100644 --- a/test/cases/safety/@tagName on corrupted union value.zig +++ b/test/cases/safety/@tagName on corrupted union value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); diff --git a/test/cases/safety/array slice sentinel mismatch vector.zig b/test/cases/safety/array slice sentinel mismatch vector.zig index 723288c437ea4d4ed4fcf7d93267a2db578600e5..408d18f2842e91648e8610d17847076c7eddf156 100644 --- a/test/cases/safety/array slice sentinel mismatch vector.zig +++ b/test/cases/safety/array slice sentinel mismatch vector.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected { 0, 0 }, found { 4, 4 }")) { std.process.exit(0); diff --git a/test/cases/safety/array slice sentinel mismatch.zig b/test/cases/safety/array slice sentinel mismatch.zig index 49e9d8caaad5a0c145a151a5286f894bf144e87c..f58e43ab03a94951c778867879aae0b0628a3224 100644 --- a/test/cases/safety/array slice sentinel mismatch.zig +++ b/test/cases/safety/array slice sentinel mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) { std.process.exit(0); diff --git a/test/cases/safety/bad union field access.zig b/test/cases/safety/bad union field access.zig index 7cf0c30417ca14b3439662cddc5f0ca8a296eeb6..68568729f21471186c4c288b019f1ba7926c8ea7 100644 --- a/test/cases/safety/bad union field access.zig +++ b/test/cases/safety/bad union field access.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "access of union field 'float' while field 'int' is active")) { std.process.exit(0); diff --git a/test/cases/safety/calling panic.zig b/test/cases/safety/calling panic.zig index d77104bbb39e6b6f0ab70138faee5c403a2953a7..23455e1d4553c9c2af277a66fcd5707dfebc0751 100644 --- a/test/cases/safety/calling panic.zig +++ b/test/cases/safety/calling panic.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "oh no")) { std.process.exit(0); diff --git a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig index de15051993518235a1f7ff42d3b0cedfb5a4b5b5..220a215a9cc1e9057aa6f958831c3b8d3a68ddad 100644 --- a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig +++ b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "exact division produced remainder")) { std.process.exit(0); diff --git a/test/cases/safety/cast integer to global error and no code matches.zig b/test/cases/safety/cast integer to global error and no code matches.zig index 51adb1ac1e8dc7f2705e31d1b3ff6a09d25825d6..4570c44dcde5ddda49201093dade7655577c560e 100644 --- a/test/cases/safety/cast integer to global error and no code matches.zig +++ b/test/cases/safety/cast integer to global error and no code matches.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid error code")) { std.process.exit(0); diff --git a/test/cases/safety/empty slice with sentinel out of bounds.zig b/test/cases/safety/empty slice with sentinel out of bounds.zig index 1dacc309587582870dbe94e9e5639cd047a3ffcf..fab386becd991618300fe2eb945bc915b82ac155 100644 --- a/test/cases/safety/empty slice with sentinel out of bounds.zig +++ b/test/cases/safety/empty slice with sentinel out of bounds.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 1, len 0")) { std.process.exit(0); diff --git a/test/cases/safety/exact division failure - vectors.zig b/test/cases/safety/exact division failure - vectors.zig index 0693b7b1286d7310129c112716d3643fc3568bc5..22bd4a924b2fbff185fe656d0d3365464c071b03 100644 --- a/test/cases/safety/exact division failure - vectors.zig +++ b/test/cases/safety/exact division failure - vectors.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "exact division produced remainder")) { std.process.exit(0); diff --git a/test/cases/safety/exact division failure.zig b/test/cases/safety/exact division failure.zig index 262f921e923805f599afcdc1f8db94b0098991d6..f9b4677f01d8bb93edfd9202de7b776c94a2a788 100644 --- a/test/cases/safety/exact division failure.zig +++ b/test/cases/safety/exact division failure.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "exact division produced remainder")) { std.process.exit(0); diff --git a/test/cases/safety/for_len_mismatch.zig b/test/cases/safety/for_len_mismatch.zig index 4b9affab36f2648de12387826668dc462bff2071..1887eb97e384f0d1c27525c4c0f760134d8d7709 100644 --- a/test/cases/safety/for_len_mismatch.zig +++ b/test/cases/safety/for_len_mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "for loop over objects with non-equal lengths")) { std.process.exit(0); diff --git a/test/cases/safety/for_len_mismatch_three.zig b/test/cases/safety/for_len_mismatch_three.zig index aed7479bf26b8cbe23b8b22951c9a026d78e6bde..0a0454ab5caff129b453f5910cc8d8042f64be63 100644 --- a/test/cases/safety/for_len_mismatch_three.zig +++ b/test/cases/safety/for_len_mismatch_three.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "for loop over objects with non-equal lengths")) { std.process.exit(0); diff --git a/test/cases/safety/ignored expression integer overflow.zig b/test/cases/safety/ignored expression integer overflow.zig index b92bfd4c266b25870444db4da90f5f409f7df586..6d3d9e0af0da5b35c63a18700f52981970a28e44 100644 --- a/test/cases/safety/ignored expression integer overflow.zig +++ b/test/cases/safety/ignored expression integer overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/integer addition overflow.zig b/test/cases/safety/integer addition overflow.zig index 336b4831ac0f37b4860eb51018a35c435c26ef3e..808938c12298fe3c1a3b9ac587ba61376be2803e 100644 --- a/test/cases/safety/integer addition overflow.zig +++ b/test/cases/safety/integer addition overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/integer division by zero - vectors.zig b/test/cases/safety/integer division by zero - vectors.zig index fe3aefeb1abae6f4ee63cbe701a91c2283f6f42c..ed0fa971c930b3d836f187349cd897b6de6bd2b6 100644 --- a/test/cases/safety/integer division by zero - vectors.zig +++ b/test/cases/safety/integer division by zero - vectors.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/integer division by zero.zig b/test/cases/safety/integer division by zero.zig index a667c7c20658a6444f89f90f5caf6c5935ec2e48..7fe895d70e125dac8927aa9e0b30bdb7b1d9abff 100644 --- a/test/cases/safety/integer division by zero.zig +++ b/test/cases/safety/integer division by zero.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/integer multiplication overflow.zig b/test/cases/safety/integer multiplication overflow.zig index 311869657b1f988c76280242ece4c59b510e5ccd..6a026c2221168fdc7d86449d06fdbcb648534418 100644 --- a/test/cases/safety/integer multiplication overflow.zig +++ b/test/cases/safety/integer multiplication overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/integer negation overflow.zig b/test/cases/safety/integer negation overflow.zig index 5d2681dee049831b26c0ebdc56faf4abb1242310..d5777a6834951cfb77135028361cb832d41fe876 100644 --- a/test/cases/safety/integer negation overflow.zig +++ b/test/cases/safety/integer negation overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/integer subtraction overflow.zig b/test/cases/safety/integer subtraction overflow.zig index 142f1f44cdd404c56ac2f291d66faa5d99f463a0..758dfa898e1473eaff63f75b13f50c763e730dd6 100644 --- a/test/cases/safety/integer subtraction overflow.zig +++ b/test/cases/safety/integer subtraction overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/memcpy_alias.zig b/test/cases/safety/memcpy_alias.zig index cdd5aeb2e251142fd9410103b46615c9f010f47c..5fa007e198d992281abca5997962dfb62b66aa60 100644 --- a/test/cases/safety/memcpy_alias.zig +++ b/test/cases/safety/memcpy_alias.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "@memcpy arguments alias")) { std.process.exit(0); diff --git a/test/cases/safety/memcpy_len_mismatch.zig b/test/cases/safety/memcpy_len_mismatch.zig index 3728ca2a0173dd97a48371ab31facd0ba32bd3f5..e95ae542dbde4b4898d18b2123a8b3e9fe9ec8bf 100644 --- a/test/cases/safety/memcpy_len_mismatch.zig +++ b/test/cases/safety/memcpy_len_mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "source and destination arguments have non-equal lengths")) { std.process.exit(0); diff --git a/test/cases/safety/memmove_len_mismatch.zig b/test/cases/safety/memmove_len_mismatch.zig index 97624a4710dd5e86c9e7d173103b21db1da38c95..4dc28246babe1630867200f6e082d44a3adb5adc 100644 --- a/test/cases/safety/memmove_len_mismatch.zig +++ b/test/cases/safety/memmove_len_mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "source and destination arguments have non-equal lengths")) { std.process.exit(0); diff --git a/test/cases/safety/memset_array_undefined_bytes.zig b/test/cases/safety/memset_array_undefined_bytes.zig index 6e374647c38cc979f46e3ca3d5ba5ccd1c319131..3e6d85f1186f1cf1932c4949d8485ec489081f69 100644 --- a/test/cases/safety/memset_array_undefined_bytes.zig +++ b/test/cases/safety/memset_array_undefined_bytes.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/memset_array_undefined_large.zig b/test/cases/safety/memset_array_undefined_large.zig index 3ea5bcc2e790bbdf2d6553e0cbfe3d12c0f5d0e7..479441b7dcbcda0b2705f031235ec542624886e4 100644 --- a/test/cases/safety/memset_array_undefined_large.zig +++ b/test/cases/safety/memset_array_undefined_large.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/memset_slice_undefined_bytes.zig b/test/cases/safety/memset_slice_undefined_bytes.zig index e3d8f2a5121629d7d54c6a0a69109bba0f085379..4514e9a4a6fff19f7f3843529d3214a6dcc38648 100644 --- a/test/cases/safety/memset_slice_undefined_bytes.zig +++ b/test/cases/safety/memset_slice_undefined_bytes.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/memset_slice_undefined_large.zig b/test/cases/safety/memset_slice_undefined_large.zig index 5131e592f9a386ae7a0d2e74e42af761d255a886..181cdb50ca41bfb0d7f6d853febae8d2b4d94b9f 100644 --- a/test/cases/safety/memset_slice_undefined_large.zig +++ b/test/cases/safety/memset_slice_undefined_large.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/modrem by zero.zig b/test/cases/safety/modrem by zero.zig index 365eeaba4389920f8f0c8aaf90b2dfa8b6bb5fad..4293baa0e0a0991555c1928d4174ed95c5357450 100644 --- a/test/cases/safety/modrem by zero.zig +++ b/test/cases/safety/modrem by zero.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/modulus by zero.zig b/test/cases/safety/modulus by zero.zig index 844f6e3b75be682abe3f17b2e9148263fbcc4e82..d133ce883a32761e95a02081eeb8408d74c9f7fc 100644 --- a/test/cases/safety/modulus by zero.zig +++ b/test/cases/safety/modulus by zero.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/noreturn returned.zig b/test/cases/safety/noreturn returned.zig index 58e392d224c1fce72ecdc297a743caacb7c45ccd..3bc6ab68c0e486b7ac460599e2d6773d1e3e9bcc 100644 --- a/test/cases/safety/noreturn returned.zig +++ b/test/cases/safety/noreturn returned.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "'noreturn' function returned")) { std.process.exit(0); diff --git a/test/cases/safety/optional unwrap operator on C pointer.zig b/test/cases/safety/optional unwrap operator on C pointer.zig index 308d97983592db1fc0aeb2906712761a8faa78a2..6009c758f01450cd213f9cfa25672e6ea944f766 100644 --- a/test/cases/safety/optional unwrap operator on C pointer.zig +++ b/test/cases/safety/optional unwrap operator on C pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to use null value")) { std.process.exit(0); diff --git a/test/cases/safety/optional unwrap operator on null pointer.zig b/test/cases/safety/optional unwrap operator on null pointer.zig index 63ee03facb462b4fd9972370188ca9713a272387..1aae8fa1df3938eb345a0e68b794c0c6420fa29f 100644 --- a/test/cases/safety/optional unwrap operator on null pointer.zig +++ b/test/cases/safety/optional unwrap operator on null pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to use null value")) { std.process.exit(0); diff --git a/test/cases/safety/optional_empty_error_set.zig b/test/cases/safety/optional_empty_error_set.zig index 60e6c5c3eb490955d9d18f198d7b0759bb76ed06..44dea2233b47dee5bde0845dd0349955d1d51450 100644 --- a/test/cases/safety/optional_empty_error_set.zig +++ b/test/cases/safety/optional_empty_error_set.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, ra: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, ra: ?usize) noreturn { _ = stack_trace; _ = ra; if (std.mem.eql(u8, message, "attempt to use null value")) { diff --git a/test/cases/safety/out of bounds array slice by length.zig b/test/cases/safety/out of bounds array slice by length.zig index cc9bb0205a643ad8df46d488b192ed7309d6918c..bb8012458143eaa5d7bad6180b24aad2e0e3f143 100644 --- a/test/cases/safety/out of bounds array slice by length.zig +++ b/test/cases/safety/out of bounds array slice by length.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 16, len 5")) { std.process.exit(0); diff --git a/test/cases/safety/out of bounds slice access.zig b/test/cases/safety/out of bounds slice access.zig index 61ae983fbab8ebea65a191b02722f9af9f9defe5..c2ea85b864cc7a57489eb07b37908d24f4bfab48 100644 --- a/test/cases/safety/out of bounds slice access.zig +++ b/test/cases/safety/out of bounds slice access.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 4, len 4")) { std.process.exit(0); diff --git a/test/cases/safety/pointer casting null to non-optional pointer.zig b/test/cases/safety/pointer casting null to non-optional pointer.zig index e10297dc49cf00fb006fd5ad2459782bb43f235a..491dc69dca06f727bf7356882b81986a28b69711 100644 --- a/test/cases/safety/pointer casting null to non-optional pointer.zig +++ b/test/cases/safety/pointer casting null to non-optional pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "cast causes pointer to be null")) { std.process.exit(0); diff --git a/test/cases/safety/pointer casting to null function pointer.zig b/test/cases/safety/pointer casting to null function pointer.zig index 892e6cbfd98010617fbcc1551cd90245ede3269f..bf8d2a502edc71e7f1fd5998a526dde3c10a9be1 100644 --- a/test/cases/safety/pointer casting to null function pointer.zig +++ b/test/cases/safety/pointer casting to null function pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "cast causes pointer to be null")) { std.process.exit(0); diff --git a/test/cases/safety/pointer slice sentinel mismatch.zig b/test/cases/safety/pointer slice sentinel mismatch.zig index 9ad91109d90de3261c5d1fe5857fbc62e526e744..5b0f8618c06d548048892726ffc7d374084c0cbe 100644 --- a/test/cases/safety/pointer slice sentinel mismatch.zig +++ b/test/cases/safety/pointer slice sentinel mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) { std.process.exit(0); diff --git a/test/cases/safety/remainder division by zero.zig b/test/cases/safety/remainder division by zero.zig index 754f160c9cad768a2540dc3697944d1daa50ff2f..4a45e7eee96fbf90846fedd64c7ba4714aaa10a1 100644 --- a/test/cases/safety/remainder division by zero.zig +++ b/test/cases/safety/remainder division by zero.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/shift left by huge amount.zig b/test/cases/safety/shift left by huge amount.zig index 2b67721299bd6a9de1d3d2a20d898cf509c90dac..591334c1607556eba245a9eaa8dd3a8718ea1f7d 100644 --- a/test/cases/safety/shift left by huge amount.zig +++ b/test/cases/safety/shift left by huge amount.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "shift amount is greater than the type size")) { std.process.exit(0); diff --git a/test/cases/safety/shift right by huge amount.zig b/test/cases/safety/shift right by huge amount.zig index cf836eafa3a3884a490f94bf5d61a3f96147668e..a537b969c383be23828e2af8461309fdd86fba80 100644 --- a/test/cases/safety/shift right by huge amount.zig +++ b/test/cases/safety/shift right by huge amount.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "shift amount is greater than the type size")) { std.process.exit(0); diff --git a/test/cases/safety/signed integer division overflow - vectors.zig b/test/cases/safety/signed integer division overflow - vectors.zig index 56996e1e32094ca847447d3c3ea3bd3e2c893c95..a13fc604406f280b0deafad79db20b8581d05c1c 100644 --- a/test/cases/safety/signed integer division overflow - vectors.zig +++ b/test/cases/safety/signed integer division overflow - vectors.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/signed integer division overflow.zig b/test/cases/safety/signed integer division overflow.zig index fa4b124189678410414211fe9d77c35e0b9a4bf6..1742386258e789e5f4e26aecf9868c69d88133f6 100644 --- a/test/cases/safety/signed integer division overflow.zig +++ b/test/cases/safety/signed integer division overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig index be3a0ad662e441d8f803f156b88e2a10b5acc2f3..06b792e067c97bf5d53ee898649efc15ad004b2c 100644 --- a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig +++ b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig index fb636c0bce360a1b9f4290c1bd18df65a6682ed1..b1d31ac78a0eeef826aa7fa8d1e7f4f0db174227 100644 --- a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig +++ b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/signed shift left overflow.zig b/test/cases/safety/signed shift left overflow.zig index bd6bc012bb7296236551deda8c1923376121c554..93e1c5c1e77b9a72158ea15063344d3f7767c065 100644 --- a/test/cases/safety/signed shift left overflow.zig +++ b/test/cases/safety/signed shift left overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "left shift overflowed bits")) { std.process.exit(0); diff --git a/test/cases/safety/signed shift right overflow.zig b/test/cases/safety/signed shift right overflow.zig index 6dc5806e4fd042a65c94c1f4e779af349a34bc50..d51e1e926145ea2d4a09517ccacbba1ed0e7b4e3 100644 --- a/test/cases/safety/signed shift right overflow.zig +++ b/test/cases/safety/signed shift right overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "right shift overflowed bits")) { std.process.exit(0); diff --git a/test/cases/safety/signed-unsigned vector cast.zig b/test/cases/safety/signed-unsigned vector cast.zig index 50be6b84f384e980ecd5d677e7d28a978f492254..d6b2377e34e90a1084b525d264fca46817517d14 100644 --- a/test/cases/safety/signed-unsigned vector cast.zig +++ b/test/cases/safety/signed-unsigned vector cast.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/slice by length sentinel mismatch on lhs.zig b/test/cases/safety/slice by length sentinel mismatch on lhs.zig index af92f90198e71e261206b0372121a489cbe2a7de..4dbeb2b0f86c41af6acf981de3eebc6958765490 100644 --- a/test/cases/safety/slice by length sentinel mismatch on lhs.zig +++ b/test/cases/safety/slice by length sentinel mismatch on lhs.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 1, found 3")) { std.process.exit(0); diff --git a/test/cases/safety/slice by length sentinel mismatch on rhs.zig b/test/cases/safety/slice by length sentinel mismatch on rhs.zig index f9a8730a99ee7d08f039e326fa4f33db2a2ed042..7bfaca25acc3946ff658ef9bc9a8ad30ac6c7357 100644 --- a/test/cases/safety/slice by length sentinel mismatch on rhs.zig +++ b/test/cases/safety/slice by length sentinel mismatch on rhs.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 1, found 0")) { std.process.exit(0); diff --git a/test/cases/safety/slice sentinel mismatch - floats.zig b/test/cases/safety/slice sentinel mismatch - floats.zig index 30e6b8a85cd0143f200bf4c368553e251f3fa41f..51d9b17b7500236ce68d33a7c59abd6c50d95ab8 100644 --- a/test/cases/safety/slice sentinel mismatch - floats.zig +++ b/test/cases/safety/slice sentinel mismatch - floats.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 1.2, found 4")) { std.process.exit(0); diff --git a/test/cases/safety/slice sentinel mismatch - optional pointers.zig b/test/cases/safety/slice sentinel mismatch - optional pointers.zig index c931aa31f1f75f054211c8ebf28d7bf9f2622540..34bd73f56c20981342bc8b5a968ec929c5dec1aa 100644 --- a/test/cases/safety/slice sentinel mismatch - optional pointers.zig +++ b/test/cases/safety/slice sentinel mismatch - optional pointers.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected null, found i32@10")) { std.process.exit(0); diff --git a/test/cases/safety/slice slice sentinel mismatch.zig b/test/cases/safety/slice slice sentinel mismatch.zig index 881edb5d8e1c7d9938e51770ecc260371348baba..a824ad6bb8f73c783a4f93afd4dac6e30adb03d0 100644 --- a/test/cases/safety/slice slice sentinel mismatch.zig +++ b/test/cases/safety/slice slice sentinel mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) { std.process.exit(0); diff --git a/test/cases/safety/slice start index greater than end index.zig b/test/cases/safety/slice start index greater than end index.zig index 9835a253266991c229cf3aacc27508edf251f1b5..a9d90f676d56cd472618575b38dd7b401d4854b5 100644 --- a/test/cases/safety/slice start index greater than end index.zig +++ b/test/cases/safety/slice start index greater than end index.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "start index 10 is larger than end index 1")) { std.process.exit(0); diff --git a/test/cases/safety/slice with sentinel out of bounds - runtime len.zig b/test/cases/safety/slice with sentinel out of bounds - runtime len.zig index b5851d7b1137859647cdb931d081285a7d90cb07..838b31ce083edae683649daaacc1c205f5ba9bc1 100644 --- a/test/cases/safety/slice with sentinel out of bounds - runtime len.zig +++ b/test/cases/safety/slice with sentinel out of bounds - runtime len.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 5, len 4")) { std.process.exit(0); diff --git a/test/cases/safety/slice with sentinel out of bounds.zig b/test/cases/safety/slice with sentinel out of bounds.zig index a3bcb49fc17cdf63ca71f931a91cdef87d120e41..1ef2e062626776cd957660bae5ada2bdd212e1d2 100644 --- a/test/cases/safety/slice with sentinel out of bounds.zig +++ b/test/cases/safety/slice with sentinel out of bounds.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 5, len 4")) { std.process.exit(0); diff --git a/test/cases/safety/slice_cast_change_len_0.zig b/test/cases/safety/slice_cast_change_len_0.zig index d85299e6936805bbefac2b326e254c755ebe8af9..9b9a40e93b5b15942fd6c88bdd5a5034b00f8555 100644 --- a/test/cases/safety/slice_cast_change_len_0.zig +++ b/test/cases/safety/slice_cast_change_len_0.zig @@ -13,7 +13,7 @@ pub fn main() void { std.process.exit(1); } -pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "slice length '3' does not divide exactly into destination elements")) { std.process.exit(0); } diff --git a/test/cases/safety/slice_cast_change_len_1.zig b/test/cases/safety/slice_cast_change_len_1.zig index 388a052085ac54b14cac21007559be05d9451156..57a7b6a7380e3cc31d1ac630285ca2beeb2acdb7 100644 --- a/test/cases/safety/slice_cast_change_len_1.zig +++ b/test/cases/safety/slice_cast_change_len_1.zig @@ -13,7 +13,7 @@ pub fn main() void { std.process.exit(1); } -pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "slice length '1' does not divide exactly into destination elements")) { std.process.exit(0); } diff --git a/test/cases/safety/slice_cast_change_len_2.zig b/test/cases/safety/slice_cast_change_len_2.zig index ff7a18b8f0963609be205939db699764e61eb10c..f6a29feec74092d824811f7b24b0ca80f445bf07 100644 --- a/test/cases/safety/slice_cast_change_len_2.zig +++ b/test/cases/safety/slice_cast_change_len_2.zig @@ -13,7 +13,7 @@ pub fn main() void { std.process.exit(1); } -pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "slice length '1' does not divide exactly into destination elements")) { std.process.exit(0); } diff --git a/test/cases/safety/slicing null C pointer - runtime len.zig b/test/cases/safety/slicing null C pointer - runtime len.zig index e2145fedb0a8db60774ca3b337db6419a549d3d1..8266a035b70fe3b9a618422da03407ad6219cef8 100644 --- a/test/cases/safety/slicing null C pointer - runtime len.zig +++ b/test/cases/safety/slicing null C pointer - runtime len.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to use null value")) { std.process.exit(0); diff --git a/test/cases/safety/slicing null C pointer.zig b/test/cases/safety/slicing null C pointer.zig index 6fc0281d471f19f1be6c64c5d00178ca5f83ceb5..2035361cb2a0af969d68407d325d62ec12ba3700 100644 --- a/test/cases/safety/slicing null C pointer.zig +++ b/test/cases/safety/slicing null C pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to use null value")) { std.process.exit(0); diff --git a/test/cases/safety/switch else on corrupt enum value - one prong.zig b/test/cases/safety/switch else on corrupt enum value - one prong.zig index 6bc20ef1007752779753bfa296812271219e5045..4babfb9133c4d41236275b2ccf0f9ff538a5f1f8 100644 --- a/test/cases/safety/switch else on corrupt enum value - one prong.zig +++ b/test/cases/safety/switch else on corrupt enum value - one prong.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/switch else on corrupt enum value - union.zig b/test/cases/safety/switch else on corrupt enum value - union.zig index afb7bfdcdcc20f7848d1e7fbb50e4f236de08f19..20a24a81ccbe9bcfe77c60ac72f7f2fa5f8d96f1 100644 --- a/test/cases/safety/switch else on corrupt enum value - union.zig +++ b/test/cases/safety/switch else on corrupt enum value - union.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/switch else on corrupt enum value.zig b/test/cases/safety/switch else on corrupt enum value.zig index 297cde40ea92fc6504103e4aa5b5f5bffcf0f641..6cab276eab07888a21426c149faf8650f7f213b3 100644 --- a/test/cases/safety/switch else on corrupt enum value.zig +++ b/test/cases/safety/switch else on corrupt enum value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/switch on corrupted enum value.zig b/test/cases/safety/switch on corrupted enum value.zig index 7e08b3c495b4fe32412d857006357e0a63060282..c7f6f86940089cf6ba2c866eaab8a1dbdbdd5ebd 100644 --- a/test/cases/safety/switch on corrupted enum value.zig +++ b/test/cases/safety/switch on corrupted enum value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/switch on corrupted union value.zig b/test/cases/safety/switch on corrupted union value.zig index d1c8d6a3f528c56d82980f3c15d775eec151e497..e2b21fd84a4bd402cdf8b0c260e06fc932a4c85c 100644 --- a/test/cases/safety/switch on corrupted union value.zig +++ b/test/cases/safety/switch on corrupted union value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/truncating vector cast.zig b/test/cases/safety/truncating vector cast.zig index 7805a5f92d005d0410f2ac32dcd97f6920e968c5..3531ac34b0a0ddbca4c02797376d6d74bd8d202e 100644 --- a/test/cases/safety/truncating vector cast.zig +++ b/test/cases/safety/truncating vector cast.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/unreachable.zig b/test/cases/safety/unreachable.zig index 8b394e6f4f40f9be400b4b734902ed6dfecfe09e..52c20506122d5d8a2db209a514f4a75458cc1344 100644 --- a/test/cases/safety/unreachable.zig +++ b/test/cases/safety/unreachable.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "reached unreachable code")) { std.process.exit(0); diff --git a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig index 5047550800272266659c6746d5fef0e3e9666bed..c326dfb691b47c7721699f1d049555c822abdb8f 100644 --- a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig +++ b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/unsigned shift left overflow.zig b/test/cases/safety/unsigned shift left overflow.zig index 37bb1b61ea70aedbfb03e99c04929e48566cbede..178e309126399fa4d53c757ef704ea754abfced5 100644 --- a/test/cases/safety/unsigned shift left overflow.zig +++ b/test/cases/safety/unsigned shift left overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "left shift overflowed bits")) { std.process.exit(0); diff --git a/test/cases/safety/unsigned shift right overflow.zig b/test/cases/safety/unsigned shift right overflow.zig index 2de5d7c714f0d7067bff6490ce2debab4ad9b901..5ebe44bf49a8ec967de17bf7784117dc042bdbf0 100644 --- a/test/cases/safety/unsigned shift right overflow.zig +++ b/test/cases/safety/unsigned shift right overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "right shift overflowed bits")) { std.process.exit(0); diff --git a/test/cases/safety/unsigned-signed vector cast.zig b/test/cases/safety/unsigned-signed vector cast.zig index a482701b96e2d5af1b702bf2ae7e78f6aa24f560..f603999d8b267a6dfbf57f07acda968b5ab443ab 100644 --- a/test/cases/safety/unsigned-signed vector cast.zig +++ b/test/cases/safety/unsigned-signed vector cast.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/unwrap error switch.zig b/test/cases/safety/unwrap error switch.zig index e31a34593d6f9c10cc488254cc7dd970211466ce..57f1f3d7b7bfdbc22489f644101b865f5917df68 100644 --- a/test/cases/safety/unwrap error switch.zig +++ b/test/cases/safety/unwrap error switch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to unwrap error: Whatever")) { std.process.exit(0); diff --git a/test/cases/safety/unwrap error.zig b/test/cases/safety/unwrap error.zig index aae990b6444e35a3ef063e88ba146172476c5c55..ef79c5cce4d1abf76b51a74ce619cfb7b46776fc 100644 --- a/test/cases/safety/unwrap error.zig +++ b/test/cases/safety/unwrap error.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to unwrap error: Whatever")) { std.process.exit(0); diff --git a/test/cases/safety/value does not fit in shortening cast - u0.zig b/test/cases/safety/value does not fit in shortening cast - u0.zig index 0b12aed075041047081c79b9d0e6263819e79241..f8aa6ebb119cca1afa146045ee95220deb25f42b 100644 --- a/test/cases/safety/value does not fit in shortening cast - u0.zig +++ b/test/cases/safety/value does not fit in shortening cast - u0.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/value does not fit in shortening cast.zig b/test/cases/safety/value does not fit in shortening cast.zig index ff5144e3e7e5e7c6ffa8fe425bd4619c2bf4b1ea..ea74f8739b977842d5ba08f436af3fc99c256014 100644 --- a/test/cases/safety/value does not fit in shortening cast.zig +++ b/test/cases/safety/value does not fit in shortening cast.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/vector integer addition overflow.zig b/test/cases/safety/vector integer addition overflow.zig index 5f60d9c2f2cf2c30c5aee92fdb58b573e436c9a5..4b34248af58f989af47a76f5c9f4be144fc395d9 100644 --- a/test/cases/safety/vector integer addition overflow.zig +++ b/test/cases/safety/vector integer addition overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/vector integer multiplication overflow.zig b/test/cases/safety/vector integer multiplication overflow.zig index 0a7573e508b0a6683d9fa5ede52465a0d0f94761..2d4183d316761fc32096f1fc9146535d36fe4f28 100644 --- a/test/cases/safety/vector integer multiplication overflow.zig +++ b/test/cases/safety/vector integer multiplication overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/vector integer negation overflow.zig b/test/cases/safety/vector integer negation overflow.zig index 11dcfda430ba0eb484f485bc8ab039b79084a491..b06dc437541b3d703b7c4bb715aabb5760589586 100644 --- a/test/cases/safety/vector integer negation overflow.zig +++ b/test/cases/safety/vector integer negation overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/vector integer subtraction overflow.zig b/test/cases/safety/vector integer subtraction overflow.zig index 5de596085416c6e191f3a029d2ab855cbd967dc7..a6db1e5e85767d3aa2b56c2fe365b2be16fb1d9c 100644 --- a/test/cases/safety/vector integer subtraction overflow.zig +++ b/test/cases/safety/vector integer subtraction overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/zero casted to error.zig b/test/cases/safety/zero casted to error.zig index 63be84677164a494a339ad2e56bab8b07693e629..5e379643a8a758cedea138e75e11b107acb9ebc0 100644 --- a/test/cases/safety/zero casted to error.zig +++ b/test/cases/safety/zero casted to error.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid error code")) { std.process.exit(0); diff --git a/test/cases/tail_call_noreturn.zig b/test/cases/tail_call_noreturn.zig index 5cd716dd303e57453e5463a7ff9063b87456304a..875251e3f74a2a01aaa10558df8ad596ac6e8725 100644 --- a/test/cases/tail_call_noreturn.zig +++ b/test/cases/tail_call_noreturn.zig @@ -1,9 +1,9 @@ const std = @import("std"); const builtin = std.builtin; -pub fn foo(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn { +pub fn foo(message: []const u8, stack_trace: ?*std.debug.StackTrace) noreturn { @call(.always_tail, bar, .{ message, stack_trace }); } -pub fn bar(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn { +pub fn bar(message: []const u8, stack_trace: ?*std.debug.StackTrace) noreturn { _ = message; _ = stack_trace; std.process.exit(0); diff --git a/test/stack_traces.zig b/test/stack_traces.zig index d0f1acc08b281736b81cfb23bd692c75442c09fa..ec3102975edc3378c92658bd1ff90f9b8ff37f4f 100644 --- a/test/stack_traces.zig +++ b/test/stack_traces.zig @@ -118,13 +118,13 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext) void { \\ var stack_trace_buf: [8]usize = undefined; \\ dumpIt(&captureIt(&stack_trace_buf)); \\} - \\fn captureIt(buf: []usize) std.builtin.StackTrace { + \\fn captureIt(buf: []usize) std.debug.StackTrace { \\ return captureItInner(buf); \\} - \\fn dumpIt(st: *const std.builtin.StackTrace) void { + \\fn dumpIt(st: *const std.debug.StackTrace) void { \\ std.debug.dumpStackTrace(st); \\} - \\fn captureItInner(buf: []usize) std.builtin.StackTrace { + \\fn captureItInner(buf: []usize) std.debug.StackTrace { \\ return std.debug.captureCurrentStackTrace(.{}, buf); \\} \\const std = @import("std"); @@ -159,13 +159,13 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext) void { \\ var stack_trace_buf: [8]usize = undefined; \\ dumpIt(&captureIt(&stack_trace_buf)); \\} - \\fn captureIt(buf: []usize) std.builtin.StackTrace { + \\fn captureIt(buf: []usize) std.debug.StackTrace { \\ return captureItInner(buf); \\} - \\fn dumpIt(st: *const std.builtin.StackTrace) void { + \\fn dumpIt(st: *const std.debug.StackTrace) void { \\ std.debug.dumpStackTrace(st); \\} - \\fn captureItInner(buf: []usize) std.builtin.StackTrace { + \\fn captureItInner(buf: []usize) std.debug.StackTrace { \\ return std.debug.captureCurrentStackTrace(.{}, buf); \\} \\const std = @import("std"); @@ -188,13 +188,13 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext) void { \\fn threadMain(stack_trace_buf: []usize) void { \\ dumpIt(&captureIt(stack_trace_buf)); \\} - \\fn captureIt(buf: []usize) std.builtin.StackTrace { + \\fn captureIt(buf: []usize) std.debug.StackTrace { \\ return captureItInner(buf); \\} - \\fn dumpIt(st: *const std.builtin.StackTrace) void { + \\fn dumpIt(st: *const std.debug.StackTrace) void { \\ std.debug.dumpStackTrace(st); \\} - \\fn captureItInner(buf: []usize) std.builtin.StackTrace { + \\fn captureItInner(buf: []usize) std.debug.StackTrace { \\ return std.debug.captureCurrentStackTrace(.{}, buf); \\} \\const std = @import("std"); diff --git a/test/standalone/compile_asm/main.zig b/test/standalone/compile_asm/main.zig index 1e6c93e562dee9f1d7eab41b4214241cfc4cc754..a3b11b9da974d71aa022fc57a375f2a8ef90004a 100644 --- a/test/standalone/compile_asm/main.zig +++ b/test/standalone/compile_asm/main.zig @@ -4,7 +4,7 @@ export fn main(r0: u32, r1: u32, atags: u32) callconv(.c) noreturn { _ = atags; unreachable; // never gets run so it doesn't matter } -pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").debug.StackTrace, _: ?usize) noreturn { _ = msg; _ = error_return_trace; while (true) {} diff --git a/test/standalone/issue_339/test.zig b/test/standalone/issue_339/test.zig index e28839209c1988a68fb46c269a32d5d0b311cfd5..445385d16c78d0bc7ac9a075d004c85f17b56bc8 100644 --- a/test/standalone/issue_339/test.zig +++ b/test/standalone/issue_339/test.zig @@ -1,4 +1,4 @@ -const StackTrace = @import("std").builtin.StackTrace; +const StackTrace = @import("std").debug.StackTrace; pub fn panic(msg: []const u8, stack_trace: ?*StackTrace, _: ?usize) noreturn { _ = msg; _ = stack_trace; diff --git a/test/tests.zig b/test/tests.zig index 9cb7a879b251fd4c224dc141f9df7327faf03789..97f99cffed5c95a48042e8426a3d7bac8a253b09 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2200,7 +2200,7 @@ pub fn addCliTests(b: *std.Build) *Step { \\ return num * num; \\} \\extern fn zig_panic() noreturn; - \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace, _: ?usize) noreturn { + \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").debug.StackTrace, _: ?usize) noreturn { \\ _ = msg; \\ _ = error_return_trace; \\ zig_panic(); -- 2.54.0 From 6bf583c4baf6b33166176f03e7f570bbd4607a8b Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Wed, 8 Apr 2026 17:18:16 -0700 Subject: [PATCH 11/29] Further separation of stack trace and error return trace --- lib/std/Build/Step.zig | 2 +- lib/std/debug.zig | 32 ++++++++++++++++++-------------- lib/std/heap/debug_allocator.zig | 4 ++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index 5d86a0d018d636424ae252c2068ea82ac7cde723..ae7ea66974d52192d2e7a83d55c598c3548cc35d 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -328,7 +328,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T { /// For debugging purposes, prints identifying information about this Step. pub fn dump(step: *Step, t: Io.Terminal) void { const w = t.writer; - if (step.debug_stack_trace.instruction_addresses.len > 0) { + if (step.debug_stack_trace.return_addresses.len > 0) { w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {}; std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {}; } else { diff --git a/lib/std/debug.zig b/lib/std/debug.zig index c10cdf949ec5c1d893e63447c112055f7e55964b..cf5bddc2be534d34731342c2a3df1283913cd90c 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -610,7 +610,7 @@ fn waitForOtherThreadToFinishPanicking() void { /// therefore must be kept in sync with the compiler implementation. pub const StackTrace = struct { index: usize, - instruction_addresses: []usize, + return_addresses: []usize, }; pub const StackUnwindOptions = struct { @@ -634,7 +634,7 @@ pub const StackUnwindOptions = struct { pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace { const empty_trace: StackTrace = .{ .index = 0, - .instruction_addresses = &.{}, + .return_addresses = &.{}, }; if (!std.options.allow_stack_tracing) return empty_trace; var it: StackIterator = .init(options.context); @@ -669,7 +669,7 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: }; return .{ .index = index, - .instruction_addresses = addr_buf[0..index], + .return_addresses = addr_buf[0..index], }; } /// Write the current stack trace to `writer`, annotated with source locations. @@ -791,16 +791,23 @@ pub const FormatStackTrace = struct { }; /// Write a previously captured error return trace to `writer`, annotated with source locations. -pub fn writeErrorReturnTrace(st: *const std.builtin.ErrorReturnTrace, t: Io.Terminal) Writer.Error!void { - try writeTrace(st, t, false); +pub fn writeErrorReturnTrace(et: *const std.builtin.ErrorReturnTrace, t: Io.Terminal) Writer.Error!void { + // Fetch `et.index` straight away. Aside from avoiding redundant loads, this prevents issues if + // errors are encountered while writing the stack trace. + try writeTrace(et.instruction_addresses, et.index, t, false); } /// Write a previously captured stack trace to `writer`, annotated with source locations. -pub fn writeStackTrace(et: *const StackTrace, t: Io.Terminal) Writer.Error!void { - try writeTrace(et, t, true); +pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void { + try writeTrace(st.return_addresses, st.index, t, true); } -fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writer.Error!void { +fn writeTrace( + addresses: []const usize, + n_frames: usize, + t: Io.Terminal, + resolve_inline_callers: bool, +) Writer.Error!void { const writer = t.writer; if (!std.options.allow_stack_tracing) { t.setColor(.dim) catch {}; @@ -809,9 +816,6 @@ fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writ return; } - // Fetch `trace.index` straight away. Aside from avoiding redundant loads, this prevents issues if - // `trace` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. - const n_frames = trace.index; if (n_frames == 0) return writer.writeAll("(empty stack trace)\n"); const di = getSelfDebugInfo() catch |err| switch (err) { error.UnsupportedTarget => { @@ -822,8 +826,8 @@ fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writ }, }; const io = std.Options.debug_io; - const captured_frames = @min(n_frames, trace.instruction_addresses.len); - for (trace.instruction_addresses[0..captured_frames]) |ret_addr| { + const captured_frames = @min(n_frames, addresses.len); + for (addresses[0..captured_frames]) |ret_addr| { // `ret_addr` is the return address, which is *after* the function call. // Subtract 1 to get an address *in* the function call for a better source location. try printSourceAtAddress(io, di, t, .{ @@ -1729,7 +1733,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize const frames = mem.sliceTo(frames_array_mutable[0..], 0); const stack_trace: StackTrace = .{ .index = frames.len, - .instruction_addresses = frames, + .return_addresses = frames, }; writeStackTrace(&stack_trace, stderr) catch return; } diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index f49fc9493d408c0ea52eaae556a3ec3cc1b04b52..4e9c8e6faec479846b57407871f93aa1106f26d7 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -237,7 +237,7 @@ pub fn DebugAllocator(comptime config: Config) type { len += 1; } return .{ - .instruction_addresses = stack_addresses, + .return_addresses = stack_addresses, .index = len, }; } @@ -339,7 +339,7 @@ pub fn DebugAllocator(comptime config: Config) type { len += 1; } return .{ - .instruction_addresses = stack_addresses, + .return_addresses = stack_addresses, .index = len, }; } -- 2.54.0 From c2cbb944ba377db141e3dc5a890d955932accea2 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Thu, 9 Apr 2026 15:43:05 -0700 Subject: [PATCH 12/29] Further improvements to stack trace type --- lib/std/debug.zig | 89 ++++++++++++++++++++++---------- lib/std/heap/debug_allocator.zig | 10 ++-- 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index cf5bddc2be534d34731342c2a3df1283913cd90c..7297352f0aae4b48efb553c247ad1b7f971b0451 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -609,8 +609,33 @@ fn waitForOtherThreadToFinishPanicking() void { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const StackTrace = struct { - index: usize, + /// Each element is the "return address" of a function call, meaning the instruction address + /// which control flow will return to when the function returns. + /// + /// The first slice element corresponds to the innermost stack frame, and the last element to + /// the outermost. + /// + /// Inlined function calls do not have meaningful return addresses and are therefore not + /// included in this slice. Instead, when printing the stack trace, the source locations of + /// inline calls should be read from debug information and the corresponding "inline frames" + /// printed in the appropriate locations. return_addresses: []usize, + /// Indicates whether any stack frames were omitted from `return_addresses`. + skipped: SkippedAddresses, + +}; + +/// Indicates how many addresses were skipped in a trace. +pub const SkippedAddresses = enum(usize) { + /// No addresses were omitted: `return_addresses` contains all stack frames, including the + /// outermost. + none = 0, + /// It is not known whether any frames were omitted. + unknown = std.math.maxInt(usize), + /// The full stack trace was available, but some frames are not included in + /// `return_addresses` due to buffer size limitations. The enum value is the exact number of + /// addresses which were omitted. + _, }; pub const StackUnwindOptions = struct { @@ -633,8 +658,8 @@ pub const StackUnwindOptions = struct { /// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it. pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace { const empty_trace: StackTrace = .{ - .index = 0, .return_addresses = &.{}, + .skipped = .none, }; if (!std.options.allow_stack_tracing) return empty_trace; var it: StackIterator = .init(options.context); @@ -646,17 +671,17 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: var total_frames: usize = 0; var index: usize = 0; var wait_for = options.first_address; - // Ideally, we would iterate the whole stack so that the `index` in the returned trace was + // Ideally, we would iterate the whole stack so that the `index - min(buf.len, index)` would be // indicative of how many frames were skipped. However, this has a significant runtime cost // in some cases, so at least for now, we don't do that. - while (index < addr_buf.len) switch (it.next(io)) { - .switch_to_fp => if (!it.stratOk(options.allow_unsafe_unwind)) break, - .end => break, + const skipped: SkippedAddresses = while (index < addr_buf.len) switch (it.next(io)) { + .switch_to_fp => if (!it.stratOk(options.allow_unsafe_unwind)) break .unknown, + .end => break .none, .frame => |ret_addr| { if (total_frames > 10_000) { // Limit the number of frames in case of (e.g.) broken debug information which is // getting unwinding stuck in a loop. - break; + break .unknown; } total_frames += 1; if (wait_for) |target| { @@ -666,10 +691,10 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: addr_buf[index] = ret_addr; index += 1; }, - }; + } else .unknown; return .{ - .index = index, .return_addresses = addr_buf[0..index], + .skipped = skipped, }; } /// Write the current stack trace to `writer`, annotated with source locations. @@ -792,19 +817,21 @@ pub const FormatStackTrace = struct { /// Write a previously captured error return trace to `writer`, annotated with source locations. pub fn writeErrorReturnTrace(et: *const std.builtin.ErrorReturnTrace, t: Io.Terminal) Writer.Error!void { - // Fetch `et.index` straight away. Aside from avoiding redundant loads, this prevents issues if - // errors are encountered while writing the stack trace. - try writeTrace(et.instruction_addresses, et.index, t, false); + // We take the slice by value, preventing the length from being mutated if an error occurs while + // writing the stack trace. + const len = @min(et.instruction_addresses.len, et.index); + const skipped = et.index - len; + try writeTrace(et.instruction_addresses[0..len], @enumFromInt(skipped), t, false); } /// Write a previously captured stack trace to `writer`, annotated with source locations. pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void { - try writeTrace(st.return_addresses, st.index, t, true); + try writeTrace(st.return_addresses, st.skipped, t, true); } fn writeTrace( addresses: []const usize, - n_frames: usize, + skipped: SkippedAddresses, t: Io.Terminal, resolve_inline_callers: bool, ) Writer.Error!void { @@ -816,7 +843,7 @@ fn writeTrace( return; } - if (n_frames == 0) return writer.writeAll("(empty stack trace)\n"); + if (addresses.len == 0) return writer.writeAll("(empty stack trace)\n"); const di = getSelfDebugInfo() catch |err| switch (err) { error.UnsupportedTarget => { t.setColor(.dim) catch {}; @@ -826,19 +853,26 @@ fn writeTrace( }, }; const io = std.Options.debug_io; - const captured_frames = @min(n_frames, addresses.len); - for (addresses[0..captured_frames]) |ret_addr| { - // `ret_addr` is the return address, which is *after* the function call. + for (addresses) |addr| { + // `addr` is the return address, which is *after* the function call. // Subtract 1 to get an address *in* the function call for a better source location. try printSourceAtAddress(io, di, t, .{ - .address = ret_addr -| StackIterator.ra_call_offset, + .address = addr -| StackIterator.ra_call_offset, .resolve_inline_callers = resolve_inline_callers, }); } - if (n_frames > captured_frames) { - t.setColor(.bold) catch {}; - try writer.print("({d} additional stack frames skipped...)\n", .{n_frames - captured_frames}); - t.setColor(.reset) catch {}; + switch (skipped) { + .none => {}, + .unknown => { + t.setColor(.bold) catch {}; + try writer.writeAll("(additional stack frames may have been skipped...)\n"); + t.setColor(.reset) catch {}; + }, + else => |n| { + t.setColor(.bold) catch {}; + try writer.print("({d} additional stack frames skipped due to buffer size limitations...)\n", .{n}); + t.setColor(.reset) catch {}; + }, } } /// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors. @@ -1712,8 +1746,8 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize t.notes[t.index] = note; const addrs = &t.addrs[t.index]; const st = captureCurrentStackTrace(.{ .first_address = addr }, addrs); - if (st.index < addrs.len) { - @memset(addrs[st.index..], 0); // zero unused frames to indicate end of trace + if (st.return_addresses.len < addrs.len) { + @memset(addrs[st.return_addresses.len..], 0); // zero unused frames to indicate end of trace } } // Keep counting even if the end is reached so that the @@ -1731,9 +1765,10 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize stderr.writer.print("{s}:\n", .{t.notes[i]}) catch return; var frames_array_mutable = frames_array; const frames = mem.sliceTo(frames_array_mutable[0..], 0); + const len = @min(t.index, frames.len); const stack_trace: StackTrace = .{ - .index = frames.len, - .return_addresses = frames, + .return_addresses = frames[0..len], + .skipped = if (len < frames.len) .none else .unknown, }; writeStackTrace(&stack_trace, stderr) catch return; } diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index 4e9c8e6faec479846b57407871f93aa1106f26d7..30d0bcee0bb96ee8b05af525970dbf78d54455d1 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -237,8 +237,8 @@ pub fn DebugAllocator(comptime config: Config) type { len += 1; } return .{ - .return_addresses = stack_addresses, - .index = len, + .return_addresses = stack_addresses[0..len], + .skipped = if (len < stack_addresses.len) .none else .unknown, }; } @@ -339,8 +339,8 @@ pub fn DebugAllocator(comptime config: Config) type { len += 1; } return .{ - .return_addresses = stack_addresses, - .index = len, + .return_addresses = stack_addresses[0..len], + .skipped = if (len < stack_addresses.len) .none else .unknown, }; } @@ -508,7 +508,7 @@ pub fn DebugAllocator(comptime config: Config) type { fn collectStackTrace(first_trace_addr: usize, addr_buf: *[stack_n]usize) void { const st = std.debug.captureCurrentStackTrace(.{ .first_address = first_trace_addr }, addr_buf); - @memset(addr_buf[@min(st.index, addr_buf.len)..], 0); + @memset(addr_buf[@min(st.return_addresses.len, addr_buf.len)..], 0); } fn reportDoubleFree(ret_addr: usize, alloc_stack_trace: StackTrace, free_stack_trace: StackTrace) void { -- 2.54.0 From 492efd4c06541ca8add4147dfc2d766c1ba54693 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Thu, 9 Apr 2026 16:33:15 -0700 Subject: [PATCH 13/29] Adds support for running stack and error trace tests through Wine Also fixes minor bug that was preventing existing tests from passing on 32 bit Windows --- lib/std/debug/SelfInfo/Windows.zig | 2 +- test/tests.zig | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index ccf7263461284931eebd6f3646b684ae3d7328c1..710b13c1228ee3d60b097243c48fbb58f0519055 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -368,7 +368,7 @@ const Module = struct { /// iteration, e.g. because they only wanted the topmost call. inline_sites: std.ArrayList(*align(1) const std.pdb.InlineSiteSym), }, - dwarf: struct { addr: usize }, + dwarf: struct { addr: u64 }, none: void, fn init(di: *DebugInfo, vaddr: usize) Error!Symbols { diff --git a/test/tests.zig b/test/tests.zig index 97f99cffed5c95a48042e8426a3d7bac8a253b09..a4c0bbcf6e1f1973a7af897e135cbb100b90db0e 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2016,10 +2016,24 @@ fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Bu }, else => return only_native, }; - return b.graph.arena.dupe(std.Build.ResolvedTarget, &.{ - b.graph.host, - b.resolveTargetQuery(.{ .cpu_arch = arch32, .os_tag = host.os.tag }), - }) catch @panic("OOM"); + var targets = std.ArrayList(std.Build.ResolvedTarget).initCapacity(b.graph.arena, 2) + catch @panic("OOM"); + targets.appendAssumeCapacity(b.graph.host); + targets.appendAssumeCapacity(b.resolveTargetQuery(.{ + .cpu_arch = arch32, + .os_tag = host.os.tag, + })); + if (b.enable_wine and b.graph.host.result.os.tag != .windows) { + targets.append(b.graph.arena, b.resolveTargetQuery(.{ + .cpu_arch = host.cpu.arch, + .os_tag = .windows, + })) catch @panic("OOM"); + targets.append(b.graph.arena, b.resolveTargetQuery(.{ + .cpu_arch = arch32, + .os_tag = .windows, + })) catch @panic("OOM"); + } + return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM"); } pub fn addStackTraceTests( -- 2.54.0 From dcdb562c154c950ed06a23a3a267fa8cdc172dda Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Thu, 9 Apr 2026 17:27:12 -0700 Subject: [PATCH 14/29] Adds support for running the trace tests through darling, fixes compilation errors in MachO due to interface change --- lib/std/debug/SelfInfo/MachO.zig | 39 ++++++++++++++++++++++---------- test/tests.zig | 6 +++++ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index 6b184fec7a16066397c6961b7cc55492ef4fb26e..d6523d924d1cef6daf6bf21466d263119441e249 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -22,12 +22,26 @@ pub fn deinit(si: *SelfInfo, io: Io) void { si.modules.deinit(gpa); } -pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol { +pub const SymbolIterator = struct { + curr: ?Error!std.debug.Symbol, + + pub fn deinit(self: *SymbolIterator, _: Io) void { + self.* = undefined; + } + + pub fn next(self: *SymbolIterator) ?Error!std.debug.Symbol { + const result = self.curr; + self.curr = null; + return result; + } +}; + +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { const gpa = std.debug.getDebugInfoAllocator(); - const module = try si.findModule(gpa, io, address); + const module = si.findModule(gpa, io, address) catch |err| return .{ .curr = err }; defer si.mutex.unlock(io); - const file = try module.getFile(gpa, io); + const file = module.getFile(gpa, io) catch |err| return .{ .curr = err }; // This is not necessarily the same as the vmaddr_slide that dyld would report. This is // because the segments in the file on disk might differ from the ones in memory. Normally @@ -43,25 +57,26 @@ pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol { const ofile_dwarf, const ofile_vaddr = file.getDwarfForAddress(gpa, io, vaddr) catch { // Return at least the symbol name if available. - return .{ - .name = try file.lookupSymbolName(vaddr), + return .{ .curr = .{ + .name = file.lookupSymbolName(vaddr) catch |err| return .{ .curr = err }, .compile_unit_name = null, .source_location = null, - }; + } }; }; const compile_unit = ofile_dwarf.findCompileUnit(native_endian, ofile_vaddr) catch { // Return at least the symbol name if available. - return .{ - .name = try file.lookupSymbolName(vaddr), + return .{ .curr = .{ + .name = file.lookupSymbolName(vaddr) catch |err| return .{ .curr = err }, .compile_unit_name = null, .source_location = null, - }; + } }; }; - return .{ + return .{ .curr = .{ .name = ofile_dwarf.getSymbolName(ofile_vaddr) orelse - try file.lookupSymbolName(vaddr), + file.lookupSymbolName(vaddr) catch |err| + return .{ .curr = err }, .compile_unit_name = compile_unit.die.getAttrString( ofile_dwarf, native_endian, @@ -77,7 +92,7 @@ pub fn getSymbol(si: *SelfInfo, io: Io, address: usize) Error!std.debug.Symbol { compile_unit, ofile_vaddr, ) catch null, - }; + } }; } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { _ = si; diff --git a/test/tests.zig b/test/tests.zig index a4c0bbcf6e1f1973a7af897e135cbb100b90db0e..a3667385fad48bea41a42005d427ba443d61ccda 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2033,6 +2033,12 @@ fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Bu .os_tag = .windows, })) catch @panic("OOM"); } + if (b.enable_darling and b.graph.host.result.os.tag != .macos) { + targets.append(b.graph.arena, b.resolveTargetQuery(.{ + .cpu_arch = host.cpu.arch, + .os_tag = .macos, + })) catch @panic("OOM"); + } return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM"); } -- 2.54.0 From 825ba5a350cab21fff5531d645d18cd9d2facd8f Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Thu, 9 Apr 2026 19:01:20 -0700 Subject: [PATCH 15/29] Adds tests for inline traces --- test/error_traces.zig | 103 ++++++++++---------- test/src/ErrorTrace.zig | 3 - test/src/convert-stack-trace.zig | 15 ++- test/stack_traces.zig | 118 ++++++++++++++++++++++- test/tests.zig | 159 ++++++++++++++++++++++--------- 5 files changed, 292 insertions(+), 106 deletions(-) diff --git a/test/error_traces.zig b/test/error_traces.zig index 6c9cdc7166091e2980d9fc6bb632588ec6ac62ba..d033cf741b0dcdf2e079a04b8e23d3fa8b12b274 100644 --- a/test/error_traces.zig +++ b/test/error_traces.zig @@ -1,4 +1,6 @@ -pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext) void { +const std = @import("std"); + +pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.Os.Tag) void { cases.addCase(.{ .name = "return", .source = @@ -450,53 +452,54 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext) void { }, }); - cases.addCase(.{ - .name = "trace through inline call", - .source = - \\pub fn main() !void { - \\ try foo(); - \\} - \\inline fn foo() !void { - \\ try bar(); - \\} - \\fn bar() !void { - \\ return error.ThisIsSoSad; - \\} - , - .expect_error = "ThisIsSoSad", - .expect_trace = - \\source.zig:8:5: [address] in bar - \\ return error.ThisIsSoSad; - \\ ^ - \\source.zig:5:5: [address] in foo - \\ try bar(); - \\ ^ - \\source.zig:2:5: [address] in main - \\ try foo(); - \\ ^ - , - .disable_trace_optimized = &.{ - .{ .x86_64, .freebsd }, - .{ .x86_64, .netbsd }, - .{ .x86_64, .linux }, - .{ .x86, .linux }, - .{ .aarch64, .freebsd }, - .{ .aarch64, .netbsd }, - .{ .aarch64, .linux }, - .{ .loongarch64, .linux }, - .{ .powerpc64le, .linux }, - .{ .riscv64, .linux }, - .{ .s390x, .linux }, - .{ .x86_64, .openbsd }, - .{ .x86_64, .windows }, - .{ .x86, .windows }, - .{ .x86_64, .macos }, - .{ .aarch64, .macos }, - }, - // TODO: the standard library has a bug in PDB parsing where given an address corresponding - // to an inline call, the frame we see will be for the *caller*, not the *callee*. As a - // result this test gives bogus results on Windows right now. - // This is a part of https://codeberg.org/ziglang/zig/issues/30847. - .disable_trace_pdb = true, - }); + // TODO: the standard library has a bug in PDB parsing where given an address corresponding + // to an inline call, the frame we see will be for the *caller*, not the *callee*. As a + // result this test gives bogus results on Windows right now. + // This is a part of https://codeberg.org/ziglang/zig/issues/30847. + if (os != .windows) { + cases.addCase(.{ + .name = "trace through inline call", + .source = + \\pub fn main() !void { + \\ try foo(); + \\} + \\inline fn foo() !void { + \\ try bar(); + \\} + \\fn bar() !void { + \\ return error.ThisIsSoSad; + \\} + , + .expect_error = "ThisIsSoSad", + .expect_trace = + \\source.zig:8:5: [address] in bar + \\ return error.ThisIsSoSad; + \\ ^ + \\source.zig:5:5: [address] in foo + \\ try bar(); + \\ ^ + \\source.zig:2:5: [address] in main + \\ try foo(); + \\ ^ + , + .disable_trace_optimized = &.{ + .{ .x86_64, .freebsd }, + .{ .x86_64, .netbsd }, + .{ .x86_64, .linux }, + .{ .x86, .linux }, + .{ .aarch64, .freebsd }, + .{ .aarch64, .netbsd }, + .{ .aarch64, .linux }, + .{ .loongarch64, .linux }, + .{ .powerpc64le, .linux }, + .{ .riscv64, .linux }, + .{ .s390x, .linux }, + .{ .x86_64, .openbsd }, + .{ .x86_64, .windows }, + .{ .x86, .windows }, + .{ .x86_64, .macos }, + .{ .aarch64, .macos }, + }, + }); + } } diff --git a/test/src/ErrorTrace.zig b/test/src/ErrorTrace.zig index ac93f3a57d12c254ac4a98dd41e6828efad59d7f..f6f80f8b138d2f7a663b4fe1d5d8d58bc8ef43de 100644 --- a/test/src/ErrorTrace.zig +++ b/test/src/ErrorTrace.zig @@ -17,8 +17,6 @@ pub const Case = struct { /// LLVM ReleaseSmall builds always have the trace disabled regardless of this field, because it /// seems that LLVM is particularly good at optimizing traces away in those. disable_trace_optimized: []const DisableConfig = &.{}, - /// If `true` then we will not test the error trace on Windows due to bugs in PDB handling. - disable_trace_pdb: bool = false, pub const DisableConfig = struct { std.Target.Cpu.Arch, std.Target.Os.Tag }; pub const Backend = enum { llvm, selfhosted }; @@ -62,7 +60,6 @@ fn addCaseConfig( const b = self.b; const error_tracing: bool = tracing: { - if (target.result.os.tag == .windows and case.disable_trace_pdb) break :tracing false; if (optimize == .Debug) break :tracing true; if (backend != .llvm) break :tracing true; if (optimize == .ReleaseSmall) break :tracing false; diff --git a/test/src/convert-stack-trace.zig b/test/src/convert-stack-trace.zig index 272c43e31171494f8df667690e4a725c404bb9b7..259e34ae5932ed6e2f9061cc459d4a0a556f09b5 100644 --- a/test/src/convert-stack-trace.zig +++ b/test/src/convert-stack-trace.zig @@ -52,20 +52,19 @@ pub fn main(init: std.process.Init) !void { continue; } - const src_col_end = std.mem.indexOf(u8, in_line, ": 0x") orelse { + // If both the row and column are present, this it he column end. Otherwise it's the line end. + const src_pos_end = std.mem.indexOf(u8, in_line, ": 0x") orelse { try w.writeAll(in_line); continue; }; - const src_row_end = std.mem.lastIndexOfScalar(u8, in_line[0..src_col_end], ':') orelse { - try w.writeAll(in_line); - continue; - }; - const src_path_end = std.mem.lastIndexOfScalar(u8, in_line[0..src_row_end], ':') orelse { + const src_row_or_path_end = std.mem.lastIndexOfScalar(u8, in_line[0..src_pos_end], ':') orelse { try w.writeAll(in_line); continue; }; + const src_path_end = std.mem.lastIndexOfScalar(u8, in_line[0..src_row_or_path_end], ':') + orelse src_row_or_path_end; - const addr_end = std.mem.indexOfPos(u8, in_line, src_col_end, " in ") orelse { + const addr_end = std.mem.indexOfPos(u8, in_line, src_pos_end, " in ") orelse { try w.writeAll(in_line); continue; }; @@ -91,7 +90,7 @@ pub fn main(init: std.process.Init) !void { const src_path = in_line[0..src_path_end]; const basename_start = if (std.mem.lastIndexOfAny(u8, src_path, "/\\")) |i| i + 1 else 0; const symbol_start = addr_end + " in ".len; - try w.writeAll(in_line[basename_start..src_col_end]); + try w.writeAll(in_line[basename_start..src_pos_end]); try w.writeAll(": [address] in "); try w.writeAll(in_line[symbol_start..symbol_end]); try w.writeByte('\n'); diff --git a/test/stack_traces.zig b/test/stack_traces.zig index ec3102975edc3378c92658bd1ff90f9b8ff37f4f..3b5ed8d54173d1897fa77827bacc859e1a5c392a 100644 --- a/test/stack_traces.zig +++ b/test/stack_traces.zig @@ -1,4 +1,6 @@ -pub fn addCases(cases: *@import("tests.zig").StackTracesContext) void { +const std = @import("std"); + +pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.Os.Tag) void { cases.addCase(.{ .name = "simple panic", .source = @@ -221,4 +223,118 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext) void { \\ , }); + + cases.addCase(.{ + .name = "simple inline panic", + .source = + \\pub fn main() void { + \\ foo(); + \\} + \\inline fn foo() void { + \\ @panic("oh no"); + \\} + \\ + , + .unwind = .any, + .expect_panic = true, + .expect = switch (os) { + // We use the information present in PDBs to resolve inlines when dumping stack traces + // on Windows. Column numbers are missing as LLVM doesn't emit column info in the PDBs + // for inline functions. + .windows => + \\panic: oh no + \\source.zig:5: [address] in foo + \\ @panic("oh no"); + \\ + \\source.zig:2:8: [address] in main + \\ foo(); + \\ ^ + \\ + , + // We don't yet resolve inlines on other platforms. + else => + \\panic: oh no + \\source.zig:5:5: [address] in foo + \\ @panic("oh no"); + \\ ^ + , + }, + .expect_strip = switch (os) { + .windows => + \\panic: oh no + \\???:?:?: [address] in source.foo + \\???:?:?: [address] in source.main + \\ + , + else => + \\panic: oh no + \\???:?:?: [address] in source.foo + \\ + , + }, + }); + + // Make sure all inline calls are resolved and in the right order! + cases.addCase(.{ + .name = "nested inline panic", + .source = + \\pub fn main() void { + \\ foo(); + \\} + \\inline fn foo() void { + \\ bar(); + \\} + \\inline fn bar() void { + \\ baz(); + \\} + \\inline fn baz() void { + \\ @panic("oh no"); + \\} + \\ + , + .unwind = .any, + .expect_panic = true, + .expect = switch (os) { + // Similarly to "inline panic", we can resolve inlines from PDBs but LLVM doesn't emit + // column info for them. + .windows => + \\panic: oh no + \\source.zig:11: [address] in baz + \\ @panic("oh no"); + \\ + \\source.zig:8: [address] in bar + \\ baz(); + \\ + \\source.zig:5: [address] in foo + \\ bar(); + \\ + \\source.zig:2:8: [address] in main + \\ foo(); + \\ ^ + \\ + , + // Similarly to "inline panic", we don't yet resolve inlines on other platforms. + else => + \\panic: oh no + \\source.zig:11:5: [address] in baz + \\ @panic("oh no"); + \\ ^ + , + }, + .expect_strip = switch (os) { + .windows => + \\panic: oh no + \\???:?:?: [address] in baz + \\???:?:?: [address] in bar + \\???:?:?: [address] in foo + \\???:?:?: [address] in main + \\ + , + else => + \\panic: oh no + \\???:?:?: [address] in baz + \\ + , + }, + }); } diff --git a/test/tests.zig b/test/tests.zig index a3667385fad48bea41a42005d427ba443d61ccda..511846dd312e516e1f74acdb74b50fb39993cb0d 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1989,56 +1989,75 @@ const c_abi_targets = blk: { }; }; -/// For stack trace tests, we only test native, because external executors are pretty unreliable at -/// stack tracing. However, if there's a 32-bit equivalent target which the host can trivially run, -/// we may as well at least test that! -fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget { +fn compatible32bitArch(b: *std.Build) ?std.Target.Cpu.Arch { const host = b.graph.host.result; - const only_native = (&b.graph.host)[0..1]; - if (skip_non_native) return only_native; - const arch32: std.Target.Cpu.Arch = switch (host.os.tag) { + return switch (host.os.tag) { .windows => switch (host.cpu.arch) { .x86_64 => .x86, .aarch64 => .thumb, .aarch64_be => .thumbeb, - else => return only_native, + else => null, }, .freebsd => switch (host.cpu.arch) { .aarch64 => .arm, .aarch64_be => .armeb, - else => return only_native, + else => null, }, .linux, .netbsd => switch (host.cpu.arch) { .x86_64 => .x86, .aarch64 => .arm, .aarch64_be => .armeb, - else => return only_native, + else => null, }, - else => return only_native, + else => null, }; - var targets = std.ArrayList(std.Build.ResolvedTarget).initCapacity(b.graph.arena, 2) - catch @panic("OOM"); - targets.appendAssumeCapacity(b.graph.host); - targets.appendAssumeCapacity(b.resolveTargetQuery(.{ - .cpu_arch = arch32, - .os_tag = host.os.tag, - })); - if (b.enable_wine and b.graph.host.result.os.tag != .windows) { - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = host.cpu.arch, - .os_tag = .windows, - })) catch @panic("OOM"); - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = arch32, - .os_tag = .windows, - })) catch @panic("OOM"); - } - if (b.enable_darling and b.graph.host.result.os.tag != .macos) { - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = host.cpu.arch, - .os_tag = .macos, - })) catch @panic("OOM"); +} + +/// For stack trace tests, we only test native by default, because external executors are pretty +/// unreliable at stack tracing. However, if there's a 32-bit equivalent target which the host can +/// trivially run, we may as well at least test that! +fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget { + const host = b.graph.host.result; + const only_native = (&b.graph.host)[0..1]; + if (skip_non_native) return only_native; + const arch32 = compatible32bitArch(b) orelse return only_native; + return b.graph.arena.dupe(std.Build.ResolvedTarget, &.{ + b.graph.host, + b.resolveTargetQuery(.{ .cpu_arch = arch32, .os_tag = host.os.tag }), + }) catch @panic("OOM"); +} + +fn wineAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget { + var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty; + + const host = b.graph.host.result; + + targets.append(b.graph.arena, b.resolveTargetQuery(.{ + .cpu_arch = host.cpu.arch, + .os_tag = .windows, + })) catch @panic("OOM"); + if (!skip_non_native) { + if (compatible32bitArch(b)) |arch| { + targets.append(b.graph.arena, b.resolveTargetQuery(.{ + .cpu_arch = arch, + .os_tag = .windows, + })) catch @panic("OOM"); + } } + + return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM"); +} + +fn darlingTargets(b: *std.Build) []const std.Build.ResolvedTarget { + var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty; + + const host = b.graph.host.result; + + targets.append(b.graph.arena, b.resolveTargetQuery(.{ + .cpu_arch = host.cpu.arch, + .os_tag = .macos, + })) catch @panic("OOM"); + return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM"); } @@ -2047,6 +2066,8 @@ pub fn addStackTraceTests( test_filters: []const []const u8, skip_non_native: bool, ) *Step { + const step = b.step("test-stack-traces", "Run the stack trace tests"); + const convert_exe = b.addExecutable(.{ .name = "convert-stack-trace", .root_module = b.createModule(.{ @@ -2056,19 +2077,41 @@ pub fn addStackTraceTests( }), }); - const cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); - - cases.* = .{ + const host_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); + host_cases.* = .{ .b = b, - .step = b.step("test-stack-traces", "Run the stack trace tests"), + .step = step, .test_filters = test_filters, .targets = nativeAndCompatible32bit(b, skip_non_native), .convert_exe = convert_exe, }; + stack_traces.addCases(host_cases, b.graph.host.result.os.tag); - stack_traces.addCases(cases); + if (b.enable_wine) { + const wine_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); + wine_cases.* = .{ + .b = b, + .step = step, + .test_filters = test_filters, + .targets = wineAndCompatible32bit(b, skip_non_native), + .convert_exe = convert_exe, + }; + stack_traces.addCases(wine_cases, .windows); + } - return cases.step; + if (b.enable_darling) { + const darling_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); + darling_cases.* = .{ + .b = b, + .step = step, + .test_filters = test_filters, + .targets = darlingTargets(b), + .convert_exe = convert_exe, + }; + stack_traces.addCases(darling_cases, .macos); + } + + return step; } pub fn addErrorTraceTests( @@ -2077,6 +2120,8 @@ pub fn addErrorTraceTests( optimize_modes: []const OptimizeMode, skip_non_native: bool, ) *Step { + const step = b.step("test-error-traces", "Run the error trace tests"); + const convert_exe = b.addExecutable(.{ .name = "convert-stack-trace", .root_module = b.createModule(.{ @@ -2086,19 +2131,45 @@ pub fn addErrorTraceTests( }), }); - const cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); - cases.* = .{ + const host_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); + host_cases.* = .{ .b = b, - .step = b.step("test-error-traces", "Run the error trace tests"), + .step = step, .test_filters = test_filters, .targets = nativeAndCompatible32bit(b, skip_non_native), .optimize_modes = optimize_modes, .convert_exe = convert_exe, }; + error_traces.addCases(host_cases, b.graph.host.result.os.tag); - error_traces.addCases(cases); + if (b.enable_wine) { + const wine_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); + wine_cases.* = .{ + .b = b, + .step = step, + .test_filters = test_filters, + .targets = wineAndCompatible32bit(b, skip_non_native), + .optimize_modes = optimize_modes, + .convert_exe = convert_exe, + }; + error_traces.addCases(wine_cases, .windows); + } - return cases.step; + if (b.enable_darling) { + const darling_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); + darling_cases.* = .{ + .b = b, + .step = step, + .test_filters = test_filters, + .targets = darlingTargets(b), + .optimize_modes = optimize_modes, + .convert_exe = convert_exe, + }; + error_traces.addCases(darling_cases, .macos); + } + + + return step; } fn compilerHasPackageManager(b: *std.Build) bool { -- 2.54.0 From 5a4b5c8b94236429263ef25d9287b6c5cc829bde Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Fri, 10 Apr 2026 13:53:41 -0700 Subject: [PATCH 16/29] Uses dwarf iterator if dwarf symbols found for windows executable --- lib/std/debug/Dwarf.zig | 35 ++++++++++++++++++----- lib/std/debug/Pdb.zig | 2 +- lib/std/debug/SelfInfo/Elf.zig | 30 ++------------------ lib/std/debug/SelfInfo/Windows.zig | 45 +++++++----------------------- 4 files changed, 41 insertions(+), 71 deletions(-) diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index f82b4829deb2658317a3b296cd0560f03276d71d..0cd2a608e9e4b914c8d562fe4782236d143bc6ee 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -22,7 +22,9 @@ const cast = std.math.cast; const maxInt = std.math.maxInt; const ArrayList = std.ArrayList; const Endian = std.builtin.Endian; -const Reader = std.Io.Reader; +const Io = std.Io; +const Reader = Io.Reader; +const Error = std.debug.SelfInfoError; const Dwarf = @This(); @@ -1543,21 +1545,40 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { return str[casted_offset..last :0]; } -pub fn getSymbol(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) !std.debug.Symbol { +pub const SymbolIterator = struct { + curr: ?std.debug.SelfInfoError!std.debug.Symbol, + + pub fn deinit(self: *SymbolIterator, _: Io) void { + self.* = undefined; + } + + pub fn next(self: *SymbolIterator) ?Error!std.debug.Symbol { + const result = self.curr; + self.curr = null; + return result; + } +}; + +pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) SymbolIterator { const compile_unit = di.findCompileUnit(endian, address) catch |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => return .unknown, - else => return err, + error.EndOfStream, error.Overflow => return .{ .curr = error.InvalidDebugInfo }, + else => |e| return .{ .curr = e }, }; - return .{ + return .{ .curr = .{ .name = di.getSymbolName(address), .compile_unit_name = compile_unit.die.getAttrString(di, endian, std.dwarf.AT.name, di.section(.debug_str), compile_unit) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, }, .source_location = di.getLineNumberInfo(gpa, endian, compile_unit, address) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, - else => return err, + error.ReadFailed, + error.EndOfStream, + error.Overflow, + error.StreamTooLong, + => return .{ .curr = error.InvalidDebugInfo }, + else => |e| return .{ .curr = e }, }, - }; + } }; } /// DWARF5 7.4: "In the 32-bit DWARF format, all values that represent lengths of DWARF sections and diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index 198e81534628967a923f3e9ef558be8a6f0e6178..b76ed9e47c7602bb7f50abb2bca5349410fc1c63 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -358,7 +358,7 @@ pub const BinaryAnnotation = union(enum) { self.curr.file_id = file_id; }, // LLVM never emits this opcode, but it's clear enough how to interpret it so we - // may as well in case they use it in the future + // may as well handle it in case they emit it in the future .change_code_length_and_code_offset => |info| { self.curr.code_length = info.length; self.curr.code_offset += info.delta; diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 7955dd32c6277d8f66044d94f9eaa832f66d79aa..8a0535c4870484597f825fd207752d5d68b5a25b 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -30,19 +30,7 @@ pub fn deinit(si: *SelfInfo, io: Io) void { if (si.unwind_cache) |cache| gpa.free(cache); } -pub const SymbolIterator = struct { - curr: ?Error!std.debug.Symbol, - - pub fn deinit(self: *SymbolIterator, _: Io) void { - self.* = undefined; - } - - pub fn next(self: *SymbolIterator) ?Error!std.debug.Symbol { - const result = self.curr; - self.curr = null; - return result; - } -}; +pub const SymbolIterator = std.debug.Dwarf.SymbolIterator; pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { const gpa = std.debug.getDebugInfoAllocator(); @@ -67,21 +55,7 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { }; loaded_elf.scanned_dwarf = true; } - if (dwarf.getSymbol(gpa, native_endian, vaddr)) |sym| { - return .{ .curr = sym }; - } else |err| switch (err) { - error.MissingDebugInfo => {}, - - error.InvalidDebugInfo, - error.OutOfMemory, - => |e| return .{ .curr = e }, - - error.ReadFailed, - error.EndOfStream, - error.Overflow, - error.StreamTooLong, - => return .{ .curr = error.InvalidDebugInfo }, - } + return dwarf.getSymbols(gpa, native_endian, vaddr); } // When DWARF is unavailable, fall back to searching the symtab. const symbol = loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index 710b13c1228ee3d60b097243c48fbb58f0519055..c3d72d4558b01fac19c1dde3be1ed1c3e936aa45 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -33,7 +33,7 @@ pub const SymbolIterator = struct { pub fn deinit(self: *SymbolIterator, io: Io) void { if (self.lock) |lock| lock.unlockShared(io); - self.symbols.deinit(); + self.symbols.deinit(io); self.* = undefined; } @@ -105,29 +105,7 @@ pub const SymbolIterator = struct { .source_location = pdb.getLineNumberInfo(info.module, info.addr) catch null, }; }, - .dwarf => |info| { - // The failure cases are unreachable because we only set the dwarf field if these - // are set - const di = if (self.module.di.?) |*di| di else |_| unreachable; - const dwarf = if (di.dwarf) |*dwarf| dwarf else unreachable; - - // Return the main symbol and then return the iterator - defer self.symbols = .none; - const gpa = std.debug.getDebugInfoAllocator(); - return dwarf.getSymbol(gpa, native_endian, info.addr) catch |err| switch (err) { - error.MissingDebugInfo => return null, - - error.InvalidDebugInfo, - error.OutOfMemory, - => |e| return e, - - error.ReadFailed, - error.EndOfStream, - error.Overflow, - error.StreamTooLong, - => return error.InvalidDebugInfo, - }; - }, + .dwarf => |*info| return info.next(), .none => return null, } } @@ -368,7 +346,7 @@ const Module = struct { /// iteration, e.g. because they only wanted the topmost call. inline_sites: std.ArrayList(*align(1) const std.pdb.InlineSiteSym), }, - dwarf: struct { addr: u64 }, + dwarf: std.debug.Dwarf.SymbolIterator, none: void, fn init(di: *DebugInfo, vaddr: usize) Error!Symbols { @@ -425,23 +403,20 @@ const Module = struct { // Dwarf dwarf: { - if (di.dwarf == null) break :dwarf; + const dwarf = &(di.dwarf orelse break :dwarf); const addr = vaddr + di.coff_image_base; - return .{ .dwarf = .{ - .addr = addr, - } }; + return .{ .dwarf = dwarf.getSymbols(gpa, native_endian, addr) }; } return error.MissingDebugInfo; } - fn deinit(self: *Symbols) void { + fn deinit(self: *Symbols, io: Io) void { + const gpa = std.debug.getDebugInfoAllocator(); switch (self.*) { - .pdb => |*info| { - const gpa = std.debug.getDebugInfoAllocator(); - info.inline_sites.deinit(gpa); - }, - .dwarf, .none => {}, + .pdb => |*info| info.inline_sites.deinit(gpa), + .dwarf => |*info| info.deinit(io), + .none => {}, } } }; -- 2.54.0 From f6a3a0ca723325b2b84e67b1f7ef78a8f69df650 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Fri, 10 Apr 2026 19:29:43 -0700 Subject: [PATCH 17/29] Replaces the inline symbol iterator with an array of symbols The intention behind the iterator was to avoid needing to allocate the symbols, but in practice we need to allocate them anyway since we need to reverse their order and don't have random access. The alternative would be an N^2 algorithm. In practice this isn't that bad, because even if the allocation fails, we'll still end up printing the address, so the user still ends up with the necessary information to reconstruct the crash. I don't think it's worth it to try to set up some kind of ring buffer or return partial results on failure, but may revisit this. --- lib/std/debug.zig | 54 +++--- lib/std/debug/Dwarf.zig | 34 ++-- lib/std/debug/SelfInfo/Elf.zig | 35 ++-- lib/std/debug/SelfInfo/MachO.zig | 41 +++-- lib/std/debug/SelfInfo/Windows.zig | 267 +++++++++++------------------ 5 files changed, 188 insertions(+), 243 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7297352f0aae4b48efb553c247ad1b7f971b0451..9ff960147857ab20e11d7552340e79998a159fb6 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -38,8 +38,12 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// pub const init: SelfInfo; /// pub fn deinit(si: *SelfInfo, io: Io) void; /// -/// /// Returns an iterator over the symbols and source locations of the instruction at `address`. -/// pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SelfInfo.SymbolIterator; +/// /// Returns the the symbols and source locations of the instruction at `address`. Often this +/// /// will return a single result, but in the case of inlines it may return multiple. When +/// /// multiple results are returned, they are sorted from innermost to outermost. +/// pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const Symbol; +/// /// Frees symbols returned from `getSymbols`. +/// pub fn freeSymbols(si: *SelfInfo, symbols: []const Symbol) void; /// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`. /// pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const u8; /// pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) SelfInfoError!usize; @@ -60,11 +64,6 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// /// Only required if `can_unwind == true`. Unwinds a single stack frame, returning the frame's /// /// return address, or 0 if the end of the stack has been reached. /// pub fn unwindFrame(si: *SelfInfo, io: Io, context: *UnwindContext) SelfInfoError!usize; -/// /// Iterates symbols found at an address. -/// pub const SymbolIterator = struct { -/// pub fn deinit(Self: *SymbolIterator, io: Io) void; -/// pub fn next(self: *SymbolIterator) ?SelfInfoError!Symbol; -/// }; /// ``` pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo")) root.debug.SelfInfo @@ -1193,35 +1192,35 @@ fn printSourceAtAddress( t: Io.Terminal, options: PrintSourceAddressOptions, ) Writer.Error!void { - var symbols: SelfInfo.SymbolIterator = debug_info.getSymbols(io, options.address); - defer symbols.deinit(io); - while (symbols.next()) |curr| { - const symbol: Symbol = curr catch |err| switch (err) { + const symbols: []const Symbol = debug_info.getSymbols(io, options.address) catch |err| { + t.setColor(.dim) catch {}; + defer t.setColor(.reset) catch {}; + switch (err) { error.MissingDebugInfo, error.UnsupportedDebugInfo, error.InvalidDebugInfo, - => .unknown, - error.ReadFailed, error.Unexpected, error.Canceled => s: { - t.setColor(.dim) catch {}; + => {}, + error.ReadFailed, error.Unexpected, error.Canceled => { try t.writer.print("Failed to read debug info from filesystem, trace may be incomplete\n\n", .{}); - t.setColor(.reset) catch {}; - break :s .unknown; }, - error.OutOfMemory => s: { + error.OutOfMemory => { t.setColor(.dim) catch {}; try t.writer.print("Ran out of memory loading debug info, trace may be incomplete\n\n", .{}); t.setColor(.reset) catch {}; - break :s .unknown; }, - }; - defer if (symbol.source_location) |sl| getDebugInfoAllocator().free(sl.file_name); + } + return printLineInfo(io, t, debug_info, null, options.address, null, null); + }; + defer debug_info.freeSymbols(symbols); + for (symbols) |symbol| { try printLineInfo( io, t, + debug_info, symbol.source_location, options.address, - symbol.name orelse "???", - symbol.compile_unit_name orelse debug_info.getModuleName(io, options.address) catch "???", + symbol.name, + symbol.compile_unit_name, ); if (!options.resolve_inline_callers) break; } @@ -1229,10 +1228,11 @@ fn printSourceAtAddress( fn printLineInfo( io: Io, t: Io.Terminal, + debug_info: *SelfInfo, source_location: ?SourceLocation, address: usize, - symbol_name: []const u8, - compile_unit_name: []const u8, + symbol_name: ?[]const u8, + compile_unit_name: ?[]const u8, ) Writer.Error!void { const writer = t.writer; t.setColor(.bold) catch {}; @@ -1250,7 +1250,11 @@ fn printLineInfo( t.setColor(.reset) catch {}; try writer.writeAll(": "); t.setColor(.dim) catch {}; - try writer.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name }); + try writer.print("0x{x} in {s} ({s})", .{ + address, + symbol_name orelse "???", + compile_unit_name orelse debug_info.getModuleName(io, address) catch "???", + }); t.setColor(.reset) catch {}; try writer.writeAll("\n"); diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 0cd2a608e9e4b914c8d562fe4782236d143bc6ee..24288a515e40d46d8bc2fad158be843f4fc7bc80 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -1545,26 +1545,17 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { return str[casted_offset..last :0]; } -pub const SymbolIterator = struct { - curr: ?std.debug.SelfInfoError!std.debug.Symbol, - - pub fn deinit(self: *SymbolIterator, _: Io) void { - self.* = undefined; - } - - pub fn next(self: *SymbolIterator) ?Error!std.debug.Symbol { - const result = self.curr; - self.curr = null; - return result; - } -}; - -pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) SymbolIterator { +pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) std.debug.SelfInfoError![]const std.debug.Symbol { + const symbol = try gpa.create(std.debug.Symbol); + errdefer gpa.destroy(symbol); const compile_unit = di.findCompileUnit(endian, address) catch |err| switch (err) { - error.EndOfStream, error.Overflow => return .{ .curr = error.InvalidDebugInfo }, - else => |e| return .{ .curr = e }, + error.EndOfStream, error.Overflow => { + symbol.* = .unknown; + return symbol[0..1]; + }, + else => |e| return e, }; - return .{ .curr = .{ + symbol.* = .{ .name = di.getSymbolName(address), .compile_unit_name = compile_unit.die.getAttrString(di, endian, std.dwarf.AT.name, di.section(.debug_str), compile_unit) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, @@ -1575,10 +1566,11 @@ pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) Symb error.EndOfStream, error.Overflow, error.StreamTooLong, - => return .{ .curr = error.InvalidDebugInfo }, - else => |e| return .{ .curr = e }, + => return error.InvalidDebugInfo, + else => |e| return e, }, - } }; + }; + return symbol[0..1]; } /// DWARF5 7.4: "In the 32-bit DWARF format, all values that represent lengths of DWARF sections and diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 8a0535c4870484597f825fd207752d5d68b5a25b..71f172200fd73bf9314005e89a239248af3a98ab 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -30,41 +30,50 @@ pub fn deinit(si: *SelfInfo, io: Io) void { if (si.unwind_cache) |cache| gpa.free(cache); } -pub const SymbolIterator = std.debug.Dwarf.SymbolIterator; - -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { const gpa = std.debug.getDebugInfoAllocator(); - const module = si.findModule(gpa, io, address, .exclusive) catch |err| return .{ .curr = err }; + const module = try si.findModule(gpa, io, address, .exclusive); defer si.rwlock.unlock(io); const vaddr = address - module.load_offset; - const loaded_elf = module.getLoadedElf(gpa, io) catch |err| return .{ .curr = err }; + const loaded_elf = try module.getLoadedElf(gpa, io); if (loaded_elf.file.dwarf) |*dwarf| { if (!loaded_elf.scanned_dwarf) { dwarf.open(gpa, native_endian) catch |err| switch (err) { error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory, - => |e| return .{ .curr = e }, + => |e| return e, error.EndOfStream, error.Overflow, error.ReadFailed, error.StreamTooLong, - => return .{ .curr = error.InvalidDebugInfo }, + => return error.InvalidDebugInfo, }; loaded_elf.scanned_dwarf = true; } return dwarf.getSymbols(gpa, native_endian, vaddr); } // When DWARF is unavailable, fall back to searching the symtab. - const symbol = loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { - error.NoSymtab, error.NoStrtab => return .{ .curr = error.MissingDebugInfo }, - error.BadSymtab => return .{ .curr = error.InvalidDebugInfo }, - error.OutOfMemory => |e| return .{ .curr = e }, + const symbol = try gpa.create(std.debug.Symbol); + errdefer gpa.destroy(symbol); + symbol.* = loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { + error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo, + error.BadSymtab => return error.InvalidDebugInfo, + error.OutOfMemory => |e| return e, }; - - return .{ .curr = symbol }; + return symbol[0..1]; +} +pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { + _ = si; + const gpa = std.debug.getDebugInfoAllocator(); + for (symbols) |symbol| { + if (symbol.source_location) |source_location| { + gpa.free(source_location.file_name); + } + } + gpa.free(symbols); } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { const gpa = std.debug.getDebugInfoAllocator(); diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index d6523d924d1cef6daf6bf21466d263119441e249..d8f73976d0b3512154c633c58dffb8dec46acd0a 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -36,12 +36,15 @@ pub const SymbolIterator = struct { } }; -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { const gpa = std.debug.getDebugInfoAllocator(); - const module = si.findModule(gpa, io, address) catch |err| return .{ .curr = err }; + const module = try si.findModule(gpa, io, address); defer si.mutex.unlock(io); - const file = module.getFile(gpa, io) catch |err| return .{ .curr = err }; + const file = try module.getFile(gpa, io); + + const symbol = try gpa.create(std.debug.Symbol); + errdefer gpa.destroy(symbol); // This is not necessarily the same as the vmaddr_slide that dyld would report. This is // because the segments in the file on disk might differ from the ones in memory. Normally @@ -57,26 +60,27 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { const ofile_dwarf, const ofile_vaddr = file.getDwarfForAddress(gpa, io, vaddr) catch { // Return at least the symbol name if available. - return .{ .curr = .{ - .name = file.lookupSymbolName(vaddr) catch |err| return .{ .curr = err }, + symbol.* = .{ + .name = try file.lookupSymbolName(vaddr), .compile_unit_name = null, .source_location = null, - } }; + }; + return symbol[0..1]; }; const compile_unit = ofile_dwarf.findCompileUnit(native_endian, ofile_vaddr) catch { // Return at least the symbol name if available. - return .{ .curr = .{ - .name = file.lookupSymbolName(vaddr) catch |err| return .{ .curr = err }, + symbol.* = .{ + .name = try file.lookupSymbolName(vaddr), .compile_unit_name = null, .source_location = null, - } }; + }; + return symbol[0..1]; }; - return .{ .curr = .{ + symbol.* = .{ .name = ofile_dwarf.getSymbolName(ofile_vaddr) orelse - file.lookupSymbolName(vaddr) catch |err| - return .{ .curr = err }, + try file.lookupSymbolName(vaddr), .compile_unit_name = compile_unit.die.getAttrString( ofile_dwarf, native_endian, @@ -92,7 +96,18 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { compile_unit, ofile_vaddr, ) catch null, - } }; + }; + return symbol[0..1]; +} +pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { + _ = si; + const gpa = std.debug.getDebugInfoAllocator(); + for (symbols) |symbol| { + if (symbol.source_location) |source_location| { + gpa.free(source_location.file_name); + } + } + gpa.free(symbols); } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { _ = si; diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index c3d72d4558b01fac19c1dde3be1ed1c3e936aa45..d2a28803b133f3811c5fa6c0a062417d023d20db 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -25,107 +25,26 @@ pub fn deinit(si: *SelfInfo, io: Io) void { si.modules.deinit(gpa); } -pub const SymbolIterator = struct { - err: Error!void = {}, - lock: ?*Io.RwLock, - module: *Module, - symbols: Module.DebugInfo.Symbols, - - pub fn deinit(self: *SymbolIterator, io: Io) void { - if (self.lock) |lock| lock.unlockShared(io); - self.symbols.deinit(io); - self.* = undefined; - } - - fn failing(err: Error) SymbolIterator { - return .{ - .err = err, - .lock = null, - .module = undefined, - .symbols = .none, - }; - } - - pub fn next(self: *SymbolIterator) ?Error!std.debug.Symbol { - // Check for errors - self.err catch |err| { - self.err = {}; - self.symbols = .none; - return err; - }; - - // Return the next symbol for the debug info type - switch (self.symbols) { - .pdb => |*info| { - // The failure cases are unreachable because we only set the pdb field if these are - // set - const di = if (self.module.di.?) |*di| di else |_| unreachable; - const pdb = if (di.pdb) |*pdb| pdb else unreachable; - - // Get the next inlinee if it exists - if (info.proc) |proc| { - const offset_in_func = info.addr - proc.code_offset; - while (info.inline_sites.pop()) |site| { - // If our address points into this site, get the source location it points - // at - const inlinee_src_line = pdb.getInlineeSourceLine( - info.module, - site.inlinee, - ) orelse continue; - const maybe_loc = pdb.getInlineSiteSourceLocation( - info.module, - site, - inlinee_src_line.info, - offset_in_func, - ) catch continue; - const loc = maybe_loc orelse continue; - - // If we've found a match, filter out any duplicates that might follow. - // Tools like llvm-addr2line output duplicate sites in the same cases as us, - // implying that they exist in the underlying data and are not indicative of - // a parser bug. - while (info.inline_sites.getLastOrNull()) |top| { - if (top.inlinee != site.inlinee) break; - _ = info.inline_sites.pop(); - } - - return .{ - .name = pdb.findInlineeName(site.inlinee), - .compile_unit_name = fs.path.basename(info.module.obj_file_name), - .source_location = loc, - }; - } - } - - // Return the main symbol and end the iterator - defer self.symbols = .none; - return .{ - .name = if (info.proc) |proc| pdb.getSymbolName(proc) else null, - .compile_unit_name = fs.path.basename(info.module.obj_file_name), - .source_location = pdb.getLineNumberInfo(info.module, info.addr) catch null, - }; - }, - .dwarf => |*info| return info.next(), - .none => return null, +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { + const gpa = std.debug.getDebugInfoAllocator(); + try si.lock.lockShared(io); + defer si.lock.unlockShared(io); + const module = try si.findModule(gpa, address); + const di = try module.getDebugInfo(gpa, io); + return di.getSymbols(gpa, address - @intFromPtr(module.entry.DllBase)); +} + +pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { + _ = si; + const gpa = std.debug.getDebugInfoAllocator(); + for (symbols) |symbol| { + if (symbol.source_location) |source_location| { + gpa.free(source_location.file_name); } } -}; - -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { - const gpa = std.debug.getDebugInfoAllocator(); - si.lock.lockShared(io) catch |err| return .failing(err); - errdefer si.lock.unlockShared(io); - const module = si.findModule(gpa, address) catch |err| return .failing(err); - const di = module.getDebugInfo(gpa, io) catch |err| return .failing(err); - const symbols = Module.DebugInfo.Symbols.init(di, address - @intFromPtr(module.entry.DllBase)) - catch |err| return .failing(err); - errdefer comptime unreachable; - return .{ - .lock = &si.lock, - .module = module, - .symbols = symbols, - }; + gpa.free(symbols); } + pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { const gpa = std.debug.getDebugInfoAllocator(); try si.lock.lockShared(io); @@ -333,94 +252,100 @@ const Module = struct { arena.deinit(); } - pub const Symbols = union(enum) { - pdb: struct { - module: *Pdb.Module, - proc: ?*align(1) const std.pdb.ProcSym, - addr: usize, - /// Inline sites are stored in the pdb in reverse order, so we build up a list of up - /// front so that our iterator can return them in the correct order without doing an - /// n^2 search. We don't try to filter inline sites based on address until the user - /// calls `next` as this requires parsing binary annotations, and this is work we - /// may be able to elide if the caller chooses to early out before finishing - /// iteration, e.g. because they only wanted the topmost call. - inline_sites: std.ArrayList(*align(1) const std.pdb.InlineSiteSym), - }, - dwarf: std.debug.Dwarf.SymbolIterator, - none: void, + fn getSymbols(di: *DebugInfo, gpa: Allocator, vaddr: usize) Error![]const std.debug.Symbol { + pdb: { + const pdb = &(di.pdb orelse break :pdb); + var coff_section: *align(1) const coff.SectionHeader = undefined; + const mod_index = for (pdb.sect_contribs) |sect_contrib| { + if (sect_contrib.section > di.coff_section_headers.len) continue; + // Remember that SectionContribEntry.Section is 1-based. + coff_section = &di.coff_section_headers[sect_contrib.section - 1]; - fn init(di: *DebugInfo, vaddr: usize) Error!Symbols { - const gpa = std.debug.getDebugInfoAllocator(); + const vaddr_start = coff_section.virtual_address + sect_contrib.offset; + const vaddr_end = vaddr_start + sect_contrib.size; + if (vaddr >= vaddr_start and vaddr < vaddr_end) { + break sect_contrib.module_index; + } + } else { + // we have no information to add to the address + break :pdb; + }; + const module = pdb.getModule(mod_index) catch |err| switch (err) { + error.InvalidDebugInfo, + error.MissingDebugInfo, + error.OutOfMemory, + => |e| return e, - pdb: { - const pdb = &(di.pdb orelse break :pdb); - var coff_section: *align(1) const coff.SectionHeader = undefined; - const mod_index = for (pdb.sect_contribs) |sect_contrib| { - if (sect_contrib.section > di.coff_section_headers.len) continue; - // Remember that SectionContribEntry.Section is 1-based. - coff_section = &di.coff_section_headers[sect_contrib.section - 1]; + error.ReadFailed, + error.EndOfStream, + => return error.InvalidDebugInfo, + } orelse { + return error.InvalidDebugInfo; // bad module index + }; - const vaddr_start = coff_section.virtual_address + sect_contrib.offset; - const vaddr_end = vaddr_start + sect_contrib.size; - if (vaddr >= vaddr_start and vaddr < vaddr_end) { - break sect_contrib.module_index; - } - } else { - // we have no information to add to the address - break :pdb; - }; - const module = pdb.getModule(mod_index) catch |err| switch (err) { - error.InvalidDebugInfo, - error.MissingDebugInfo, - error.OutOfMemory, - => |e| return e, + const addr = vaddr - coff_section.virtual_address; + const maybe_proc = pdb.getProcSym(module, addr); + var symbols: std.ArrayList(std.debug.Symbol) = .empty; + errdefer symbols.deinit(gpa); - error.ReadFailed, - error.EndOfStream, - => return error.InvalidDebugInfo, - } orelse { - return error.InvalidDebugInfo; // bad module index - }; + if (maybe_proc) |proc| { + const offset_in_func = addr - proc.code_offset; + var last_inlinee: ?u32 = null; + var iter = pdb.getInlinees(module, proc); + while (iter.next(module)) |inline_site| { + // If our address points into this site, get the source location it + // points at + const inlinee_src_line = pdb.getInlineeSourceLine( + module, + inline_site.inlinee, + ) orelse continue; + const maybe_loc = pdb.getInlineSiteSourceLocation( + module, + inline_site, + inlinee_src_line.info, + offset_in_func, + ) catch continue; + const loc = maybe_loc orelse continue; - const addr = vaddr - coff_section.virtual_address; - const maybe_proc = pdb.getProcSym(module, addr); + // Filter out duplicate inline sites. Tools like llvm-addr2line output + // duplicate sites in the same cases as us if we elide this check, + // implying that they exist in the underlying data and are not + // indicative of a parser bug. No useful information is lost here since an + // inline site can't actually reference itself. + if (inline_site.inlinee == last_inlinee) continue; + last_inlinee = inline_site.inlinee; - var inline_sites: std.ArrayList(*align(1) const std.pdb.InlineSiteSym) = .empty; - if (maybe_proc) |proc| { - var iter = pdb.getInlinees(module, proc); - while (iter.next(module)) |inline_site| { - try inline_sites.append(gpa, inline_site); - } + try symbols.append(gpa, .{ + .name = pdb.findInlineeName(inline_site.inlinee), + .compile_unit_name = fs.path.basename(module.obj_file_name), + .source_location = loc, + }); } - return .{ .pdb = .{ - .module = module, - .proc = maybe_proc, - .addr = addr, - .inline_sites = inline_sites, - } }; + // Inline sites are stored in the pdb in reverse order, so we reverse the + // matching sites here. We could alternatively use the parent fields to + // determine the order, but this would introduce seemingly unecessary + // complexity. + std.mem.reverse(std.debug.Symbol, symbols.items); } - // Dwarf - dwarf: { - const dwarf = &(di.dwarf orelse break :dwarf); - const addr = vaddr + di.coff_image_base; - return .{ .dwarf = dwarf.getSymbols(gpa, native_endian, addr) }; - } + try symbols.append(gpa, .{ + .name = if (maybe_proc) |proc| pdb.getSymbolName(proc) else null, + .compile_unit_name = fs.path.basename(module.obj_file_name), + .source_location = pdb.getLineNumberInfo(module, addr) catch null, + }); - return error.MissingDebugInfo; + return symbols.toOwnedSlice(gpa); } - fn deinit(self: *Symbols, io: Io) void { - const gpa = std.debug.getDebugInfoAllocator(); - switch (self.*) { - .pdb => |*info| info.inline_sites.deinit(gpa), - .dwarf => |*info| info.deinit(io), - .none => {}, - } + dwarf: { + const dwarf = &(di.dwarf orelse break :dwarf); + const addr = vaddr + di.coff_image_base; + return dwarf.getSymbols(gpa, native_endian, addr); } - }; + return error.MissingDebugInfo; + } }; fn deinit(module: *Module, gpa: Allocator, io: Io) void { -- 2.54.0 From 9edbf00ddfb3f8316d82e191b7aca281a0939ac0 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Fri, 10 Apr 2026 22:38:32 -0700 Subject: [PATCH 18/29] Enables disabled error trace test on Windows --- test/error_traces.zig | 87 ++++++++++++++++++++++++------------------- test/stack_traces.zig | 12 +++--- 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/test/error_traces.zig b/test/error_traces.zig index d033cf741b0dcdf2e079a04b8e23d3fa8b12b274..4f3c20ba7f7668851b9844ea4a0e79b108793ce7 100644 --- a/test/error_traces.zig +++ b/test/error_traces.zig @@ -452,26 +452,37 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }, }); - // TODO: the standard library has a bug in PDB parsing where given an address corresponding - // to an inline call, the frame we see will be for the *caller*, not the *callee*. As a - // result this test gives bogus results on Windows right now. - // This is a part of https://codeberg.org/ziglang/zig/issues/30847. - if (os != .windows) { - cases.addCase(.{ - .name = "trace through inline call", - .source = - \\pub fn main() !void { - \\ try foo(); - \\} - \\inline fn foo() !void { - \\ try bar(); - \\} - \\fn bar() !void { + cases.addCase(.{ + .name = "trace through inline call", + .source = + \\pub fn main() !void { + \\ try foo(); + \\} + \\inline fn foo() !void { + \\ try bar(); + \\} + \\fn bar() !void { + \\ return error.ThisIsSoSad; + \\} + , + .expect_error = "ThisIsSoSad", + .expect_trace = + switch (os) { + // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs, + // so our expected result is slightly different for Windows than on other operating + // systems. + .windows => + \\source.zig:8:5: [address] in bar \\ return error.ThisIsSoSad; - \\} + \\ ^ + \\source.zig:5: [address] in foo + \\ try bar(); + \\ + \\source.zig:2:5: [address] in main + \\ try foo(); + \\ ^ , - .expect_error = "ThisIsSoSad", - .expect_trace = + else => \\source.zig:8:5: [address] in bar \\ return error.ThisIsSoSad; \\ ^ @@ -482,24 +493,24 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. \\ try foo(); \\ ^ , - .disable_trace_optimized = &.{ - .{ .x86_64, .freebsd }, - .{ .x86_64, .netbsd }, - .{ .x86_64, .linux }, - .{ .x86, .linux }, - .{ .aarch64, .freebsd }, - .{ .aarch64, .netbsd }, - .{ .aarch64, .linux }, - .{ .loongarch64, .linux }, - .{ .powerpc64le, .linux }, - .{ .riscv64, .linux }, - .{ .s390x, .linux }, - .{ .x86_64, .openbsd }, - .{ .x86_64, .windows }, - .{ .x86, .windows }, - .{ .x86_64, .macos }, - .{ .aarch64, .macos }, - }, - }); - } + }, + .disable_trace_optimized = &.{ + .{ .x86_64, .freebsd }, + .{ .x86_64, .netbsd }, + .{ .x86_64, .linux }, + .{ .x86, .linux }, + .{ .aarch64, .freebsd }, + .{ .aarch64, .netbsd }, + .{ .aarch64, .linux }, + .{ .loongarch64, .linux }, + .{ .powerpc64le, .linux }, + .{ .riscv64, .linux }, + .{ .s390x, .linux }, + .{ .x86_64, .openbsd }, + .{ .x86_64, .windows }, + .{ .x86, .windows }, + .{ .x86_64, .macos }, + .{ .aarch64, .macos }, + }, + }); } diff --git a/test/stack_traces.zig b/test/stack_traces.zig index 3b5ed8d54173d1897fa77827bacc859e1a5c392a..037399d36c7094f80949c49697475292ada364bf 100644 --- a/test/stack_traces.zig +++ b/test/stack_traces.zig @@ -238,9 +238,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. .unwind = .any, .expect_panic = true, .expect = switch (os) { - // We use the information present in PDBs to resolve inlines when dumping stack traces - // on Windows. Column numbers are missing as LLVM doesn't emit column info in the PDBs - // for inline functions. + // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs, + // so the first location has only a row. .windows => \\panic: oh no \\source.zig:5: [address] in foo @@ -251,7 +250,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. \\ ^ \\ , - // We don't yet resolve inlines on other platforms. + // On all other platforms, we resolve the innermost inline callee but we don't yet + // resolve the inline callers. else => \\panic: oh no \\source.zig:5:5: [address] in foo @@ -294,9 +294,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. , .unwind = .any, .expect_panic = true, + // This switch serves a similar purpose as in "inline panic". .expect = switch (os) { - // Similarly to "inline panic", we can resolve inlines from PDBs but LLVM doesn't emit - // column info for them. .windows => \\panic: oh no \\source.zig:11: [address] in baz @@ -313,7 +312,6 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. \\ ^ \\ , - // Similarly to "inline panic", we don't yet resolve inlines on other platforms. else => \\panic: oh no \\source.zig:11:5: [address] in baz -- 2.54.0 From 4efbb27aa2b841357c03d6ab158418ccad022415 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sat, 11 Apr 2026 00:28:48 -0700 Subject: [PATCH 19/29] Don't bother resolving symbol names that won't be used Also fixes some memory management issues --- lib/std/debug.zig | 22 ++++++---- lib/std/debug/Dwarf.zig | 21 +++++---- lib/std/debug/SelfInfo/Elf.zig | 27 +++++------- lib/std/debug/SelfInfo/MachO.zig | 39 ++++++++--------- lib/std/debug/SelfInfo/Windows.zig | 69 +++++++++++++++++------------- 5 files changed, 93 insertions(+), 85 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 9ff960147857ab20e11d7552340e79998a159fb6..1cda6b50180b496b2f00d50aa6a78e216da3226e 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -38,12 +38,8 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// pub const init: SelfInfo; /// pub fn deinit(si: *SelfInfo, io: Io) void; /// -/// /// Returns the the symbols and source locations of the instruction at `address`. Often this -/// /// will return a single result, but in the case of inlines it may return multiple. When -/// /// multiple results are returned, they are sorted from innermost to outermost. -/// pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const Symbol; -/// /// Frees symbols returned from `getSymbols`. -/// pub fn freeSymbols(si: *SelfInfo, symbols: []const Symbol) void; +/// /// Returns the the symbols and source locations of the instruction at `address`. +/// pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, include_inline_callers: bool) SelfInfoError![]Symbol; /// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`. /// pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const u8; /// pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) SelfInfoError!usize; @@ -233,6 +229,11 @@ pub const Symbol = struct { .compile_unit_name = null, .source_location = null, }; + + pub fn deinit(self: *Symbol, gpa: Allocator) void { + if (self.source_location) |sl| gpa.free(sl.file_name); + self.* = undefined; + } }; /// Deprecated because it returns the optimization mode of the standard @@ -1192,7 +1193,8 @@ fn printSourceAtAddress( t: Io.Terminal, options: PrintSourceAddressOptions, ) Writer.Error!void { - const symbols: []const Symbol = debug_info.getSymbols(io, options.address) catch |err| { + const gpa = getDebugInfoAllocator(); + const symbols: []Symbol = debug_info.getSymbols(io, options.address, options.resolve_inline_callers) catch |err| { t.setColor(.dim) catch {}; defer t.setColor(.reset) catch {}; switch (err) { @@ -1211,7 +1213,10 @@ fn printSourceAtAddress( } return printLineInfo(io, t, debug_info, null, options.address, null, null); }; - defer debug_info.freeSymbols(symbols); + defer { + for (symbols) |*symbol| symbol.deinit(gpa); + gpa.free(symbols); + } for (symbols) |symbol| { try printLineInfo( io, @@ -1222,7 +1227,6 @@ fn printSourceAtAddress( symbol.name, symbol.compile_unit_name, ); - if (!options.resolve_inline_callers) break; } } fn printLineInfo( diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 24288a515e40d46d8bc2fad158be843f4fc7bc80..8ffddf4b39fd6fd0df3de434d0c694a619d4127c 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -1545,17 +1545,22 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { return str[casted_offset..last :0]; } -pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) std.debug.SelfInfoError![]const std.debug.Symbol { - const symbol = try gpa.create(std.debug.Symbol); - errdefer gpa.destroy(symbol); +pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64, resolve_inline_callers: bool) std.debug.SelfInfoError![]std.debug.Symbol { + _ = resolve_inline_callers; + + var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); + errdefer { + for (symbols.items) |*symbol| symbol.deinit(gpa); + symbols.deinit(gpa); + } const compile_unit = di.findCompileUnit(endian, address) catch |err| switch (err) { error.EndOfStream, error.Overflow => { - symbol.* = .unknown; - return symbol[0..1]; + symbols.appendAssumeCapacity(.unknown); + return symbols.toOwnedSlice(gpa); }, else => |e| return e, }; - symbol.* = .{ + symbols.appendAssumeCapacity(.{ .name = di.getSymbolName(address), .compile_unit_name = compile_unit.die.getAttrString(di, endian, std.dwarf.AT.name, di.section(.debug_str), compile_unit) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, @@ -1569,8 +1574,8 @@ pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) std. => return error.InvalidDebugInfo, else => |e| return e, }, - }; - return symbol[0..1]; + }); + return symbols.toOwnedSlice(gpa); } /// DWARF5 7.4: "In the 32-bit DWARF format, all values that represent lengths of DWARF sections and diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 71f172200fd73bf9314005e89a239248af3a98ab..bd045126ffcfa43462b5662876385fd9ebf08f97 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -30,7 +30,7 @@ pub fn deinit(si: *SelfInfo, io: Io) void { if (si.unwind_cache) |cache| gpa.free(cache); } -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { const gpa = std.debug.getDebugInfoAllocator(); const module = try si.findModule(gpa, io, address, .exclusive); defer si.rwlock.unlock(io); @@ -53,27 +53,20 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug }; loaded_elf.scanned_dwarf = true; } - return dwarf.getSymbols(gpa, native_endian, vaddr); + return dwarf.getSymbols(gpa, native_endian, vaddr, resolve_inline_callers); } // When DWARF is unavailable, fall back to searching the symtab. - const symbol = try gpa.create(std.debug.Symbol); - errdefer gpa.destroy(symbol); - symbol.* = loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { + var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); + errdefer { + for (symbols.items) |*symbol| symbol.deinit(gpa); + symbols.deinit(gpa); + } + symbols.appendAssumeCapacity(loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo, error.BadSymtab => return error.InvalidDebugInfo, error.OutOfMemory => |e| return e, - }; - return symbol[0..1]; -} -pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { - _ = si; - const gpa = std.debug.getDebugInfoAllocator(); - for (symbols) |symbol| { - if (symbol.source_location) |source_location| { - gpa.free(source_location.file_name); - } - } - gpa.free(symbols); + }); + return symbols.toOwnedSlice(gpa); } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { const gpa = std.debug.getDebugInfoAllocator(); diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index d8f73976d0b3512154c633c58dffb8dec46acd0a..894a4163da2117da3d7f7d369252075e5800ba93 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -36,15 +36,20 @@ pub const SymbolIterator = struct { } }; -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { + _ = resolve_inline_callers; + const gpa = std.debug.getDebugInfoAllocator(); const module = try si.findModule(gpa, io, address); defer si.mutex.unlock(io); const file = try module.getFile(gpa, io); - const symbol = try gpa.create(std.debug.Symbol); - errdefer gpa.destroy(symbol); + var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); + errdefer { + for (symbols.items) |*symbol| symbol.deinit(gpa); + symbols.deinit(gpa); + } // This is not necessarily the same as the vmaddr_slide that dyld would report. This is // because the segments in the file on disk might differ from the ones in memory. Normally @@ -60,25 +65,25 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug const ofile_dwarf, const ofile_vaddr = file.getDwarfForAddress(gpa, io, vaddr) catch { // Return at least the symbol name if available. - symbol.* = .{ + symbols.appendAssumeCapacity(.{ .name = try file.lookupSymbolName(vaddr), .compile_unit_name = null, .source_location = null, - }; - return symbol[0..1]; + }); + return symbols.toOwnedSlice(gpa); }; const compile_unit = ofile_dwarf.findCompileUnit(native_endian, ofile_vaddr) catch { // Return at least the symbol name if available. - symbol.* = .{ + symbols.appendAssumeCapacity(.{ .name = try file.lookupSymbolName(vaddr), .compile_unit_name = null, .source_location = null, - }; - return symbol[0..1]; + }); + return symbols.toOwnedSlice(gpa); }; - symbol.* = .{ + symbols.appendAssumeCapacity(.{ .name = ofile_dwarf.getSymbolName(ofile_vaddr) orelse try file.lookupSymbolName(vaddr), .compile_unit_name = compile_unit.die.getAttrString( @@ -96,18 +101,8 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug compile_unit, ofile_vaddr, ) catch null, - }; - return symbol[0..1]; -} -pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { - _ = si; - const gpa = std.debug.getDebugInfoAllocator(); - for (symbols) |symbol| { - if (symbol.source_location) |source_location| { - gpa.free(source_location.file_name); - } - } - gpa.free(symbols); + }); + return symbols.toOwnedSlice(gpa); } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { _ = si; diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index d2a28803b133f3811c5fa6c0a062417d023d20db..3a4d7b68786a6a92beba26f3c2dc4cb01fff417d 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -25,24 +25,13 @@ pub fn deinit(si: *SelfInfo, io: Io) void { si.modules.deinit(gpa); } -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { +pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { const gpa = std.debug.getDebugInfoAllocator(); try si.lock.lockShared(io); defer si.lock.unlockShared(io); const module = try si.findModule(gpa, address); const di = try module.getDebugInfo(gpa, io); - return di.getSymbols(gpa, address - @intFromPtr(module.entry.DllBase)); -} - -pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { - _ = si; - const gpa = std.debug.getDebugInfoAllocator(); - for (symbols) |symbol| { - if (symbol.source_location) |source_location| { - gpa.free(source_location.file_name); - } - } - gpa.free(symbols); + return di.getSymbols(gpa, address - @intFromPtr(module.entry.DllBase), resolve_inline_callers); } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { @@ -252,7 +241,7 @@ const Module = struct { arena.deinit(); } - fn getSymbols(di: *DebugInfo, gpa: Allocator, vaddr: usize) Error![]const std.debug.Symbol { + fn getSymbols(di: *DebugInfo, gpa: Allocator, vaddr: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { pdb: { const pdb = &(di.pdb orelse break :pdb); var coff_section: *align(1) const coff.SectionHeader = undefined; @@ -285,8 +274,12 @@ const Module = struct { const addr = vaddr - coff_section.virtual_address; const maybe_proc = pdb.getProcSym(module, addr); - var symbols: std.ArrayList(std.debug.Symbol) = .empty; - errdefer symbols.deinit(gpa); + const compile_unit_name = fs.path.basename(module.obj_file_name); + var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); + errdefer { + for (symbols.items) |*symbol| symbol.deinit(gpa); + symbols.deinit(gpa); + } if (maybe_proc) |proc| { const offset_in_func = addr - proc.code_offset; @@ -315,25 +308,43 @@ const Module = struct { if (inline_site.inlinee == last_inlinee) continue; last_inlinee = inline_site.inlinee; + // If we're appending this symbol, resolve the name. If we're replacing the + // last symbol, clear the previous symbols and wait to resolve the name + // until we've reached the last symbol to avoid doing work and then + // throwing it out. + const name = b: { + if (resolve_inline_callers) break :b pdb.findInlineeName(inline_site.inlinee); + symbols.items.len = 0; + break :b null; + }; + try symbols.append(gpa, .{ - .name = pdb.findInlineeName(inline_site.inlinee), - .compile_unit_name = fs.path.basename(module.obj_file_name), + .name = name, + .compile_unit_name = compile_unit_name, .source_location = loc, }); } - // Inline sites are stored in the pdb in reverse order, so we reverse the - // matching sites here. We could alternatively use the parent fields to - // determine the order, but this would introduce seemingly unecessary - // complexity. - std.mem.reverse(std.debug.Symbol, symbols.items); + if (resolve_inline_callers) { + // Inline sites are stored in the pdb in reverse order, so we reverse the + // matching sites here. We could alternatively use the parent fields to + // determine the order, but this would introduce seemingly unecessary + // complexity. + std.mem.reverse(std.debug.Symbol, symbols.items); + } else if (last_inlinee) |inlinee| { + // If we haven't resolved the name yet, resolve it now + symbols.items[symbols.items.len - 1].name = pdb.findInlineeName(inlinee); + } } - try symbols.append(gpa, .{ - .name = if (maybe_proc) |proc| pdb.getSymbolName(proc) else null, - .compile_unit_name = fs.path.basename(module.obj_file_name), - .source_location = pdb.getLineNumberInfo(module, addr) catch null, - }); + // If there's room for another symbol, add the actual proc + if (resolve_inline_callers or symbols.items.len == 0) { + try symbols.append(gpa, .{ + .name = if (maybe_proc) |proc| pdb.getSymbolName(proc) else null, + .compile_unit_name = compile_unit_name, + .source_location = pdb.getLineNumberInfo(module, addr) catch null, + }); + } return symbols.toOwnedSlice(gpa); } @@ -341,7 +352,7 @@ const Module = struct { dwarf: { const dwarf = &(di.dwarf orelse break :dwarf); const addr = vaddr + di.coff_image_base; - return dwarf.getSymbols(gpa, native_endian, addr); + return dwarf.getSymbols(gpa, native_endian, addr, resolve_inline_callers); } return error.MissingDebugInfo; -- 2.54.0 From 334f40576e48e7204455f264c883f9ea86588e1a Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sat, 11 Apr 2026 01:01:22 -0700 Subject: [PATCH 20/29] Cleans up some PDB parsing logic --- lib/std/debug/Pdb.zig | 63 +++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index b76ed9e47c7602bb7f50abb2bca5349410fc1c63..38a2d50cc94b8971767f62c0605de2c157c3804e 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -315,6 +315,21 @@ pub const BinaryAnnotation = union(enum) { file_id: ?u32, code_offset: u32, code_length: ?u32, + + /// Resolves a partial range to a range with a definite length, or returns null if this + /// is not possible. + fn resolve(self: PartialRange, next_code_offset: ?u32) ?Range { + return .{ + .line_offset = self.line_offset, + .file_id = self.file_id, + .code_offset = self.code_offset, + .code_length = b: { + if (self.code_length) |l| break :b l; + const end = next_code_offset orelse return null; + break :b end - self.code_offset; + }, + }; + } }; pub fn init(annotations: Iterator) RangeIterator { @@ -391,6 +406,8 @@ pub const BinaryAnnotation = union(enum) { }, } + // If we have a new code offset, return the previous range if it exists, resolving + // its length if necessary. switch (annotation) { .change_code_offset, .change_code_offset_and_line_offset, @@ -398,38 +415,16 @@ pub const BinaryAnnotation = union(enum) { => {}, else => continue, } - - if (self.prev) |*prev| { - if (prev.code_length == null) { - prev.code_length = self.curr.code_offset - prev.code_offset; - } - } - - defer self.prev = .{ - .code_offset = self.curr.code_offset, - .code_length = self.curr.code_length, - .line_offset = self.curr.line_offset, - .file_id = self.curr.file_id, - }; + defer self.prev = self.curr; const prev = self.prev orelse continue; - const prev_code_length = prev.code_length orelse continue; - return .{ - .code_offset = prev.code_offset, - .code_length = prev_code_length, - .line_offset = prev.line_offset, - .file_id = prev.file_id, - }; + return prev.resolve(self.curr.code_offset); } + // If we've processed all the binary operations but still have a previous range leftover + // with a known length, return it. const prev = self.prev orelse return null; defer self.prev = null; - const prev_code_length = prev.code_length orelse return null; - return .{ - .code_offset = prev.code_offset, - .code_length = prev_code_length, - .line_offset = prev.line_offset, - .file_id = prev.file_id, - }; + return prev.resolve(null); } }; @@ -452,6 +447,10 @@ pub const BinaryAnnotation = union(enum) { try takePackedU32(reader), ) orelse return error.ReadFailed; switch (op) { + // Microsoft's docs say that invalid is used as padding, though it is left ambiguous + // whether padding is allowed internally or only after all instructions are complete. + // Empircally, the latter appears to be the case, at lest with the output from LLVM that + // I've tested. .invalid => return error.EndOfStream, .code_offset => return .{ .code_offset = try expect(takePackedU32(reader)), @@ -547,13 +546,19 @@ pub const BinaryAnnotation = union(enum) { }; pub fn findInlineeName(self: *const Pdb, inlinee: u32) ?[]const u8 { + // According to LLVM, the high bit *can* be used to indicate that a type index comes from the + // ipi stream in which case that bit needs to be cleared. LLVM doesn't generate data in this + // manner, but we may as well handle it since it just involves a single bitwise and. + // https://llvm.org/docs/PDB/TpiStream.html#type-indices + const type_index = inlinee & 0x7FFFFFFF; + var reader: Io.Reader = .fixed(self.ipi orelse return null); const header = reader.takeStructPointer(pdb.IpiStreamHeader) catch return null; - for (header.type_index_begin..header.type_index_end) |type_index| { + for (header.type_index_begin..header.type_index_end) |curr_type_index| { const prefix = reader.takeStructPointer(pdb.LfRecordPrefix) catch return null; reader.discardAll(prefix.len - @sizeOf(@FieldType(pdb.LfRecordPrefix, "len"))) catch return null; - if (type_index == inlinee) { + if (curr_type_index == type_index) { switch (prefix.kind) { .func_id => { const func: *align(1) pdb.LfFuncId = @ptrCast(prefix); -- 2.54.0 From cbd7f54f06e788f54573dbbe261b9defad32020b Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sat, 11 Apr 2026 02:27:45 -0700 Subject: [PATCH 21/29] Use readers to simplify PDB parsing --- lib/std/debug/Pdb.zig | 67 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index 38a2d50cc94b8971767f62c0605de2c157c3804e..c75df3874808a353bb89e550a028cda94122281d 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -225,14 +225,13 @@ pub fn parseInfoStream(self: *Pdb) !void { pub fn getProcSym(self: *Pdb, module: *Module, address: u64) ?*align(1) pdb.ProcSym { _ = self; - std.debug.assert(module.populated); - - var symbol_i: usize = 0; - while (symbol_i != module.symbols.len) { - const prefix: *align(1) pdb.RecordPrefix = @ptrCast(&module.symbols[symbol_i]); + var reader: Io.Reader = .fixed(module.symbols); + while (true) { + const prefix = reader.takeStructPointer(pdb.RecordPrefix) catch return null; if (prefix.record_len < 2) return null; + reader.discardAll(prefix.record_len - @sizeOf(u16)) catch return null; switch (prefix.record_kind) { .lproc32, .gproc32 => { const proc_sym: *align(1) pdb.ProcSym = @ptrCast(prefix); @@ -242,9 +241,7 @@ pub fn getProcSym(self: *Pdb, module: *Module, address: u64) ?*align(1) pdb.Proc }, else => {}, } - symbol_i += prefix.record_len + @sizeOf(u16); } - return null; } @@ -253,12 +250,17 @@ pub const InlineSiteSymIterator = struct { offset: usize, end: usize, + const empty: InlineSiteSymIterator = .{ + .module_index = 0, + .offset = 0, + .end = 0, + }; + pub fn next(iter: *InlineSiteSymIterator, module: *Module) ?*align(1) pdb.InlineSiteSym { while (iter.offset < iter.end) { const inline_prefix: *align(1) pdb.RecordPrefix = @ptrCast(&module.symbols[iter.offset]); - if (inline_prefix.record_len < 2) - return null; const end = iter.offset + inline_prefix.record_len + @sizeOf(u16); + if (end > iter.end) return null; defer iter.offset = end; switch (inline_prefix.record_kind) { // Skip nested procedures @@ -556,7 +558,8 @@ pub fn findInlineeName(self: *const Pdb, inlinee: u32) ?[]const u8 { const header = reader.takeStructPointer(pdb.IpiStreamHeader) catch return null; for (header.type_index_begin..header.type_index_end) |curr_type_index| { const prefix = reader.takeStructPointer(pdb.LfRecordPrefix) catch return null; - reader.discardAll(prefix.len - @sizeOf(@FieldType(pdb.LfRecordPrefix, "len"))) catch return null; + if (prefix.len < 2) return null; + reader.discardAll(prefix.len - @sizeOf(u16)) catch return null; if (curr_type_index == type_index) { switch (prefix.kind) { @@ -580,7 +583,9 @@ pub fn getInlinees(self: *Pdb, module: *Module, proc_sym: *align(1) const pdb.Pr const offset = @intFromPtr(proc_sym) - @intFromPtr(module.symbols.ptr) + proc_sym.record_len + - @sizeOf(@FieldType(pdb.ProcSym, "record_len")); + @sizeOf(u16); + const symbols_end = @intFromPtr(module.symbols.ptr) + module.symbols.len; + if (offset > symbols_end or proc_sym.end > symbols_end) return .empty; return .{ .module_index = module_index, .offset = offset, @@ -588,17 +593,19 @@ pub fn getInlinees(self: *Pdb, module: *Module, proc_sym: *align(1) const pdb.Pr }; } -pub fn getBinaryAnnotations(self: *Pdb, site: *align(1) const pdb.InlineSiteSym) BinaryAnnotation.Iterator { +pub fn getBinaryAnnotations(self: *Pdb, module: *Module, site: *align(1) const pdb.InlineSiteSym) BinaryAnnotation.Iterator { _ = self; var start: usize = @intFromPtr(site) + @sizeOf(pdb.InlineSiteSym); - var end = start + site.record_len + @sizeOf(@FieldType(pdb.InlineSiteSym, "record_len")) - @sizeOf(pdb.InlineSiteSym); + var end = start + site.record_len + @sizeOf(u16) - @sizeOf(pdb.InlineSiteSym); switch (site.record_kind) { .inlinesite => {}, .inlinesite2 => start += @sizeOf(pdb.InlineSiteSym2) - @sizeOf(pdb.InlineSiteSym), else => end = start, } + if (start < @intFromPtr(module.symbols.ptr) or end > @intFromPtr(module.symbols.ptr) + module.symbols.len) return .empty; + const len = end - start; const ptr: [*]const u8 = @ptrFromInt(start); - const slice = ptr[0..end - start]; + const slice = ptr[0..len]; return .{ .reader = Io.Reader.fixed(slice) }; } @@ -609,7 +616,7 @@ pub fn getInlineSiteSourceLocation( inlinee_src_line: *align(1) const pdb.InlineeSourceLine, offset_in_func: usize, ) !?std.debug.SourceLocation { - var ranges: BinaryAnnotation.RangeIterator = .init(self.getBinaryAnnotations(site)); + var ranges: BinaryAnnotation.RangeIterator = .init(self.getBinaryAnnotations(mod, site)); while (try ranges.next()) |range| { if (!range.contains(offset_in_func)) continue; @@ -658,36 +665,26 @@ pub fn getInlineeSourceLine( inlinee: u32, ) ?InlineeSourceLine { _ = self; - var sect_offset: usize = 0; - var skip_len: usize = undefined; - while (sect_offset < mod.subsect_info.len) : (sect_offset += skip_len) { - const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&mod.subsect_info[sect_offset]); - skip_len = subsect_hdr.length; - sect_offset += @sizeOf(pdb.DebugSubsectionHeader); - + var subsects: Io.Reader = .fixed(mod.subsect_info); + while (subsects.takeStructPointer(pdb.DebugSubsectionHeader) catch null) |subsect_hdr| { + var subsect: Io.Reader = .fixed(subsects.take(subsect_hdr.length) catch return null); if (subsect_hdr.kind == .inlinee_lines) { - var offset = sect_offset; - const signature: *const align(1) pdb.InlineeSourceLineSignature = @ptrCast(&mod.subsect_info[offset]); - offset += @sizeOf(pdb.InlineeSourceLineSignature); - - const has_extra_files = switch (signature.*) { + const signature = subsect.takeEnum(pdb.InlineeSourceLineSignature, .little) catch return null; + const has_extra_files = switch (signature) { .normal => false, .ex => true, else => continue, }; - while (offset < sect_offset + subsect_hdr.length) { - const inlinee_src_line: *const align(1) pdb.InlineeSourceLine = @ptrCast(&mod.subsect_info[offset]); - offset += @sizeOf(pdb.InlineeSourceLine); - + while (subsect.takeStructPointer(pdb.InlineeSourceLine) catch null) |inlinee_src_line| { if (has_extra_files) { - const file_count: *const align(1) u32 = @ptrCast(&mod.subsect_info[offset]); - offset += @sizeOf(u32); - offset += file_count.* * @sizeOf(u32); + const file_count = subsect.takeInt(u32, .little) catch return null; + const file_bytes = std.math.mul(usize, file_count, @sizeOf(u32)) catch return null; + subsect.discardAll(file_bytes) catch return null; } if (inlinee_src_line.inlinee == inlinee) return .{ - .signature = signature.*, + .signature = signature, .info = inlinee_src_line, }; } -- 2.54.0 From ac207073f3426e615e7d4735994f73f67af7ee8e Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sat, 11 Apr 2026 16:04:57 -0700 Subject: [PATCH 22/29] Reverts renaming of builtin.StackTrace -> ErrorReturnTrace We can defer this change until the next time zig1 needs to be updated --- doc/langref.html.in | 2 +- lib/build-web/main.zig | 2 +- lib/docs/wasm/main.zig | 2 +- lib/std/builtin.zig | 2 +- lib/std/debug.zig | 4 +- src/Sema.zig | 45 ++++++++++--------- src/Zcu.zig | 4 +- src/codegen/llvm.zig | 2 +- .../panic_has_source_location.zig | 2 +- test/cases/safety/@alignCast misaligned.zig | 2 +- .../@enumFromInt - no matching tag value.zig | 2 +- ...numFromInt truncated bits - exhaustive.zig | 2 +- ...FromInt truncated bits - nonexhaustive.zig | 2 +- ...rCast error not present in destination.zig | 2 +- ...ast error union casted to disjoint set.zig | 2 +- test/cases/safety/@intCast to u0.zig | 2 +- ...at cannot fit - boundary case - i0 max.zig | 2 +- ...at cannot fit - boundary case - i0 min.zig | 2 +- ...annot fit - boundary case - signed max.zig | 2 +- ...annot fit - boundary case - signed min.zig | 2 +- ...at cannot fit - boundary case - u0 max.zig | 2 +- ...at cannot fit - boundary case - u0 min.zig | 2 +- ...not fit - boundary case - unsigned max.zig | 2 +- ...not fit - boundary case - unsigned min.zig | 2 +- ...annot fit - boundary case - vector max.zig | 2 +- ...annot fit - boundary case - vector min.zig | 2 +- ...oat cannot fit - negative out of range.zig | 2 +- ...loat cannot fit - negative to unsigned.zig | 2 +- ...oat cannot fit - positive out of range.zig | 2 +- ...o to non-optional byte-aligned pointer.zig | 2 +- ...t address zero to non-optional pointer.zig | 2 +- .../@ptrFromInt with misaligned address.zig | 2 +- .../@tagName on corrupted enum value.zig | 2 +- .../@tagName on corrupted union value.zig | 2 +- .../array slice sentinel mismatch vector.zig | 2 +- .../safety/array slice sentinel mismatch.zig | 2 +- test/cases/safety/bad union field access.zig | 2 +- test/cases/safety/calling panic.zig | 2 +- ...ast []u8 to bigger slice of wrong size.zig | 2 +- ...er to global error and no code matches.zig | 2 +- ...mpty slice with sentinel out of bounds.zig | 2 +- .../exact division failure - vectors.zig | 2 +- test/cases/safety/exact division failure.zig | 2 +- test/cases/safety/for_len_mismatch.zig | 2 +- test/cases/safety/for_len_mismatch_three.zig | 2 +- .../ignored expression integer overflow.zig | 2 +- .../safety/integer addition overflow.zig | 2 +- .../integer division by zero - vectors.zig | 2 +- .../cases/safety/integer division by zero.zig | 2 +- .../integer multiplication overflow.zig | 2 +- .../safety/integer negation overflow.zig | 2 +- .../safety/integer subtraction overflow.zig | 2 +- test/cases/safety/memcpy_alias.zig | 2 +- test/cases/safety/memcpy_len_mismatch.zig | 2 +- test/cases/safety/memmove_len_mismatch.zig | 2 +- .../safety/memset_array_undefined_bytes.zig | 2 +- .../safety/memset_array_undefined_large.zig | 2 +- .../safety/memset_slice_undefined_bytes.zig | 2 +- .../safety/memset_slice_undefined_large.zig | 2 +- test/cases/safety/modrem by zero.zig | 2 +- test/cases/safety/modulus by zero.zig | 2 +- test/cases/safety/noreturn returned.zig | 2 +- .../optional unwrap operator on C pointer.zig | 2 +- ...tional unwrap operator on null pointer.zig | 2 +- .../cases/safety/optional_empty_error_set.zig | 2 +- .../out of bounds array slice by length.zig | 2 +- .../safety/out of bounds slice access.zig | 2 +- ...r casting null to non-optional pointer.zig | 2 +- ...inter casting to null function pointer.zig | 2 +- .../pointer slice sentinel mismatch.zig | 2 +- .../safety/remainder division by zero.zig | 2 +- .../safety/shift left by huge amount.zig | 2 +- .../safety/shift right by huge amount.zig | 2 +- ...ed integer division overflow - vectors.zig | 2 +- .../signed integer division overflow.zig | 2 +- ...in cast to unsigned integer - widening.zig | 2 +- ...ot fitting in cast to unsigned integer.zig | 2 +- .../safety/signed shift left overflow.zig | 2 +- .../safety/signed shift right overflow.zig | 2 +- .../safety/signed-unsigned vector cast.zig | 2 +- ...ice by length sentinel mismatch on lhs.zig | 2 +- ...ice by length sentinel mismatch on rhs.zig | 2 +- .../slice sentinel mismatch - floats.zig | 2 +- ... sentinel mismatch - optional pointers.zig | 2 +- .../safety/slice slice sentinel mismatch.zig | 2 +- ...ice start index greater than end index.zig | 2 +- ...h sentinel out of bounds - runtime len.zig | 2 +- .../slice with sentinel out of bounds.zig | 2 +- test/cases/safety/slice_cast_change_len_0.zig | 2 +- test/cases/safety/slice_cast_change_len_1.zig | 2 +- test/cases/safety/slice_cast_change_len_2.zig | 2 +- .../slicing null C pointer - runtime len.zig | 2 +- test/cases/safety/slicing null C pointer.zig | 2 +- ...else on corrupt enum value - one prong.zig | 2 +- ...tch else on corrupt enum value - union.zig | 2 +- .../switch else on corrupt enum value.zig | 2 +- .../safety/switch on corrupted enum value.zig | 2 +- .../switch on corrupted union value.zig | 2 +- test/cases/safety/truncating vector cast.zig | 2 +- test/cases/safety/unreachable.zig | 2 +- ...ast to signed integer - same bit count.zig | 2 +- .../safety/unsigned shift left overflow.zig | 2 +- .../safety/unsigned shift right overflow.zig | 2 +- .../safety/unsigned-signed vector cast.zig | 2 +- test/cases/safety/unwrap error switch.zig | 2 +- test/cases/safety/unwrap error.zig | 2 +- ...e does not fit in shortening cast - u0.zig | 2 +- .../value does not fit in shortening cast.zig | 2 +- .../vector integer addition overflow.zig | 2 +- ...vector integer multiplication overflow.zig | 2 +- .../vector integer negation overflow.zig | 2 +- .../vector integer subtraction overflow.zig | 2 +- test/cases/safety/zero casted to error.zig | 2 +- test/cases/tail_call_noreturn.zig | 4 +- test/standalone/compile_asm/main.zig | 2 +- test/standalone/issue_339/test.zig | 2 +- test/tests.zig | 2 +- 117 files changed, 142 insertions(+), 141 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 0d2564a23935821462732926d5fb647233f09b2e..9f32e05896e3eccf237f6388b79198f65c90a0b8 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4900,7 +4900,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val {#header_close#} {#header_open|@errorReturnTrace#} -

{#syntax#}@errorReturnTrace() ?*builtin.ErrorReturnTrace{#endsyntax#}
+
{#syntax#}@errorReturnTrace() ?*builtin.StackTrace{#endsyntax#}

If the binary is built with error return tracing, and this function is invoked in a function that calls a function with an error or error union return type, returns a diff --git a/lib/build-web/main.zig b/lib/build-web/main.zig index 5899e5626563f9d82721569479e38e81abfada4f..e71c47707b2a5fa6f93df8398ccf7778c1a81b9d 100644 --- a/lib/build-web/main.zig +++ b/lib/build-web/main.zig @@ -40,7 +40,7 @@ pub const std_options: std.Options = .{ .logFn = logFn, }; -pub fn panic(msg: []const u8, st: ?*std.debug.StackTrace, addr: ?usize) noreturn { +pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noreturn { _ = st; _ = addr; log.err("panic: {s}", .{msg}); diff --git a/lib/docs/wasm/main.zig b/lib/docs/wasm/main.zig index dadc6a34926debd48caa1de9500c818ce329b38f..bee3e4acbcc370261f3b137d40584ea2ad2f8065 100644 --- a/lib/docs/wasm/main.zig +++ b/lib/docs/wasm/main.zig @@ -33,7 +33,7 @@ pub const std_options: std.Options = .{ //.log_level = .debug, }; -pub fn panic(msg: []const u8, st: ?*std.debug.StackTrace, addr: ?usize) noreturn { +pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noreturn { _ = st; _ = addr; log.err("panic: {s}", .{msg}); diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 04959733c1b6adb7f8b71bccff2a1fad43e85b5c..00ae6199d1d9cdf96e8202a29b3f0b7385b5d387 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -8,7 +8,7 @@ pub const assembly = @import("builtin/assembly.zig"); /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const ErrorReturnTrace = struct { +pub const StackTrace = struct { index: usize, instruction_addresses: []usize, }; diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 1cda6b50180b496b2f00d50aa6a78e216da3226e..afd47d981d465b6795661196dd9ee0c738ad9a59 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -816,7 +816,7 @@ pub const FormatStackTrace = struct { }; /// Write a previously captured error return trace to `writer`, annotated with source locations. -pub fn writeErrorReturnTrace(et: *const std.builtin.ErrorReturnTrace, t: Io.Terminal) Writer.Error!void { +pub fn writeErrorReturnTrace(et: *const std.builtin.StackTrace, t: Io.Terminal) Writer.Error!void { // We take the slice by value, preventing the length from being mutated if an error occurs while // writing the stack trace. const len = @min(et.instruction_addresses.len, et.index); @@ -885,7 +885,7 @@ pub fn dumpStackTrace(st: *const StackTrace) void { } /// A thin wrapper around `writeErrorReturnTrace` which writes to stderr and ignores write errors. -pub fn dumpErrorReturnTrace(et: *const std.builtin.ErrorReturnTrace) void { +pub fn dumpErrorReturnTrace(et: *const std.builtin.StackTrace) void { const stderr = lockStderr(&.{}).terminal(); defer unlockStderr(); writeErrorReturnTrace(et, stderr) catch |err| switch (err) { diff --git a/src/Sema.zig b/src/Sema.zig index 1767e058e0d627e663a41236a69bdc6d7f3c3a22..4702241a71aba52188f51cd1605131785673f95d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2252,8 +2252,9 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) }); const addrs_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(addr_arr_ty)); - const error_return_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .ErrorReturnTrace); - const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(error_return_trace_ty)); + // var st: StackTrace = undefined; + const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); + const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(stack_trace_ty)); // st.instruction_addresses = &addrs; const instruction_addresses_field_name = try ip.getOrPutString(gpa, io, pt.tid, "instruction_addresses", .no_embedded_nulls); @@ -6165,10 +6166,10 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref if (!block.ownerModule().error_tracing) return .none; - const error_return_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .ErrorReturnTrace); + const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); - const field_index = sema.structFieldIndex(block, error_return_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { - error.AnalysisFail => @panic("std.builtin.ErrorReturnTrace is corrupt"), + const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { + error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"), error.ComptimeReturn, error.ComptimeBreak => unreachable, error.OutOfMemory, error.Canceled => |e| return e, }; @@ -6176,7 +6177,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref return try block.addInst(.{ .tag = .save_err_return_trace_index, .data = .{ .ty_pl = .{ - .ty = Air.internedToRef(error_return_trace_ty.toIntern()), + .ty = Air.internedToRef(stack_trace_ty.toIntern()), .payload = @intCast(field_index), } }, }); @@ -6208,11 +6209,11 @@ fn popErrorReturnTrace( // AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or // the result is comptime-known to be a non-error. Either way, pop unconditionally. - const error_return_trace_ty = try sema.getBuiltinType(src, .ErrorReturnTrace); - const ptr_error_return_trace_ty = try pt.singleMutPtrType(error_return_trace_ty); - const err_return_trace = try block.addTy(.err_return_trace, ptr_error_return_trace_ty); + const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace); + const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); + const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); - const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, error_return_trace_ty); + const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty); try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); } else if (is_non_error == null) { // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need @@ -6233,11 +6234,11 @@ fn popErrorReturnTrace( defer then_block.instructions.deinit(gpa); // If non-error, then pop the error return trace by restoring the index. - const error_return_trace_ty = try sema.getBuiltinType(src, .ErrorReturnTrace); - const ptr_error_return_trace_ty = try pt.singleMutPtrType(error_return_trace_ty); - const err_return_trace = try then_block.addTy(.err_return_trace, ptr_error_return_trace_ty); + const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace); + const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); + const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); - const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, error_return_trace_ty); + const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty); try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); _ = try then_block.addBr(cond_block_inst, .void_value); @@ -6372,15 +6373,15 @@ fn zirCall( // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only // need to clean-up our own trace if we were passed to a non-error-handling expression. if (input_is_error or (pop_error_return_trace and return_ty.isError(zcu))) { - const error_return_trace_ty = try sema.getBuiltinType(call_src, .ErrorReturnTrace); + const stack_trace_ty = try sema.getBuiltinType(call_src, .StackTrace); const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); - const field_index = try sema.structFieldIndex(block, error_return_trace_ty, field_name, call_src); + const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); // Insert a save instruction before the arg resolution + call instructions we just generated const save_inst = try block.insertInst(block_index, .{ .tag = .save_err_return_trace_index, .data = .{ .ty_pl = .{ - .ty = Air.internedToRef(error_return_trace_ty.toIntern()), + .ty = Air.internedToRef(stack_trace_ty.toIntern()), .payload = @intCast(field_index), } }, }); @@ -19528,13 +19529,13 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - const error_return_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .ErrorReturnTrace); - const ptr_error_return_trace_ty = try pt.singleMutPtrType(error_return_trace_ty); - const opt_ptr_error_return_trace_ty = try pt.optionalType(ptr_error_return_trace_ty.toIntern()); + const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); + const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); + const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern()); switch (sema.owner.unwrap()) { .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) { - return block.addTy(.err_return_trace, opt_ptr_error_return_trace_ty); + return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); }, .@"comptime", @@ -19546,7 +19547,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { => {}, } return Air.internedToRef(try pt.intern(.{ .opt = .{ - .ty = opt_ptr_error_return_trace_ty.toIntern(), + .ty = opt_ptr_stack_trace_ty.toIntern(), .val = .none, } })); } diff --git a/src/Zcu.zig b/src/Zcu.zig index 9b56b68c69f06cbfc1b4af238c3fdd5a389c025e..88258b236acf77c69a5b3e97b2d9e20ebc346c04 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -434,7 +434,7 @@ pub const BuiltinDecl = enum { AddressSpace, CallingConvention, returnError, - ErrorReturnTrace, + StackTrace, SourceLocation, CallModifier, AtomicOrder, @@ -512,7 +512,7 @@ pub const BuiltinDecl = enum { return switch (decl) { .returnError => .func, - .ErrorReturnTrace, + .StackTrace, .CallingConvention, .SourceLocation, .Signedness, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index b138c852621e81bad93f3c462efb52d02db71a08..1ba3b272da797e44061a16136a8269fb3c61b195 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3374,7 +3374,7 @@ pub const Object = struct { } if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) { - // First parameter is a pointer to `std.builtin.ErrorReturnTrace`. + // First parameter is a pointer to `std.builtin.StackTrace`. const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(.generic, target)); try llvm_params.append(o.gpa, llvm_ptr_ty); } diff --git a/test/cases/compile_errors/panic_has_source_location.zig b/test/cases/compile_errors/panic_has_source_location.zig index 2db115ebf66d39a7c27e44d3d9b404af2ca20174..a04d89c3ee3a9dd134fbe037a9ead08f59cd1edf 100644 --- a/test/cases/compile_errors/panic_has_source_location.zig +++ b/test/cases/compile_errors/panic_has_source_location.zig @@ -6,7 +6,7 @@ export fn foo() void { @panic("oh no"); } -pub fn panic(_: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { @compileError("panic"); } diff --git a/test/cases/safety/@alignCast misaligned.zig b/test/cases/safety/@alignCast misaligned.zig index 92b2badb5a056e9ef05e77b4098cd05ff8f50efa..f5e0dc87a7923dde14215dc4383477ee24830775 100644 --- a/test/cases/safety/@alignCast misaligned.zig +++ b/test/cases/safety/@alignCast misaligned.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "incorrect alignment")) { std.process.exit(0); diff --git a/test/cases/safety/@enumFromInt - no matching tag value.zig b/test/cases/safety/@enumFromInt - no matching tag value.zig index e9bb3a2abc0ccdb69c1709580c3b5ea673d02354..35d23b2be7543f1f4f92e84408e5ea7491e34a7f 100644 --- a/test/cases/safety/@enumFromInt - no matching tag value.zig +++ b/test/cases/safety/@enumFromInt - no matching tag value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); diff --git a/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig b/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig index f93677cf7e01a6888a6f7165498df060a0594210..4edbfae996280f074e9600f65e5c5aae5b646882 100644 --- a/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig +++ b/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); } diff --git a/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig b/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig index f7bcd690634919b703dfa5958f2833609f672c26..16e4699478c5f0448211fbe855a1eecadab0fd6e 100644 --- a/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig +++ b/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); } diff --git a/test/cases/safety/@errorCast error not present in destination.zig b/test/cases/safety/@errorCast error not present in destination.zig index b7a7b2ae2ab531be8644d9de6702fb002c8a5655..bb8379042b279d385b91d12db0328fdd595c2a5e 100644 --- a/test/cases/safety/@errorCast error not present in destination.zig +++ b/test/cases/safety/@errorCast error not present in destination.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid error code")) { std.process.exit(0); diff --git a/test/cases/safety/@errorCast error union casted to disjoint set.zig b/test/cases/safety/@errorCast error union casted to disjoint set.zig index a8b0b8dcfaa846df7b6fb1b374597ac794c1e753..267c136e9e8b139c9bdc78c9aa1daa17ded5871d 100644 --- a/test/cases/safety/@errorCast error union casted to disjoint set.zig +++ b/test/cases/safety/@errorCast error union casted to disjoint set.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid error code")) { std.process.exit(0); diff --git a/test/cases/safety/@intCast to u0.zig b/test/cases/safety/@intCast to u0.zig index 0649df2fb1bb37b22684b2a5c8b8bb8b92c55ba4..180ee78512fccc28ba1b33ef2b78e0570f0044cb 100644 --- a/test/cases/safety/@intCast to u0.zig +++ b/test/cases/safety/@intCast to u0.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig index 2b3a9c35562e7553c2e1f809128957bed00c8863..dd5c62e07cc10c5f317c60eb96ff6603fd6297d2 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig index 65a3d904c27770d438061333a51687ff077553ac..0b0fab15d9ca8ec6abbdb1b85c86bde0b4f2dd4b 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig index fda0fbd8c184bb951ed3c8fae3c6653b3006c312..8c42449a87a8b8c6a1d5dc28763864b34f6fca4d 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig index 847a65e3aee059bf156684526483a3fd8e42bfbc..49cee6a78613742cb8ac22dc7110ec906d207f7d 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig index 748d89e12a1e8bbd4ed5283a6c205b8e2cea2bb5..0a786bff7baaced248118379e0fc586b6ee8932b 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig index ab43e1d9e8e1895c7916941dfd380cf93f2077ea..07f5ff3e42b1cf2ee315c84d1f889c8510a1bd4a 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig index f28cc6de0c2110a22d6a846e5edcbdc9b8ba40bd..e54bc221da96a0562862c01b81106bf97f8ab2bf 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig index af03ad840a26d288a3ec60cd12dc79adc9fd0df4..90bbb696e274792bbc0be62939124096410e8dc1 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig index f2b25df616080eb1bcdda4152ae3a0810e3cf669..77b1ef5a14fe37276ba85d468acb196240932881 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig index 8e5208a882d20bba75b445c637cfc44544eb303c..095298e6facfca3d405da16b71e7a6967f69af3e 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig @@ -1,5 +1,5 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig b/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig index 95e077c774fa83ffd13485319f8ed91e6ddf8678..b67604541cec32e182f68c5d447f9b4cdf040e54 100644 --- a/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig +++ b/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig b/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig index 74cb95297a24aaead6bb48fb0bed5de39eed3de9..f6e6f4662cf7c37d1683a5deb60ff9a679ac3c3d 100644 --- a/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig +++ b/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig b/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig index faba3ffa639b2c5bf9efb3e987cd78fcb229ecf0..594cedf8ed0d31ebf0d4bf21271daffc009670cc 100644 --- a/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig +++ b/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) { std.process.exit(0); diff --git a/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig b/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig index ce9aa416493935048a5bb8e46882f0d1d04b5e20..16630b6f6a7dc374e998a4359b9e761c23659bf3 100644 --- a/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig +++ b/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "cast causes pointer to be null")) { std.process.exit(0); diff --git a/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig b/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig index 3b162c85e4b50cc162e1ac99ba13be798b3e38f1..21cfda643470e04be687f796323fc30cf2101d59 100644 --- a/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig +++ b/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "cast causes pointer to be null")) { std.process.exit(0); diff --git a/test/cases/safety/@ptrFromInt with misaligned address.zig b/test/cases/safety/@ptrFromInt with misaligned address.zig index 7f2e527c1f498864355a035f64b2e0c249f644fd..81e2ffb91ef238d758deb6ff7a7184579219f8e5 100644 --- a/test/cases/safety/@ptrFromInt with misaligned address.zig +++ b/test/cases/safety/@ptrFromInt with misaligned address.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "incorrect alignment")) { std.process.exit(0); diff --git a/test/cases/safety/@tagName on corrupted enum value.zig b/test/cases/safety/@tagName on corrupted enum value.zig index e1e9f6bb261b6f835778b78c972a34fcf48cc0d2..faf8103880cdc478d1dd2aef8e8311c554bd054f 100644 --- a/test/cases/safety/@tagName on corrupted enum value.zig +++ b/test/cases/safety/@tagName on corrupted enum value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); diff --git a/test/cases/safety/@tagName on corrupted union value.zig b/test/cases/safety/@tagName on corrupted union value.zig index 01d1e7f882732be6c1b4bf900169c173719d8e24..73e62a60b8ffcc3e0e6250c45dbd5a8d1030cac3 100644 --- a/test/cases/safety/@tagName on corrupted union value.zig +++ b/test/cases/safety/@tagName on corrupted union value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid enum value")) { std.process.exit(0); diff --git a/test/cases/safety/array slice sentinel mismatch vector.zig b/test/cases/safety/array slice sentinel mismatch vector.zig index 408d18f2842e91648e8610d17847076c7eddf156..723288c437ea4d4ed4fcf7d93267a2db578600e5 100644 --- a/test/cases/safety/array slice sentinel mismatch vector.zig +++ b/test/cases/safety/array slice sentinel mismatch vector.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected { 0, 0 }, found { 4, 4 }")) { std.process.exit(0); diff --git a/test/cases/safety/array slice sentinel mismatch.zig b/test/cases/safety/array slice sentinel mismatch.zig index f58e43ab03a94951c778867879aae0b0628a3224..49e9d8caaad5a0c145a151a5286f894bf144e87c 100644 --- a/test/cases/safety/array slice sentinel mismatch.zig +++ b/test/cases/safety/array slice sentinel mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) { std.process.exit(0); diff --git a/test/cases/safety/bad union field access.zig b/test/cases/safety/bad union field access.zig index 68568729f21471186c4c288b019f1ba7926c8ea7..7cf0c30417ca14b3439662cddc5f0ca8a296eeb6 100644 --- a/test/cases/safety/bad union field access.zig +++ b/test/cases/safety/bad union field access.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "access of union field 'float' while field 'int' is active")) { std.process.exit(0); diff --git a/test/cases/safety/calling panic.zig b/test/cases/safety/calling panic.zig index 23455e1d4553c9c2af277a66fcd5707dfebc0751..d77104bbb39e6b6f0ab70138faee5c403a2953a7 100644 --- a/test/cases/safety/calling panic.zig +++ b/test/cases/safety/calling panic.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "oh no")) { std.process.exit(0); diff --git a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig index 220a215a9cc1e9057aa6f958831c3b8d3a68ddad..de15051993518235a1f7ff42d3b0cedfb5a4b5b5 100644 --- a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig +++ b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "exact division produced remainder")) { std.process.exit(0); diff --git a/test/cases/safety/cast integer to global error and no code matches.zig b/test/cases/safety/cast integer to global error and no code matches.zig index 4570c44dcde5ddda49201093dade7655577c560e..51adb1ac1e8dc7f2705e31d1b3ff6a09d25825d6 100644 --- a/test/cases/safety/cast integer to global error and no code matches.zig +++ b/test/cases/safety/cast integer to global error and no code matches.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid error code")) { std.process.exit(0); diff --git a/test/cases/safety/empty slice with sentinel out of bounds.zig b/test/cases/safety/empty slice with sentinel out of bounds.zig index fab386becd991618300fe2eb945bc915b82ac155..1dacc309587582870dbe94e9e5639cd047a3ffcf 100644 --- a/test/cases/safety/empty slice with sentinel out of bounds.zig +++ b/test/cases/safety/empty slice with sentinel out of bounds.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 1, len 0")) { std.process.exit(0); diff --git a/test/cases/safety/exact division failure - vectors.zig b/test/cases/safety/exact division failure - vectors.zig index 22bd4a924b2fbff185fe656d0d3365464c071b03..0693b7b1286d7310129c112716d3643fc3568bc5 100644 --- a/test/cases/safety/exact division failure - vectors.zig +++ b/test/cases/safety/exact division failure - vectors.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "exact division produced remainder")) { std.process.exit(0); diff --git a/test/cases/safety/exact division failure.zig b/test/cases/safety/exact division failure.zig index f9b4677f01d8bb93edfd9202de7b776c94a2a788..262f921e923805f599afcdc1f8db94b0098991d6 100644 --- a/test/cases/safety/exact division failure.zig +++ b/test/cases/safety/exact division failure.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "exact division produced remainder")) { std.process.exit(0); diff --git a/test/cases/safety/for_len_mismatch.zig b/test/cases/safety/for_len_mismatch.zig index 1887eb97e384f0d1c27525c4c0f760134d8d7709..4b9affab36f2648de12387826668dc462bff2071 100644 --- a/test/cases/safety/for_len_mismatch.zig +++ b/test/cases/safety/for_len_mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "for loop over objects with non-equal lengths")) { std.process.exit(0); diff --git a/test/cases/safety/for_len_mismatch_three.zig b/test/cases/safety/for_len_mismatch_three.zig index 0a0454ab5caff129b453f5910cc8d8042f64be63..aed7479bf26b8cbe23b8b22951c9a026d78e6bde 100644 --- a/test/cases/safety/for_len_mismatch_three.zig +++ b/test/cases/safety/for_len_mismatch_three.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "for loop over objects with non-equal lengths")) { std.process.exit(0); diff --git a/test/cases/safety/ignored expression integer overflow.zig b/test/cases/safety/ignored expression integer overflow.zig index 6d3d9e0af0da5b35c63a18700f52981970a28e44..b92bfd4c266b25870444db4da90f5f409f7df586 100644 --- a/test/cases/safety/ignored expression integer overflow.zig +++ b/test/cases/safety/ignored expression integer overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/integer addition overflow.zig b/test/cases/safety/integer addition overflow.zig index 808938c12298fe3c1a3b9ac587ba61376be2803e..336b4831ac0f37b4860eb51018a35c435c26ef3e 100644 --- a/test/cases/safety/integer addition overflow.zig +++ b/test/cases/safety/integer addition overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/integer division by zero - vectors.zig b/test/cases/safety/integer division by zero - vectors.zig index ed0fa971c930b3d836f187349cd897b6de6bd2b6..fe3aefeb1abae6f4ee63cbe701a91c2283f6f42c 100644 --- a/test/cases/safety/integer division by zero - vectors.zig +++ b/test/cases/safety/integer division by zero - vectors.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/integer division by zero.zig b/test/cases/safety/integer division by zero.zig index 7fe895d70e125dac8927aa9e0b30bdb7b1d9abff..a667c7c20658a6444f89f90f5caf6c5935ec2e48 100644 --- a/test/cases/safety/integer division by zero.zig +++ b/test/cases/safety/integer division by zero.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/integer multiplication overflow.zig b/test/cases/safety/integer multiplication overflow.zig index 6a026c2221168fdc7d86449d06fdbcb648534418..311869657b1f988c76280242ece4c59b510e5ccd 100644 --- a/test/cases/safety/integer multiplication overflow.zig +++ b/test/cases/safety/integer multiplication overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/integer negation overflow.zig b/test/cases/safety/integer negation overflow.zig index d5777a6834951cfb77135028361cb832d41fe876..5d2681dee049831b26c0ebdc56faf4abb1242310 100644 --- a/test/cases/safety/integer negation overflow.zig +++ b/test/cases/safety/integer negation overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/integer subtraction overflow.zig b/test/cases/safety/integer subtraction overflow.zig index 758dfa898e1473eaff63f75b13f50c763e730dd6..142f1f44cdd404c56ac2f291d66faa5d99f463a0 100644 --- a/test/cases/safety/integer subtraction overflow.zig +++ b/test/cases/safety/integer subtraction overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/memcpy_alias.zig b/test/cases/safety/memcpy_alias.zig index 5fa007e198d992281abca5997962dfb62b66aa60..cdd5aeb2e251142fd9410103b46615c9f010f47c 100644 --- a/test/cases/safety/memcpy_alias.zig +++ b/test/cases/safety/memcpy_alias.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "@memcpy arguments alias")) { std.process.exit(0); diff --git a/test/cases/safety/memcpy_len_mismatch.zig b/test/cases/safety/memcpy_len_mismatch.zig index e95ae542dbde4b4898d18b2123a8b3e9fe9ec8bf..3728ca2a0173dd97a48371ab31facd0ba32bd3f5 100644 --- a/test/cases/safety/memcpy_len_mismatch.zig +++ b/test/cases/safety/memcpy_len_mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "source and destination arguments have non-equal lengths")) { std.process.exit(0); diff --git a/test/cases/safety/memmove_len_mismatch.zig b/test/cases/safety/memmove_len_mismatch.zig index 4dc28246babe1630867200f6e082d44a3adb5adc..97624a4710dd5e86c9e7d173103b21db1da38c95 100644 --- a/test/cases/safety/memmove_len_mismatch.zig +++ b/test/cases/safety/memmove_len_mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "source and destination arguments have non-equal lengths")) { std.process.exit(0); diff --git a/test/cases/safety/memset_array_undefined_bytes.zig b/test/cases/safety/memset_array_undefined_bytes.zig index 3e6d85f1186f1cf1932c4949d8485ec489081f69..6e374647c38cc979f46e3ca3d5ba5ccd1c319131 100644 --- a/test/cases/safety/memset_array_undefined_bytes.zig +++ b/test/cases/safety/memset_array_undefined_bytes.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/memset_array_undefined_large.zig b/test/cases/safety/memset_array_undefined_large.zig index 479441b7dcbcda0b2705f031235ec542624886e4..3ea5bcc2e790bbdf2d6553e0cbfe3d12c0f5d0e7 100644 --- a/test/cases/safety/memset_array_undefined_large.zig +++ b/test/cases/safety/memset_array_undefined_large.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/memset_slice_undefined_bytes.zig b/test/cases/safety/memset_slice_undefined_bytes.zig index 4514e9a4a6fff19f7f3843529d3214a6dcc38648..e3d8f2a5121629d7d54c6a0a69109bba0f085379 100644 --- a/test/cases/safety/memset_slice_undefined_bytes.zig +++ b/test/cases/safety/memset_slice_undefined_bytes.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/memset_slice_undefined_large.zig b/test/cases/safety/memset_slice_undefined_large.zig index 181cdb50ca41bfb0d7f6d853febae8d2b4d94b9f..5131e592f9a386ae7a0d2e74e42af761d255a886 100644 --- a/test/cases/safety/memset_slice_undefined_large.zig +++ b/test/cases/safety/memset_slice_undefined_large.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/modrem by zero.zig b/test/cases/safety/modrem by zero.zig index 4293baa0e0a0991555c1928d4174ed95c5357450..365eeaba4389920f8f0c8aaf90b2dfa8b6bb5fad 100644 --- a/test/cases/safety/modrem by zero.zig +++ b/test/cases/safety/modrem by zero.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/modulus by zero.zig b/test/cases/safety/modulus by zero.zig index d133ce883a32761e95a02081eeb8408d74c9f7fc..844f6e3b75be682abe3f17b2e9148263fbcc4e82 100644 --- a/test/cases/safety/modulus by zero.zig +++ b/test/cases/safety/modulus by zero.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/noreturn returned.zig b/test/cases/safety/noreturn returned.zig index 3bc6ab68c0e486b7ac460599e2d6773d1e3e9bcc..58e392d224c1fce72ecdc297a743caacb7c45ccd 100644 --- a/test/cases/safety/noreturn returned.zig +++ b/test/cases/safety/noreturn returned.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "'noreturn' function returned")) { std.process.exit(0); diff --git a/test/cases/safety/optional unwrap operator on C pointer.zig b/test/cases/safety/optional unwrap operator on C pointer.zig index 6009c758f01450cd213f9cfa25672e6ea944f766..308d97983592db1fc0aeb2906712761a8faa78a2 100644 --- a/test/cases/safety/optional unwrap operator on C pointer.zig +++ b/test/cases/safety/optional unwrap operator on C pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to use null value")) { std.process.exit(0); diff --git a/test/cases/safety/optional unwrap operator on null pointer.zig b/test/cases/safety/optional unwrap operator on null pointer.zig index 1aae8fa1df3938eb345a0e68b794c0c6420fa29f..63ee03facb462b4fd9972370188ca9713a272387 100644 --- a/test/cases/safety/optional unwrap operator on null pointer.zig +++ b/test/cases/safety/optional unwrap operator on null pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to use null value")) { std.process.exit(0); diff --git a/test/cases/safety/optional_empty_error_set.zig b/test/cases/safety/optional_empty_error_set.zig index 44dea2233b47dee5bde0845dd0349955d1d51450..60e6c5c3eb490955d9d18f198d7b0759bb76ed06 100644 --- a/test/cases/safety/optional_empty_error_set.zig +++ b/test/cases/safety/optional_empty_error_set.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, ra: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, ra: ?usize) noreturn { _ = stack_trace; _ = ra; if (std.mem.eql(u8, message, "attempt to use null value")) { diff --git a/test/cases/safety/out of bounds array slice by length.zig b/test/cases/safety/out of bounds array slice by length.zig index bb8012458143eaa5d7bad6180b24aad2e0e3f143..cc9bb0205a643ad8df46d488b192ed7309d6918c 100644 --- a/test/cases/safety/out of bounds array slice by length.zig +++ b/test/cases/safety/out of bounds array slice by length.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 16, len 5")) { std.process.exit(0); diff --git a/test/cases/safety/out of bounds slice access.zig b/test/cases/safety/out of bounds slice access.zig index c2ea85b864cc7a57489eb07b37908d24f4bfab48..61ae983fbab8ebea65a191b02722f9af9f9defe5 100644 --- a/test/cases/safety/out of bounds slice access.zig +++ b/test/cases/safety/out of bounds slice access.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 4, len 4")) { std.process.exit(0); diff --git a/test/cases/safety/pointer casting null to non-optional pointer.zig b/test/cases/safety/pointer casting null to non-optional pointer.zig index 491dc69dca06f727bf7356882b81986a28b69711..e10297dc49cf00fb006fd5ad2459782bb43f235a 100644 --- a/test/cases/safety/pointer casting null to non-optional pointer.zig +++ b/test/cases/safety/pointer casting null to non-optional pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "cast causes pointer to be null")) { std.process.exit(0); diff --git a/test/cases/safety/pointer casting to null function pointer.zig b/test/cases/safety/pointer casting to null function pointer.zig index bf8d2a502edc71e7f1fd5998a526dde3c10a9be1..892e6cbfd98010617fbcc1551cd90245ede3269f 100644 --- a/test/cases/safety/pointer casting to null function pointer.zig +++ b/test/cases/safety/pointer casting to null function pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "cast causes pointer to be null")) { std.process.exit(0); diff --git a/test/cases/safety/pointer slice sentinel mismatch.zig b/test/cases/safety/pointer slice sentinel mismatch.zig index 5b0f8618c06d548048892726ffc7d374084c0cbe..9ad91109d90de3261c5d1fe5857fbc62e526e744 100644 --- a/test/cases/safety/pointer slice sentinel mismatch.zig +++ b/test/cases/safety/pointer slice sentinel mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) { std.process.exit(0); diff --git a/test/cases/safety/remainder division by zero.zig b/test/cases/safety/remainder division by zero.zig index 4a45e7eee96fbf90846fedd64c7ba4714aaa10a1..754f160c9cad768a2540dc3697944d1daa50ff2f 100644 --- a/test/cases/safety/remainder division by zero.zig +++ b/test/cases/safety/remainder division by zero.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "division by zero")) { std.process.exit(0); diff --git a/test/cases/safety/shift left by huge amount.zig b/test/cases/safety/shift left by huge amount.zig index 591334c1607556eba245a9eaa8dd3a8718ea1f7d..2b67721299bd6a9de1d3d2a20d898cf509c90dac 100644 --- a/test/cases/safety/shift left by huge amount.zig +++ b/test/cases/safety/shift left by huge amount.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "shift amount is greater than the type size")) { std.process.exit(0); diff --git a/test/cases/safety/shift right by huge amount.zig b/test/cases/safety/shift right by huge amount.zig index a537b969c383be23828e2af8461309fdd86fba80..cf836eafa3a3884a490f94bf5d61a3f96147668e 100644 --- a/test/cases/safety/shift right by huge amount.zig +++ b/test/cases/safety/shift right by huge amount.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "shift amount is greater than the type size")) { std.process.exit(0); diff --git a/test/cases/safety/signed integer division overflow - vectors.zig b/test/cases/safety/signed integer division overflow - vectors.zig index a13fc604406f280b0deafad79db20b8581d05c1c..56996e1e32094ca847447d3c3ea3bd3e2c893c95 100644 --- a/test/cases/safety/signed integer division overflow - vectors.zig +++ b/test/cases/safety/signed integer division overflow - vectors.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/signed integer division overflow.zig b/test/cases/safety/signed integer division overflow.zig index 1742386258e789e5f4e26aecf9868c69d88133f6..fa4b124189678410414211fe9d77c35e0b9a4bf6 100644 --- a/test/cases/safety/signed integer division overflow.zig +++ b/test/cases/safety/signed integer division overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig index 06b792e067c97bf5d53ee898649efc15ad004b2c..be3a0ad662e441d8f803f156b88e2a10b5acc2f3 100644 --- a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig +++ b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig index b1d31ac78a0eeef826aa7fa8d1e7f4f0db174227..fb636c0bce360a1b9f4290c1bd18df65a6682ed1 100644 --- a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig +++ b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/signed shift left overflow.zig b/test/cases/safety/signed shift left overflow.zig index 93e1c5c1e77b9a72158ea15063344d3f7767c065..bd6bc012bb7296236551deda8c1923376121c554 100644 --- a/test/cases/safety/signed shift left overflow.zig +++ b/test/cases/safety/signed shift left overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "left shift overflowed bits")) { std.process.exit(0); diff --git a/test/cases/safety/signed shift right overflow.zig b/test/cases/safety/signed shift right overflow.zig index d51e1e926145ea2d4a09517ccacbba1ed0e7b4e3..6dc5806e4fd042a65c94c1f4e779af349a34bc50 100644 --- a/test/cases/safety/signed shift right overflow.zig +++ b/test/cases/safety/signed shift right overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "right shift overflowed bits")) { std.process.exit(0); diff --git a/test/cases/safety/signed-unsigned vector cast.zig b/test/cases/safety/signed-unsigned vector cast.zig index d6b2377e34e90a1084b525d264fca46817517d14..50be6b84f384e980ecd5d677e7d28a978f492254 100644 --- a/test/cases/safety/signed-unsigned vector cast.zig +++ b/test/cases/safety/signed-unsigned vector cast.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/slice by length sentinel mismatch on lhs.zig b/test/cases/safety/slice by length sentinel mismatch on lhs.zig index 4dbeb2b0f86c41af6acf981de3eebc6958765490..af92f90198e71e261206b0372121a489cbe2a7de 100644 --- a/test/cases/safety/slice by length sentinel mismatch on lhs.zig +++ b/test/cases/safety/slice by length sentinel mismatch on lhs.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 1, found 3")) { std.process.exit(0); diff --git a/test/cases/safety/slice by length sentinel mismatch on rhs.zig b/test/cases/safety/slice by length sentinel mismatch on rhs.zig index 7bfaca25acc3946ff658ef9bc9a8ad30ac6c7357..f9a8730a99ee7d08f039e326fa4f33db2a2ed042 100644 --- a/test/cases/safety/slice by length sentinel mismatch on rhs.zig +++ b/test/cases/safety/slice by length sentinel mismatch on rhs.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 1, found 0")) { std.process.exit(0); diff --git a/test/cases/safety/slice sentinel mismatch - floats.zig b/test/cases/safety/slice sentinel mismatch - floats.zig index 51d9b17b7500236ce68d33a7c59abd6c50d95ab8..30e6b8a85cd0143f200bf4c368553e251f3fa41f 100644 --- a/test/cases/safety/slice sentinel mismatch - floats.zig +++ b/test/cases/safety/slice sentinel mismatch - floats.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 1.2, found 4")) { std.process.exit(0); diff --git a/test/cases/safety/slice sentinel mismatch - optional pointers.zig b/test/cases/safety/slice sentinel mismatch - optional pointers.zig index 34bd73f56c20981342bc8b5a968ec929c5dec1aa..c931aa31f1f75f054211c8ebf28d7bf9f2622540 100644 --- a/test/cases/safety/slice sentinel mismatch - optional pointers.zig +++ b/test/cases/safety/slice sentinel mismatch - optional pointers.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected null, found i32@10")) { std.process.exit(0); diff --git a/test/cases/safety/slice slice sentinel mismatch.zig b/test/cases/safety/slice slice sentinel mismatch.zig index a824ad6bb8f73c783a4f93afd4dac6e30adb03d0..881edb5d8e1c7d9938e51770ecc260371348baba 100644 --- a/test/cases/safety/slice slice sentinel mismatch.zig +++ b/test/cases/safety/slice slice sentinel mismatch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) { std.process.exit(0); diff --git a/test/cases/safety/slice start index greater than end index.zig b/test/cases/safety/slice start index greater than end index.zig index a9d90f676d56cd472618575b38dd7b401d4854b5..9835a253266991c229cf3aacc27508edf251f1b5 100644 --- a/test/cases/safety/slice start index greater than end index.zig +++ b/test/cases/safety/slice start index greater than end index.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "start index 10 is larger than end index 1")) { std.process.exit(0); diff --git a/test/cases/safety/slice with sentinel out of bounds - runtime len.zig b/test/cases/safety/slice with sentinel out of bounds - runtime len.zig index 838b31ce083edae683649daaacc1c205f5ba9bc1..b5851d7b1137859647cdb931d081285a7d90cb07 100644 --- a/test/cases/safety/slice with sentinel out of bounds - runtime len.zig +++ b/test/cases/safety/slice with sentinel out of bounds - runtime len.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 5, len 4")) { std.process.exit(0); diff --git a/test/cases/safety/slice with sentinel out of bounds.zig b/test/cases/safety/slice with sentinel out of bounds.zig index 1ef2e062626776cd957660bae5ada2bdd212e1d2..a3bcb49fc17cdf63ca71f931a91cdef87d120e41 100644 --- a/test/cases/safety/slice with sentinel out of bounds.zig +++ b/test/cases/safety/slice with sentinel out of bounds.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "index out of bounds: index 5, len 4")) { std.process.exit(0); diff --git a/test/cases/safety/slice_cast_change_len_0.zig b/test/cases/safety/slice_cast_change_len_0.zig index 9b9a40e93b5b15942fd6c88bdd5a5034b00f8555..d85299e6936805bbefac2b326e254c755ebe8af9 100644 --- a/test/cases/safety/slice_cast_change_len_0.zig +++ b/test/cases/safety/slice_cast_change_len_0.zig @@ -13,7 +13,7 @@ pub fn main() void { std.process.exit(1); } -pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "slice length '3' does not divide exactly into destination elements")) { std.process.exit(0); } diff --git a/test/cases/safety/slice_cast_change_len_1.zig b/test/cases/safety/slice_cast_change_len_1.zig index 57a7b6a7380e3cc31d1ac630285ca2beeb2acdb7..388a052085ac54b14cac21007559be05d9451156 100644 --- a/test/cases/safety/slice_cast_change_len_1.zig +++ b/test/cases/safety/slice_cast_change_len_1.zig @@ -13,7 +13,7 @@ pub fn main() void { std.process.exit(1); } -pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "slice length '1' does not divide exactly into destination elements")) { std.process.exit(0); } diff --git a/test/cases/safety/slice_cast_change_len_2.zig b/test/cases/safety/slice_cast_change_len_2.zig index f6a29feec74092d824811f7b24b0ca80f445bf07..ff7a18b8f0963609be205939db699764e61eb10c 100644 --- a/test/cases/safety/slice_cast_change_len_2.zig +++ b/test/cases/safety/slice_cast_change_len_2.zig @@ -13,7 +13,7 @@ pub fn main() void { std.process.exit(1); } -pub fn panic(message: []const u8, _: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { if (std.mem.eql(u8, message, "slice length '1' does not divide exactly into destination elements")) { std.process.exit(0); } diff --git a/test/cases/safety/slicing null C pointer - runtime len.zig b/test/cases/safety/slicing null C pointer - runtime len.zig index 8266a035b70fe3b9a618422da03407ad6219cef8..e2145fedb0a8db60774ca3b337db6419a549d3d1 100644 --- a/test/cases/safety/slicing null C pointer - runtime len.zig +++ b/test/cases/safety/slicing null C pointer - runtime len.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to use null value")) { std.process.exit(0); diff --git a/test/cases/safety/slicing null C pointer.zig b/test/cases/safety/slicing null C pointer.zig index 2035361cb2a0af969d68407d325d62ec12ba3700..6fc0281d471f19f1be6c64c5d00178ca5f83ceb5 100644 --- a/test/cases/safety/slicing null C pointer.zig +++ b/test/cases/safety/slicing null C pointer.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to use null value")) { std.process.exit(0); diff --git a/test/cases/safety/switch else on corrupt enum value - one prong.zig b/test/cases/safety/switch else on corrupt enum value - one prong.zig index 4babfb9133c4d41236275b2ccf0f9ff538a5f1f8..6bc20ef1007752779753bfa296812271219e5045 100644 --- a/test/cases/safety/switch else on corrupt enum value - one prong.zig +++ b/test/cases/safety/switch else on corrupt enum value - one prong.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/switch else on corrupt enum value - union.zig b/test/cases/safety/switch else on corrupt enum value - union.zig index 20a24a81ccbe9bcfe77c60ac72f7f2fa5f8d96f1..afb7bfdcdcc20f7848d1e7fbb50e4f236de08f19 100644 --- a/test/cases/safety/switch else on corrupt enum value - union.zig +++ b/test/cases/safety/switch else on corrupt enum value - union.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/switch else on corrupt enum value.zig b/test/cases/safety/switch else on corrupt enum value.zig index 6cab276eab07888a21426c149faf8650f7f213b3..297cde40ea92fc6504103e4aa5b5f5bffcf0f641 100644 --- a/test/cases/safety/switch else on corrupt enum value.zig +++ b/test/cases/safety/switch else on corrupt enum value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/switch on corrupted enum value.zig b/test/cases/safety/switch on corrupted enum value.zig index c7f6f86940089cf6ba2c866eaab8a1dbdbdd5ebd..7e08b3c495b4fe32412d857006357e0a63060282 100644 --- a/test/cases/safety/switch on corrupted enum value.zig +++ b/test/cases/safety/switch on corrupted enum value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/switch on corrupted union value.zig b/test/cases/safety/switch on corrupted union value.zig index e2b21fd84a4bd402cdf8b0c260e06fc932a4c85c..d1c8d6a3f528c56d82980f3c15d775eec151e497 100644 --- a/test/cases/safety/switch on corrupted union value.zig +++ b/test/cases/safety/switch on corrupted union value.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "switch on corrupt value")) { std.process.exit(0); diff --git a/test/cases/safety/truncating vector cast.zig b/test/cases/safety/truncating vector cast.zig index 3531ac34b0a0ddbca4c02797376d6d74bd8d202e..7805a5f92d005d0410f2ac32dcd97f6920e968c5 100644 --- a/test/cases/safety/truncating vector cast.zig +++ b/test/cases/safety/truncating vector cast.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/unreachable.zig b/test/cases/safety/unreachable.zig index 52c20506122d5d8a2db209a514f4a75458cc1344..8b394e6f4f40f9be400b4b734902ed6dfecfe09e 100644 --- a/test/cases/safety/unreachable.zig +++ b/test/cases/safety/unreachable.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "reached unreachable code")) { std.process.exit(0); diff --git a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig index c326dfb691b47c7721699f1d049555c822abdb8f..5047550800272266659c6746d5fef0e3e9666bed 100644 --- a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig +++ b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/unsigned shift left overflow.zig b/test/cases/safety/unsigned shift left overflow.zig index 178e309126399fa4d53c757ef704ea754abfced5..37bb1b61ea70aedbfb03e99c04929e48566cbede 100644 --- a/test/cases/safety/unsigned shift left overflow.zig +++ b/test/cases/safety/unsigned shift left overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "left shift overflowed bits")) { std.process.exit(0); diff --git a/test/cases/safety/unsigned shift right overflow.zig b/test/cases/safety/unsigned shift right overflow.zig index 5ebe44bf49a8ec967de17bf7784117dc042bdbf0..2de5d7c714f0d7067bff6490ce2debab4ad9b901 100644 --- a/test/cases/safety/unsigned shift right overflow.zig +++ b/test/cases/safety/unsigned shift right overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "right shift overflowed bits")) { std.process.exit(0); diff --git a/test/cases/safety/unsigned-signed vector cast.zig b/test/cases/safety/unsigned-signed vector cast.zig index f603999d8b267a6dfbf57f07acda968b5ab443ab..a482701b96e2d5af1b702bf2ae7e78f6aa24f560 100644 --- a/test/cases/safety/unsigned-signed vector cast.zig +++ b/test/cases/safety/unsigned-signed vector cast.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/unwrap error switch.zig b/test/cases/safety/unwrap error switch.zig index 57f1f3d7b7bfdbc22489f644101b865f5917df68..e31a34593d6f9c10cc488254cc7dd970211466ce 100644 --- a/test/cases/safety/unwrap error switch.zig +++ b/test/cases/safety/unwrap error switch.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to unwrap error: Whatever")) { std.process.exit(0); diff --git a/test/cases/safety/unwrap error.zig b/test/cases/safety/unwrap error.zig index ef79c5cce4d1abf76b51a74ce619cfb7b46776fc..aae990b6444e35a3ef063e88ba146172476c5c55 100644 --- a/test/cases/safety/unwrap error.zig +++ b/test/cases/safety/unwrap error.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "attempt to unwrap error: Whatever")) { std.process.exit(0); diff --git a/test/cases/safety/value does not fit in shortening cast - u0.zig b/test/cases/safety/value does not fit in shortening cast - u0.zig index f8aa6ebb119cca1afa146045ee95220deb25f42b..0b12aed075041047081c79b9d0e6263819e79241 100644 --- a/test/cases/safety/value does not fit in shortening cast - u0.zig +++ b/test/cases/safety/value does not fit in shortening cast - u0.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/value does not fit in shortening cast.zig b/test/cases/safety/value does not fit in shortening cast.zig index ea74f8739b977842d5ba08f436af3fc99c256014..ff5144e3e7e5e7c6ffa8fe425bd4619c2bf4b1ea 100644 --- a/test/cases/safety/value does not fit in shortening cast.zig +++ b/test/cases/safety/value does not fit in shortening cast.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer does not fit in destination type")) { std.process.exit(0); diff --git a/test/cases/safety/vector integer addition overflow.zig b/test/cases/safety/vector integer addition overflow.zig index 4b34248af58f989af47a76f5c9f4be144fc395d9..5f60d9c2f2cf2c30c5aee92fdb58b573e436c9a5 100644 --- a/test/cases/safety/vector integer addition overflow.zig +++ b/test/cases/safety/vector integer addition overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/vector integer multiplication overflow.zig b/test/cases/safety/vector integer multiplication overflow.zig index 2d4183d316761fc32096f1fc9146535d36fe4f28..0a7573e508b0a6683d9fa5ede52465a0d0f94761 100644 --- a/test/cases/safety/vector integer multiplication overflow.zig +++ b/test/cases/safety/vector integer multiplication overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/vector integer negation overflow.zig b/test/cases/safety/vector integer negation overflow.zig index b06dc437541b3d703b7c4bb715aabb5760589586..11dcfda430ba0eb484f485bc8ab039b79084a491 100644 --- a/test/cases/safety/vector integer negation overflow.zig +++ b/test/cases/safety/vector integer negation overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/vector integer subtraction overflow.zig b/test/cases/safety/vector integer subtraction overflow.zig index a6db1e5e85767d3aa2b56c2fe365b2be16fb1d9c..5de596085416c6e191f3a029d2ab855cbd967dc7 100644 --- a/test/cases/safety/vector integer subtraction overflow.zig +++ b/test/cases/safety/vector integer subtraction overflow.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "integer overflow")) { std.process.exit(0); diff --git a/test/cases/safety/zero casted to error.zig b/test/cases/safety/zero casted to error.zig index 5e379643a8a758cedea138e75e11b107acb9ebc0..63be84677164a494a339ad2e56bab8b07693e629 100644 --- a/test/cases/safety/zero casted to error.zig +++ b/test/cases/safety/zero casted to error.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.debug.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { _ = stack_trace; if (std.mem.eql(u8, message, "invalid error code")) { std.process.exit(0); diff --git a/test/cases/tail_call_noreturn.zig b/test/cases/tail_call_noreturn.zig index 875251e3f74a2a01aaa10558df8ad596ac6e8725..5cd716dd303e57453e5463a7ff9063b87456304a 100644 --- a/test/cases/tail_call_noreturn.zig +++ b/test/cases/tail_call_noreturn.zig @@ -1,9 +1,9 @@ const std = @import("std"); const builtin = std.builtin; -pub fn foo(message: []const u8, stack_trace: ?*std.debug.StackTrace) noreturn { +pub fn foo(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn { @call(.always_tail, bar, .{ message, stack_trace }); } -pub fn bar(message: []const u8, stack_trace: ?*std.debug.StackTrace) noreturn { +pub fn bar(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn { _ = message; _ = stack_trace; std.process.exit(0); diff --git a/test/standalone/compile_asm/main.zig b/test/standalone/compile_asm/main.zig index a3b11b9da974d71aa022fc57a375f2a8ef90004a..1e6c93e562dee9f1d7eab41b4214241cfc4cc754 100644 --- a/test/standalone/compile_asm/main.zig +++ b/test/standalone/compile_asm/main.zig @@ -4,7 +4,7 @@ export fn main(r0: u32, r1: u32, atags: u32) callconv(.c) noreturn { _ = atags; unreachable; // never gets run so it doesn't matter } -pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").debug.StackTrace, _: ?usize) noreturn { +pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace, _: ?usize) noreturn { _ = msg; _ = error_return_trace; while (true) {} diff --git a/test/standalone/issue_339/test.zig b/test/standalone/issue_339/test.zig index 445385d16c78d0bc7ac9a075d004c85f17b56bc8..e28839209c1988a68fb46c269a32d5d0b311cfd5 100644 --- a/test/standalone/issue_339/test.zig +++ b/test/standalone/issue_339/test.zig @@ -1,4 +1,4 @@ -const StackTrace = @import("std").debug.StackTrace; +const StackTrace = @import("std").builtin.StackTrace; pub fn panic(msg: []const u8, stack_trace: ?*StackTrace, _: ?usize) noreturn { _ = msg; _ = stack_trace; diff --git a/test/tests.zig b/test/tests.zig index 511846dd312e516e1f74acdb74b50fb39993cb0d..dcdbd762afc671a2dc3c81c66e16bf7e943fcb81 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2291,7 +2291,7 @@ pub fn addCliTests(b: *std.Build) *Step { \\ return num * num; \\} \\extern fn zig_panic() noreturn; - \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").debug.StackTrace, _: ?usize) noreturn { + \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("builtin").StackTrace, _: ?usize) noreturn { \\ _ = msg; \\ _ = error_return_trace; \\ zig_panic(); -- 2.54.0 From 87fb7df25794d12b2316dd41a9111e2206c00152 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sat, 11 Apr 2026 18:20:26 -0700 Subject: [PATCH 23/29] Updates stack trace vs error return trace in more places --- doc/langref.html.in | 2 +- lib/compiler/test_runner.zig | 6 +++--- lib/std/Thread.zig | 4 ++-- lib/std/std.zig | 2 ++ 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 9f32e05896e3eccf237f6388b79198f65c90a0b8..1974d76791234254c570e2fcdf5e3339748e0eb6 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -3263,7 +3263,7 @@ fn createFoo(param: i32) !Foo {

  • Return an error from main
  • An error makes its way to {#syntax#}catch unreachable{#endsyntax#} and you have not overridden the default panic handler
  • -
  • Use {#link|errorReturnTrace#} to access the current return trace. You can use {#syntax#}std.debug.dumpStackTrace{#endsyntax#} to print it. This function returns comptime-known {#link|null#} when building without error return tracing support.
  • +
  • Use {#link|errorReturnTrace#} to access the current return trace. You can use {#syntax#}std.debug.dumpErrorReturnTrace{#endsyntax#} to print it. This function returns comptime-known {#link|null#} when building without error return tracing support.
{#header_open|Implementation Details#}

diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index fd4ac20eb0f2f5bc6cd89ddbe00739dbcdb3450e..2a5483907ebc830ff0df2e37b391ab2ca573d457 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -144,7 +144,7 @@ fn mainServer(init: std.process.Init.Minimal) !void { error.SkipZigTest => .skip, else => s: { if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace); + std.debug.dumpErrorReturnTrace(trace); } break :s .fail; }, @@ -312,7 +312,7 @@ fn mainTerminal(init: std.process.Init.Minimal) void { std.debug.print("FAIL ({t})\n", .{err}); } if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace); + std.debug.dumpErrorReturnTrace(trace); } test_node.end(); }, @@ -438,7 +438,7 @@ var fuzz_runner: if (builtin.fuzz) struct { error.SkipZigTest => return, else => { if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace); + std.debug.dumpErrorReturnTrace(trace); } std.debug.print("failed with error.{t}\n", .{err}); std.process.exit(1); diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 8f31add6e20892c48bf1872fc6829ca55a4bd357..6e9f7fb5401d66294ad4c2377a651a5c0d323caa 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -442,7 +442,7 @@ fn callFn(comptime f: anytype, args: anytype) switch (Impl) { @call(.auto, f, args) catch |err| { std.debug.print("error: {s}\n", .{@errorName(err)}); if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace); + std.debug.dumpErrorReturnTrace(trace); } }; @@ -932,7 +932,7 @@ const WasiThreadImpl = struct { @call(.auto, f, w.args) catch |err| { std.debug.print("error: {s}\n", .{@errorName(err)}); if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace); + std.debug.dumpErrorReturnTrace(trace); } }; }, diff --git a/lib/std/std.zig b/lib/std/std.zig index 5cb856f9cc09695f0799a144b1ce3a62579494f4..e700c728c10fd811a18cef3b826d3b2296af685d 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -165,6 +165,8 @@ pub const Options = struct { /// * `debug.dumpCurrentStackTrace` /// * `debug.writeStackTrace` /// * `debug.dumpStackTrace` + /// * `debug.writeErrorReturnTrace` + /// * `debug.dumpErrorReturnTrace` /// /// Stack traces can generally be collected and printed when debug info is stripped, but are /// often less useful since they usually cannot be mapped to source locations and/or have bad -- 2.54.0 From 541bd6c3693cc57850dc5d78257584dd82f00ec6 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sat, 11 Apr 2026 22:27:23 -0700 Subject: [PATCH 24/29] Updates more failing tests --- lib/std/debug.zig | 2 +- lib/std/testing/FailingAllocator.zig | 4 ++-- test/standalone/coff_dwarf/main.zig | 12 ++++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index afd47d981d465b6795661196dd9ee0c738ad9a59..d7df04457afeeb9f99c8da5ae96536022d21a4a1 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1704,7 +1704,7 @@ test "manage resources correctly" { const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color }; try printSourceAtAddress(io, &di, t, .{ .address = S.showMyTrace(), - .inlines = true, + .resolve_inline_callers = true, }); } diff --git a/lib/std/testing/FailingAllocator.zig b/lib/std/testing/FailingAllocator.zig index bcd88567106dca6804b32b85ec32ac58319106fb..e5c807cac73f365070ea9736cd4495cb2894c448 100644 --- a/lib/std/testing/FailingAllocator.zig +++ b/lib/std/testing/FailingAllocator.zig @@ -65,7 +65,7 @@ fn alloc( if (self.alloc_index == self.fail_index) { if (!self.has_induced_failure) { const st = std.debug.captureCurrentStackTrace(.{ .first_address = return_address }, &self.stack_addresses); - @memset(self.stack_addresses[@min(st.index, self.stack_addresses.len)..], 0); + @memset(self.stack_addresses[@min(st.return_addresses.len, self.stack_addresses.len)..], 0); self.has_induced_failure = true; } return null; @@ -138,7 +138,7 @@ pub fn getStackTrace(self: *FailingAllocator) std.debug.StackTrace { len += 1; } return .{ - .instruction_addresses = &self.stack_addresses, + .return_addresses = &self.stack_addresses, .index = len, }; } diff --git a/test/standalone/coff_dwarf/main.zig b/test/standalone/coff_dwarf/main.zig index 24684d3830e7ff35719fe9d6a90f037d8a984630..853f8a14aba4f27791d1d7971f312a7199016e2b 100644 --- a/test/standalone/coff_dwarf/main.zig +++ b/test/standalone/coff_dwarf/main.zig @@ -12,8 +12,16 @@ pub fn main(init: std.process.Init) void { var add_addr: usize = undefined; _ = add(1, 2, &add_addr); - const symbol = di.getSymbol(io, add_addr) catch |err| fatal("failed to get symbol: {t}", .{err}); - defer if (symbol.source_location) |sl| std.debug.getDebugInfoAllocator().free(sl.file_name); + const symbols = di.getSymbols(io, add_addr) catch |err| fatal("failed to get symbol: {t}", .{err}); + const debug_gpa = std.debug.getDebugInfoAllocator(); + defer for (symbols) |symbol| { + if (symbol.source_location) |sl| { + debug_gpa.free(sl.file_name); + } + } + + if (symbols.len != 1) fatal("expected 1 symbol, found {}", .{symbols.len}); + const symbol = symbols[0]; if (symbol.name == null) fatal("failed to resolve symbol name", .{}); if (symbol.compile_unit_name == null) fatal("failed to resolve compile unit", .{}); -- 2.54.0 From 312ef9558b68898b5402796a94f4bc97a05b308d Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sat, 11 Apr 2026 22:59:52 -0700 Subject: [PATCH 25/29] Mitigation for bug that results in reuse of inlinee IDs when functions share names --- lib/std/debug/Pdb.zig | 112 ++++++++++++++++++++++------- lib/std/debug/SelfInfo/Windows.zig | 75 ++++++++++--------- 2 files changed, 128 insertions(+), 59 deletions(-) diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index c75df3874808a353bb89e550a028cda94122281d..f845273dc1991ab250d297a71bb44288bb4bbb8c 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -26,6 +26,10 @@ pub const Module = struct { symbols: []u8, subsect_info: []u8, checksum_offset: ?usize, + /// The inlinee source lines, sorted by inlinee. This saves us from repeatedly doing linear + /// searches over all inlinees. We prefer binary search over a hashmap as LLVM somtimes outputs + /// multiple entries for a single inlinee ID, see `getInlineeSourceLines` for more info. + inlinee_source_lines: []InlineeSourceLine, pub fn deinit(self: *Module, allocator: Allocator) void { allocator.free(self.module_name); @@ -33,6 +37,7 @@ pub const Module = struct { if (self.populated) { allocator.free(self.symbols); allocator.free(self.subsect_info); + allocator.free(self.inlinee_source_lines); } } }; @@ -117,6 +122,7 @@ pub fn parseDbiStream(self: *Pdb) !void { .symbols = undefined, .subsect_info = undefined, .checksum_offset = null, + .inlinee_source_lines = undefined, }); mod_info_offset += this_record_len; @@ -657,40 +663,58 @@ pub fn getSymbolName(self: *Pdb, proc_sym: *align(1) const pdb.ProcSym) []const pub const InlineeSourceLine = struct { signature: pdb.InlineeSourceLineSignature, info: *align(1) const pdb.InlineeSourceLine, + + fn lessThan(_: void, lhs: InlineeSourceLine, rhs: InlineeSourceLine) bool { + return lhs.info.inlinee < rhs.info.inlinee; + } + + fn compare(inlinee: u32, self: InlineeSourceLine) std.math.Order { + return std.math.order(inlinee, self.info.inlinee); + } }; -pub fn getInlineeSourceLine( +/// Returns all `InlineeSourceLine`s for a given module with the given inlinee. Ideally there would +/// only be one entry per inlinee, but LLVM appears to assign all functions that share a name the +/// same inlinee ID. This appears to be a bug, so the best the caller can do right now is print all +/// the results. +pub fn getInlineeSourceLines( self: *Pdb, mod: *Module, inlinee: u32, -) ?InlineeSourceLine { +) []const InlineeSourceLine { _ = self; - var subsects: Io.Reader = .fixed(mod.subsect_info); - while (subsects.takeStructPointer(pdb.DebugSubsectionHeader) catch null) |subsect_hdr| { - var subsect: Io.Reader = .fixed(subsects.take(subsect_hdr.length) catch return null); - if (subsect_hdr.kind == .inlinee_lines) { - const signature = subsect.takeEnum(pdb.InlineeSourceLineSignature, .little) catch return null; - const has_extra_files = switch (signature) { - .normal => false, - .ex => true, - else => continue, - }; - while (subsect.takeStructPointer(pdb.InlineeSourceLine) catch null) |inlinee_src_line| { - if (has_extra_files) { - const file_count = subsect.takeInt(u32, .little) catch return null; - const file_bytes = std.math.mul(usize, file_count, @sizeOf(u32)) catch return null; - subsect.discardAll(file_bytes) catch return null; - } + // Binary search to an arbitrary match, if there are other matches they will be adjacent + const any = std.sort.binarySearch( + InlineeSourceLine, + mod.inlinee_source_lines, + inlinee, + InlineeSourceLine.compare, + ) orelse return &.{}; - if (inlinee_src_line.inlinee == inlinee) return .{ - .signature = signature, - .info = inlinee_src_line, - }; - } + // Linearly scan to the first match + const begin = b: { + var begin = any; + while (begin > 0) { + const prev = begin - 1; + if (mod.inlinee_source_lines[prev].info.inlinee != inlinee) break; + begin = prev; } - } - return null; + break :b begin; + }; + + // Linearly scan to the last match + const end = b: { + var end = any + 1; + while ( + end < mod.inlinee_source_lines.len and + mod.inlinee_source_lines[end].info.inlinee == inlinee + ) : (end += 1) {} + break :b end; + }; + + // Return a slice of all the matches + return mod.inlinee_source_lines[begin..end]; } pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.SourceLocation { @@ -810,7 +834,45 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { const gpa = self.allocator; mod.symbols = try reader.readAlloc(gpa, mod.mod_info.sym_byte_size - 4); + errdefer gpa.free(mod.symbols); mod.subsect_info = try reader.readAlloc(gpa, mod.mod_info.c13_byte_size); + errdefer gpa.free(mod.subsect_info); + mod.inlinee_source_lines = b: { + var inlinee_source_lines: std.ArrayList(InlineeSourceLine) = .empty; + defer inlinee_source_lines.deinit(gpa); + var subsects: Io.Reader = .fixed(mod.subsect_info); + while (subsects.takeStructPointer(pdb.DebugSubsectionHeader) catch null) |subsect_hdr| { + var subsect: Io.Reader = .fixed(subsects.take(subsect_hdr.length) catch return null); + if (subsect_hdr.kind == .inlinee_lines) { + const inlinee_source_line_signature = subsect.takeEnum(pdb.InlineeSourceLineSignature, .little) + catch return error.InvalidDebugInfo; + const has_extra_files = switch (inlinee_source_line_signature) { + .normal => false, + .ex => true, + else => continue, + }; + while (subsect.takeStructPointer(pdb.InlineeSourceLine) catch null) |info| { + if (has_extra_files) { + const file_count = subsect.takeInt(u32, .little) catch + return error.InvalidDebugInfo; + const file_bytes = std.math.mul(usize, file_count, @sizeOf(u32)) + catch return error.InvalidDebugInfo; + subsect.discardAll(file_bytes) catch + return error.InvalidDebugInfo; + } + + try inlinee_source_lines.append(gpa, .{ + .signature = inlinee_source_line_signature, + .info = info, + }); + } + } + } + + std.mem.sort(InlineeSourceLine, inlinee_source_lines.items, {}, InlineeSourceLine.lessThan); + break :b try inlinee_source_lines.toOwnedSlice(gpa); + }; + errdefer gpa.free(mod.inlinee_source_lines); var sect_offset: usize = 0; var skip_len: usize = undefined; diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index 3a4d7b68786a6a92beba26f3c2dc4cb01fff417d..1a888e7205a8b5fbb28c57eabc24e8a2c35cb0b3 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -286,43 +286,48 @@ const Module = struct { var last_inlinee: ?u32 = null; var iter = pdb.getInlinees(module, proc); while (iter.next(module)) |inline_site| { - // If our address points into this site, get the source location it - // points at - const inlinee_src_line = pdb.getInlineeSourceLine( - module, - inline_site.inlinee, - ) orelse continue; - const maybe_loc = pdb.getInlineSiteSourceLocation( - module, - inline_site, - inlinee_src_line.info, - offset_in_func, - ) catch continue; - const loc = maybe_loc orelse continue; - // Filter out duplicate inline sites. Tools like llvm-addr2line output // duplicate sites in the same cases as us if we elide this check, - // implying that they exist in the underlying data and are not - // indicative of a parser bug. No useful information is lost here since an - // inline site can't actually reference itself. + // implying that they exist in the underlying data and are not indicative + // of a parser bug. No useful information is lost here since an inline site + // can't actually reference itself. if (inline_site.inlinee == last_inlinee) continue; - last_inlinee = inline_site.inlinee; - // If we're appending this symbol, resolve the name. If we're replacing the - // last symbol, clear the previous symbols and wait to resolve the name - // until we've reached the last symbol to avoid doing work and then - // throwing it out. - const name = b: { - if (resolve_inline_callers) break :b pdb.findInlineeName(inline_site.inlinee); - symbols.items.len = 0; - break :b null; - }; + // If our address points into this site, get the source location(s) it + // points at + for (pdb.getInlineeSourceLines( + module, + inline_site.inlinee, + )) |inlinee_src_line| { + const maybe_loc = pdb.getInlineSiteSourceLocation( + module, + inline_site, + inlinee_src_line.info, + offset_in_func, + ) catch continue; + const loc = maybe_loc orelse continue; - try symbols.append(gpa, .{ - .name = name, - .compile_unit_name = compile_unit_name, - .source_location = loc, - }); + // If we aren't trying to resolve inline callers, and we've matched a + // new inline site, we want to overwrite the previous results. + if (!resolve_inline_callers and inline_site.inlinee != last_inlinee) { + symbols.items.len = 0; + } + + // Only resolve the name if we're resolving inline callers, otherwise + // wait until we're done to avoid duplicated work. + const name = if (resolve_inline_callers) + pdb.findInlineeName(inline_site.inlinee) + else + null; + + try symbols.append(gpa, .{ + .name = name, + .compile_unit_name = compile_unit_name, + .source_location = loc, + }); + + last_inlinee = inline_site.inlinee; + } } if (resolve_inline_callers) { @@ -332,8 +337,10 @@ const Module = struct { // complexity. std.mem.reverse(std.debug.Symbol, symbols.items); } else if (last_inlinee) |inlinee| { - // If we haven't resolved the name yet, resolve it now - symbols.items[symbols.items.len - 1].name = pdb.findInlineeName(inlinee); + // If we aren't resolving inline callers, then all results will have the + // same inline site, and we resolve its name once at the end. + const name = pdb.findInlineeName(inlinee); + for (symbols.items) |*symbol| symbol.name = name; } } -- 2.54.0 From df2413cf69a834253bf36a45242a92da6fa8ecae Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sat, 11 Apr 2026 23:28:45 -0700 Subject: [PATCH 26/29] Removes dead code, updates some tests, fixes typos in comments, formats --- lib/std/debug.zig | 1 - lib/std/debug/Pdb.zig | 63 +++++++++++++--------------- lib/std/debug/SelfInfo/MachO.zig | 14 ------- lib/std/pdb.zig | 7 +--- lib/std/testing/FailingAllocator.zig | 4 +- test/cases/disable_stack_tracing.zig | 2 +- test/error_traces.zig | 3 +- test/src/convert-stack-trace.zig | 19 +++++---- test/standalone/coff_dwarf/main.zig | 4 +- test/tests.zig | 3 +- 10 files changed, 48 insertions(+), 72 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index d7df04457afeeb9f99c8da5ae96536022d21a4a1..e38741e43caa1c177af3d9035ac333aa46b2bf8d 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -622,7 +622,6 @@ pub const StackTrace = struct { return_addresses: []usize, /// Indicates whether any stack frames were omitted from `return_addresses`. skipped: SkippedAddresses, - }; /// Indicates how many addresses were skipped in a trace. diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index f845273dc1991ab250d297a71bb44288bb4bbb8c..3f41e0885d324d349e656729062ebb6599ec5a0d 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -285,7 +285,7 @@ pub const InlineSiteSymIterator = struct { .inlinesite, .inlinesite2, => return @ptrCast(inline_prefix), - else => {} + else => {}, } } @@ -332,9 +332,9 @@ pub const BinaryAnnotation = union(enum) { .file_id = self.file_id, .code_offset = self.code_offset, .code_length = b: { - if (self.code_length) |l| break :b l; - const end = next_code_offset orelse return null; - break :b end - self.code_offset; + if (self.code_length) |l| break :b l; + const end = next_code_offset orelse return null; + break :b end - self.code_offset; }, }; } @@ -345,7 +345,7 @@ pub const BinaryAnnotation = union(enum) { .annotations = annotations, .curr = .{ .line_offset = 0, - .file_id = null, + .file_id = null, .code_offset = 0, .code_length = null, }, @@ -395,22 +395,22 @@ pub const BinaryAnnotation = union(enum) { }, // Not emitted by LLVM at the time of writing, and we don't want to add support - // without a test csae. Safe to ignore since we don't use this info right now. + // without a test case. Safe to ignore since we don't use this info right now. .change_line_end_delta, .change_column_start, .change_column_end_delta, .change_column_end, - => {}, + => {}, - // Not emitted by LLVM at the time of writing. Various sources conflict on how - // these opcodes should be interpreted, so we make no attempt to handle them. + // Not emitted by LLVM at the time of writing. Various sources conflict on how + // these opcodes should be interpreted, so we make no attempt to handle them. .code_offset, .change_code_offset_base, .change_range_kind, => { - self.annotations = .empty; - self.prev = null; - return null; + self.annotations = .empty; + self.prev = null; + return null; }, } @@ -457,8 +457,8 @@ pub const BinaryAnnotation = union(enum) { switch (op) { // Microsoft's docs say that invalid is used as padding, though it is left ambiguous // whether padding is allowed internally or only after all instructions are complete. - // Empircally, the latter appears to be the case, at lest with the output from LLVM that - // I've tested. + // Empirically, the latter appears to be the case, at least with the output from LLVM + // that I've tested. .invalid => return error.EndOfStream, .code_offset => return .{ .code_offset = try expect(takePackedU32(reader)), @@ -547,7 +547,7 @@ pub const BinaryAnnotation = union(enum) { } } - fn expect(value: anytype) error { ReadFailed }!@typeInfo(@TypeOf(value)).error_union.payload { + fn expect(value: anytype) error{ReadFailed}!@typeInfo(@TypeOf(value)).error_union.payload { comptime assert(@typeInfo(@TypeOf(value)).error_union.error_set == Io.Reader.Error); return value catch error.ReadFailed; } @@ -661,16 +661,16 @@ pub fn getSymbolName(self: *Pdb, proc_sym: *align(1) const pdb.ProcSym) []const } pub const InlineeSourceLine = struct { - signature: pdb.InlineeSourceLineSignature, - info: *align(1) const pdb.InlineeSourceLine, + signature: pdb.InlineeSourceLineSignature, + info: *align(1) const pdb.InlineeSourceLine, - fn lessThan(_: void, lhs: InlineeSourceLine, rhs: InlineeSourceLine) bool { - return lhs.info.inlinee < rhs.info.inlinee; - } + fn lessThan(_: void, lhs: InlineeSourceLine, rhs: InlineeSourceLine) bool { + return lhs.info.inlinee < rhs.info.inlinee; + } - fn compare(inlinee: u32, self: InlineeSourceLine) std.math.Order { - return std.math.order(inlinee, self.info.inlinee); - } + fn compare(inlinee: u32, self: InlineeSourceLine) std.math.Order { + return std.math.order(inlinee, self.info.inlinee); + } }; /// Returns all `InlineeSourceLine`s for a given module with the given inlinee. Ideally there would @@ -694,7 +694,7 @@ pub fn getInlineeSourceLines( // Linearly scan to the first match const begin = b: { - var begin = any; + var begin = any; while (begin > 0) { const prev = begin - 1; if (mod.inlinee_source_lines[prev].info.inlinee != inlinee) break; @@ -706,10 +706,9 @@ pub fn getInlineeSourceLines( // Linearly scan to the last match const end = b: { var end = any + 1; - while ( - end < mod.inlinee_source_lines.len and - mod.inlinee_source_lines[end].info.inlinee == inlinee - ) : (end += 1) {} + while (end < mod.inlinee_source_lines.len and + mod.inlinee_source_lines[end].info.inlinee == inlinee) : (end += 1) + {} break :b end; }; @@ -844,8 +843,7 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { while (subsects.takeStructPointer(pdb.DebugSubsectionHeader) catch null) |subsect_hdr| { var subsect: Io.Reader = .fixed(subsects.take(subsect_hdr.length) catch return null); if (subsect_hdr.kind == .inlinee_lines) { - const inlinee_source_line_signature = subsect.takeEnum(pdb.InlineeSourceLineSignature, .little) - catch return error.InvalidDebugInfo; + const inlinee_source_line_signature = subsect.takeEnum(pdb.InlineeSourceLineSignature, .little) catch return error.InvalidDebugInfo; const has_extra_files = switch (inlinee_source_line_signature) { .normal => false, .ex => true, @@ -855,8 +853,7 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { if (has_extra_files) { const file_count = subsect.takeInt(u32, .little) catch return error.InvalidDebugInfo; - const file_bytes = std.math.mul(usize, file_count, @sizeOf(u32)) - catch return error.InvalidDebugInfo; + const file_bytes = std.math.mul(usize, file_count, @sizeOf(u32)) catch return error.InvalidDebugInfo; subsect.discardAll(file_bytes) catch return error.InvalidDebugInfo; } @@ -868,7 +865,7 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { } } } - + std.mem.sort(InlineeSourceLine, inlinee_source_lines.items, {}, InlineeSourceLine.lessThan); break :b try inlinee_source_lines.toOwnedSlice(gpa); }; diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index 894a4163da2117da3d7f7d369252075e5800ba93..76187764347eadc8987a72525f9127156b493004 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -22,20 +22,6 @@ pub fn deinit(si: *SelfInfo, io: Io) void { si.modules.deinit(gpa); } -pub const SymbolIterator = struct { - curr: ?Error!std.debug.Symbol, - - pub fn deinit(self: *SymbolIterator, _: Io) void { - self.* = undefined; - } - - pub fn next(self: *SymbolIterator) ?Error!std.debug.Symbol { - const result = self.curr; - self.curr = null; - return result; - } -}; - pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { _ = resolve_inline_callers; diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig index bff15d89de61342d6efc3a38e068764a52211a52..5478c01c41574001d14bdeb121c7f017e19e198d 100644 --- a/lib/std/pdb.zig +++ b/lib/std/pdb.zig @@ -616,11 +616,7 @@ pub const InlineSiteSym2 = extern struct { invocations: u32, }; -pub const InlineeSourceLineSignature = enum(u32) { - normal = 0, - ex = 1, - _ -}; +pub const InlineeSourceLineSignature = enum(u32) { normal = 0, ex = 1, _ }; pub const InlineeSourceLine = extern struct { inlinee: u32, @@ -651,4 +647,3 @@ pub const BinaryAnnotationOpcode = enum(u8) { change_code_length_and_code_offset = 12, change_column_end = 13, }; - diff --git a/lib/std/testing/FailingAllocator.zig b/lib/std/testing/FailingAllocator.zig index e5c807cac73f365070ea9736cd4495cb2894c448..a3852fe09ed3755914c1dc9f0f07da9ede7ed529 100644 --- a/lib/std/testing/FailingAllocator.zig +++ b/lib/std/testing/FailingAllocator.zig @@ -138,8 +138,8 @@ pub fn getStackTrace(self: *FailingAllocator) std.debug.StackTrace { len += 1; } return .{ - .return_addresses = &self.stack_addresses, - .index = len, + .return_addresses = self.stack_addresses[0..len], + .skipped = if (len == self.stack_addresses.len) .unknown else .none, }; } diff --git a/test/cases/disable_stack_tracing.zig b/test/cases/disable_stack_tracing.zig index a1659f2bd46fa0428d59c117e47c1f15dfebc62d..b360b0b26ec374765be51c619e7774e611fc7103 100644 --- a/test/cases/disable_stack_tracing.zig +++ b/test/cases/disable_stack_tracing.zig @@ -9,7 +9,7 @@ pub fn main() !void { const captured_st = try foo(&stdout.interface, &st_buf); try std.debug.writeStackTrace(&captured_st, .{ .writer = &stdout.interface, .mode = .no_color }); - try stdout.interface.print("stack trace index: {d}\n", .{captured_st.index}); + try stdout.interface.print("stack trace index: {d}\n", .{captured_st.return_addresses.len}); try stdout.interface.flush(); } diff --git a/test/error_traces.zig b/test/error_traces.zig index 4f3c20ba7f7668851b9844ea4a0e79b108793ce7..356a4440c6e568de2958a9288af0aece2fbe6afa 100644 --- a/test/error_traces.zig +++ b/test/error_traces.zig @@ -466,8 +466,7 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. \\} , .expect_error = "ThisIsSoSad", - .expect_trace = - switch (os) { + .expect_trace = switch (os) { // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs, // so our expected result is slightly different for Windows than on other operating // systems. diff --git a/test/src/convert-stack-trace.zig b/test/src/convert-stack-trace.zig index 259e34ae5932ed6e2f9061cc459d4a0a556f09b5..5d7356a2d48e92e8577d4c3013a062dec0d63899 100644 --- a/test/src/convert-stack-trace.zig +++ b/test/src/convert-stack-trace.zig @@ -52,23 +52,24 @@ pub fn main(init: std.process.Init) !void { continue; } - // If both the row and column are present, this it he column end. Otherwise it's the line end. const src_pos_end = std.mem.indexOf(u8, in_line, ": 0x") orelse { try w.writeAll(in_line); continue; }; - const src_row_or_path_end = std.mem.lastIndexOfScalar(u8, in_line[0..src_pos_end], ':') orelse { - try w.writeAll(in_line); - continue; + const src_pos_start = b: { + const postfix = ".zig:"; + const postfix_index = std.mem.lastIndexOf(u8, in_line[0..src_pos_end], postfix) orelse { + try w.writeAll(in_line); + continue; + }; + break :b postfix_index + postfix.len; }; - const src_path_end = std.mem.lastIndexOfScalar(u8, in_line[0..src_row_or_path_end], ':') - orelse src_row_or_path_end; - const addr_end = std.mem.indexOfPos(u8, in_line, src_pos_end, " in ") orelse { + const addr_end = std.mem.findPos(u8, in_line, src_pos_end, " in ") orelse { try w.writeAll(in_line); continue; }; - const symbol_end = std.mem.indexOfPos(u8, in_line, addr_end, " (") orelse { + const symbol_end = std.mem.findPos(u8, in_line, addr_end, " (") orelse { try w.writeAll(in_line); continue; }; @@ -87,7 +88,7 @@ pub fn main(init: std.process.Init) !void { // // ...with that first '_' being replaced by its basename. - const src_path = in_line[0..src_path_end]; + const src_path = in_line[0..src_pos_start]; const basename_start = if (std.mem.lastIndexOfAny(u8, src_path, "/\\")) |i| i + 1 else 0; const symbol_start = addr_end + " in ".len; try w.writeAll(in_line[basename_start..src_pos_end]); diff --git a/test/standalone/coff_dwarf/main.zig b/test/standalone/coff_dwarf/main.zig index 853f8a14aba4f27791d1d7971f312a7199016e2b..66b7e3656b344563a3227a780a12e26232ea52e6 100644 --- a/test/standalone/coff_dwarf/main.zig +++ b/test/standalone/coff_dwarf/main.zig @@ -12,13 +12,13 @@ pub fn main(init: std.process.Init) void { var add_addr: usize = undefined; _ = add(1, 2, &add_addr); - const symbols = di.getSymbols(io, add_addr) catch |err| fatal("failed to get symbol: {t}", .{err}); + const symbols = di.getSymbols(io, add_addr, false) catch |err| fatal("failed to get symbol: {t}", .{err}); const debug_gpa = std.debug.getDebugInfoAllocator(); defer for (symbols) |symbol| { if (symbol.source_location) |sl| { debug_gpa.free(sl.file_name); } - } + }; if (symbols.len != 1) fatal("expected 1 symbol, found {}", .{symbols.len}); const symbol = symbols[0]; diff --git a/test/tests.zig b/test/tests.zig index dcdbd762afc671a2dc3c81c66e16bf7e943fcb81..ce9a55f3cf4f81bb00b6f38eeecd6702a39f4427 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2168,7 +2168,6 @@ pub fn addErrorTraceTests( error_traces.addCases(darling_cases, .macos); } - return step; } @@ -2291,7 +2290,7 @@ pub fn addCliTests(b: *std.Build) *Step { \\ return num * num; \\} \\extern fn zig_panic() noreturn; - \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("builtin").StackTrace, _: ?usize) noreturn { + \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace, _: ?usize) noreturn { \\ _ = msg; \\ _ = error_return_trace; \\ zig_panic(); -- 2.54.0 From e968e6d00473a0fb9de86ae99400503e4e40f0ef Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sun, 12 Apr 2026 14:09:22 -0700 Subject: [PATCH 27/29] Fixes typos/out of date comments, switches to unstable sort --- lib/std/debug.zig | 2 -- lib/std/debug/Pdb.zig | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index e38741e43caa1c177af3d9035ac333aa46b2bf8d..80dfb144597bf1db1cc41e81183a09a2a4a0f489 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -606,8 +606,6 @@ fn waitForOtherThreadToFinishPanicking() void { } } -/// This data structure is used by the Zig language code generation and -/// therefore must be kept in sync with the compiler implementation. pub const StackTrace = struct { /// Each element is the "return address" of a function call, meaning the instruction address /// which control flow will return to when the function returns. diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index 3f41e0885d324d349e656729062ebb6599ec5a0d..59a16968ff95e95ce86c0f4e1aca972677a3a26d 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -518,7 +518,7 @@ pub const BinaryAnnotation = union(enum) { } } - // Adapated from: + // Adapted from: // https://github.com/microsoft/microsoft-pdb/blob/805655a28bd8198004be2ac27e6e0290121a5e89/include/cvinfo.h#L4942 pub fn takePackedU32(reader: *Io.Reader) Io.Reader.Error!u32 { const b0: u32 = try reader.takeByte(); @@ -866,7 +866,7 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { } } - std.mem.sort(InlineeSourceLine, inlinee_source_lines.items, {}, InlineeSourceLine.lessThan); + std.mem.sortUnstable(InlineeSourceLine, inlinee_source_lines.items, {}, InlineeSourceLine.lessThan); break :b try inlinee_source_lines.toOwnedSlice(gpa); }; errdefer gpa.free(mod.inlinee_source_lines); -- 2.54.0 From 4ad665d3c8cd6a9d4f6b0e2f065098436142b450 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sun, 12 Apr 2026 14:50:34 -0700 Subject: [PATCH 28/29] Writes symbols to array list argument --- lib/std/debug.zig | 29 +++++++++++++-------- lib/std/debug/Dwarf.zig | 25 +++++++++--------- lib/std/debug/SelfInfo/Elf.zig | 20 +++++++-------- lib/std/debug/SelfInfo/MachO.zig | 25 ++++++++---------- lib/std/debug/SelfInfo/Windows.zig | 41 ++++++++++++++++++++---------- 5 files changed, 79 insertions(+), 61 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 80dfb144597bf1db1cc41e81183a09a2a4a0f489..e4a91a6fc5e82df20cf1fb1835d9f2e63fa9dc77 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -38,8 +38,8 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// pub const init: SelfInfo; /// pub fn deinit(si: *SelfInfo, io: Io) void; /// -/// /// Returns the the symbols and source locations of the instruction at `address`. -/// pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, include_inline_callers: bool) SelfInfoError![]Symbol; +/// /// Appends the symbols for the instruction at `address` to `symbols`. +/// pub fn getSymbols(si: *SelfInfo, io: Io, gpa: Allocator, address: usize, include_inline_callers: bool, symbols: *std.ArrayList(Symbol)) SelfInfoError!void; /// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`. /// pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const u8; /// pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) SelfInfoError!usize; @@ -1190,8 +1190,17 @@ fn printSourceAtAddress( t: Io.Terminal, options: PrintSourceAddressOptions, ) Writer.Error!void { - const gpa = getDebugInfoAllocator(); - const symbols: []Symbol = debug_info.getSymbols(io, options.address, options.resolve_inline_callers) catch |err| { + // In the common case where there's only one symbol, allocate it on the stack. Reserve enough + // space for one item regardless of alignment. + var stack_fallback = std.heap.stackFallback(@sizeOf(Symbol) + @alignOf(Symbol) - 1, getDebugInfoAllocator()); + const sfa = stack_fallback.get(); + var symbols = std.ArrayList(Symbol).initCapacity(sfa, 1) catch unreachable; + defer { + for (symbols.items) |*symbol| symbol.deinit(sfa); + symbols.deinit(sfa); + } + + debug_info.getSymbols(io, sfa, options.address, options.resolve_inline_callers, &symbols) catch |err| { t.setColor(.dim) catch {}; defer t.setColor(.reset) catch {}; switch (err) { @@ -1208,13 +1217,13 @@ fn printSourceAtAddress( t.setColor(.reset) catch {}; }, } - return printLineInfo(io, t, debug_info, null, options.address, null, null); }; - defer { - for (symbols) |*symbol| symbol.deinit(gpa); - gpa.free(symbols); - } - for (symbols) |symbol| { + + // If we failed to get any symbols, append the unknown symbol. We initialized with a capacity of + // one using a stack fallback allocator so this can't fail. + if (symbols.items.len == 0) symbols.appendAssumeCapacity(.unknown); + + for (symbols.items) |symbol| { try printLineInfo( io, t, diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 8ffddf4b39fd6fd0df3de434d0c694a619d4127c..599597759b499b54c711b3662ed73991de2676b8 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -1545,22 +1545,22 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { return str[casted_offset..last :0]; } -pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64, resolve_inline_callers: bool) std.debug.SelfInfoError![]std.debug.Symbol { +pub fn getSymbols( + di: *Dwarf, + gpa: Allocator, + endian: Endian, + address: u64, + resolve_inline_callers: bool, + symbols: *std.ArrayList(std.debug.Symbol), +) std.debug.SelfInfoError!void { _ = resolve_inline_callers; - var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); - errdefer { - for (symbols.items) |*symbol| symbol.deinit(gpa); - symbols.deinit(gpa); - } const compile_unit = di.findCompileUnit(endian, address) catch |err| switch (err) { - error.EndOfStream, error.Overflow => { - symbols.appendAssumeCapacity(.unknown); - return symbols.toOwnedSlice(gpa); - }, - else => |e| return e, + error.EndOfStream => return error.MissingDebugInfo, + error.Overflow => return error.InvalidDebugInfo, + error.ReadFailed, error.InvalidDebugInfo, error.MissingDebugInfo => |e| return e, }; - symbols.appendAssumeCapacity(.{ + try symbols.append(gpa, .{ .name = di.getSymbolName(address), .compile_unit_name = compile_unit.die.getAttrString(di, endian, std.dwarf.AT.name, di.section(.debug_str), compile_unit) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, @@ -1575,7 +1575,6 @@ pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64, reso else => |e| return e, }, }); - return symbols.toOwnedSlice(gpa); } /// DWARF5 7.4: "In the 32-bit DWARF format, all values that represent lengths of DWARF sections and diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index bd045126ffcfa43462b5662876385fd9ebf08f97..bc607569f8193c3c83e643c54eb4e621d2113c76 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -30,8 +30,14 @@ pub fn deinit(si: *SelfInfo, io: Io) void { if (si.unwind_cache) |cache| gpa.free(cache); } -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { - const gpa = std.debug.getDebugInfoAllocator(); +pub fn getSymbols( + si: *SelfInfo, + io: Io, + gpa: Allocator, + address: usize, + resolve_inline_callers: bool, + symbols: *std.ArrayList(std.debug.Symbol), +) Error!void { const module = try si.findModule(gpa, io, address, .exclusive); defer si.rwlock.unlock(io); @@ -53,20 +59,14 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: }; loaded_elf.scanned_dwarf = true; } - return dwarf.getSymbols(gpa, native_endian, vaddr, resolve_inline_callers); + return dwarf.getSymbols(gpa, native_endian, vaddr, resolve_inline_callers, symbols); } // When DWARF is unavailable, fall back to searching the symtab. - var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); - errdefer { - for (symbols.items) |*symbol| symbol.deinit(gpa); - symbols.deinit(gpa); - } - symbols.appendAssumeCapacity(loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { + try symbols.append(gpa, loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo, error.BadSymtab => return error.InvalidDebugInfo, error.OutOfMemory => |e| return e, }); - return symbols.toOwnedSlice(gpa); } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { const gpa = std.debug.getDebugInfoAllocator(); diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index 76187764347eadc8987a72525f9127156b493004..e53e39f8e576fd724999befdf36643e79d339526 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -22,21 +22,21 @@ pub fn deinit(si: *SelfInfo, io: Io) void { si.modules.deinit(gpa); } -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { +pub fn getSymbols( + si: *SelfInfo, + io: Io, + gpa: Allocator, + address: usize, + resolve_inline_callers: bool, + symbols: *std.ArrayList(std.debug.Symbol), +) Error!void { _ = resolve_inline_callers; - const gpa = std.debug.getDebugInfoAllocator(); const module = try si.findModule(gpa, io, address); defer si.mutex.unlock(io); const file = try module.getFile(gpa, io); - var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); - errdefer { - for (symbols.items) |*symbol| symbol.deinit(gpa); - symbols.deinit(gpa); - } - // This is not necessarily the same as the vmaddr_slide that dyld would report. This is // because the segments in the file on disk might differ from the ones in memory. Normally // we wouldn't necessarily expect that to work, but /usr/lib/dyld is incredibly annoying: @@ -51,25 +51,23 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: const ofile_dwarf, const ofile_vaddr = file.getDwarfForAddress(gpa, io, vaddr) catch { // Return at least the symbol name if available. - symbols.appendAssumeCapacity(.{ + return symbols.append(gpa, .{ .name = try file.lookupSymbolName(vaddr), .compile_unit_name = null, .source_location = null, }); - return symbols.toOwnedSlice(gpa); }; const compile_unit = ofile_dwarf.findCompileUnit(native_endian, ofile_vaddr) catch { // Return at least the symbol name if available. - symbols.appendAssumeCapacity(.{ + return symbols.append(gpa, .{ .name = try file.lookupSymbolName(vaddr), .compile_unit_name = null, .source_location = null, }); - return symbols.toOwnedSlice(gpa); }; - symbols.appendAssumeCapacity(.{ + try symbols.append(gpa, .{ .name = ofile_dwarf.getSymbolName(ofile_vaddr) orelse try file.lookupSymbolName(vaddr), .compile_unit_name = compile_unit.die.getAttrString( @@ -88,7 +86,6 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: ofile_vaddr, ) catch null, }); - return symbols.toOwnedSlice(gpa); } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { _ = si; diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index 1a888e7205a8b5fbb28c57eabc24e8a2c35cb0b3..686dec41706601e3cd41675d7da1d137fcadd750 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -25,13 +25,24 @@ pub fn deinit(si: *SelfInfo, io: Io) void { si.modules.deinit(gpa); } -pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { - const gpa = std.debug.getDebugInfoAllocator(); +pub fn getSymbols( + si: *SelfInfo, + io: Io, + gpa: Allocator, + address: usize, + resolve_inline_callers: bool, + symbols: *std.ArrayList(std.debug.Symbol), +) Error!void { try si.lock.lockShared(io); defer si.lock.unlockShared(io); const module = try si.findModule(gpa, address); const di = try module.getDebugInfo(gpa, io); - return di.getSymbols(gpa, address - @intFromPtr(module.entry.DllBase), resolve_inline_callers); + return di.getSymbols( + gpa, + address - @intFromPtr(module.entry.DllBase), + resolve_inline_callers, + symbols, + ); } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { @@ -241,7 +252,13 @@ const Module = struct { arena.deinit(); } - fn getSymbols(di: *DebugInfo, gpa: Allocator, vaddr: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { + fn getSymbols( + di: *DebugInfo, + gpa: Allocator, + vaddr: usize, + resolve_inline_callers: bool, + symbols: *std.ArrayList(std.debug.Symbol), + ) Error!void { pdb: { const pdb = &(di.pdb orelse break :pdb); var coff_section: *align(1) const coff.SectionHeader = undefined; @@ -275,12 +292,7 @@ const Module = struct { const addr = vaddr - coff_section.virtual_address; const maybe_proc = pdb.getProcSym(module, addr); const compile_unit_name = fs.path.basename(module.obj_file_name); - var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); - errdefer { - for (symbols.items) |*symbol| symbol.deinit(gpa); - symbols.deinit(gpa); - } - + const symbols_top = symbols.items.len; if (maybe_proc) |proc| { const offset_in_func = addr - proc.code_offset; var last_inlinee: ?u32 = null; @@ -308,9 +320,10 @@ const Module = struct { const loc = maybe_loc orelse continue; // If we aren't trying to resolve inline callers, and we've matched a - // new inline site, we want to overwrite the previous results. + // new inline site, we want to overwrite the previously appended + // results. if (!resolve_inline_callers and inline_site.inlinee != last_inlinee) { - symbols.items.len = 0; + symbols.items.len = symbols_top; } // Only resolve the name if we're resolving inline callers, otherwise @@ -353,13 +366,13 @@ const Module = struct { }); } - return symbols.toOwnedSlice(gpa); + return; } dwarf: { const dwarf = &(di.dwarf orelse break :dwarf); const addr = vaddr + di.coff_image_base; - return dwarf.getSymbols(gpa, native_endian, addr, resolve_inline_callers); + return dwarf.getSymbols(gpa, native_endian, addr, resolve_inline_callers, symbols); } return error.MissingDebugInfo; -- 2.54.0 From 6707a5efeea1ab973c3274495bb0a5640e4f568b Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 13 Apr 2026 00:43:34 -0700 Subject: [PATCH 29/29] Arena allocates text --- lib/std/debug.zig | 75 +++++++++++++++-------------- lib/std/debug/Dwarf.zig | 11 +++-- lib/std/debug/Pdb.zig | 12 ++--- lib/std/debug/SelfInfo/Elf.zig | 15 ++++-- lib/std/debug/SelfInfo/MachO.zig | 11 +++-- lib/std/debug/SelfInfo/Windows.zig | 26 +++++++--- test/standalone/coff_dwarf/main.zig | 28 +++++++---- 7 files changed, 108 insertions(+), 70 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index e4a91a6fc5e82df20cf1fb1835d9f2e63fa9dc77..3dac7229f782d5ee834ae0224929b8cd1c805c50 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -39,7 +39,7 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// pub fn deinit(si: *SelfInfo, io: Io) void; /// /// /// Appends the symbols for the instruction at `address` to `symbols`. -/// pub fn getSymbols(si: *SelfInfo, io: Io, gpa: Allocator, address: usize, include_inline_callers: bool, symbols: *std.ArrayList(Symbol)) SelfInfoError!void; +/// pub fn getSymbols(si: *SelfInfo, io: Io, symbol_allocator: Allocator, text_arena: Allocator, address: usize, include_inline_callers: bool, symbols: *std.ArrayList(Symbol)) SelfInfoError!void; /// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`. /// pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const u8; /// pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) SelfInfoError!usize; @@ -229,11 +229,6 @@ pub const Symbol = struct { .compile_unit_name = null, .source_location = null, }; - - pub fn deinit(self: *Symbol, gpa: Allocator) void { - if (self.source_location) |sl| gpa.free(sl.file_name); - self.* = undefined; - } }; /// Deprecated because it returns the optimization mode of the standard @@ -699,6 +694,10 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: /// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing. pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Terminal) Writer.Error!void { const writer = t.writer; + + var text_arena: std.heap.ArenaAllocator = .init(getDebugInfoAllocator()); + defer text_arena.deinit(); + if (!std.options.allow_stack_tracing) { t.setColor(.dim) catch {}; try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); @@ -776,7 +775,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin } // `ret_addr` is the return address, which is *after* the function call. // Subtract 1 to get an address *in* the function call for a better source location. - try printSourceAtAddress(io, di, t, .{ + try printSourceAtAddress(io, &text_arena, di, t, .{ .address = ret_addr -| StackIterator.ra_call_offset, .resolve_inline_callers = true, }); @@ -832,6 +831,9 @@ fn writeTrace( t: Io.Terminal, resolve_inline_callers: bool, ) Writer.Error!void { + var text_arena: std.heap.ArenaAllocator = .init(getDebugInfoAllocator()); + defer text_arena.deinit(); + const writer = t.writer; if (!std.options.allow_stack_tracing) { t.setColor(.dim) catch {}; @@ -853,7 +855,7 @@ fn writeTrace( for (addresses) |addr| { // `addr` is the return address, which is *after* the function call. // Subtract 1 to get an address *in* the function call for a better source location. - try printSourceAtAddress(io, di, t, .{ + try printSourceAtAddress(io, &text_arena, di, t, .{ .address = addr -| StackIterator.ra_call_offset, .resolve_inline_callers = resolve_inline_callers, }); @@ -1186,21 +1188,28 @@ const PrintSourceAddressOptions = struct { fn printSourceAtAddress( io: Io, + text_arena: *std.heap.ArenaAllocator, debug_info: *SelfInfo, t: Io.Terminal, options: PrintSourceAddressOptions, ) Writer.Error!void { - // In the common case where there's only one symbol, allocate it on the stack. Reserve enough - // space for one item regardless of alignment. - var stack_fallback = std.heap.stackFallback(@sizeOf(Symbol) + @alignOf(Symbol) - 1, getDebugInfoAllocator()); - const sfa = stack_fallback.get(); - var symbols = std.ArrayList(Symbol).initCapacity(sfa, 1) catch unreachable; - defer { - for (symbols.items) |*symbol| symbol.deinit(sfa); - symbols.deinit(sfa); - } + defer _ = text_arena.reset(.retain_capacity); - debug_info.getSymbols(io, sfa, options.address, options.resolve_inline_callers, &symbols) catch |err| { + // Initialize the symbol array with space for at least one element, allocating this on the stack + // in the common case where only one element is needed + var symbol_fallback_allocator = std.heap.stackFallback(@sizeOf(Symbol) + @alignOf(Symbol) - 1, getDebugInfoAllocator()); + const symbol_allocator = symbol_fallback_allocator.get(); + var symbols = std.ArrayList(Symbol).initCapacity(symbol_allocator, 1) catch unreachable; + defer symbols.deinit(symbol_allocator); + + debug_info.getSymbols( + io, + symbol_allocator, + text_arena.allocator(), + options.address, + options.resolve_inline_callers, + &symbols, + ) catch |err| { t.setColor(.dim) catch {}; defer t.setColor(.reset) catch {}; switch (err) { @@ -1219,35 +1228,25 @@ fn printSourceAtAddress( } }; - // If we failed to get any symbols, append the unknown symbol. We initialized with a capacity of - // one using a stack fallback allocator so this can't fail. + // If we failed to write any symbols, at least write the unknown symbol. Can't fail since we + // initialized with a capacity of 1. if (symbols.items.len == 0) symbols.appendAssumeCapacity(.unknown); for (symbols.items) |symbol| { - try printLineInfo( - io, - t, - debug_info, - symbol.source_location, - options.address, - symbol.name, - symbol.compile_unit_name, - ); + try printLineInfo(io, t, debug_info, options.address, symbol); } } fn printLineInfo( io: Io, t: Io.Terminal, debug_info: *SelfInfo, - source_location: ?SourceLocation, address: usize, - symbol_name: ?[]const u8, - compile_unit_name: ?[]const u8, + symbol: Symbol, ) Writer.Error!void { const writer = t.writer; t.setColor(.bold) catch {}; - if (source_location) |*sl| { + if (symbol.source_location) |*sl| { if (sl.column == 0) { try writer.print("{s}:{d}", .{ sl.file_name, sl.line }); } else { @@ -1262,14 +1261,14 @@ fn printLineInfo( t.setColor(.dim) catch {}; try writer.print("0x{x} in {s} ({s})", .{ address, - symbol_name orelse "???", - compile_unit_name orelse debug_info.getModuleName(io, address) catch "???", + symbol.name orelse "???", + symbol.compile_unit_name orelse debug_info.getModuleName(io, address) catch "???", }); t.setColor(.reset) catch {}; try writer.writeAll("\n"); // Show the matching source code line if possible - if (source_location) |sl| { + if (symbol.source_location) |sl| { if (printLineFromFile(io, writer, sl)) { if (sl.column > 0) { // The caret already takes one char @@ -1708,7 +1707,9 @@ test "manage resources correctly" { var di: SelfInfo = .init; defer di.deinit(io); const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color }; - try printSourceAtAddress(io, &di, t, .{ + var text_arena: std.heap.ArenaAllocator = .init(std.testing.allocator); + defer text_arena.deinit(); + try printSourceAtAddress(io, &text_arena, &di, t, .{ .address = S.showMyTrace(), .resolve_inline_callers = true, }); diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 599597759b499b54c711b3662ed73991de2676b8..fe28baf8bffbab92b58276f3973726aeeb4876ba 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -1220,6 +1220,7 @@ pub fn populateSrcLocCache(d: *Dwarf, gpa: Allocator, endian: Endian, cu: *Compi pub fn getLineNumberInfo( d: *Dwarf, gpa: Allocator, + text_arena: Allocator, endian: Endian, compile_unit: *CompileUnit, target_address: u64, @@ -1232,7 +1233,7 @@ pub fn getLineNumberInfo( const file_entry = &slc.files[file_index]; if (file_entry.dir_index >= slc.directories.len) return bad(); const dir_name = slc.directories[file_entry.dir_index].path; - const file_name = try std.fs.path.join(gpa, &.{ dir_name, file_entry.path }); + const file_name = try std.fs.path.join(text_arena, &.{ dir_name, file_entry.path }); return .{ .line = entry.line, .column = entry.column, @@ -1547,25 +1548,27 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { pub fn getSymbols( di: *Dwarf, - gpa: Allocator, + symbol_allocator: Allocator, + text_arena: Allocator, endian: Endian, address: u64, resolve_inline_callers: bool, symbols: *std.ArrayList(std.debug.Symbol), ) std.debug.SelfInfoError!void { _ = resolve_inline_callers; + const gpa = std.debug.getDebugInfoAllocator(); const compile_unit = di.findCompileUnit(endian, address) catch |err| switch (err) { error.EndOfStream => return error.MissingDebugInfo, error.Overflow => return error.InvalidDebugInfo, error.ReadFailed, error.InvalidDebugInfo, error.MissingDebugInfo => |e| return e, }; - try symbols.append(gpa, .{ + try symbols.append(symbol_allocator, .{ .name = di.getSymbolName(address), .compile_unit_name = compile_unit.die.getAttrString(di, endian, std.dwarf.AT.name, di.section(.debug_str), compile_unit) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, }, - .source_location = di.getLineNumberInfo(gpa, endian, compile_unit, address) catch |err| switch (err) { + .source_location = di.getLineNumberInfo(gpa, text_arena, endian, compile_unit, address) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, error.ReadFailed, error.EndOfStream, diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index 59a16968ff95e95ce86c0f4e1aca972677a3a26d..6c48d10dcd68fc7bab3c0122e4908006a8d65ac2 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -617,6 +617,7 @@ pub fn getBinaryAnnotations(self: *Pdb, module: *Module, site: *align(1) const p pub fn getInlineSiteSourceLocation( self: *Pdb, + gpa: Allocator, mod: *Module, site: *align(1) const pdb.InlineSiteSym, inlinee_src_line: *align(1) const pdb.InlineeSourceLine, @@ -627,7 +628,7 @@ pub fn getInlineSiteSourceLocation( if (!range.contains(offset_in_func)) continue; const file_id = range.file_id orelse inlinee_src_line.file_id; - const file_name = try self.getFileName(mod, file_id); + const file_name = try self.getFileName(gpa, mod, file_id); errdefer self.allocator.free(file_name); return .{ @@ -640,14 +641,14 @@ pub fn getInlineSiteSourceLocation( return null; } -pub fn getFileName(self: *Pdb, mod: *Module, file_id: u32) ![]const u8 { +pub fn getFileName(self: *Pdb, gpa: Allocator, mod: *Module, file_id: u32) ![]const u8 { const checksum_offset = mod.checksum_offset orelse return error.MissingDebugInfo; const subsect_index = checksum_offset + file_id; const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&mod.subsect_info[subsect_index]); const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; self.string_table.?.seekTo(strtab_offset) catch return error.InvalidDebugInfo; const string_reader = &self.string_table.?.interface; - var source_file_name: Io.Writer.Allocating = .init(self.allocator); + var source_file_name: Io.Writer.Allocating = .init(gpa); defer source_file_name.deinit(); _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024)); assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API @@ -716,10 +717,9 @@ pub fn getInlineeSourceLines( return mod.inlinee_source_lines[begin..end]; } -pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.SourceLocation { +pub fn getLineNumberInfo(self: *Pdb, gpa: Allocator, module: *Module, address: u64) !std.debug.SourceLocation { std.debug.assert(module.populated); const subsect_info = module.subsect_info; - const gpa = self.allocator; var sect_offset: usize = 0; var skip_len: usize = undefined; @@ -769,7 +769,7 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S // line_i == 0 would mean that no matching pdb.LineNumberEntry was found. if (line_i > 0) { - const file_name = try self.getFileName(module, block_hdr.name_index); + const file_name = try self.getFileName(gpa, module, block_hdr.name_index); errdefer gpa.free(file_name); const line_entry_idx = line_i - 1; diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index bc607569f8193c3c83e643c54eb4e621d2113c76..b56e32983f78bf52d89b5a604ba3b6aa169767b3 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -33,11 +33,13 @@ pub fn deinit(si: *SelfInfo, io: Io) void { pub fn getSymbols( si: *SelfInfo, io: Io, - gpa: Allocator, + symbol_allocator: Allocator, + text_arena: Allocator, address: usize, resolve_inline_callers: bool, symbols: *std.ArrayList(std.debug.Symbol), ) Error!void { + const gpa = std.debug.getDebugInfoAllocator(); const module = try si.findModule(gpa, io, address, .exclusive); defer si.rwlock.unlock(io); @@ -59,10 +61,17 @@ pub fn getSymbols( }; loaded_elf.scanned_dwarf = true; } - return dwarf.getSymbols(gpa, native_endian, vaddr, resolve_inline_callers, symbols); + return dwarf.getSymbols( + symbol_allocator, + text_arena, + native_endian, + vaddr, + resolve_inline_callers, + symbols, + ); } // When DWARF is unavailable, fall back to searching the symtab. - try symbols.append(gpa, loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { + try symbols.append(symbol_allocator, loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo, error.BadSymtab => return error.InvalidDebugInfo, error.OutOfMemory => |e| return e, diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index e53e39f8e576fd724999befdf36643e79d339526..91c8cd41dc8268673bb2c742f0d505c2569a7fa0 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -25,12 +25,14 @@ pub fn deinit(si: *SelfInfo, io: Io) void { pub fn getSymbols( si: *SelfInfo, io: Io, - gpa: Allocator, + symbol_allocator: Allocator, + text_arena: Allocator, address: usize, resolve_inline_callers: bool, symbols: *std.ArrayList(std.debug.Symbol), ) Error!void { _ = resolve_inline_callers; + const gpa = std.debug.getDebugInfoAllocator(); const module = try si.findModule(gpa, io, address); defer si.mutex.unlock(io); @@ -51,7 +53,7 @@ pub fn getSymbols( const ofile_dwarf, const ofile_vaddr = file.getDwarfForAddress(gpa, io, vaddr) catch { // Return at least the symbol name if available. - return symbols.append(gpa, .{ + return symbols.append(symbol_allocator, .{ .name = try file.lookupSymbolName(vaddr), .compile_unit_name = null, .source_location = null, @@ -60,14 +62,14 @@ pub fn getSymbols( const compile_unit = ofile_dwarf.findCompileUnit(native_endian, ofile_vaddr) catch { // Return at least the symbol name if available. - return symbols.append(gpa, .{ + return symbols.append(symbol_allocator, .{ .name = try file.lookupSymbolName(vaddr), .compile_unit_name = null, .source_location = null, }); }; - try symbols.append(gpa, .{ + try symbols.append(symbol_allocator, .{ .name = ofile_dwarf.getSymbolName(ofile_vaddr) orelse try file.lookupSymbolName(vaddr), .compile_unit_name = compile_unit.die.getAttrString( @@ -81,6 +83,7 @@ pub fn getSymbols( }, .source_location = ofile_dwarf.getLineNumberInfo( gpa, + text_arena, native_endian, compile_unit, ofile_vaddr, diff --git a/lib/std/debug/SelfInfo/Windows.zig b/lib/std/debug/SelfInfo/Windows.zig index 686dec41706601e3cd41675d7da1d137fcadd750..50684e9b2a8d6288dcfba85a170420784756d935 100644 --- a/lib/std/debug/SelfInfo/Windows.zig +++ b/lib/std/debug/SelfInfo/Windows.zig @@ -28,17 +28,20 @@ pub fn deinit(si: *SelfInfo, io: Io) void { pub fn getSymbols( si: *SelfInfo, io: Io, - gpa: Allocator, + symbol_allocator: Allocator, + text_arena: Allocator, address: usize, resolve_inline_callers: bool, symbols: *std.ArrayList(std.debug.Symbol), ) Error!void { + const gpa = std.debug.getDebugInfoAllocator(); try si.lock.lockShared(io); defer si.lock.unlockShared(io); const module = try si.findModule(gpa, address); const di = try module.getDebugInfo(gpa, io); return di.getSymbols( - gpa, + symbol_allocator, + text_arena, address - @intFromPtr(module.entry.DllBase), resolve_inline_callers, symbols, @@ -254,7 +257,8 @@ const Module = struct { fn getSymbols( di: *DebugInfo, - gpa: Allocator, + symbol_allocator: Allocator, + text_arena: Allocator, vaddr: usize, resolve_inline_callers: bool, symbols: *std.ArrayList(std.debug.Symbol), @@ -312,6 +316,7 @@ const Module = struct { inline_site.inlinee, )) |inlinee_src_line| { const maybe_loc = pdb.getInlineSiteSourceLocation( + text_arena, module, inline_site, inlinee_src_line.info, @@ -333,7 +338,7 @@ const Module = struct { else null; - try symbols.append(gpa, .{ + try symbols.append(symbol_allocator, .{ .name = name, .compile_unit_name = compile_unit_name, .source_location = loc, @@ -359,10 +364,10 @@ const Module = struct { // If there's room for another symbol, add the actual proc if (resolve_inline_callers or symbols.items.len == 0) { - try symbols.append(gpa, .{ + try symbols.append(symbol_allocator, .{ .name = if (maybe_proc) |proc| pdb.getSymbolName(proc) else null, .compile_unit_name = compile_unit_name, - .source_location = pdb.getLineNumberInfo(module, addr) catch null, + .source_location = pdb.getLineNumberInfo(text_arena, module, addr) catch null, }); } @@ -372,7 +377,14 @@ const Module = struct { dwarf: { const dwarf = &(di.dwarf orelse break :dwarf); const addr = vaddr + di.coff_image_base; - return dwarf.getSymbols(gpa, native_endian, addr, resolve_inline_callers, symbols); + return dwarf.getSymbols( + symbol_allocator, + text_arena, + native_endian, + addr, + resolve_inline_callers, + symbols, + ); } return error.MissingDebugInfo; diff --git a/test/standalone/coff_dwarf/main.zig b/test/standalone/coff_dwarf/main.zig index 66b7e3656b344563a3227a780a12e26232ea52e6..9dbee9ec787a87c3b35a8d3e5485dd719bd85b43 100644 --- a/test/standalone/coff_dwarf/main.zig +++ b/test/standalone/coff_dwarf/main.zig @@ -12,16 +12,26 @@ pub fn main(init: std.process.Init) void { var add_addr: usize = undefined; _ = add(1, 2, &add_addr); - const symbols = di.getSymbols(io, add_addr, false) catch |err| fatal("failed to get symbol: {t}", .{err}); const debug_gpa = std.debug.getDebugInfoAllocator(); - defer for (symbols) |symbol| { - if (symbol.source_location) |sl| { - debug_gpa.free(sl.file_name); - } - }; - - if (symbols.len != 1) fatal("expected 1 symbol, found {}", .{symbols.len}); - const symbol = symbols[0]; + const symbol_allocator = debug_gpa; + + var symbols: std.ArrayList(std.debug.Symbol) = .empty; + defer symbols.deinit(symbol_allocator); + + var text_arena: std.heap.ArenaAllocator = .init(debug_gpa); + defer text_arena.deinit(); + + di.getSymbols( + io, + symbol_allocator, + text_arena.allocator(), + add_addr, + false, + &symbols, + ) catch |err| fatal("failed to get symbol: {t}", .{err}); + + if (symbols.items.len != 1) fatal("expected 1 symbol, found {}", .{symbols.items.len}); + const symbol = symbols.items[0]; if (symbol.name == null) fatal("failed to resolve symbol name", .{}); if (symbol.compile_unit_name == null) fatal("failed to resolve compile unit", .{}); -- 2.54.0