feature. See also
. The project being documented here (as the example) is the Zig library itself.
File
Code
pub const Native = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "CpuContext"))
root.debug.CpuContext
else switch (native_arch) {
.aarch64, .aarch64_be => Aarch64,
.alpha => Alpha,
.arc, .arceb => Arc,
.arm, .armeb, .thumb, .thumbeb => Arm,
.csky => Csky,
.hexagon => Hexagon,
.kvx => Kvx,
.lanai => Lanai,
.loongarch32, .loongarch64 => LoongArch,
.m68k => M68k,
.m88k => M88k,
.mips, .mipsel, .mips64, .mips64el => Mips,
.or1k => Or1k,
.powerpc, .powerpcle, .powerpc64, .powerpc64le => Powerpc,
.sparc, .sparc64 => Sparc,
.riscv32, .riscv32be, .riscv64, .riscv64be => Riscv,
.ve => Ve,
.s390x => S390x,
.x86_16 => X86_16,
.x86 => X86,
.x86_64 => X86_64,
else => noreturn,
};
pub const DwarfRegisterError = error{
InvalidRegister,
UnsupportedRegister,
};
pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
if (signal_ucontext_t == void) return null;
const uc: *const signal_ucontext_t = @ptrCast(@alignCast(ctx_ptr));
if (native_arch.isArc() and native_os == .linux) {
var native: Native = .{
.r = [_]u32{ uc.mcontext.r31, uc.mcontext.r30, 0, uc.mcontext.r28 } ++
uc.mcontext.r27_26 ++
uc.mcontext.r25_13 ++
uc.mcontext.r12_0,
.pcl = uc.mcontext.pcl,
};
std.mem.reverse(u32, native.r[0..]);
return native;
} else if (native_arch == .loongarch32 and native_os == .linux) {
return .{
.r = s: {
var regs: [32]LoongArch.Gpr = undefined;
for (uc.mcontext.r, 0..) |r, i| regs[i] = @truncate(r);
break :s regs;
},
.pc = @truncate(uc.mcontext.pc),
};
} else if (native_arch == .m88k and native_os == .openbsd) {
// to user space, so we need to do that here.
return .{
.r = uc.mcontext.r,
.xip = uc.mcontext.xip & ~@as(u32, 0b11),
};
} else if (native_arch.isMIPS32() and native_os == .linux) {
return .{
.r = s: {
var regs: [32]Mips.Gpr = undefined;
for (uc.mcontext.r, 0..) |r, i| regs[i] = @truncate(r);
break :s regs;
},
.pc = @truncate(uc.mcontext.pc),
};
} else if (native_arch.isSPARC() and native_os == .linux) {
const SparcStackFrame = extern struct {
l: [8]usize,
i: [8]usize,
_x: [8]usize,
};
// stack and passes a pointer to its `info` field to the signal handler. This implies that
// prior to said `info` field, we will find the `ss` field which, among other things,
// contains the incoming and local registers of the interrupted code.
const frame = @as(*const SparcStackFrame, @ptrFromInt(@as(usize, @intFromPtr(ctx_ptr)) - @sizeOf(SparcStackFrame)));
return .{
.g = uc.mcontext.g,
.o = uc.mcontext.o,
.l = frame.l,
.i = frame.i,
.pc = uc.mcontext.pc,
};
}
return switch (native_arch) {
.arm, .armeb, .thumb, .thumbeb => .{
.r = uc.mcontext.r ++ [_]u32{uc.mcontext.pc},
},
.aarch64, .aarch64_be => .{
.x = uc.mcontext.x ++ [_]u64{uc.mcontext.lr},
.sp = uc.mcontext.sp,
.pc = uc.mcontext.pc,
},
.alpha => .{
.r = uc.mcontext.r,
.pc = uc.mcontext.pc,
},
.csky => .{
.r = uc.mcontext.r0_13 ++
[_]u32{ uc.mcontext.r14, uc.mcontext.r15 } ++
uc.mcontext.r16_30 ++
[_]u32{uc.mcontext.r31},
.pc = uc.mcontext.pc,
},
.hexagon, .loongarch32, .loongarch64, .mips, .mipsel, .mips64, .mips64el, .or1k => .{
.r = uc.mcontext.r,
.pc = uc.mcontext.pc,
},
.m68k => .{
.d = uc.mcontext.d,
.a = uc.mcontext.a,
.pc = uc.mcontext.pc,
},
.powerpc, .powerpcle, .powerpc64, .powerpc64le => .{
.r = uc.mcontext.r,
.pc = uc.mcontext.pc,
.lr = uc.mcontext.lr,
},
.riscv32, .riscv32be, .riscv64, .riscv64be => .{
// group the registers by ABI mnemonic rather than register number.
.x = [_]Riscv.Gpr{0} ++
uc.mcontext.ra_sp_gp_tp ++
uc.mcontext.t0_2 ++
uc.mcontext.s0_1 ++
uc.mcontext.a ++
uc.mcontext.s2_11 ++
uc.mcontext.t3_6,
.pc = uc.mcontext.pc,
},
.s390x => .{
.r = uc.mcontext.r,
.psw = .{
.mask = uc.mcontext.psw.mask,
.addr = uc.mcontext.psw.addr,
},
},
.x86 => .{ .gprs = .init(.{
.eax = uc.mcontext.eax,
.ecx = uc.mcontext.ecx,
.edx = uc.mcontext.edx,
.ebx = uc.mcontext.ebx,
.esp = uc.mcontext.esp,
.ebp = uc.mcontext.ebp,
.esi = uc.mcontext.esi,
.edi = uc.mcontext.edi,
.eip = uc.mcontext.eip,
}) },
.x86_64 => .{ .gprs = .init(.{
.rax = uc.mcontext.rax,
.rdx = uc.mcontext.rdx,
.rcx = uc.mcontext.rcx,
.rbx = uc.mcontext.rbx,
.rsi = uc.mcontext.rsi,
.rdi = uc.mcontext.rdi,
.rbp = uc.mcontext.rbp,
.rsp = uc.mcontext.rsp,
.r8 = uc.mcontext.r8,
.r9 = uc.mcontext.r9,
.r10 = uc.mcontext.r10,
.r11 = uc.mcontext.r11,
.r12 = uc.mcontext.r12,
.r13 = uc.mcontext.r13,
.r14 = uc.mcontext.r14,
.r15 = uc.mcontext.r15,
.rip = uc.mcontext.rip,
}) },
else => comptime unreachable,
};
}
pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native {
return switch (native_arch) {
.x86 => .{ .gprs = .init(.{
.eax = ctx.Eax,
.ecx = ctx.Ecx,
.edx = ctx.Edx,
.ebx = ctx.Ebx,
.esp = ctx.Esp,
.ebp = ctx.Ebp,
.esi = ctx.Esi,
.edi = ctx.Edi,
.eip = ctx.Eip,
}) },
.x86_64 => .{ .gprs = .init(.{
.rax = ctx.Rax,
.rdx = ctx.Rdx,
.rcx = ctx.Rcx,
.rbx = ctx.Rbx,
.rsi = ctx.Rsi,
.rdi = ctx.Rdi,
.rbp = ctx.Rbp,
.rsp = ctx.Rsp,
.r8 = ctx.R8,
.r9 = ctx.R9,
.r10 = ctx.R10,
.r11 = ctx.R11,
.r12 = ctx.R12,
.r13 = ctx.R13,
.r14 = ctx.R14,
.r15 = ctx.R15,
.rip = ctx.Rip,
}) },
.aarch64 => .{
.x = ctx.DUMMYUNIONNAME.X[0..31].*,
.sp = ctx.Sp,
.pc = ctx.Pc,
},
.thumb => .{ .r = .{
ctx.R0, ctx.R1, ctx.R2, ctx.R3,
ctx.R4, ctx.R5, ctx.R6, ctx.R7,
ctx.R8, ctx.R9, ctx.R10, ctx.R11,
ctx.R12, ctx.Sp, ctx.Lr, ctx.Pc,
} },
else => comptime unreachable,
};
}
const Aarch64 = extern struct {
x: [31]Gpr,
sp: Gpr,
pc: Gpr,
pub const Gpr = u64;
pub inline fn current() Aarch64 {
var ctx: Aarch64 = undefined;
asm volatile (
\\ stp x0, x1, [x0, #0x000]
\\ stp x2, x3, [x0, #0x010]
\\ stp x4, x5, [x0, #0x020]
\\ stp x6, x7, [x0, #0x030]
\\ stp x8, x9, [x0, #0x040]
\\ stp x10, x11, [x0, #0x050]
\\ stp x12, x13, [x0, #0x060]
\\ stp x14, x15, [x0, #0x070]
\\ stp x16, x17, [x0, #0x080]
\\ stp x18, x19, [x0, #0x090]
\\ stp x20, x21, [x0, #0x0a0]
\\ stp x22, x23, [x0, #0x0b0]
\\ stp x24, x25, [x0, #0x0c0]
\\ stp x26, x27, [x0, #0x0d0]
\\ stp x28, x29, [x0, #0x0e0]
\\ str x30, [x0, #0x0f0]
\\ mov x1, sp
\\ str x1, [x0, #0x0f8]
\\ adr x1, .
\\ str x1, [x0, #0x100]
:
: [ctx] "{x0}" (&ctx),
: .{ .x1 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Aarch64) usize {
return ctx.x[29];
}
pub fn getPc(ctx: *const Aarch64) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Aarch64, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...30 => return @ptrCast(&ctx.x[register_num]),
31 => return @ptrCast(&ctx.sp),
32 => return @ptrCast(&ctx.pc),
33 => return error.UnsupportedRegister,
34 => return error.UnsupportedRegister,
35 => return error.UnsupportedRegister,
36 => return error.UnsupportedRegister,
37 => return error.UnsupportedRegister,
38 => return error.UnsupportedRegister,
39 => return error.UnsupportedRegister,
40...45 => return error.UnsupportedRegister,
46 => return error.UnsupportedRegister,
47 => return error.UnsupportedRegister,
48...63 => return error.UnsupportedRegister,
64...95 => return error.UnsupportedRegister,
96...127 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Alpha = extern struct {
r: [32]Gpr,
pc: Gpr,
pub const Gpr = u64;
pub inline fn current() Alpha {
var ctx: Alpha = undefined;
asm volatile (
\\ stq $0 , 0x000($0)
\\ stq $1 , 0x008($0)
\\ stq $2 , 0x010($0)
\\ stq $3 , 0x018($0)
\\ stq $4 , 0x020($0)
\\ stq $5 , 0x028($0)
\\ stq $6 , 0x030($0)
\\ stq $7 , 0x038($0)
\\ stq $8 , 0x040($0)
\\ stq $9 , 0x048($0)
\\ stq $10, 0x050($0)
\\ stq $11, 0x058($0)
\\ stq $12, 0x060($0)
\\ stq $13, 0x068($0)
\\ stq $14, 0x070($0)
\\ stq $15, 0x078($0)
\\ stq $16, 0x080($0)
\\ stq $17, 0x088($0)
\\ stq $18, 0x090($0)
\\ stq $19, 0x098($0)
\\ stq $20, 0x0a0($0)
\\ stq $21, 0x0a8($0)
\\ stq $22, 0x0b0($0)
\\ stq $23, 0x0b8($0)
\\ stq $24, 0x0c0($0)
\\ stq $25, 0x0c8($0)
\\ stq $26, 0x0d0($0)
\\ stq $27, 0x0d8($0)
\\ stq $28, 0x0e0($0)
\\ stq $29, 0x0e8($0)
\\ stq $30, 0x0f0($0)
\\
\\ br $1, 1f
\\1:
\\ stq $1, 0x100($0)
:
: [ctx] "{$0}" (&ctx),
: .{ .r1 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Alpha) usize {
return ctx.r[15];
}
pub fn getPc(ctx: *const Alpha) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Alpha, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
64 => return @ptrCast(&ctx.pc),
32...63 => return error.UnsupportedRegister,
66 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Arc = extern struct {
r: [32]Gpr,
pcl: Gpr,
pub const Gpr = u32;
pub inline fn current() Arc {
var ctx: Arc = undefined;
asm volatile (
\\ st r0, [r8, 0]
\\ st r1, [r8, 4]
\\ st r2, [r8, 8]
\\ st r3, [r8, 12]
\\ st r4, [r8, 16]
\\ st r5, [r8, 20]
\\ st r6, [r8, 24]
\\ st r7, [r8, 28]
\\ st r8, [r8, 32]
\\ st r9, [r8, 36]
\\ st r10, [r8, 40]
\\ st r11, [r8, 44]
\\ st r12, [r8, 48]
\\ st r13, [r8, 52]
\\ st r14, [r8, 56]
\\ st r15, [r8, 60]
\\ st r16, [r8, 64]
\\ st r17, [r8, 68]
\\ st r18, [r8, 72]
\\ st r19, [r8, 76]
\\ st r20, [r8, 80]
\\ st r21, [r8, 84]
\\ st r22, [r8, 88]
\\ st r23, [r8, 92]
\\ st r24, [r8, 96]
\\ st r25, [r8, 100]
\\ st r26, [r8, 104]
\\ st r27, [r8, 108]
\\ st r28, [r8, 112]
\\ st r29, [r8, 116]
\\ st r30, [r8, 120]
\\ st r31, [r8, 124]
\\ st pcl, [r8, 128]
:
: [ctx] "{r8}" (&ctx),
: .{ .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Arc) usize {
return ctx.r[27];
}
pub fn getPc(ctx: *const Arc) usize {
return ctx.pcl;
}
pub fn dwarfRegisterBytes(ctx: *Arc, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
160 => return @ptrCast(&ctx.pcl),
32...57 => return error.UnsupportedRegister,
58...127 => return error.UnsupportedRegister,
128...159 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Arm = struct {
r: [16]Gpr,
pub const Gpr = u32;
pub inline fn current() Arm {
var ctx: Arm = undefined;
asm volatile (
\\ // For compatibility with Thumb, we can't write r13 (sp) or r15 (pc) with stm.
\\ stm r0, {r0-r12}
\\ str r13, [r0, #0x34]
\\ str r14, [r0, #0x38]
\\ str r15, [r0, #0x3c]
:
: [r] "{r0}" (&ctx.r),
: .{ .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Arm) usize {
return ctx.r[11];
}
pub fn getPc(ctx: *const Arm) usize {
return ctx.r[15];
}
pub fn dwarfRegisterBytes(ctx: *Arm, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...15 => return @ptrCast(&ctx.r[register_num]),
64...95 => return error.UnsupportedRegister,
96...103 => return error.UnsupportedRegister,
104...111 => return error.UnsupportedRegister,
112...127 => return error.UnsupportedRegister,
128 => return error.UnsupportedRegister,
129 => return error.UnsupportedRegister,
130 => return error.UnsupportedRegister,
131 => return error.UnsupportedRegister,
132 => return error.UnsupportedRegister,
133 => return error.UnsupportedRegister,
134...142 => return error.UnsupportedRegister,
143 => return error.UnsupportedRegister,
144...150 => return error.UnsupportedRegister,
151...157 => return error.UnsupportedRegister,
158...159 => return error.UnsupportedRegister,
160...161 => return error.UnsupportedRegister,
162...163 => return error.UnsupportedRegister,
164...165 => return error.UnsupportedRegister,
166...191 => return error.UnsupportedRegister,
192...199 => return error.UnsupportedRegister,
200...255 => return error.UnsupportedRegister,
256...287 => return error.UnsupportedRegister,
288...319 => return error.UnsupportedRegister,
320 => return error.UnsupportedRegister,
321 => return error.UnsupportedRegister,
322 => return error.UnsupportedRegister,
323 => return error.UnsupportedRegister,
324...8191 => return error.UnsupportedRegister,
8192...16383 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Csky = extern struct {
r: [32]Gpr,
pc: Gpr,
pub const Gpr = u32;
pub inline fn current() Csky {
var ctx: Csky = undefined;
asm volatile (
\\ stm r0-r31, (t0)
\\ grs t1, 1f
\\1:
\\ st32.w t1, (t0, 128)
:
: [ctx] "{r12}" (&ctx),
: .{ .r13 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Csky) usize {
return ctx.r[14];
}
pub fn getPc(ctx: *const Csky) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Csky, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
64 => return @ptrCast(&ctx.pc),
32...63 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Hexagon = extern struct {
r: [32]Gpr,
pc: Gpr,
pub const Gpr = u32;
pub inline fn current() Hexagon {
var ctx: Hexagon = undefined;
asm volatile (
\\ memw(r0 + #0) = r0
\\ memw(r0 + #4) = r1
\\ memw(r0 + #8) = r2
\\ memw(r0 + #12) = r3
\\ memw(r0 + #16) = r4
\\ memw(r0 + #20) = r5
\\ memw(r0 + #24) = r6
\\ memw(r0 + #28) = r7
\\ memw(r0 + #32) = r8
\\ memw(r0 + #36) = r9
\\ memw(r0 + #40) = r10
\\ memw(r0 + #44) = r11
\\ memw(r0 + #48) = r12
\\ memw(r0 + #52) = r13
\\ memw(r0 + #56) = r14
\\ memw(r0 + #60) = r15
\\ memw(r0 + #64) = r16
\\ memw(r0 + #68) = r17
\\ memw(r0 + #72) = r18
\\ memw(r0 + #76) = r19
\\ memw(r0 + #80) = r20
\\ memw(r0 + #84) = r21
\\ memw(r0 + #88) = r22
\\ memw(r0 + #92) = r23
\\ memw(r0 + #96) = r24
\\ memw(r0 + #100) = r25
\\ memw(r0 + #104) = r26
\\ memw(r0 + #108) = r27
\\ memw(r0 + #112) = r28
\\ memw(r0 + #116) = r29
\\ memw(r0 + #120) = r30
\\ memw(r0 + #124) = r31
\\ r1 = pc
\\ memw(r0 + #128) = r1
:
: [ctx] "{r0}" (&ctx),
: .{ .r1 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Hexagon) usize {
return ctx.r[30];
}
pub fn getPc(ctx: *const Hexagon) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Hexagon, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
76 => return @ptrCast(&ctx.pc),
// look at that file. I really can't be bothered to make it more precise.
32...75 => return error.UnsupportedRegister,
77...259 => return error.UnsupportedRegister,
// 9999999...10000030 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Kvx = extern struct {
r: [64]Gpr,
ra: Gpr,
pc: Gpr,
pub const Gpr = u64;
pub inline fn current() Kvx {
var ctx: Kvx = undefined;
asm volatile (
\\ so (0)[$r32] = $r0r1r2r3
\\ ;;
\\ so (32)[$r32] = $r4r5r6r7
\\ ;;
\\ so (64)[$r32] = $r8r9r10r11
\\ ;;
\\ so (96)[$r32] = $r12r13r14r15
\\ ;;
\\ so (128)[$r32] = $r16r17r18r19
\\ ;;
\\ so (160)[$r32] = $r20r21r22r23
\\ ;;
\\ so (192)[$r32] = $r24r25r26r27
\\ ;;
\\ so (224)[$r32] = $r28r29r30r31
\\ ;;
\\ so (256)[$r32] = $r32r33r34r35
\\ ;;
\\ so (288)[$r32] = $r36r37r38r39
\\ ;;
\\ so (320)[$r32] = $r40r41r42r43
\\ ;;
\\ so (352)[$r32] = $r44r45r46r47
\\ ;;
\\ so (384)[$r32] = $r48r49r50r51
\\ ;;
\\ so (416)[$r32] = $r52r53r54r55
\\ ;;
\\ so (448)[$r32] = $r56r57r58r59
\\ get $r34 = $pc
\\ ;;
\\ so (480)[$r32] = $r60r61r62r63
\\ get $r35 = $ra
\\ ;;
\\ sq (512)[$r32] = $r34r35
:
: [ctx] "{r32}" (&ctx),
: .{ .r34 = true, .r35 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Kvx) usize {
return ctx.r[14];
}
pub fn getPc(ctx: *const Kvx) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Kvx, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...63 => return @ptrCast(&ctx.r[register_num]),
64 => return @ptrCast(&ctx.pc),
67 => return @ptrCast(&ctx.ra),
65...66 => return error.UnsupportedRegister,
68...255 => return error.UnsupportedRegister,
256...767 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Lanai = extern struct {
r: [32]Gpr,
pub const Gpr = u32;
pub inline fn current() Lanai {
var ctx: Lanai = undefined;
asm volatile (
\\ st %%r0, 0[r9]
\\ st %%r1, 4[r9]
\\ st %%r2, 8[r9]
\\ st %%r3, 12[r9]
\\ st %%r4, 16[r9]
\\ st %%r5, 20[r9]
\\ st %%r6, 24[r9]
\\ st %%r7, 28[r9]
\\ st %%r8, 32[r9]
\\ st %%r9, 36[r9]
\\ st %%r10, 40[r9]
\\ st %%r11, 44[r9]
\\ st %%r12, 48[r9]
\\ st %%r13, 52[r9]
\\ st %%r14, 56[r9]
\\ st %%r15, 60[r9]
\\ st %%r16, 64[r9]
\\ st %%r17, 68[r9]
\\ st %%r18, 72[r9]
\\ st %%r19, 76[r9]
\\ st %%r20, 80[r9]
\\ st %%r21, 84[r9]
\\ st %%r22, 88[r9]
\\ st %%r23, 92[r9]
\\ st %%r24, 96[r9]
\\ st %%r25, 100[r9]
\\ st %%r26, 104[r9]
\\ st %%r27, 108[r9]
\\ st %%r28, 112[r9]
\\ st %%r29, 116[r9]
\\ st %%r30, 120[r9]
\\ st %%r31, 124[r9]
:
: [ctx] "{r9}" (&ctx),
: .{ .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Lanai) usize {
return ctx.r[5];
}
pub fn getPc(ctx: *const Lanai) usize {
return ctx.r[2];
}
pub fn dwarfRegisterBytes(ctx: *Lanai, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.s[register_num]),
else => return error.InvalidRegister,
}
}
};
const LoongArch = extern struct {
r: [32]Gpr,
pc: Gpr,
pub const Gpr = if (native_arch == .loongarch64) u64 else u32;
pub inline fn current() LoongArch {
var ctx: LoongArch = undefined;
asm volatile (if (Gpr == u64)
\\ st.d $zero, $t0, 0
\\ st.d $ra, $t0, 8
\\ st.d $tp, $t0, 16
\\ st.d $sp, $t0, 24
\\ st.d $a0, $t0, 32
\\ st.d $a1, $t0, 40
\\ st.d $a2, $t0, 48
\\ st.d $a3, $t0, 56
\\ st.d $a4, $t0, 64
\\ st.d $a5, $t0, 72
\\ st.d $a6, $t0, 80
\\ st.d $a7, $t0, 88
\\ st.d $t0, $t0, 96
\\ st.d $t1, $t0, 104
\\ st.d $t2, $t0, 112
\\ st.d $t3, $t0, 120
\\ st.d $t4, $t0, 128
\\ st.d $t5, $t0, 136
\\ st.d $t6, $t0, 144
\\ st.d $t7, $t0, 152
\\ st.d $t8, $t0, 160
\\ st.d $r21, $t0, 168
\\ st.d $fp, $t0, 176
\\ st.d $s0, $t0, 184
\\ st.d $s1, $t0, 192
\\ st.d $s2, $t0, 200
\\ st.d $s3, $t0, 208
\\ st.d $s4, $t0, 216
\\ st.d $s5, $t0, 224
\\ st.d $s6, $t0, 232
\\ st.d $s7, $t0, 240
\\ st.d $s8, $t0, 248
\\ bl 1f
\\1:
\\ st.d $ra, $t0, 256
else
\\ st.w $zero, $t0, 0
\\ st.w $ra, $t0, 4
\\ st.w $tp, $t0, 8
\\ st.w $sp, $t0, 12
\\ st.w $a0, $t0, 16
\\ st.w $a1, $t0, 20
\\ st.w $a2, $t0, 24
\\ st.w $a3, $t0, 28
\\ st.w $a4, $t0, 32
\\ st.w $a5, $t0, 36
\\ st.w $a6, $t0, 40
\\ st.w $a7, $t0, 44
\\ st.w $t0, $t0, 48
\\ st.w $t1, $t0, 52
\\ st.w $t2, $t0, 56
\\ st.w $t3, $t0, 60
\\ st.w $t4, $t0, 64
\\ st.w $t5, $t0, 68
\\ st.w $t6, $t0, 72
\\ st.w $t7, $t0, 76
\\ st.w $t8, $t0, 80
\\ st.w $r21, $t0, 84
\\ st.w $fp, $t0, 88
\\ st.w $s0, $t0, 92
\\ st.w $s1, $t0, 96
\\ st.w $s2, $t0, 100
\\ st.w $s3, $t0, 104
\\ st.w $s4, $t0, 108
\\ st.w $s5, $t0, 112
\\ st.w $s6, $t0, 116
\\ st.w $s7, $t0, 120
\\ st.w $s8, $t0, 124
\\ bl 1f
\\1:
\\ st.w $ra, $t0, 128
:
: [ctx] "{$r12}" (&ctx),
: .{ .r1 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const LoongArch) usize {
return ctx.r[22];
}
pub fn getPc(ctx: *const LoongArch) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *LoongArch, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
64 => return @ptrCast(&ctx.pc),
32...63 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const M68k = extern struct {
d: [8]Gpr,
a: [8]Gpr,
pc: Gpr,
pub const Gpr = u32;
pub inline fn current() M68k {
var ctx: M68k = undefined;
asm volatile (
\\ movem.l %%d0 - %%a7, (%%a0)
\\ lea.l (%%pc), %%a1
\\ move.l %%a1, (%%a0, 64)
:
: [ctx] "{a0}" (&ctx),
: .{ .a1 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const M68k) usize {
return ctx.a[6];
}
pub fn getPc(ctx: *const M68k) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *M68k, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...7 => return @ptrCast(&ctx.d[register_num]),
8...15 => return @ptrCast(&ctx.a[register_num - 8]),
26 => return @ptrCast(&ctx.pc),
16...23 => return error.UnsupportedRegister,
24...25 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const M88k = extern struct {
r: [32]Gpr,
xip: Gpr,
pub const Gpr = u32;
pub inline fn current() M88k {
var ctx: M88k = undefined;
asm volatile (
\\ st %%r0, %%r2, 0
\\ st %%r1, %%r2, 4
\\ st %%r2, %%r2, 8
\\ st %%r3, %%r2, 12
\\ st %%r4, %%r2, 16
\\ st %%r5, %%r2, 20
\\ st %%r6, %%r2, 24
\\ st %%r7, %%r2, 28
\\ st %%r8, %%r2, 32
\\ st %%r9, %%r2, 36
\\ st %%r10, %%r2, 40
\\ st %%r11, %%r2, 44
\\ st %%r12, %%r2, 48
\\ st %%r13, %%r2, 52
\\ st %%r14, %%r2, 56
\\ st %%r15, %%r2, 60
\\ st %%r16, %%r2, 64
\\ st %%r17, %%r2, 68
\\ st %%r18, %%r2, 72
\\ st %%r19, %%r2, 76
\\ st %%r20, %%r2, 80
\\ st %%r21, %%r2, 84
\\ st %%r22, %%r2, 88
\\ st %%r23, %%r2, 92
\\ st %%r24, %%r2, 96
\\ st %%r25, %%r2, 100
\\ st %%r26, %%r2, 104
\\ st %%r27, %%r2, 108
\\ st %%r28, %%r2, 112
\\ st %%r29, %%r2, 116
\\ st %%r30, %%r2, 120
\\ st %%r31, %%r2, 124
\\ bsr.n 1f
\\1:
\\ st %%r1, %%r2, 128
:
: [ctx] "{r2}" (&ctx),
: .{ .r1 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const M88k) usize {
return ctx.r[30];
}
pub fn getPc(ctx: *const M88k) usize {
return ctx.xip;
}
pub fn dwarfRegisterBytes(ctx: *M88k, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
64 => return @ptrCast(&ctx.xip),
32...63 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Mips = extern struct {
r: [32]Gpr,
pc: Gpr,
pub const Gpr = if (native_arch.isMIPS64()) u64 else u32;
pub inline fn current() Mips {
var ctx: Mips = undefined;
asm volatile (if (Gpr == u64)
\\ .set push
\\ .set noat
\\ .set noreorder
\\ .set nomacro
\\ sd $zero, 0($t0)
\\ sd $at, 8($t0)
\\ sd $v0, 16($t0)
\\ sd $v1, 24($t0)
\\ sd $a0, 32($t0)
\\ sd $a1, 40($t0)
\\ sd $a2, 48($t0)
\\ sd $a3, 56($t0)
\\ sd $a4, 64($t0)
\\ sd $a5, 72($t0)
\\ sd $a6, 80($t0)
\\ sd $a7, 88($t0)
\\ sd $t0, 96($t0)
\\ sd $t1, 104($t0)
\\ sd $t2, 112($t0)
\\ sd $t3, 120($t0)
\\ sd $s0, 128($t0)
\\ sd $s1, 136($t0)
\\ sd $s2, 144($t0)
\\ sd $s3, 152($t0)
\\ sd $s4, 160($t0)
\\ sd $s5, 168($t0)
\\ sd $s6, 176($t0)
\\ sd $s7, 184($t0)
\\ sd $t8, 192($t0)
\\ sd $t9, 200($t0)
\\ sd $k0, 208($t0)
\\ sd $k1, 216($t0)
\\ sd $gp, 224($t0)
\\ sd $sp, 232($t0)
\\ sd $fp, 240($t0)
\\ sd $ra, 248($t0)
\\ bal 1f
\\1:
\\ sd $ra, 256($t0)
\\ .set pop
else
\\ .set push
\\ .set noat
\\ .set noreorder
\\ .set nomacro
\\ sw $zero, 0($t4)
\\ sw $at, 4($t4)
\\ sw $v0, 8($t4)
\\ sw $v1, 12($t4)
\\ sw $a0, 16($t4)
\\ sw $a1, 20($t4)
\\ sw $a2, 24($t4)
\\ sw $a3, 28($t4)
\\ sw $t0, 32($t4)
\\ sw $t1, 36($t4)
\\ sw $t2, 40($t4)
\\ sw $t3, 44($t4)
\\ sw $t4, 48($t4)
\\ sw $t5, 52($t4)
\\ sw $t6, 56($t4)
\\ sw $t7, 60($t4)
\\ sw $s0, 64($t4)
\\ sw $s1, 68($t4)
\\ sw $s2, 72($t4)
\\ sw $s3, 76($t4)
\\ sw $s4, 80($t4)
\\ sw $s5, 84($t4)
\\ sw $s6, 88($t4)
\\ sw $s7, 92($t4)
\\ sw $t8, 96($t4)
\\ sw $t9, 100($t4)
\\ sw $k0, 104($t4)
\\ sw $k1, 108($t4)
\\ sw $gp, 112($t4)
\\ sw $sp, 116($t4)
\\ sw $fp, 120($t4)
\\ sw $ra, 124($t4)
\\ bal 1f
\\1:
\\ sw $ra, 128($t4)
\\ .set pop
:
: [ctx] "{$12}" (&ctx),
: .{ .r31 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Mips) usize {
return @intCast(ctx.r[30]);
}
pub fn getPc(ctx: *const Mips) usize {
return @intCast(ctx.pc);
}
pub fn dwarfRegisterBytes(ctx: *Mips, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
66 => return @ptrCast(&ctx.pc),
// specification anyway? We don't need that nonsense.
32...63 => return error.UnsupportedRegister,
64 => return error.UnsupportedRegister,
65 => return error.UnsupportedRegister,
176 => return error.UnsupportedRegister,
177 => return error.UnsupportedRegister,
178 => return error.UnsupportedRegister,
179 => return error.UnsupportedRegister,
180 => return error.UnsupportedRegister,
181 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Or1k = extern struct {
r: [32]Gpr,
pc: Gpr,
pub const Gpr = u32;
pub inline fn current() Or1k {
var ctx: Or1k = undefined;
asm volatile (
\\ l.sw 0(r15), r0
\\ l.sw 4(r15), r1
\\ l.sw 8(r15), r2
\\ l.sw 12(r15), r3
\\ l.sw 16(r15), r4
\\ l.sw 20(r15), r5
\\ l.sw 24(r15), r6
\\ l.sw 28(r15), r7
\\ l.sw 32(r15), r8
\\ l.sw 36(r15), r9
\\ l.sw 40(r15), r10
\\ l.sw 44(r15), r11
\\ l.sw 48(r15), r12
\\ l.sw 52(r15), r13
\\ l.sw 56(r15), r14
\\ l.sw 60(r15), r15
\\ l.sw 64(r15), r16
\\ l.sw 68(r15), r17
\\ l.sw 72(r15), r18
\\ l.sw 76(r15), r19
\\ l.sw 80(r15), r20
\\ l.sw 84(r15), r21
\\ l.sw 88(r15), r22
\\ l.sw 92(r15), r23
\\ l.sw 96(r15), r24
\\ l.sw 100(r15), r25
\\ l.sw 104(r15), r26
\\ l.sw 108(r15), r27
\\ l.sw 112(r15), r28
\\ l.sw 116(r15), r29
\\ l.sw 120(r15), r30
\\ l.sw 124(r15), r31
\\ l.jal 1f
\\1:
\\ l.sw 128(r15), r9
:
: [ctx] "{r15}" (&ctx),
: .{ .r9 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Or1k) usize {
return ctx.r[2];
}
pub fn getPc(ctx: *const Or1k) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Or1k, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
35 => return @ptrCast(&ctx.pc),
else => return error.InvalidRegister,
}
}
};
const Powerpc = extern struct {
r: [32]Gpr,
pc: Gpr,
lr: Gpr,
pub const Gpr = if (native_arch.isPowerPC64()) u64 else u32;
pub inline fn current() Powerpc {
var ctx: Powerpc = undefined;
asm volatile (if (Gpr == u64)
\\ std 0, 0(10)
\\ std 1, 8(10)
\\ std 2, 16(10)
\\ std 3, 24(10)
\\ std 4, 32(10)
\\ std 5, 40(10)
\\ std 6, 48(10)
\\ std 7, 56(10)
\\ std 8, 64(10)
\\ std 9, 72(10)
\\ std 10, 80(10)
\\ std 11, 88(10)
\\ std 12, 96(10)
\\ std 13, 104(10)
\\ std 14, 112(10)
\\ std 15, 120(10)
\\ std 16, 128(10)
\\ std 17, 136(10)
\\ std 18, 144(10)
\\ std 19, 152(10)
\\ std 20, 160(10)
\\ std 21, 168(10)
\\ std 22, 176(10)
\\ std 23, 184(10)
\\ std 24, 192(10)
\\ std 25, 200(10)
\\ std 26, 208(10)
\\ std 27, 216(10)
\\ std 28, 224(10)
\\ std 29, 232(10)
\\ std 30, 240(10)
\\ std 31, 248(10)
\\ mflr 8
\\ std 8, 264(10)
\\ bl 1f
\\1:
\\ mflr 8
\\ std 8, 256(10)
else
\\ stw 0, 0(10)
\\ stw 1, 4(10)
\\ stw 2, 8(10)
\\ stw 3, 12(10)
\\ stw 4, 16(10)
\\ stw 5, 20(10)
\\ stw 6, 24(10)
\\ stw 7, 28(10)
\\ stw 8, 32(10)
\\ stw 9, 36(10)
\\ stw 10, 40(10)
\\ stw 11, 44(10)
\\ stw 12, 48(10)
\\ stw 13, 52(10)
\\ stw 14, 56(10)
\\ stw 15, 60(10)
\\ stw 16, 64(10)
\\ stw 17, 68(10)
\\ stw 18, 72(10)
\\ stw 19, 76(10)
\\ stw 20, 80(10)
\\ stw 21, 84(10)
\\ stw 22, 88(10)
\\ stw 23, 92(10)
\\ stw 24, 96(10)
\\ stw 25, 100(10)
\\ stw 26, 104(10)
\\ stw 27, 108(10)
\\ stw 28, 112(10)
\\ stw 29, 116(10)
\\ stw 30, 120(10)
\\ stw 31, 124(10)
\\ mflr 8
\\ stw 8, 132(10)
\\ bl 1f
\\1:
\\ mflr 8
\\ stw 8, 128(10)
:
: [ctx] "{r10}" (&ctx),
: .{ .r8 = true, .lr = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Powerpc) usize {
return ctx.r[1];
}
pub fn getPc(ctx: *const Powerpc) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Powerpc, register_num: u16) DwarfRegisterError![]u8 {
//
// * System V Application Binary Interface - PowerPC Processor Supplement ยง3-46
// * Power Architecture 32-bit Application Binary Interface Supplement 1.0 - Linux & Embedded ยง3.4
// * 64-bit ELF V2 ABI Specification - Power Architecture Revision 1.5 ยง2.4
//
// Are we having fun yet?
if (Gpr == u64) switch (register_num) {
65 => return @ptrCast(&ctx.lr),
66 => return error.UnsupportedRegister,
68...75 => return error.UnsupportedRegister,
76 => return error.UnsupportedRegister,
77...108 => return error.UnsupportedRegister,
109 => return error.UnsupportedRegister,
110 => return error.UnsupportedRegister,
114 => return error.UnsupportedRegister,
115 => return error.UnsupportedRegister,
116 => return error.UnsupportedRegister,
else => {},
} else switch (register_num) {
65 => return @ptrCast(&ctx.lr),
108 => return @ptrCast(&ctx.lr),
64 => return error.UnsupportedRegister,
66 => return error.UnsupportedRegister,
68...75 => return error.UnsupportedRegister,
76 => return error.UnsupportedRegister,
99 => return error.UnsupportedRegister,
100 => return error.UnsupportedRegister,
101 => return error.UnsupportedRegister,
102...107 => return error.UnsupportedRegister,
109 => return error.UnsupportedRegister,
110...111 => return error.UnsupportedRegister,
112 => return error.UnsupportedRegister,
113...1123 => return error.UnsupportedRegister,
1124...1155 => return error.UnsupportedRegister,
1200...1231 => return error.UnsupportedRegister,
3072...4095 => return error.UnsupportedRegister,
4096...5120 => return error.UnsupportedRegister,
else => {},
}
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
67 => return @ptrCast(&ctx.pc),
32...63 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Riscv = extern struct {
x: [32]Gpr,
pc: Gpr,
pub const Gpr = if (native_arch.isRiscv64()) u64 else u32;
pub inline fn current() Riscv {
var ctx: Riscv = undefined;
asm volatile (if (Gpr == u64)
\\ sd zero, 0(t0)
\\ sd ra, 8(t0)
\\ sd sp, 16(t0)
\\ sd gp, 24(t0)
\\ sd tp, 32(t0)
\\ sd t0, 40(t0)
\\ sd t1, 48(t0)
\\ sd t2, 56(t0)
\\ sd s0, 64(t0)
\\ sd s1, 72(t0)
\\ sd a0, 80(t0)
\\ sd a1, 88(t0)
\\ sd a2, 96(t0)
\\ sd a3, 104(t0)
\\ sd a4, 112(t0)
\\ sd a5, 120(t0)
\\ sd a6, 128(t0)
\\ sd a7, 136(t0)
\\ sd s2, 144(t0)
\\ sd s3, 152(t0)
\\ sd s4, 160(t0)
\\ sd s5, 168(t0)
\\ sd s6, 176(t0)
\\ sd s7, 184(t0)
\\ sd s8, 192(t0)
\\ sd s9, 200(t0)
\\ sd s10, 208(t0)
\\ sd s11, 216(t0)
\\ sd t3, 224(t0)
\\ sd t4, 232(t0)
\\ sd t5, 240(t0)
\\ sd t6, 248(t0)
\\ jal ra, 1f
\\1:
\\ sd ra, 256(t0)
else
\\ sw zero, 0(t0)
\\ sw ra, 4(t0)
\\ sw sp, 8(t0)
\\ sw gp, 12(t0)
\\ sw tp, 16(t0)
\\ sw t0, 20(t0)
\\ sw t1, 24(t0)
\\ sw t2, 28(t0)
\\ sw s0, 32(t0)
\\ sw s1, 36(t0)
\\ sw a0, 40(t0)
\\ sw a1, 44(t0)
\\ sw a2, 48(t0)
\\ sw a3, 52(t0)
\\ sw a4, 56(t0)
\\ sw a5, 60(t0)
\\ sw a6, 64(t0)
\\ sw a7, 68(t0)
\\ sw s2, 72(t0)
\\ sw s3, 76(t0)
\\ sw s4, 80(t0)
\\ sw s5, 84(t0)
\\ sw s6, 88(t0)
\\ sw s7, 92(t0)
\\ sw s8, 96(t0)
\\ sw s9, 100(t0)
\\ sw s10, 104(t0)
\\ sw s11, 108(t0)
\\ sw t3, 112(t0)
\\ sw t4, 116(t0)
\\ sw t5, 120(t0)
\\ sw t6, 124(t0)
\\ jal ra, 1f
\\1:
\\ sw ra, 128(t0)
:
: [ctx] "{t0}" (&ctx),
: .{ .x1 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Riscv) usize {
return ctx.x[8];
}
pub fn getPc(ctx: *const Riscv) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Riscv, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.x[register_num]),
65 => return @ptrCast(&ctx.pc),
32...63 => return error.UnsupportedRegister,
64 => return error.UnsupportedRegister,
96...127 => return error.UnsupportedRegister,
3072...4095 => return error.UnsupportedRegister,
4096...8191 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const S390x = extern struct {
r: [16]Gpr,
psw: extern struct {
mask: Gpr,
addr: Gpr,
},
pub const Gpr = u64;
pub inline fn current() S390x {
var ctx: S390x = undefined;
asm volatile (
\\ stmg %%r0, %%r15, 0(%%r2)
\\ epsw %%r0, %%r1
\\ stm %%r0, %%r1, 128(%%r2)
\\ larl %%r0, .
\\ stg %%r0, 136(%%r2)
:
: [ctx] "{r2}" (&ctx),
: .{ .r0 = true, .r1 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const S390x) usize {
return ctx.r[11];
}
pub fn getPc(ctx: *const S390x) usize {
return ctx.psw.addr;
}
pub fn dwarfRegisterBytes(ctx: *S390x, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...15 => return @ptrCast(&ctx.r[register_num]),
64 => return @ptrCast(&ctx.psw.mask),
65 => return @ptrCast(&ctx.psw.addr),
16...31 => return error.UnsupportedRegister,
32...47 => return error.UnsupportedRegister,
48...63 => return error.UnsupportedRegister,
66...67 => return error.UnsupportedRegister,
68...83 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const Sparc = extern struct {
g: [8]Gpr,
o: [8]Gpr,
l: [8]Gpr,
i: [8]Gpr,
pc: Gpr,
pub const Gpr = if (native_arch == .sparc64) u64 else u32;
pub inline fn current() Sparc {
flushWindows();
var ctx: Sparc = undefined;
asm volatile (if (Gpr == u64)
\\ stx %g0, [%l0 + 0]
\\ stx %g1, [%l0 + 8]
\\ stx %g2, [%l0 + 16]
\\ stx %g3, [%l0 + 24]
\\ stx %g4, [%l0 + 32]
\\ stx %g5, [%l0 + 40]
\\ stx %g6, [%l0 + 48]
\\ stx %g7, [%l0 + 56]
\\ stx %o0, [%l0 + 64]
\\ stx %o1, [%l0 + 72]
\\ stx %o2, [%l0 + 80]
\\ stx %o3, [%l0 + 88]
\\ stx %o4, [%l0 + 96]
\\ stx %o5, [%l0 + 104]
\\ stx %o6, [%l0 + 112]
\\ stx %o7, [%l0 + 120]
\\ stx %l0, [%l0 + 128]
\\ stx %l1, [%l0 + 136]
\\ stx %l2, [%l0 + 144]
\\ stx %l3, [%l0 + 152]
\\ stx %l4, [%l0 + 160]
\\ stx %l5, [%l0 + 168]
\\ stx %l6, [%l0 + 176]
\\ stx %l7, [%l0 + 184]
\\ stx %i0, [%l0 + 192]
\\ stx %i1, [%l0 + 200]
\\ stx %i2, [%l0 + 208]
\\ stx %i3, [%l0 + 216]
\\ stx %i4, [%l0 + 224]
\\ stx %i5, [%l0 + 232]
\\ stx %i6, [%l0 + 240]
\\ stx %i7, [%l0 + 248]
\\ call 1f
\\1:
\\ stx %o7, [%l0 + 256]
else
\\ std %g0, [%l0 + 0]
\\ std %g2, [%l0 + 8]
\\ std %g4, [%l0 + 16]
\\ std %g6, [%l0 + 24]
\\ std %o0, [%l0 + 32]
\\ std %o2, [%l0 + 40]
\\ std %o4, [%l0 + 48]
\\ std %o6, [%l0 + 56]
\\ std %l0, [%l0 + 64]
\\ std %l2, [%l0 + 72]
\\ std %l4, [%l0 + 80]
\\ std %l6, [%l0 + 88]
\\ std %i0, [%l0 + 96]
\\ std %i2, [%l0 + 104]
\\ std %i4, [%l0 + 112]
\\ std %i6, [%l0 + 120]
\\ call 1f
\\1:
\\ st %o7, [%l0 + 128]
:
: [ctx] "{l0}" (&ctx),
: .{ .o7 = true, .memory = true });
return ctx;
}
noinline fn flushWindows() void {
// we actually see meaningful data on the stack when we walk the frame chain.
if (comptime builtin.target.cpu.has(.sparc, .v9))
asm volatile ("flushw" ::: .{ .memory = true })
else
asm volatile ("ta 3" ::: .{ .memory = true });
}
pub fn getFp(ctx: *const Sparc) usize {
return ctx.i[6];
}
pub fn getPc(ctx: *const Sparc) usize {
return ctx.pc;
}
pub fn dwarfRegisterBytes(ctx: *Sparc, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...7 => return @ptrCast(&ctx.g[register_num]),
8...15 => return @ptrCast(&ctx.o[register_num - 8]),
16...23 => return @ptrCast(&ctx.l[register_num - 16]),
24...31 => return @ptrCast(&ctx.i[register_num - 24]),
32 => return @ptrCast(&ctx.pc),
else => return error.InvalidRegister,
}
}
};
const Ve = extern struct {
s: [64]Gpr,
ic: Gpr,
pub const Gpr = u64;
pub inline fn current() Ve {
var ctx: Ve = undefined;
asm volatile (
\\ st %%s0, 0(, %%s8)
\\ st %%s1, 8(, %%s8)
\\ st %%s2, 16(, %%s8)
\\ st %%s3, 24(, %%s8)
\\ st %%s4, 32(, %%s8)
\\ st %%s5, 40(, %%s8)
\\ st %%s6, 48(, %%s8)
\\ st %%s7, 56(, %%s8)
\\ st %%s8, 64(, %%s8)
\\ st %%s9, 72(, %%s8)
\\ st %%s10, 80(, %%s8)
\\ st %%s11, 88(, %%s8)
\\ st %%s12, 96(, %%s8)
\\ st %%s13, 104(, %%s8)
\\ st %%s14, 112(, %%s8)
\\ st %%s15, 120(, %%s8)
\\ st %%s16, 128(, %%s8)
\\ st %%s17, 136(, %%s8)
\\ st %%s18, 144(, %%s8)
\\ st %%s19, 152(, %%s8)
\\ st %%s20, 160(, %%s8)
\\ st %%s21, 168(, %%s8)
\\ st %%s22, 176(, %%s8)
\\ st %%s23, 184(, %%s8)
\\ st %%s24, 192(, %%s8)
\\ st %%s25, 200(, %%s8)
\\ st %%s26, 208(, %%s8)
\\ st %%s27, 216(, %%s8)
\\ st %%s28, 224(, %%s8)
\\ st %%s29, 232(, %%s8)
\\ st %%s30, 240(, %%s8)
\\ st %%s31, 248(, %%s8)
\\ st %%s32, 256(, %%s8)
\\ st %%s33, 264(, %%s8)
\\ st %%s34, 272(, %%s8)
\\ st %%s35, 280(, %%s8)
\\ st %%s36, 288(, %%s8)
\\ st %%s37, 296(, %%s8)
\\ st %%s38, 304(, %%s8)
\\ st %%s39, 312(, %%s8)
\\ st %%s40, 320(, %%s8)
\\ st %%s41, 328(, %%s8)
\\ st %%s42, 336(, %%s8)
\\ st %%s43, 344(, %%s8)
\\ st %%s44, 352(, %%s8)
\\ st %%s45, 360(, %%s8)
\\ st %%s46, 368(, %%s8)
\\ st %%s47, 376(, %%s8)
\\ st %%s48, 384(, %%s8)
\\ st %%s49, 392(, %%s8)
\\ st %%s50, 400(, %%s8)
\\ st %%s51, 408(, %%s8)
\\ st %%s52, 416(, %%s8)
\\ st %%s53, 424(, %%s8)
\\ st %%s54, 432(, %%s8)
\\ st %%s55, 440(, %%s8)
\\ st %%s56, 448(, %%s8)
\\ st %%s57, 456(, %%s8)
\\ st %%s58, 464(, %%s8)
\\ st %%s59, 472(, %%s8)
\\ st %%s60, 480(, %%s8)
\\ st %%s61, 488(, %%s8)
\\ st %%s62, 496(, %%s8)
\\ st %%s63, 504(, %%s8)
\\ br.l 1f
\\1:
\\ st %%lr, 512(, %%s8)
:
: [ctx] "{s8}" (&ctx),
: .{ .s10 = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const Ve) usize {
return ctx.s[9];
}
pub fn getPc(ctx: *const Ve) usize {
return ctx.ic;
}
pub fn dwarfRegisterBytes(ctx: *Ve, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...63 => return @ptrCast(&ctx.s[register_num]),
144 => return @ptrCast(&ctx.ic),
64...127 => return error.UnsupportedRegister,
128...143 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const X86_16 = struct {
regs: std.enums.EnumArray(GprName, Gpr),
pub const GprName = enum {
sp, bp, ss,
ip, cs,
};
pub const Gpr = u16;
pub inline fn current() X86_16 {
var ctx: X86_16 = undefined;
asm volatile (
\\ movw %%sp, 0x00(%%di)
\\ movw %%bp, 0x02(%%di)
\\ movw %%ss, 0x04(%%di)
\\ pushw %%cs
\\ call 1f
\\1:
\\ popw 0x06(%%di)
\\ popw 0x08(%%di)
:
: [gprs] "{di}" (&ctx.regs.values),
: .{ .memory = true });
return ctx;
}
pub fn getFp(ctx: *const X86_16) usize {
return ctx.regs.get(.bp);
}
pub fn getPc(ctx: *const X86_16) usize {
return ctx.regs.get(.ip);
}
pub fn dwarfRegisterBytes(ctx: *X86_16, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
4 => return @ptrCast(ctx.regs.getPtr(.sp)),
5 => return @ptrCast(ctx.regs.getPtr(.bp)),
6 => return @ptrCast(ctx.regs.getPtr(.ip)),
41 => return @ptrCast(ctx.regs.getPtr(.cs)),
42 => return @ptrCast(ctx.regs.getPtr(.ss)),
else => return error.InvalidRegister,
}
}
};
const X86 = struct {
gprs: std.enums.EnumArray(GprName, Gpr),
pub const GprName = enum {
eax, ecx, edx, ebx,
esp, ebp, esi, edi,
eip,
};
pub const Gpr = u32;
pub inline fn current() X86 {
var ctx: X86 = undefined;
asm volatile (
\\ movl %%eax, 0x00(%%edi)
\\ movl %%ecx, 0x04(%%edi)
\\ movl %%edx, 0x08(%%edi)
\\ movl %%ebx, 0x0c(%%edi)
\\ movl %%esp, 0x10(%%edi)
\\ movl %%ebp, 0x14(%%edi)
\\ movl %%esi, 0x18(%%edi)
\\ movl %%edi, 0x1c(%%edi)
\\ call 1f
\\1:
\\ popl 0x20(%%edi)
:
: [gprs] "{edi}" (&ctx.gprs.values),
: .{ .memory = true });
return ctx;
}
pub fn getFp(ctx: *const X86) usize {
return ctx.gprs.get(.ebp);
}
pub fn getPc(ctx: *const X86) usize {
return ctx.gprs.get(.eip);
}
pub fn dwarfRegisterBytes(ctx: *X86, register_num: u16) DwarfRegisterError![]u8 {
// ยง 2.4.2 "DWARF Register Number Mapping"
switch (register_num) {
//
// x86-macos sometimes uses different mappings (ebp and esp are reversed when the unwind
// information is from `__eh_frame`). This deviation is not considered here, because
// x86-macos is a deprecated target which is not supported by the Zig Standard Library.
0...8 => return @ptrCast(&ctx.gprs.values[register_num]),
9 => return error.UnsupportedRegister,
11...18 => return error.UnsupportedRegister,
21...28 => return error.UnsupportedRegister,
29...36 => return error.UnsupportedRegister,
39 => return error.UnsupportedRegister,
40...45 => return error.UnsupportedRegister,
48 => return error.UnsupportedRegister,
49 => return error.UnsupportedRegister,
93...100 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const X86_64 = struct {
gprs: std.enums.EnumArray(GprName, Gpr),
pub const GprName = enum {
rax, rdx, rcx, rbx,
rsi, rdi, rbp, rsp,
r8, r9, r10, r11,
r12, r13, r14, r15,
rip,
};
pub const Gpr = u64;
pub inline fn current() X86_64 {
var ctx: X86_64 = undefined;
asm volatile (
\\ movq %%rax, 0x00(%%rdi)
\\ movq %%rdx, 0x08(%%rdi)
\\ movq %%rcx, 0x10(%%rdi)
\\ movq %%rbx, 0x18(%%rdi)
\\ movq %%rsi, 0x20(%%rdi)
\\ movq %%rdi, 0x28(%%rdi)
\\ movq %%rbp, 0x30(%%rdi)
\\ movq %%rsp, 0x38(%%rdi)
\\ movq %%r8, 0x40(%%rdi)
\\ movq %%r9, 0x48(%%rdi)
\\ movq %%r10, 0x50(%%rdi)
\\ movq %%r11, 0x58(%%rdi)
\\ movq %%r12, 0x60(%%rdi)
\\ movq %%r13, 0x68(%%rdi)
\\ movq %%r14, 0x70(%%rdi)
\\ movq %%r15, 0x78(%%rdi)
\\ leaq (%%rip), %%rax
\\ movq %%rax, 0x80(%%rdi)
:
: [gprs] "{rdi}" (&ctx.gprs.values),
: .{ .rax = true, .memory = true });
return ctx;
}
pub fn getFp(ctx: *const X86_64) usize {
return @intCast(ctx.gprs.get(.rbp));
}
pub fn getPc(ctx: *const X86_64) usize {
return @intCast(ctx.gprs.get(.rip));
}
pub fn dwarfRegisterBytes(ctx: *X86_64, register_num: u16) DwarfRegisterError![]u8 {
// ยง 3.6.2 "DWARF Register Number Mapping"
switch (register_num) {
0...16 => return @ptrCast(&ctx.gprs.values[register_num]),
17...32 => return error.UnsupportedRegister,
33...40 => return error.UnsupportedRegister,
41...48 => return error.UnsupportedRegister,
49 => return error.UnsupportedRegister,
50...55 => return error.UnsupportedRegister,
58...59 => return error.UnsupportedRegister,
62 => return error.UnsupportedRegister,
63 => return error.UnsupportedRegister,
64 => return error.UnsupportedRegister,
65 => return error.UnsupportedRegister,
66 => return error.UnsupportedRegister,
67...82 => return error.UnsupportedRegister,
118...125 => return error.UnsupportedRegister,
130...145 => return error.UnsupportedRegister,
else => return error.InvalidRegister,
}
}
};
const signal_ucontext_t = switch (native_os) {
.linux => switch (native_arch) {
.alpha => extern struct {
_flags: u64,
_link: ?*signal_ucontext_t,
_osf_sigmask: u64,
_stack: std.os.linux.stack_t,
mcontext: extern struct {
_onstack: i64,
_mask: i64,
pc: u64,
_ps: i64,
r: [32]u64,
},
},
.aarch64,
.aarch64_be,
.loongarch32,
.loongarch64,
.powerpc64,
.powerpc64le,
.riscv32,
.riscv64,
=> extern struct {
_flags: usize,
_link: ?*signal_ucontext_t,
_stack: std.os.linux.stack_t,
_sigmask: std.os.linux.sigset_t,
_unused: [120]u8,
mcontext: switch (native_arch) {
.aarch64, .aarch64_be => extern struct {
_fault_address: u64 align(16),
x: [30]u64,
lr: u64,
sp: u64,
pc: u64,
},
.loongarch32, .loongarch64 => extern struct {
pc: u64 align(16),
r: [32]u64,
},
.powerpc64, .powerpc64le => extern struct {
_unused: [4]u64,
_signal: i32,
_pad: i32,
_handler: u64,
_oldmask: u64,
_regs: ?*anyopaque,
r: [32]u64,
pc: u64,
_msr: u64,
_orig_r3: u64,
_ctr: u64,
lr: u64,
},
.riscv32, .riscv64 => extern struct {
pc: usize align(16),
ra_sp_gp_tp: [4]usize,
t0_2: [3]usize,
s0_1: [2]usize,
a: [8]usize,
s2_11: [10]usize,
t3_6: [4]usize,
},
else => unreachable,
},
},
.arc,
.arceb,
.arm,
.armeb,
.thumb,
.thumbeb,
.csky,
.hexagon,
.hppa,
.hppa64,
.m68k,
.mips,
.mipsel,
.mips64,
.mips64el,
.or1k,
.s390x,
.x86,
.x86_64,
.xtensa,
.xtensaeb,
=> extern struct {
_flags: usize,
_link: ?*signal_ucontext_t,
_stack: std.os.linux.stack_t,
mcontext: switch (native_arch) {
.arc, .arceb => extern struct {
_pad1: u32,
_bta: u32,
_lp: extern struct {
_start: u32,
_end: u32,
_count: u32,
},
_status32: u32,
pcl: u32,
r31: u32,
r27_26: [2]u32,
r12_0: [13]u32,
r28: u32,
_pad2: u32,
r25_13: [13]u32,
_efa: u32,
_stop_pc: u32,
r30: u32,
},
.arm, .armeb, .thumb, .thumbeb => extern struct {
_trap_no: u32,
_error_code: u32,
_oldmask: u32,
r: [15]u32,
pc: u32,
},
.csky => extern struct {
r31: u32,
r15: u32,
pc: u32,
_sr: u32,
r14: u32,
_orig_a0: u32,
r0_13: [14]u32,
r16_30: [15]u32,
},
.hexagon => extern struct {
r: [32]u32 align(8),
_salc: [2]extern struct {
_sa: u32,
_lc: u32,
},
_m: [2]u32,
_usr: u32,
_p: u32,
_gp: u32,
_ugp: u32,
pc: u32,
},
.hppa, .hppa64 => extern struct {
_flags: usize,
_psw: usize,
r1_19: [19]usize,
r20: usize,
r21: usize,
r22: usize,
r23_29: [7]usize,
r30: usize,
r31: usize,
_fr: [32]f64,
_iasq: [2]usize,
iaoq: [2]usize,
},
.m68k => extern struct {
_version: i32,
d: [8]u32,
a: [8]u32,
pc: u32,
},
.microblaze, .microblazeel => extern struct {
r: [32]u32,
pc: u32,
},
.mips, .mipsel => extern struct {
_regmask: u32,
_status: u32,
pc: u64,
r: [32]u64,
},
.mips64, .mips64el => extern struct {
r: [32]u64,
_fpregs: [32]u64,
_hi: [4]u64,
_lo: [4]u64,
pc: u64,
},
.or1k => extern struct {
r: [32]u32,
pc: u32,
},
.s390x => extern struct {
psw: extern struct {
mask: u64,
addr: u64,
},
r: [16]u64,
},
.sh, .sheb => extern struct {
_oldmask: u32,
r: [16]u32,
pc: u32,
pr: u32,
},
.x86 => extern struct {
_gs: u32,
_fs: u32,
_es: u32,
_ds: u32,
edi: u32,
esi: u32,
ebp: u32,
esp: u32,
ebx: u32,
edx: u32,
ecx: u32,
eax: u32,
_trapno: u32,
_err: u32,
eip: u32,
},
.x86_64 => extern struct {
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
rdi: u64,
rsi: u64,
rbp: u64,
rbx: u64,
rdx: u64,
rax: u64,
rcx: u64,
rsp: u64,
rip: u64,
},
.xtensa, .xtensaeb => extern struct {
pc: u32,
_ps: u32,
_l: extern struct {
_beg: u32,
_end: u32,
_count: u32,
},
_sar: u32,
_acc: extern struct {
_lo: u32,
_hi: u32,
},
a: [16]u32,
},
else => unreachable,
},
},
.powerpc, .powerpcle => extern struct {
_flags: u32,
_link: ?*signal_ucontext_t,
_stack: std.os.linux.stack_t,
_pad1: [7]i32,
_regs: ?*anyopaque,
_sigmask: std.os.linux.sigset_t,
_unused: [120]u8,
_pad2: [3]i32,
mcontext: extern struct {
r: [32]u32 align(16),
pc: u32,
_msr: u32,
_orig_r3: u32,
_ctr: u32,
lr: u32,
},
},
.sparc => extern struct {
_info: std.os.linux.siginfo_t,
mcontext: extern struct {
_psr: u32,
pc: u32,
_npc: u32,
_y: u32,
g: [8]u32,
o: [8]u32,
},
},
.sparc64 => extern struct {
_info: std.os.linux.siginfo_t,
mcontext: extern struct {
g: [8]u64,
o: [8]u64,
_tstate: u64,
pc: u64,
},
},
else => unreachable,
},
.freebsd => extern struct {
_sigmask: std.c.sigset_t,
mcontext: switch (native_arch) {
.aarch64 => extern struct {
x: [30]u64 align(16),
lr: u64,
sp: u64,
pc: u64,
},
.arm => extern struct {
r: [15]u32,
pc: u32,
},
.powerpc64, .powerpc64le => extern struct {
_vers: i32 align(16),
_flags: i32,
_onstack: i32,
_len: i32,
_avec: [32 * 2]u64,
_av: [2]u32,
r: [32]u64,
lr: u64,
_cr: u64,
_xer: u64,
_ctr: u64,
pc: u64,
},
.riscv64 => extern struct {
ra_sp_gp_tp: [4]u64,
t0_2: [3]u64,
t3_6: [4]u64,
s0_1: [2]u64,
s2_11: [10]u64,
a: [8]u64,
pc: u64,
},
.x86 => extern struct {
_onstack: i32 align(16),
_gs: i32,
_fs: i32,
_es: i32,
_ds: i32,
edi: u32,
esi: u32,
ebp: u32,
_isp: i32,
ebx: u32,
edx: u32,
ecx: u32,
eax: u32,
_trapno: i32,
_err: i32,
eip: u32,
_cs: i32,
_eflags: i32,
esp: u32,
},
.x86_64 => extern struct {
_onstack: i64 align(16),
rdi: u64,
rsi: u64,
rdx: u64,
rcx: u64,
r8: u64,
r9: u64,
rax: u64,
rbx: u64,
rbp: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
_trapno: i32,
_fs: i16,
_gs: i16,
_addr: i64,
_flags: i32,
_es: i16,
_ds: i16,
_err: i64,
rip: u64,
_cs: i64,
_rflags: i64,
rsp: u64,
},
else => unreachable,
},
},
.driverkit, .ios, .maccatalyst, .macos, .tvos, .watchos, .visionos => extern struct {
_onstack: i32,
_sigmask: std.c.sigset_t,
_stack: std.c.stack_t,
_link: ?*signal_ucontext_t,
_mcsize: u64,
mcontext: *switch (native_arch) {
// https://github.com/ziglang/zig/blob/60be67d3c0ba6ae15fa7115596734ab1e74fbcd3/lib/libc/include/any-macos-any/mach/arm/_structs.h
.aarch64 => extern struct {
_far: u64 align(16),
_esr: u64,
x: [30]u64,
lr: u64,
sp: u64,
pc: u64,
},
// https://github.com/ziglang/zig/blob/60be67d3c0ba6ae15fa7115596734ab1e74fbcd3/lib/libc/include/any-macos-any/mach/i386/_structs.h
.x86_64 => extern struct {
_trapno: u16,
_cpu: u16,
_err: u32,
_faultvaddr: u64,
rax: u64,
rbx: u64,
rcx: u64,
rdx: u64,
rdi: u64,
rsi: u64,
rbp: u64,
rsp: u64,
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
rip: u64,
},
else => unreachable,
},
},
.illumos => extern struct {
_flags: usize,
_link: ?*signal_ucontext_t,
_sigmask: std.c.sigset_t,
_stack: std.c.stack_t,
mcontext: switch (native_arch) {
.x86 => extern struct {
_gs: u32,
_fs: u32,
_es: u32,
_ds: u32,
edi: u32,
esi: u32,
ebp: u32,
esp: u32,
ebx: u32,
edx: u32,
ecx: u32,
eax: u32,
_trapno: i32,
_err: i32,
eip: u32,
},
.x86_64 => extern struct {
r15: u64 align(16),
r14: u64,
r13: u64,
r12: u64,
r11: u64,
r10: u64,
r9: u64,
r8: u64,
rdi: u64,
rsi: u64,
rbp: u64,
rbx: u64,
rdx: u64,
rcx: u64,
rax: u64,
_trapno: i64,
_err: i64,
rip: u64,
_cs: i64,
_rflags: i64,
rsp: u64,
},
else => unreachable,
},
},
.openbsd => switch (native_arch) {
.aarch64 => extern struct {
_unused: i32,
_mask: i32,
mcontext: extern struct {
sp: u64,
lr: u64,
pc: u64,
_spsr: u64,
x: [30]u64,
},
},
.alpha => extern struct {
_cookie: i64,
_mask: i64,
mcontext: extern struct {
pc: u64,
_ps: i64,
r: [32]u64,
},
},
.arm => extern struct {
_cookie: i32,
_mask: i32,
mcontext: extern struct {
_spsr: u32 align(8),
r: [15]u32,
_svc_lr: u32,
pc: u32,
},
},
.hppa => extern struct {
_unused: u32,
_mask: i32,
_fp: u32,
iaoq: [2]u32,
_resv: [2]u32,
r22: u32,
r21: u32,
r30: u32,
r20: u32,
_sar: u32,
r1_19: [19]u32,
r23_29: [7]u32,
r31: u32,
},
.m88k => extern struct {
_cookie: i32,
_mask: i32,
mcontext: extern struct {
r: [32]u32,
_epsr: u32,
_fpsr: u32,
_fpcr: u32,
xip: u32,
},
},
.mips64, .mips64el => extern struct {
_cookie: i64,
_mask: i64,
mcontext: extern struct {
pc: u64,
r: [32]u64,
},
},
// https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/powerpc64/include/signal.h
.powerpc, .powerpc64 => extern struct {
_cookie: isize,
_mask: i32,
mcontext: extern struct {
r: [32]usize,
lr: usize,
_cr: usize,
_xer: usize,
_ctr: usize,
pc: usize,
},
},
.riscv64 => extern struct {
_unused: i32,
_mask: i32,
mcontext: extern struct {
ra_sp_gp_tp: [4]u64,
t0_2: [3]u64,
t3_6: [4]u64,
s0_1: [2]u64,
s2_11: [10]u64,
a: [8]u64,
pc: u64,
},
},
.sparc64 => @compileError("sparc64-openbsd ucontext_t missing"),
.sh => extern struct {
pc: u32,
_sr: i32,
_gbr: i32,
_macl: i32,
_mach: i32,
pr: u32,
r13_0: [14]u32,
r15: u32,
r14: u32,
},
.x86 => extern struct {
mcontext: extern struct {
_gs: i32,
_fs: i32,
_es: i32,
_ds: i32,
edi: u32,
esi: u32,
ebp: u32,
ebx: u32,
edx: u32,
ecx: u32,
eax: u32,
eip: u32,
_cs: i32,
_eflags: i32,
esp: u32,
},
},
.x86_64 => extern struct {
mcontext: extern struct {
rdi: u64,
rsi: u64,
rdx: u64,
rcx: u64,
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
rbp: u64,
rbx: u64,
rax: u64,
_gs: i64,
_fs: i64,
_es: i64,
_ds: i64,
_trapno: i64,
_err: i64,
rip: u64,
_cs: i64,
_rflags: i64,
rsp: u64,
},
},
else => unreachable,
},
.netbsd => extern struct {
_flags: u32,
_link: ?*signal_ucontext_t,
_sigmask: std.c.sigset_t,
_stack: std.c.stack_t,
mcontext: switch (native_arch) {
.aarch64, .aarch64_be => extern struct {
x: [30]u64 align(16),
lr: u64,
sp: u64,
pc: u64,
},
.alpha => extern struct {
r: [32]u64,
pc: u64,
},
.arm, .armeb => extern struct {
r: [15]u32 align(8),
pc: u32,
},
.hppa => extern struct {
r1_19: [19]u32 align(8),
r20: u32,
r21: u32,
r22: u32,
r23_29: [7]u32,
r30: u32,
r31: u32,
_sar: u32,
_pcsqh: u32,
_pcsqt: u32,
iaoq: [2]u32,
},
.m68k => extern struct {
d: [8]u32,
a: [8]u32,
pc: u32,
},
.mips, .mipsel => extern struct {
r: [32]u32 align(8),
_lo: i32,
_hi: i32,
_cause: i32,
pc: u32,
},
.mips64, .mips64el => @compileError("https://github.com/ziglang/zig/issues/23765#issuecomment-2880386178"),
.powerpc => extern struct {
r: [32]u32 align(16),
_cr: i32,
lr: u32,
pc: u32,
},
.riscv32, .riscv64 => extern struct {
ra_sp_gp_tp: [4]usize align(8),
t0_2: [3]usize,
s0_1: [2]usize,
a: [8]usize,
s2_11: [10]usize,
t3_6: [4]usize,
pc: usize,
},
.sparc => @compileError("sparc-netbsd mcontext_t missing"),
.sparc64 => @compileError("sparc64-netbsd mcontext_t missing"),
.sh, .sheb => extern struct {
_gbr: i32,
pc: u32,
_sr: i32,
_macl: i32,
_mach: i32,
pr: u32,
r14: u32,
r13_0: [14]u32,
r15: u32,
},
.x86 => extern struct {
_gs: i32,
_fs: i32,
_es: i32,
_ds: i32,
edi: u32,
esi: u32,
ebp: u32,
esp: u32,
ebx: u32,
edx: u32,
ecx: u32,
eax: u32,
_trapno: i32,
_err: i32,
eip: u32,
},
.x86_64 => extern struct {
rdi: u64,
rsi: u64,
rdx: u64,
rcx: u64,
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
rbp: u64,
rbx: u64,
rax: u64,
_gs: i64,
_fs: i64,
_es: i64,
_ds: i64,
_trapno: i64,
_err: i64,
rip: u64,
_cs: i64,
_rflags: i64,
rsp: u64,
},
else => unreachable,
},
},
.dragonfly => extern struct {
_sigmask: std.c.sigset_t,
mcontext: switch (native_arch) {
.x86_64 => extern struct {
_onstack: i64 align(64),
rdi: u64,
rsi: u64,
rdx: u64,
rcx: u64,
r8: u64,
r9: u64,
rax: u64,
rbx: u64,
rbp: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
_xflags: i64,
_trapno: i64,
_addr: i64,
_flags: i64,
_err: i64,
rip: u64,
_cs: i64,
_rflags: i64,
rsp: u64,
},
else => unreachable,
},
},
.serenity => extern struct {
_link: ?*signal_ucontext_t,
_sigmask: std.c.sigset_t,
_stack: std.c.stack_t,
mcontext: switch (native_arch) {
.aarch64 => extern struct {
x: [30]u64,
lr: u64,
sp: u64,
pc: u64,
},
.riscv64 => extern struct {
ra_sp_gp_tp: [4]u64,
t0_2: [3]u64,
s0_1: [2]u64,
a: [8]u64,
s2_11: [10]u64,
t3_6: [4]u64,
pc: u64,
},
.x86_64 => extern struct {
rax: u64,
rcx: u64,
rdx: u64,
rbx: u64,
rsp: u64,
rbp: u64,
rsi: u64,
rdi: u64,
rip: u64,
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
},
else => unreachable,
},
},
.haiku => extern struct {
_link: ?*signal_ucontext_t,
_sigmask: std.c.sigset_t,
_stack: std.c.stack_t,
mcontext: switch (native_arch) {
.arm => extern struct {
r: [15]u32 align(8),
pc: u32,
},
.aarch64 => extern struct {
x: [30]u64 align(16),
lr: u64,
sp: u64,
pc: u64,
},
.riscv64 => extern struct {
ra_sp_gp_tp: [4]u64,
t0_2: [3]u64,
s0_1: [2]u64,
a: [8]u64,
s2_11: [10]u64,
t3_6: [4]u64,
pc: u64,
},
.x86 => extern struct {
eip: u32,
_eflags: u32,
eax: u32,
ecx: u32,
edx: u32,
esp: u32,
ebp: u32,
_reserved: u32,
_xregs: extern struct {
_fp_control: u16,
_fp_status: u16,
_fp_tag: u16,
_fp_opcode: u16,
_fp_eip: u32,
_fp_cs: u16,
_reserved1: u16,
_fp_datap: u32,
_fp_ds: u16,
_reserved2: u16,
_mxcsr: u32,
_mxcsr_mask: u32,
_mmx: [8][16]u8,
_xmmx: [8][16]u8,
_reserved3: [176]u8,
_fault_address: u32,
_error_code: u32,
_cs: u16,
_ds: u16,
_es: u16,
_fs: u16,
_gs: u16,
_ss: u16,
_trap_number: u8,
_reserved4: [27]u8,
_format: u32,
},
edi: u32,
esi: u32,
ebx: u32,
},
.x86_64 => extern struct {
rax: u64,
rbx: u64,
rcx: u64,
rdx: u64,
rdi: u64,
rsi: u64,
rbp: u64,
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
rsp: u64,
rip: u64,
},
else => unreachable,
},
},
else => void,
};
const std = @import("../std.zig");
const root = @import("root");
const builtin = @import("builtin");
const native_arch = @import("builtin").target.cpu.arch;
const native_os = @import("builtin").target.os.tag;