diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 38b2cfc59b..7fac160855 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -133,7 +133,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { } } -pub const StackTraceContext = blk: { +pub const ThreadContext = blk: { if (native_os == .windows) { break :blk std.os.windows.CONTEXT; } else if (have_ucontext) { @@ -146,7 +146,7 @@ pub const StackTraceContext = blk: { /// Tries to print the stack trace starting from the supplied base pointer to stderr, /// unbuffered, and ignores any error returned. /// TODO multithreaded awareness -pub fn dumpStackTraceFromBase(context: *const StackTraceContext) void { +pub fn dumpStackTraceFromBase(context: *const ThreadContext) void { nosuspend { if (comptime builtin.target.isWasm()) { if (native_os == .wasi) { @@ -437,7 +437,7 @@ pub const have_ucontext = @hasDecl(os.system, "ucontext_t") and else => true, }); -pub inline fn getContext(context: *StackTraceContext) bool { +pub inline fn getContext(context: *ThreadContext) bool { if (native_os == .windows) { context.* = std.mem.zeroes(windows.CONTEXT); windows.ntdll.RtlCaptureContext(context); @@ -606,8 +606,8 @@ pub const StackIterator = struct { fn next_dwarf(self: *StackIterator) !usize { const module = try self.debug_info.?.getModuleForAddress(self.dwarf_context.pc); if (try module.getDwarfInfoForAddress(self.debug_info.?.allocator, self.dwarf_context.pc)) |di| { - self.dwarf_context.reg_ctx.eh_frame = true; - self.dwarf_context.reg_ctx.is_macho = di.is_macho; + self.dwarf_context.reg_context.eh_frame = true; + self.dwarf_context.reg_context.is_macho = di.is_macho; return di.unwindFrame(&self.dwarf_context, module.base_address); } else return error.MissingDebugInfo; } @@ -663,7 +663,7 @@ pub fn writeCurrentStackTrace( tty_config: io.tty.Config, start_addr: ?usize, ) !void { - var context: StackTraceContext = undefined; + var context: ThreadContext = undefined; const has_context = getContext(&context); if (native_os == .windows) { return writeStackTraceWindows(out_stream, debug_info, tty_config, &context, start_addr); diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 2d71885e9b..0909b6eafb 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -146,11 +146,11 @@ pub const CC = enum(u8) { pass_by_reference = 0x4, pass_by_value = 0x5, - lo_user = 0x40, - hi_user = 0xff, - GNU_renesas_sh = 0x40, GNU_borland_fastcall_i386 = 0x41, + + pub const lo_user = 0x40; + pub const hi_user = 0xff; }; pub const Format = enum { @"32", @"64" }; @@ -1676,13 +1676,13 @@ pub const DwarfInfo = struct { var expression_context = .{ .isValidMemory = context.isValidMemory, .compile_unit = di.findCompileUnit(fde.pc_begin) catch null, - .ucontext = &context.ucontext, - .reg_ctx = context.reg_ctx, + .thread_context = &context.thread_context, + .reg_context = context.reg_context, .cfa = context.cfa, }; context.vm.reset(); - context.reg_ctx.eh_frame = cie.version != 4; + context.reg_context.eh_frame = cie.version != 4; _ = try context.vm.runToNative(context.allocator, mapped_pc, cie, fde); const row = &context.vm.current_row; @@ -1690,7 +1690,7 @@ pub const DwarfInfo = struct { context.cfa = switch (row.cfa.rule) { .val_offset => |offset| blk: { const register = row.cfa.register orelse return error.InvalidCFARule; - const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register, context.reg_ctx)); + const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, register, context.reg_context)); break :blk try call_frame.applyOffset(value, offset); }, .expression => |expression| blk: { @@ -1711,14 +1711,14 @@ pub const DwarfInfo = struct { if (!context.isValidMemory(context.cfa.?)) return error.InvalidCFA; expression_context.cfa = context.cfa; - // Buffering the modifications is done because copying the ucontext is not portable, + // Buffering the modifications is done because copying the thread context is not portable, // some implementations (ie. darwin) use internal pointers to the mcontext. var arena = std.heap.ArenaAllocator.init(context.allocator); defer arena.deinit(); const update_allocator = arena.allocator(); const RegisterUpdate = struct { - // Backed by ucontext + // Backed by thread_context old_value: []u8, // Backed by arena new_value: []const u8, @@ -1733,7 +1733,7 @@ pub const DwarfInfo = struct { has_next_ip = column.rule != .undefined; } - const old_value = try abi.regBytes(&context.ucontext, register, context.reg_ctx); + const old_value = try abi.regBytes(&context.thread_context, register, context.reg_context); const new_value = try update_allocator.alloc(u8, old_value.len); const prev = update_tail; @@ -1758,12 +1758,12 @@ pub const DwarfInfo = struct { } if (has_next_ip) { - context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, comptime abi.ipRegNum(), context.reg_ctx)); + context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, comptime abi.ipRegNum(), context.reg_context)); } else { context.pc = 0; } - mem.writeIntSliceNative(usize, try abi.regBytes(&context.ucontext, abi.spRegNum(context.reg_ctx), context.reg_ctx), context.cfa.?); + mem.writeIntSliceNative(usize, try abi.regBytes(&context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?); // The call instruction will have pushed the address of the instruction that follows the call as the return address // However, this return address may be past the end of the function if the caller was `noreturn`. @@ -1779,20 +1779,24 @@ pub const UnwindContext = struct { allocator: mem.Allocator, cfa: ?usize, pc: usize, - ucontext: os.ucontext_t, - reg_ctx: abi.RegisterContext, + thread_context: debug.ThreadContext, + reg_context: abi.RegisterContext, isValidMemory: *const fn (address: usize) bool, vm: call_frame.VirtualMachine = .{}, stack_machine: expressions.StackMachine(.{ .call_frame_context = true }) = .{}, - pub fn init(allocator: mem.Allocator, ucontext: *const os.ucontext_t, isValidMemory: *const fn (address: usize) bool) !UnwindContext { - const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null)); + pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext { + const pc = mem.readIntSliceNative(usize, try abi.regBytes(thread_context, abi.ipRegNum(), null)); + + if (builtin.os.tag == .macos) @compileError("Fix below TODO"); + return .{ .allocator = allocator, .cfa = null, .pc = pc, - .ucontext = ucontext.*, - .reg_ctx = undefined, + // TODO: This is broken on macos, need a function that knows how to copy the OSs mcontext properly + .thread_context = thread_context.*, + .reg_context = undefined, .isValidMemory = isValidMemory, }; } @@ -1803,7 +1807,7 @@ pub const UnwindContext = struct { } pub fn getFp(self: *const UnwindContext) !usize { - return mem.readIntSliceNative(usize, try abi.regBytes(&self.ucontext, abi.fpRegNum(self.reg_ctx), self.reg_ctx)); + return mem.readIntSliceNative(usize, try abi.regBytes(&self.thread_context, abi.fpRegNum(self.reg_context), self.reg_context)); } }; @@ -2388,3 +2392,7 @@ fn pcRelBase(field_ptr: usize, pc_rel_offset: i64) !usize { return math.add(usize, field_ptr, @as(usize, @intCast(pc_rel_offset))); } } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/lib/std/dwarf/abi.zig b/lib/std/dwarf/abi.zig index 7b1418a293..1927e3df1a 100644 --- a/lib/std/dwarf/abi.zig +++ b/lib/std/dwarf/abi.zig @@ -3,11 +3,6 @@ const std = @import("../std.zig"); const os = std.os; const mem = std.mem; -pub const RegisterContext = struct { - eh_frame: bool, - is_macho: bool, -}; - pub fn isSupportedArch(arch: std.Target.Cpu.Arch) bool { return switch (arch) { .x86, @@ -29,10 +24,10 @@ pub fn ipRegNum() u8 { }; } -pub fn fpRegNum(reg_ctx: RegisterContext) u8 { +pub fn fpRegNum(reg_context: RegisterContext) u8 { return switch (builtin.cpu.arch) { // GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO - .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 4 else 5, + .x86 => if (reg_context.eh_frame and reg_context.is_macho) 4 else 5, .x86_64 => 6, .arm => 11, .aarch64 => 29, @@ -40,9 +35,9 @@ pub fn fpRegNum(reg_ctx: RegisterContext) u8 { }; } -pub fn spRegNum(reg_ctx: RegisterContext) u8 { +pub fn spRegNum(reg_context: RegisterContext) u8 { return switch (builtin.cpu.arch) { - .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 5 else 4, + .x86 => if (reg_context.eh_frame and reg_context.is_macho) 5 else 4, .x86_64 => 7, .arm => 13, .aarch64 => 31, @@ -52,21 +47,76 @@ pub fn spRegNum(reg_ctx: RegisterContext) u8 { fn RegBytesReturnType(comptime ContextPtrType: type) type { const info = @typeInfo(ContextPtrType); - if (info != .Pointer or info.Pointer.child != os.ucontext_t) { - @compileError("Expected a pointer to ucontext_t, got " ++ @typeName(@TypeOf(ContextPtrType))); + if (info != .Pointer or info.Pointer.child != std.debug.ThreadContext) { + @compileError("Expected a pointer to std.debug.ThreadContext, got " ++ @typeName(@TypeOf(ContextPtrType))); } return if (info.Pointer.is_const) return []const u8 else []u8; } +pub const RegisterContext = struct { + eh_frame: bool, + is_macho: bool, +}; + /// Returns a slice containing the backing storage for `reg_number`. /// -/// `reg_ctx` describes in what context the register number is used, as it can have different +/// `reg_context` describes in what context the register number is used, as it can have different /// meanings depending on the DWARF container. It is only required when getting the stack or /// frame pointer register on some architectures. -pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext) !RegBytesReturnType(@TypeOf(ucontext_ptr)) { - var m = &ucontext_ptr.mcontext; +pub fn regBytes(thread_context_ptr: anytype, reg_number: u8, reg_context: ?RegisterContext) !RegBytesReturnType(@TypeOf(thread_context_ptr)) { + if (builtin.os.tag == .windows) { + return switch (builtin.cpu.arch) { + .x86 => switch (reg_number) { + 0 => mem.asBytes(&thread_context_ptr.Eax), + 1 => mem.asBytes(&thread_context_ptr.Ecx), + 2 => mem.asBytes(&thread_context_ptr.Edx), + 3 => mem.asBytes(&thread_context_ptr.Ebx), + 4 => mem.asBytes(&thread_context_ptr.Esp), + 5 => mem.asBytes(&thread_context_ptr.Ebp), + 6 => mem.asBytes(&thread_context_ptr.Esi), + 7 => mem.asBytes(&thread_context_ptr.Edi), + 8 => mem.asBytes(&thread_context_ptr.Eip), + 9 => mem.asBytes(&thread_context_ptr.EFlags), + 10 => mem.asBytes(&thread_context_ptr.SegCs), + 11 => mem.asBytes(&thread_context_ptr.SegSs), + 12 => mem.asBytes(&thread_context_ptr.SegDs), + 13 => mem.asBytes(&thread_context_ptr.SegEs), + 14 => mem.asBytes(&thread_context_ptr.SegFs), + 15 => mem.asBytes(&thread_context_ptr.SegGs), + else => error.InvalidRegister, + }, + .x86_64 => switch (reg_number) { + 0 => mem.asBytes(&thread_context_ptr.Rax), + 1 => mem.asBytes(&thread_context_ptr.Rdx), + 2 => mem.asBytes(&thread_context_ptr.Rcx), + 3 => mem.asBytes(&thread_context_ptr.Rbx), + 4 => mem.asBytes(&thread_context_ptr.Rsi), + 5 => mem.asBytes(&thread_context_ptr.Rdi), + 6 => mem.asBytes(&thread_context_ptr.Rbp), + 7 => mem.asBytes(&thread_context_ptr.Rsp), + 8 => mem.asBytes(&thread_context_ptr.R8), + 9 => mem.asBytes(&thread_context_ptr.R9), + 10 => mem.asBytes(&thread_context_ptr.R10), + 11 => mem.asBytes(&thread_context_ptr.R11), + 12 => mem.asBytes(&thread_context_ptr.R12), + 13 => mem.asBytes(&thread_context_ptr.R13), + 14 => mem.asBytes(&thread_context_ptr.R14), + 15 => mem.asBytes(&thread_context_ptr.R15), + 16 => mem.asBytes(&thread_context_ptr.Rip), + else => error.InvalidRegister, + }, + .aarch64 => switch (reg_number) { + 0...30 => mem.asBytes(&thread_context_ptr.DUMMYUNIONNAME.X[reg_number]), + 31 => mem.asBytes(&thread_context_ptr.Sp), + 32 => mem.asBytes(&thread_context_ptr.Pc), + }, + else => error.UnimplementedArch, + }; + } + const ucontext_ptr = thread_context_ptr; + var m = &ucontext_ptr.mcontext; return switch (builtin.cpu.arch) { .x86 => switch (builtin.os.tag) { .linux, .netbsd, .solaris => switch (reg_number) { @@ -74,7 +124,7 @@ pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ECX]), 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDX]), 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBX]), - 4...5 => if (reg_ctx) |r| bytes: { + 4...5 => if (reg_context) |r| bytes: { if (reg_number == 4) { break :bytes if (r.eh_frame and r.is_macho) mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP]) @@ -98,7 +148,6 @@ pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.FS]), 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.GS]), 16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs - // TODO: Map TRAPNO, ERR, UESP 32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs else => error.InvalidRegister, }, diff --git a/lib/std/dwarf/call_frame.zig b/lib/std/dwarf/call_frame.zig index 45c947d88b..49772e2ae5 100644 --- a/lib/std/dwarf/call_frame.zig +++ b/lib/std/dwarf/call_frame.zig @@ -2,10 +2,10 @@ const builtin = @import("builtin"); const std = @import("../std.zig"); const mem = std.mem; const debug = std.debug; -const leb = @import("../leb128.zig"); -const abi = @import("abi.zig"); -const dwarf = @import("../dwarf.zig"); -const expressions = @import("expressions.zig"); +const leb = std.leb; +const dwarf = std.dwarf; +const abi = dwarf.abi; +const expressions = dwarf.expressions; const assert = std.debug.assert; const Opcode = enum(u8) { @@ -315,9 +315,9 @@ pub const VirtualMachine = struct { } else return error.InvalidCFA; }, .register => |register| { - const src = try abi.regBytes(&context.ucontext, register, context.reg_ctx); + const src = try abi.regBytes(&context.thread_context, register, context.reg_context); if (src.len != out.len) return error.RegisterTypeMismatch; - @memcpy(out, try abi.regBytes(&context.ucontext, register, context.reg_ctx)); + @memcpy(out, try abi.regBytes(&context.thread_context, register, context.reg_context)); }, .expression => |expression| { context.stack_machine.reset(); diff --git a/lib/std/dwarf/expressions.zig b/lib/std/dwarf/expressions.zig index beff1e6754..a617244db2 100644 --- a/lib/std/dwarf/expressions.zig +++ b/lib/std/dwarf/expressions.zig @@ -1,8 +1,8 @@ const std = @import("std"); const builtin = @import("builtin"); const OP = @import("OP.zig"); -const leb = @import("../leb128.zig"); -const dwarf = @import("../dwarf.zig"); +const leb = std.leb; +const dwarf = std.dwarf; const abi = dwarf.abi; const mem = std.mem; const assert = std.debug.assert; @@ -17,12 +17,12 @@ pub const ExpressionContext = struct { /// The compilation unit this expression relates to, if any compile_unit: ?*const dwarf.CompileUnit = null, - /// Register context - ucontext: ?*std.os.ucontext_t, - reg_ctx: ?abi.RegisterContext, + /// Thread context + thread_context: ?*std.debug.ThreadContext = null, + reg_context: ?abi.RegisterContext = null, /// Call frame address, if in a CFI context - cfa: ?usize, + cfa: ?usize = null, }; pub const ExpressionOptions = struct { @@ -344,13 +344,13 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { OP.breg0...OP.breg31, OP.bregx, => { - if (context.ucontext == null) return error.IncompleteExpressionContext; + if (context.thread_context == null) return error.IncompleteExpressionContext; const base_register = (try readOperand(stream, opcode)).?.base_register; var value: i64 = @intCast(mem.readIntSliceNative(usize, try abi.regBytes( - context.ucontext.?, + context.thread_context.?, base_register.base_register, - context.reg_ctx, + context.reg_context, ))); value += base_register.offset; try self.stack.append(allocator, .{ .generic = @intCast(value) }); @@ -358,9 +358,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { OP.regval_type => { const register_type = (try readOperand(stream, opcode)).?.register_type; const value = mem.readIntSliceNative(usize, try abi.regBytes( - context.ucontext.?, + context.thread_context.?, register_type.register, - context.reg_ctx, + context.reg_context, )); try self.stack.append(allocator, .{ .regval_type = .{ @@ -464,7 +464,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { // 2.5.1.4: Arithmetic and Logical Operations OP.abs => { if (self.stack.items.len == 0) return error.InvalidExpression; - const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); + const value: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); self.stack.items[self.stack.items.len - 1] = .{ .generic = std.math.absCast(value), }; @@ -478,10 +478,10 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { }, OP.div => { if (self.stack.items.len < 2) return error.InvalidExpression; - const a: isize = @bitCast(try self.stack.pop().asIntegral()); - const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); + const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral()); + const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); self.stack.items[self.stack.items.len - 1] = .{ - .generic = @bitCast(try std.math.divTrunc(isize, b, a)), + .generic = @bitCast(try std.math.divTrunc(addr_type_signed, b, a)), }; }, OP.minus => { @@ -493,16 +493,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { }, OP.mod => { if (self.stack.items.len < 2) return error.InvalidExpression; - const a: isize = @bitCast(try self.stack.pop().asIntegral()); - const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); + const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral()); + const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); self.stack.items[self.stack.items.len - 1] = .{ .generic = @bitCast(@mod(b, a)), }; }, OP.mul => { if (self.stack.items.len < 2) return error.InvalidExpression; - const a: isize = @bitCast(try self.stack.pop().asIntegral()); - const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); + const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral()); + const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); self.stack.items[self.stack.items.len - 1] = .{ .generic = @bitCast(@mulWithOverflow(a, b)[0]), }; @@ -512,7 +512,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { self.stack.items[self.stack.items.len - 1] = .{ .generic = @bitCast( try std.math.negate( - @as(isize, @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral())), + @as(addr_type_signed, @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral())), ), ), }; @@ -563,9 +563,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { OP.shra => { if (self.stack.items.len < 2) return error.InvalidExpression; const a = try self.stack.pop().asIntegral(); - const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); + const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); self.stack.items[self.stack.items.len - 1] = .{ - .generic = @bitCast(std.math.shr(isize, b, a)), + .generic = @bitCast(std.math.shr(addr_type_signed, b, a)), }; }, OP.xor => { @@ -589,8 +589,8 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { const b = self.stack.items[self.stack.items.len - 1]; if (a == .generic and b == .generic) { - const a_int: isize = @bitCast(a.asIntegral() catch unreachable); - const b_int: isize = @bitCast(b.asIntegral() catch unreachable); + const a_int: addr_type_signed = @bitCast(a.asIntegral() catch unreachable); + const b_int: addr_type_signed = @bitCast(b.asIntegral() catch unreachable); const result = @intFromBool(switch (opcode) { OP.le => b_int < a_int, OP.ge => b_int >= a_int, @@ -617,7 +617,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { if (condition) { const new_pos = std.math.cast( usize, - try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset), + try std.math.add(addr_type_signed, @as(addr_type_signed, @intCast(stream.pos)), branch_offset), ) orelse return error.InvalidExpression; if (new_pos < 0 or new_pos >= stream.buffer.len) return error.InvalidExpression; @@ -710,7 +710,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { }; } -pub fn Writer(options: ExpressionOptions) type { +pub fn Builder(comptime options: ExpressionOptions) type { const addr_type = switch (options.addr_size) { 2 => u16, 4 => u32, @@ -959,10 +959,33 @@ fn opcodeValidInCFA(opcode: u8) bool { }; } +const testing = std.testing; test "DWARF expressions" { const allocator = std.testing.allocator; const options = ExpressionOptions{}; - const stack_machine = StackMachine(options){}; + var stack_machine = StackMachine(options){}; defer stack_machine.deinit(allocator); + + const b = Builder(options); + + var program = std.ArrayList(u8).init(allocator); + defer program.deinit(); + + const writer = program.writer(); + + // Literals + { + const context = ExpressionContext{}; + for (0..32) |i| { + try b.writeLiteral(writer, @intCast(i)); + } + + _ = try stack_machine.run(program.items, allocator, context, 0); + + for (0..32) |i| { + const expected = 31 - i; + try testing.expectEqual(expected, stack_machine.stack.popOrNull().?.generic); + } + } } diff --git a/src/crash_report.zig b/src/crash_report.zig index f09fce14f9..82be4211c7 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -271,7 +271,7 @@ const StackContext = union(enum) { current: struct { ret_addr: ?usize, }, - exception: *const debug.StackTraceContext, + exception: *const debug.ThreadContext, not_supported: void, pub fn dumpStackTrace(ctx: @This()) void { diff --git a/test/standalone/dwarf_unwinding/shared_lib_unwind.zig b/test/standalone/dwarf_unwinding/shared_lib_unwind.zig index 8f42197972..543654d24f 100644 --- a/test/standalone/dwarf_unwinding/shared_lib_unwind.zig +++ b/test/standalone/dwarf_unwinding/shared_lib_unwind.zig @@ -5,7 +5,7 @@ const testing = std.testing; noinline fn frame4(expected: *[4]usize, unwound: *[4]usize) void { expected[0] = @returnAddress(); - var context: debug.StackTraceContext = undefined; + var context: debug.ThreadContext = undefined; testing.expect(debug.getContext(&context)) catch @panic("failed to getContext"); var debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo"); diff --git a/test/standalone/dwarf_unwinding/zig_unwind.zig b/test/standalone/dwarf_unwinding/zig_unwind.zig index 707c2b7632..3b13de24a1 100644 --- a/test/standalone/dwarf_unwinding/zig_unwind.zig +++ b/test/standalone/dwarf_unwinding/zig_unwind.zig @@ -5,7 +5,7 @@ const testing = std.testing; noinline fn frame3(expected: *[4]usize, unwound: *[4]usize) void { expected[0] = @returnAddress(); - var context: debug.StackTraceContext = undefined; + var context: debug.ThreadContext = undefined; testing.expect(debug.getContext(&context)) catch @panic("failed to getContext"); var debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");