authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-06 22:02:47-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:15-04:00
log5f72c6508d78291d8f0358d06d407a8d6b4a28c9
treea5f2b6043ee8ef90a64679cc5299e7d55981d384
parent8547c42ba542f77c55ce50253446fd2bf4f3592b

debug: rename StackTraceContext to ThreadContext

dwarf: use ThreadContext instead of os.ucontext_t dwarf: add regBytes impl for windows dwarf: fixup expression types for non-native

8 files changed, 157 insertions(+), 77 deletions(-)

lib/std/debug.zig+6-6
......@@ -133,7 +133,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
133133 }
134134}
135135
136pub const StackTraceContext = blk: {
136pub const ThreadContext = blk: {
137137 if (native_os == .windows) {
138138 break :blk std.os.windows.CONTEXT;
139139 } else if (have_ucontext) {
......@@ -146,7 +146,7 @@ pub const StackTraceContext = blk: {
146146/// Tries to print the stack trace starting from the supplied base pointer to stderr,
147147/// unbuffered, and ignores any error returned.
148148/// TODO multithreaded awareness
149pub fn dumpStackTraceFromBase(context: *const StackTraceContext) void {
149pub fn dumpStackTraceFromBase(context: *const ThreadContext) void {
150150 nosuspend {
151151 if (comptime builtin.target.isWasm()) {
152152 if (native_os == .wasi) {
......@@ -437,7 +437,7 @@ pub const have_ucontext = @hasDecl(os.system, "ucontext_t") and
437437 else => true,
438438});
439439
440pub inline fn getContext(context: *StackTraceContext) bool {
440pub inline fn getContext(context: *ThreadContext) bool {
441441 if (native_os == .windows) {
442442 context.* = std.mem.zeroes(windows.CONTEXT);
443443 windows.ntdll.RtlCaptureContext(context);
......@@ -606,8 +606,8 @@ pub const StackIterator = struct {
606606 fn next_dwarf(self: *StackIterator) !usize {
607607 const module = try self.debug_info.?.getModuleForAddress(self.dwarf_context.pc);
608608 if (try module.getDwarfInfoForAddress(self.debug_info.?.allocator, self.dwarf_context.pc)) |di| {
609 self.dwarf_context.reg_ctx.eh_frame = true;
610 self.dwarf_context.reg_ctx.is_macho = di.is_macho;
609 self.dwarf_context.reg_context.eh_frame = true;
610 self.dwarf_context.reg_context.is_macho = di.is_macho;
611611 return di.unwindFrame(&self.dwarf_context, module.base_address);
612612 } else return error.MissingDebugInfo;
613613 }
......@@ -663,7 +663,7 @@ pub fn writeCurrentStackTrace(
663663 tty_config: io.tty.Config,
664664 start_addr: ?usize,
665665) !void {
666 var context: StackTraceContext = undefined;
666 var context: ThreadContext = undefined;
667667 const has_context = getContext(&context);
668668 if (native_os == .windows) {
669669 return writeStackTraceWindows(out_stream, debug_info, tty_config, &context, start_addr);
lib/std/dwarf.zig+27-19
......@@ -146,11 +146,11 @@ pub const CC = enum(u8) {
146146 pass_by_reference = 0x4,
147147 pass_by_value = 0x5,
148148
149 lo_user = 0x40,
150 hi_user = 0xff,
151
152149 GNU_renesas_sh = 0x40,
153150 GNU_borland_fastcall_i386 = 0x41,
151
152 pub const lo_user = 0x40;
153 pub const hi_user = 0xff;
154154};
155155
156156pub const Format = enum { @"32", @"64" };
......@@ -1676,13 +1676,13 @@ pub const DwarfInfo = struct {
16761676 var expression_context = .{
16771677 .isValidMemory = context.isValidMemory,
16781678 .compile_unit = di.findCompileUnit(fde.pc_begin) catch null,
1679 .ucontext = &context.ucontext,
1680 .reg_ctx = context.reg_ctx,
1679 .thread_context = &context.thread_context,
1680 .reg_context = context.reg_context,
16811681 .cfa = context.cfa,
16821682 };
16831683
16841684 context.vm.reset();
1685 context.reg_ctx.eh_frame = cie.version != 4;
1685 context.reg_context.eh_frame = cie.version != 4;
16861686
16871687 _ = try context.vm.runToNative(context.allocator, mapped_pc, cie, fde);
16881688 const row = &context.vm.current_row;
......@@ -1690,7 +1690,7 @@ pub const DwarfInfo = struct {
16901690 context.cfa = switch (row.cfa.rule) {
16911691 .val_offset => |offset| blk: {
16921692 const register = row.cfa.register orelse return error.InvalidCFARule;
1693 const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
1693 const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, register, context.reg_context));
16941694 break :blk try call_frame.applyOffset(value, offset);
16951695 },
16961696 .expression => |expression| blk: {
......@@ -1711,14 +1711,14 @@ pub const DwarfInfo = struct {
17111711 if (!context.isValidMemory(context.cfa.?)) return error.InvalidCFA;
17121712 expression_context.cfa = context.cfa;
17131713
1714 // Buffering the modifications is done because copying the ucontext is not portable,
1714 // Buffering the modifications is done because copying the thread context is not portable,
17151715 // some implementations (ie. darwin) use internal pointers to the mcontext.
17161716 var arena = std.heap.ArenaAllocator.init(context.allocator);
17171717 defer arena.deinit();
17181718 const update_allocator = arena.allocator();
17191719
17201720 const RegisterUpdate = struct {
1721 // Backed by ucontext
1721 // Backed by thread_context
17221722 old_value: []u8,
17231723 // Backed by arena
17241724 new_value: []const u8,
......@@ -1733,7 +1733,7 @@ pub const DwarfInfo = struct {
17331733 has_next_ip = column.rule != .undefined;
17341734 }
17351735
1736 const old_value = try abi.regBytes(&context.ucontext, register, context.reg_ctx);
1736 const old_value = try abi.regBytes(&context.thread_context, register, context.reg_context);
17371737 const new_value = try update_allocator.alloc(u8, old_value.len);
17381738
17391739 const prev = update_tail;
......@@ -1758,12 +1758,12 @@ pub const DwarfInfo = struct {
17581758 }
17591759
17601760 if (has_next_ip) {
1761 context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, comptime abi.ipRegNum(), context.reg_ctx));
1761 context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, comptime abi.ipRegNum(), context.reg_context));
17621762 } else {
17631763 context.pc = 0;
17641764 }
17651765
1766 mem.writeIntSliceNative(usize, try abi.regBytes(&context.ucontext, abi.spRegNum(context.reg_ctx), context.reg_ctx), context.cfa.?);
1766 mem.writeIntSliceNative(usize, try abi.regBytes(&context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);
17671767
17681768 // The call instruction will have pushed the address of the instruction that follows the call as the return address
17691769 // 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 {
17791779 allocator: mem.Allocator,
17801780 cfa: ?usize,
17811781 pc: usize,
1782 ucontext: os.ucontext_t,
1783 reg_ctx: abi.RegisterContext,
1782 thread_context: debug.ThreadContext,
1783 reg_context: abi.RegisterContext,
17841784 isValidMemory: *const fn (address: usize) bool,
17851785 vm: call_frame.VirtualMachine = .{},
17861786 stack_machine: expressions.StackMachine(.{ .call_frame_context = true }) = .{},
17871787
1788 pub fn init(allocator: mem.Allocator, ucontext: *const os.ucontext_t, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
1789 const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));
1788 pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
1789 const pc = mem.readIntSliceNative(usize, try abi.regBytes(thread_context, abi.ipRegNum(), null));
1790
1791 if (builtin.os.tag == .macos) @compileError("Fix below TODO");
1792
17901793 return .{
17911794 .allocator = allocator,
17921795 .cfa = null,
17931796 .pc = pc,
1794 .ucontext = ucontext.*,
1795 .reg_ctx = undefined,
1797 // TODO: This is broken on macos, need a function that knows how to copy the OSs mcontext properly
1798 .thread_context = thread_context.*,
1799 .reg_context = undefined,
17961800 .isValidMemory = isValidMemory,
17971801 };
17981802 }
......@@ -1803,7 +1807,7 @@ pub const UnwindContext = struct {
18031807 }
18041808
18051809 pub fn getFp(self: *const UnwindContext) !usize {
1806 return mem.readIntSliceNative(usize, try abi.regBytes(&self.ucontext, abi.fpRegNum(self.reg_ctx), self.reg_ctx));
1810 return mem.readIntSliceNative(usize, try abi.regBytes(&self.thread_context, abi.fpRegNum(self.reg_context), self.reg_context));
18071811 }
18081812};
18091813
......@@ -2388,3 +2392,7 @@ fn pcRelBase(field_ptr: usize, pc_rel_offset: i64) !usize {
23882392 return math.add(usize, field_ptr, @as(usize, @intCast(pc_rel_offset)));
23892393 }
23902394}
2395
2396test {
2397 std.testing.refAllDecls(@This());
2398}
lib/std/dwarf/abi.zig+65-16
......@@ -3,11 +3,6 @@ const std = @import("../std.zig");
33const os = std.os;
44const mem = std.mem;
55
6pub const RegisterContext = struct {
7 eh_frame: bool,
8 is_macho: bool,
9};
10
116pub fn isSupportedArch(arch: std.Target.Cpu.Arch) bool {
127 return switch (arch) {
138 .x86,
......@@ -29,10 +24,10 @@ pub fn ipRegNum() u8 {
2924 };
3025}
3126
32pub fn fpRegNum(reg_ctx: RegisterContext) u8 {
27pub fn fpRegNum(reg_context: RegisterContext) u8 {
3328 return switch (builtin.cpu.arch) {
3429 // GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO
35 .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 4 else 5,
30 .x86 => if (reg_context.eh_frame and reg_context.is_macho) 4 else 5,
3631 .x86_64 => 6,
3732 .arm => 11,
3833 .aarch64 => 29,
......@@ -40,9 +35,9 @@ pub fn fpRegNum(reg_ctx: RegisterContext) u8 {
4035 };
4136}
4237
43pub fn spRegNum(reg_ctx: RegisterContext) u8 {
38pub fn spRegNum(reg_context: RegisterContext) u8 {
4439 return switch (builtin.cpu.arch) {
45 .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 5 else 4,
40 .x86 => if (reg_context.eh_frame and reg_context.is_macho) 5 else 4,
4641 .x86_64 => 7,
4742 .arm => 13,
4843 .aarch64 => 31,
......@@ -52,21 +47,76 @@ pub fn spRegNum(reg_ctx: RegisterContext) u8 {
5247
5348fn RegBytesReturnType(comptime ContextPtrType: type) type {
5449 const info = @typeInfo(ContextPtrType);
55 if (info != .Pointer or info.Pointer.child != os.ucontext_t) {
56 @compileError("Expected a pointer to ucontext_t, got " ++ @typeName(@TypeOf(ContextPtrType)));
50 if (info != .Pointer or info.Pointer.child != std.debug.ThreadContext) {
51 @compileError("Expected a pointer to std.debug.ThreadContext, got " ++ @typeName(@TypeOf(ContextPtrType)));
5752 }
5853
5954 return if (info.Pointer.is_const) return []const u8 else []u8;
6055}
6156
57pub const RegisterContext = struct {
58 eh_frame: bool,
59 is_macho: bool,
60};
61
6262/// Returns a slice containing the backing storage for `reg_number`.
6363///
64/// `reg_ctx` describes in what context the register number is used, as it can have different
64/// `reg_context` describes in what context the register number is used, as it can have different
6565/// meanings depending on the DWARF container. It is only required when getting the stack or
6666/// frame pointer register on some architectures.
67pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext) !RegBytesReturnType(@TypeOf(ucontext_ptr)) {
68 var m = &ucontext_ptr.mcontext;
67pub fn regBytes(thread_context_ptr: anytype, reg_number: u8, reg_context: ?RegisterContext) !RegBytesReturnType(@TypeOf(thread_context_ptr)) {
68 if (builtin.os.tag == .windows) {
69 return switch (builtin.cpu.arch) {
70 .x86 => switch (reg_number) {
71 0 => mem.asBytes(&thread_context_ptr.Eax),
72 1 => mem.asBytes(&thread_context_ptr.Ecx),
73 2 => mem.asBytes(&thread_context_ptr.Edx),
74 3 => mem.asBytes(&thread_context_ptr.Ebx),
75 4 => mem.asBytes(&thread_context_ptr.Esp),
76 5 => mem.asBytes(&thread_context_ptr.Ebp),
77 6 => mem.asBytes(&thread_context_ptr.Esi),
78 7 => mem.asBytes(&thread_context_ptr.Edi),
79 8 => mem.asBytes(&thread_context_ptr.Eip),
80 9 => mem.asBytes(&thread_context_ptr.EFlags),
81 10 => mem.asBytes(&thread_context_ptr.SegCs),
82 11 => mem.asBytes(&thread_context_ptr.SegSs),
83 12 => mem.asBytes(&thread_context_ptr.SegDs),
84 13 => mem.asBytes(&thread_context_ptr.SegEs),
85 14 => mem.asBytes(&thread_context_ptr.SegFs),
86 15 => mem.asBytes(&thread_context_ptr.SegGs),
87 else => error.InvalidRegister,
88 },
89 .x86_64 => switch (reg_number) {
90 0 => mem.asBytes(&thread_context_ptr.Rax),
91 1 => mem.asBytes(&thread_context_ptr.Rdx),
92 2 => mem.asBytes(&thread_context_ptr.Rcx),
93 3 => mem.asBytes(&thread_context_ptr.Rbx),
94 4 => mem.asBytes(&thread_context_ptr.Rsi),
95 5 => mem.asBytes(&thread_context_ptr.Rdi),
96 6 => mem.asBytes(&thread_context_ptr.Rbp),
97 7 => mem.asBytes(&thread_context_ptr.Rsp),
98 8 => mem.asBytes(&thread_context_ptr.R8),
99 9 => mem.asBytes(&thread_context_ptr.R9),
100 10 => mem.asBytes(&thread_context_ptr.R10),
101 11 => mem.asBytes(&thread_context_ptr.R11),
102 12 => mem.asBytes(&thread_context_ptr.R12),
103 13 => mem.asBytes(&thread_context_ptr.R13),
104 14 => mem.asBytes(&thread_context_ptr.R14),
105 15 => mem.asBytes(&thread_context_ptr.R15),
106 16 => mem.asBytes(&thread_context_ptr.Rip),
107 else => error.InvalidRegister,
108 },
109 .aarch64 => switch (reg_number) {
110 0...30 => mem.asBytes(&thread_context_ptr.DUMMYUNIONNAME.X[reg_number]),
111 31 => mem.asBytes(&thread_context_ptr.Sp),
112 32 => mem.asBytes(&thread_context_ptr.Pc),
113 },
114 else => error.UnimplementedArch,
115 };
116 }
69117
118 const ucontext_ptr = thread_context_ptr;
119 var m = &ucontext_ptr.mcontext;
70120 return switch (builtin.cpu.arch) {
71121 .x86 => switch (builtin.os.tag) {
72122 .linux, .netbsd, .solaris => switch (reg_number) {
......@@ -74,7 +124,7 @@ pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext
74124 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ECX]),
75125 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDX]),
76126 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBX]),
77 4...5 => if (reg_ctx) |r| bytes: {
127 4...5 => if (reg_context) |r| bytes: {
78128 if (reg_number == 4) {
79129 break :bytes if (r.eh_frame and r.is_macho)
80130 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
98148 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.FS]),
99149 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.GS]),
100150 16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs
101 // TODO: Map TRAPNO, ERR, UESP
102151 32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs
103152 else => error.InvalidRegister,
104153 },
lib/std/dwarf/call_frame.zig+6-6
......@@ -2,10 +2,10 @@ const builtin = @import("builtin");
22const std = @import("../std.zig");
33const mem = std.mem;
44const debug = std.debug;
5const leb = @import("../leb128.zig");
6const abi = @import("abi.zig");
7const dwarf = @import("../dwarf.zig");
8const expressions = @import("expressions.zig");
5const leb = std.leb;
6const dwarf = std.dwarf;
7const abi = dwarf.abi;
8const expressions = dwarf.expressions;
99const assert = std.debug.assert;
1010
1111const Opcode = enum(u8) {
......@@ -315,9 +315,9 @@ pub const VirtualMachine = struct {
315315 } else return error.InvalidCFA;
316316 },
317317 .register => |register| {
318 const src = try abi.regBytes(&context.ucontext, register, context.reg_ctx);
318 const src = try abi.regBytes(&context.thread_context, register, context.reg_context);
319319 if (src.len != out.len) return error.RegisterTypeMismatch;
320 @memcpy(out, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
320 @memcpy(out, try abi.regBytes(&context.thread_context, register, context.reg_context));
321321 },
322322 .expression => |expression| {
323323 context.stack_machine.reset();
lib/std/dwarf/expressions.zig+50-27
......@@ -1,8 +1,8 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const OP = @import("OP.zig");
4const leb = @import("../leb128.zig");
5const dwarf = @import("../dwarf.zig");
4const leb = std.leb;
5const dwarf = std.dwarf;
66const abi = dwarf.abi;
77const mem = std.mem;
88const assert = std.debug.assert;
......@@ -17,12 +17,12 @@ pub const ExpressionContext = struct {
1717 /// The compilation unit this expression relates to, if any
1818 compile_unit: ?*const dwarf.CompileUnit = null,
1919
20 /// Register context
21 ucontext: ?*std.os.ucontext_t,
22 reg_ctx: ?abi.RegisterContext,
20 /// Thread context
21 thread_context: ?*std.debug.ThreadContext = null,
22 reg_context: ?abi.RegisterContext = null,
2323
2424 /// Call frame address, if in a CFI context
25 cfa: ?usize,
25 cfa: ?usize = null,
2626};
2727
2828pub const ExpressionOptions = struct {
......@@ -344,13 +344,13 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
344344 OP.breg0...OP.breg31,
345345 OP.bregx,
346346 => {
347 if (context.ucontext == null) return error.IncompleteExpressionContext;
347 if (context.thread_context == null) return error.IncompleteExpressionContext;
348348
349349 const base_register = (try readOperand(stream, opcode)).?.base_register;
350350 var value: i64 = @intCast(mem.readIntSliceNative(usize, try abi.regBytes(
351 context.ucontext.?,
351 context.thread_context.?,
352352 base_register.base_register,
353 context.reg_ctx,
353 context.reg_context,
354354 )));
355355 value += base_register.offset;
356356 try self.stack.append(allocator, .{ .generic = @intCast(value) });
......@@ -358,9 +358,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
358358 OP.regval_type => {
359359 const register_type = (try readOperand(stream, opcode)).?.register_type;
360360 const value = mem.readIntSliceNative(usize, try abi.regBytes(
361 context.ucontext.?,
361 context.thread_context.?,
362362 register_type.register,
363 context.reg_ctx,
363 context.reg_context,
364364 ));
365365 try self.stack.append(allocator, .{
366366 .regval_type = .{
......@@ -464,7 +464,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
464464 // 2.5.1.4: Arithmetic and Logical Operations
465465 OP.abs => {
466466 if (self.stack.items.len == 0) return error.InvalidExpression;
467 const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
467 const value: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
468468 self.stack.items[self.stack.items.len - 1] = .{
469469 .generic = std.math.absCast(value),
470470 };
......@@ -478,10 +478,10 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
478478 },
479479 OP.div => {
480480 if (self.stack.items.len < 2) return error.InvalidExpression;
481 const a: isize = @bitCast(try self.stack.pop().asIntegral());
482 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
481 const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral());
482 const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
483483 self.stack.items[self.stack.items.len - 1] = .{
484 .generic = @bitCast(try std.math.divTrunc(isize, b, a)),
484 .generic = @bitCast(try std.math.divTrunc(addr_type_signed, b, a)),
485485 };
486486 },
487487 OP.minus => {
......@@ -493,16 +493,16 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
493493 },
494494 OP.mod => {
495495 if (self.stack.items.len < 2) return error.InvalidExpression;
496 const a: isize = @bitCast(try self.stack.pop().asIntegral());
497 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
496 const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral());
497 const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
498498 self.stack.items[self.stack.items.len - 1] = .{
499499 .generic = @bitCast(@mod(b, a)),
500500 };
501501 },
502502 OP.mul => {
503503 if (self.stack.items.len < 2) return error.InvalidExpression;
504 const a: isize = @bitCast(try self.stack.pop().asIntegral());
505 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
504 const a: addr_type_signed = @bitCast(try self.stack.pop().asIntegral());
505 const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
506506 self.stack.items[self.stack.items.len - 1] = .{
507507 .generic = @bitCast(@mulWithOverflow(a, b)[0]),
508508 };
......@@ -512,7 +512,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
512512 self.stack.items[self.stack.items.len - 1] = .{
513513 .generic = @bitCast(
514514 try std.math.negate(
515 @as(isize, @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral())),
515 @as(addr_type_signed, @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral())),
516516 ),
517517 ),
518518 };
......@@ -563,9 +563,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
563563 OP.shra => {
564564 if (self.stack.items.len < 2) return error.InvalidExpression;
565565 const a = try self.stack.pop().asIntegral();
566 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
566 const b: addr_type_signed = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
567567 self.stack.items[self.stack.items.len - 1] = .{
568 .generic = @bitCast(std.math.shr(isize, b, a)),
568 .generic = @bitCast(std.math.shr(addr_type_signed, b, a)),
569569 };
570570 },
571571 OP.xor => {
......@@ -589,8 +589,8 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
589589 const b = self.stack.items[self.stack.items.len - 1];
590590
591591 if (a == .generic and b == .generic) {
592 const a_int: isize = @bitCast(a.asIntegral() catch unreachable);
593 const b_int: isize = @bitCast(b.asIntegral() catch unreachable);
592 const a_int: addr_type_signed = @bitCast(a.asIntegral() catch unreachable);
593 const b_int: addr_type_signed = @bitCast(b.asIntegral() catch unreachable);
594594 const result = @intFromBool(switch (opcode) {
595595 OP.le => b_int < a_int,
596596 OP.ge => b_int >= a_int,
......@@ -617,7 +617,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
617617 if (condition) {
618618 const new_pos = std.math.cast(
619619 usize,
620 try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset),
620 try std.math.add(addr_type_signed, @as(addr_type_signed, @intCast(stream.pos)), branch_offset),
621621 ) orelse return error.InvalidExpression;
622622
623623 if (new_pos < 0 or new_pos >= stream.buffer.len) return error.InvalidExpression;
......@@ -710,7 +710,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
710710 };
711711}
712712
713pub fn Writer(options: ExpressionOptions) type {
713pub fn Builder(comptime options: ExpressionOptions) type {
714714 const addr_type = switch (options.addr_size) {
715715 2 => u16,
716716 4 => u32,
......@@ -959,10 +959,33 @@ fn opcodeValidInCFA(opcode: u8) bool {
959959 };
960960}
961961
962const testing = std.testing;
962963test "DWARF expressions" {
963964 const allocator = std.testing.allocator;
964965
965966 const options = ExpressionOptions{};
966 const stack_machine = StackMachine(options){};
967 var stack_machine = StackMachine(options){};
967968 defer stack_machine.deinit(allocator);
969
970 const b = Builder(options);
971
972 var program = std.ArrayList(u8).init(allocator);
973 defer program.deinit();
974
975 const writer = program.writer();
976
977 // Literals
978 {
979 const context = ExpressionContext{};
980 for (0..32) |i| {
981 try b.writeLiteral(writer, @intCast(i));
982 }
983
984 _ = try stack_machine.run(program.items, allocator, context, 0);
985
986 for (0..32) |i| {
987 const expected = 31 - i;
988 try testing.expectEqual(expected, stack_machine.stack.popOrNull().?.generic);
989 }
990 }
968991}
src/crash_report.zig+1-1
......@@ -271,7 +271,7 @@ const StackContext = union(enum) {
271271 current: struct {
272272 ret_addr: ?usize,
273273 },
274 exception: *const debug.StackTraceContext,
274 exception: *const debug.ThreadContext,
275275 not_supported: void,
276276
277277 pub fn dumpStackTrace(ctx: @This()) void {
test/standalone/dwarf_unwinding/shared_lib_unwind.zig+1-1
......@@ -5,7 +5,7 @@ const testing = std.testing;
55noinline fn frame4(expected: *[4]usize, unwound: *[4]usize) void {
66 expected[0] = @returnAddress();
77
8 var context: debug.StackTraceContext = undefined;
8 var context: debug.ThreadContext = undefined;
99 testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
1010
1111 var debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");
test/standalone/dwarf_unwinding/zig_unwind.zig+1-1
......@@ -5,7 +5,7 @@ const testing = std.testing;
55noinline fn frame3(expected: *[4]usize, unwound: *[4]usize) void {
66 expected[0] = @returnAddress();
77
8 var context: debug.StackTraceContext = undefined;
8 var context: debug.ThreadContext = undefined;
99 testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
1010
1111 var debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");