master
   1/// Register state for the native architecture, used by `std.debug` for stack unwinding.
   2/// `noreturn` if there is no implementation for the native architecture.
   3/// This can be overriden by exposing a declaration `root.debug.CpuContext`.
   4pub const Native = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "CpuContext"))
   5    root.debug.CpuContext
   6else switch (native_arch) {
   7    .aarch64, .aarch64_be => Aarch64,
   8    .arc, .arceb => Arc,
   9    .arm, .armeb, .thumb, .thumbeb => Arm,
  10    .csky => Csky,
  11    .hexagon => Hexagon,
  12    .kvx => Kvx,
  13    .lanai => Lanai,
  14    .loongarch32, .loongarch64 => LoongArch,
  15    .m68k => M68k,
  16    .mips, .mipsel, .mips64, .mips64el => Mips,
  17    .or1k => Or1k,
  18    .powerpc, .powerpcle, .powerpc64, .powerpc64le => Powerpc,
  19    .sparc, .sparc64 => Sparc,
  20    .riscv32, .riscv32be, .riscv64, .riscv64be => Riscv,
  21    .ve => Ve,
  22    .s390x => S390x,
  23    .x86_16 => X86_16,
  24    .x86 => X86,
  25    .x86_64 => X86_64,
  26    else => noreturn,
  27};
  28
  29pub const DwarfRegisterError = error{
  30    InvalidRegister,
  31    UnsupportedRegister,
  32};
  33
  34pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
  35    if (signal_ucontext_t == void) return null;
  36
  37    // In general, we include the hardwired zero register in the context if applicable.
  38    const uc: *const signal_ucontext_t = @ptrCast(@alignCast(ctx_ptr));
  39
  40    // Deal with some special cases first.
  41    if (native_arch.isArc() and native_os == .linux) {
  42        var native: Native = .{
  43            .r = [_]u32{ uc.mcontext.r31, uc.mcontext.r30, 0, uc.mcontext.r28 } ++
  44                uc.mcontext.r27_26 ++
  45                uc.mcontext.r25_13 ++
  46                uc.mcontext.r12_0,
  47            .pcl = uc.mcontext.pcl,
  48        };
  49
  50        // I have no idea why the kernel is storing these registers in such a bizarre order...
  51        std.mem.reverse(native.r[0..]);
  52
  53        return native;
  54    } else if (native_arch.isMIPS32() and native_os == .linux) {
  55        // The O32 kABI uses 64-bit fields for some reason.
  56        return .{
  57            .r = s: {
  58                var regs: [32]Mips.Gpr = undefined;
  59                for (uc.mcontext.r, 0..) |r, i| regs[i] = @truncate(r);
  60                break :s regs;
  61            },
  62            .pc = @truncate(uc.mcontext.pc),
  63        };
  64    } else if (native_arch.isSPARC() and native_os == .linux) {
  65        const SparcStackFrame = extern struct {
  66            l: [8]usize,
  67            i: [8]usize,
  68            _x: [8]usize,
  69        };
  70
  71        // When invoking a signal handler, the kernel builds an `rt_signal_frame` structure on the
  72        // stack and passes a pointer to its `info` field to the signal handler. This implies that
  73        // prior to said `info` field, we will find the `ss` field which, among other things,
  74        // contains the incoming and local registers of the interrupted code.
  75        const frame = @as(*const SparcStackFrame, @ptrFromInt(@as(usize, @intFromPtr(ctx_ptr)) - @sizeOf(SparcStackFrame)));
  76
  77        return .{
  78            .g = uc.mcontext.g,
  79            .o = uc.mcontext.o,
  80            .l = frame.l,
  81            .i = frame.i,
  82            .pc = uc.mcontext.pc,
  83        };
  84    }
  85
  86    // Only unified conversions from here.
  87    return switch (native_arch) {
  88        .arm, .armeb, .thumb, .thumbeb => .{
  89            .r = uc.mcontext.r ++ [_]u32{uc.mcontext.pc},
  90        },
  91        .aarch64, .aarch64_be => .{
  92            .x = uc.mcontext.x ++ [_]u64{uc.mcontext.lr},
  93            .sp = uc.mcontext.sp,
  94            .pc = uc.mcontext.pc,
  95        },
  96        .csky => .{
  97            .r = uc.mcontext.r0_13 ++
  98                [_]u32{ uc.mcontext.r14, uc.mcontext.r15 } ++
  99                uc.mcontext.r16_30 ++
 100                [_]u32{uc.mcontext.r31},
 101            .pc = uc.mcontext.pc,
 102        },
 103        .hexagon, .loongarch32, .loongarch64, .mips, .mipsel, .mips64, .mips64el, .or1k => .{
 104            .r = uc.mcontext.r,
 105            .pc = uc.mcontext.pc,
 106        },
 107        .m68k => .{
 108            .d = uc.mcontext.d,
 109            .a = uc.mcontext.a,
 110            .pc = uc.mcontext.pc,
 111        },
 112        .powerpc, .powerpcle, .powerpc64, .powerpc64le => .{
 113            .r = uc.mcontext.r,
 114            .pc = uc.mcontext.pc,
 115            .lr = uc.mcontext.lr,
 116        },
 117        .riscv32, .riscv32be, .riscv64, .riscv64be => .{
 118            // You can thank FreeBSD and OpenBSD for this silliness; they decided to be cute and
 119            // group the registers by ABI mnemonic rather than register number.
 120            .x = [_]Riscv.Gpr{0} ++
 121                uc.mcontext.ra_sp_gp_tp ++
 122                uc.mcontext.t0_2 ++
 123                uc.mcontext.s0_1 ++
 124                uc.mcontext.a ++
 125                uc.mcontext.s2_11 ++
 126                uc.mcontext.t3_6,
 127            .pc = uc.mcontext.pc,
 128        },
 129        .s390x => .{
 130            .r = uc.mcontext.r,
 131            .psw = .{
 132                .mask = uc.mcontext.psw.mask,
 133                .addr = uc.mcontext.psw.addr,
 134            },
 135        },
 136        .x86 => .{ .gprs = .init(.{
 137            .eax = uc.mcontext.eax,
 138            .ecx = uc.mcontext.ecx,
 139            .edx = uc.mcontext.edx,
 140            .ebx = uc.mcontext.ebx,
 141            .esp = uc.mcontext.esp,
 142            .ebp = uc.mcontext.ebp,
 143            .esi = uc.mcontext.esi,
 144            .edi = uc.mcontext.edi,
 145            .eip = uc.mcontext.eip,
 146        }) },
 147        .x86_64 => .{ .gprs = .init(.{
 148            .rax = uc.mcontext.rax,
 149            .rdx = uc.mcontext.rdx,
 150            .rcx = uc.mcontext.rcx,
 151            .rbx = uc.mcontext.rbx,
 152            .rsi = uc.mcontext.rsi,
 153            .rdi = uc.mcontext.rdi,
 154            .rbp = uc.mcontext.rbp,
 155            .rsp = uc.mcontext.rsp,
 156            .r8 = uc.mcontext.r8,
 157            .r9 = uc.mcontext.r9,
 158            .r10 = uc.mcontext.r10,
 159            .r11 = uc.mcontext.r11,
 160            .r12 = uc.mcontext.r12,
 161            .r13 = uc.mcontext.r13,
 162            .r14 = uc.mcontext.r14,
 163            .r15 = uc.mcontext.r15,
 164            .rip = uc.mcontext.rip,
 165        }) },
 166        else => comptime unreachable,
 167    };
 168}
 169
 170pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native {
 171    return switch (native_arch) {
 172        .x86 => .{ .gprs = .init(.{
 173            .eax = ctx.Eax,
 174            .ecx = ctx.Ecx,
 175            .edx = ctx.Edx,
 176            .ebx = ctx.Ebx,
 177            .esp = ctx.Esp,
 178            .ebp = ctx.Ebp,
 179            .esi = ctx.Esi,
 180            .edi = ctx.Edi,
 181            .eip = ctx.Eip,
 182        }) },
 183        .x86_64 => .{ .gprs = .init(.{
 184            .rax = ctx.Rax,
 185            .rdx = ctx.Rdx,
 186            .rcx = ctx.Rcx,
 187            .rbx = ctx.Rbx,
 188            .rsi = ctx.Rsi,
 189            .rdi = ctx.Rdi,
 190            .rbp = ctx.Rbp,
 191            .rsp = ctx.Rsp,
 192            .r8 = ctx.R8,
 193            .r9 = ctx.R9,
 194            .r10 = ctx.R10,
 195            .r11 = ctx.R11,
 196            .r12 = ctx.R12,
 197            .r13 = ctx.R13,
 198            .r14 = ctx.R14,
 199            .r15 = ctx.R15,
 200            .rip = ctx.Rip,
 201        }) },
 202        .aarch64 => .{
 203            .x = ctx.DUMMYUNIONNAME.X[0..31].*,
 204            .sp = ctx.Sp,
 205            .pc = ctx.Pc,
 206        },
 207        .thumb => .{ .r = .{
 208            ctx.R0,  ctx.R1, ctx.R2,  ctx.R3,
 209            ctx.R4,  ctx.R5, ctx.R6,  ctx.R7,
 210            ctx.R8,  ctx.R9, ctx.R10, ctx.R11,
 211            ctx.R12, ctx.Sp, ctx.Lr,  ctx.Pc,
 212        } },
 213        else => comptime unreachable,
 214    };
 215}
 216
 217/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 218const Aarch64 = extern struct {
 219    /// The numbered general-purpose registers X0 - X30.
 220    x: [31]u64,
 221    sp: u64,
 222    pc: u64,
 223
 224    pub inline fn current() Aarch64 {
 225        var ctx: Aarch64 = undefined;
 226        asm volatile (
 227            \\ stp x0,  x1,  [x0, #0x000]
 228            \\ stp x2,  x3,  [x0, #0x010]
 229            \\ stp x4,  x5,  [x0, #0x020]
 230            \\ stp x6,  x7,  [x0, #0x030]
 231            \\ stp x8,  x9,  [x0, #0x040]
 232            \\ stp x10, x11, [x0, #0x050]
 233            \\ stp x12, x13, [x0, #0x060]
 234            \\ stp x14, x15, [x0, #0x070]
 235            \\ stp x16, x17, [x0, #0x080]
 236            \\ stp x18, x19, [x0, #0x090]
 237            \\ stp x20, x21, [x0, #0x0a0]
 238            \\ stp x22, x23, [x0, #0x0b0]
 239            \\ stp x24, x25, [x0, #0x0c0]
 240            \\ stp x26, x27, [x0, #0x0d0]
 241            \\ stp x28, x29, [x0, #0x0e0]
 242            \\ str x30, [x0, #0x0f0]
 243            \\ mov x1, sp
 244            \\ str x1, [x0, #0x0f8]
 245            \\ adr x1, .
 246            \\ str x1, [x0, #0x100]
 247            :
 248            : [ctx] "{x0}" (&ctx),
 249            : .{ .x1 = true, .memory = true });
 250        return ctx;
 251    }
 252
 253    pub fn getFp(ctx: *const Aarch64) u64 {
 254        return ctx.x[29];
 255    }
 256    pub fn getPc(ctx: *const Aarch64) u64 {
 257        return ctx.pc;
 258    }
 259
 260    pub fn dwarfRegisterBytes(ctx: *Aarch64, register_num: u16) DwarfRegisterError![]u8 {
 261        // DWARF for the Arm(r) 64-bit Architecture (AArch64) § 4.1 "DWARF register names"
 262        switch (register_num) {
 263            0...30 => return @ptrCast(&ctx.x[register_num]),
 264            31 => return @ptrCast(&ctx.sp),
 265            32 => return @ptrCast(&ctx.pc),
 266
 267            33 => return error.UnsupportedRegister, // ELR_mode
 268            34 => return error.UnsupportedRegister, // RA_SIGN_STATE
 269            35 => return error.UnsupportedRegister, // TPIDRRO_ELO
 270            36 => return error.UnsupportedRegister, // TPIDR_ELO
 271            37 => return error.UnsupportedRegister, // TPIDR_EL1
 272            38 => return error.UnsupportedRegister, // TPIDR_EL2
 273            39 => return error.UnsupportedRegister, // TPIDR_EL3
 274            40...45 => return error.UnsupportedRegister, // Reserved
 275            46 => return error.UnsupportedRegister, // VG
 276            47 => return error.UnsupportedRegister, // FFR
 277            48...63 => return error.UnsupportedRegister, // P0 - P15
 278            64...95 => return error.UnsupportedRegister, // V0 - V31
 279            96...127 => return error.UnsupportedRegister, // Z0 - Z31
 280
 281            else => return error.InvalidRegister,
 282        }
 283    }
 284};
 285
 286/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 287const Arc = extern struct {
 288    /// The numbered general-purpose registers r0 - r31.
 289    r: [32]u32,
 290    pcl: u32,
 291
 292    pub inline fn current() Arc {
 293        var ctx: Arc = undefined;
 294        asm volatile (
 295            \\ st r0, [r8, 0]
 296            \\ st r1, [r8, 4]
 297            \\ st r2, [r8, 8]
 298            \\ st r3, [r8, 12]
 299            \\ st r4, [r8, 16]
 300            \\ st r5, [r8, 20]
 301            \\ st r6, [r8, 24]
 302            \\ st r7, [r8, 28]
 303            \\ st r8, [r8, 32]
 304            \\ st r9, [r8, 36]
 305            \\ st r10, [r8, 40]
 306            \\ st r11, [r8, 44]
 307            \\ st r12, [r8, 48]
 308            \\ st r13, [r8, 52]
 309            \\ st r14, [r8, 56]
 310            \\ st r15, [r8, 60]
 311            \\ st r16, [r8, 64]
 312            \\ st r17, [r8, 68]
 313            \\ st r18, [r8, 72]
 314            \\ st r19, [r8, 76]
 315            \\ st r20, [r8, 80]
 316            \\ st r21, [r8, 84]
 317            \\ st r22, [r8, 88]
 318            \\ st r23, [r8, 92]
 319            \\ st r24, [r8, 96]
 320            \\ st r25, [r8, 100]
 321            \\ st r26, [r8, 104]
 322            \\ st r27, [r8, 108]
 323            \\ st r28, [r8, 112]
 324            \\ st r29, [r8, 116]
 325            \\ st r30, [r8, 120]
 326            \\ st r31, [r8, 124]
 327            \\ st pcl, [r8, 128]
 328            :
 329            : [ctx] "{r8}" (&ctx),
 330            : .{ .memory = true });
 331        return ctx;
 332    }
 333
 334    pub fn getFp(ctx: *const Arc) u32 {
 335        return ctx.r[27];
 336    }
 337    pub fn getPc(ctx: *const Arc) u32 {
 338        return ctx.pcl;
 339    }
 340
 341    pub fn dwarfRegisterBytes(ctx: *Arc, register_num: u16) DwarfRegisterError![]u8 {
 342        switch (register_num) {
 343            0...31 => return @ptrCast(&ctx.r[register_num]),
 344            160 => return @ptrCast(&ctx.pcl),
 345
 346            32...57 => return error.UnsupportedRegister, // Extension Core Registers
 347            58...127 => return error.UnsupportedRegister, // Reserved
 348            128...159 => return error.UnsupportedRegister, // f0 - f31
 349
 350            else => return error.InvalidRegister,
 351        }
 352    }
 353};
 354
 355const Arm = struct {
 356    /// The numbered general-purpose registers R0 - R15.
 357    r: [16]u32,
 358
 359    pub inline fn current() Arm {
 360        var ctx: Arm = undefined;
 361        asm volatile (
 362            \\ // For compatibility with Thumb, we can't write r13 (sp) or r15 (pc) with stm.
 363            \\ stm r0, {r0-r12}
 364            \\ str r13, [r0, #0x34]
 365            \\ str r14, [r0, #0x38]
 366            \\ str r15, [r0, #0x3c]
 367            :
 368            : [r] "{r0}" (&ctx.r),
 369            : .{ .memory = true });
 370        return ctx;
 371    }
 372
 373    pub fn getFp(ctx: *const Arm) u32 {
 374        return ctx.r[11];
 375    }
 376    pub fn getPc(ctx: *const Arm) u32 {
 377        return ctx.r[15];
 378    }
 379
 380    pub fn dwarfRegisterBytes(ctx: *Arm, register_num: u16) DwarfRegisterError![]u8 {
 381        // DWARF for the Arm(r) Architecture § 4.1 "DWARF register names"
 382        switch (register_num) {
 383            0...15 => return @ptrCast(&ctx.r[register_num]),
 384
 385            64...95 => return error.UnsupportedRegister, // S0 - S31
 386            96...103 => return error.UnsupportedRegister, // F0 - F7
 387            104...111 => return error.UnsupportedRegister, // wCGR0 - wCGR7, or ACC0 - ACC7
 388            112...127 => return error.UnsupportedRegister, // wR0 - wR15
 389            128 => return error.UnsupportedRegister, // SPSR
 390            129 => return error.UnsupportedRegister, // SPSR_FIQ
 391            130 => return error.UnsupportedRegister, // SPSR_IRQ
 392            131 => return error.UnsupportedRegister, // SPSR_ABT
 393            132 => return error.UnsupportedRegister, // SPSR_UND
 394            133 => return error.UnsupportedRegister, // SPSR_SVC
 395            134...142 => return error.UnsupportedRegister, // Reserved
 396            143 => return error.UnsupportedRegister, // RA_AUTH_CODE
 397            144...150 => return error.UnsupportedRegister, // R8_USR - R14_USR
 398            151...157 => return error.UnsupportedRegister, // R8_FIQ - R14_FIQ
 399            158...159 => return error.UnsupportedRegister, // R13_IRQ - R14_IRQ
 400            160...161 => return error.UnsupportedRegister, // R13_ABT - R14_ABT
 401            162...163 => return error.UnsupportedRegister, // R13_UND - R14_UND
 402            164...165 => return error.UnsupportedRegister, // R13_SVC - R14_SVC
 403            166...191 => return error.UnsupportedRegister, // Reserved
 404            192...199 => return error.UnsupportedRegister, // wC0 - wC7
 405            200...255 => return error.UnsupportedRegister, // Reserved
 406            256...287 => return error.UnsupportedRegister, // D0 - D31
 407            288...319 => return error.UnsupportedRegister, // Reserved for FP/NEON
 408            320 => return error.UnsupportedRegister, // TPIDRURO
 409            321 => return error.UnsupportedRegister, // TPIDRURW
 410            322 => return error.UnsupportedRegister, // TPIDPR
 411            323 => return error.UnsupportedRegister, // HTPIDPR
 412            324...8191 => return error.UnsupportedRegister, // Reserved
 413            8192...16383 => return error.UnsupportedRegister, // Unspecified vendor co-processor register
 414
 415            else => return error.InvalidRegister,
 416        }
 417    }
 418};
 419
 420/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 421const Csky = extern struct {
 422    /// The numbered general-purpose registers r0 - r31.
 423    r: [32]u32,
 424    pc: u32,
 425
 426    pub inline fn current() Csky {
 427        var ctx: Csky = undefined;
 428        asm volatile (
 429            \\ stm r0-r31, (t0)
 430            \\ grs t1, 1f
 431            \\1:
 432            \\ st32.w t1, (t0, 128)
 433            :
 434            : [ctx] "{r12}" (&ctx),
 435            : .{ .r13 = true, .memory = true });
 436        return ctx;
 437    }
 438
 439    pub fn getFp(ctx: *const Csky) u32 {
 440        return ctx.r[14];
 441    }
 442    pub fn getPc(ctx: *const Csky) u32 {
 443        return ctx.pc;
 444    }
 445
 446    pub fn dwarfRegisterBytes(ctx: *Csky, register_num: u16) DwarfRegisterError![]u8 {
 447        switch (register_num) {
 448            0...31 => return @ptrCast(&ctx.r[register_num]),
 449            64 => return @ptrCast(&ctx.pc),
 450
 451            32...63 => return error.UnsupportedRegister, // f0 - f31
 452
 453            else => return error.InvalidRegister,
 454        }
 455    }
 456};
 457
 458/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 459const Hexagon = extern struct {
 460    /// The numbered general-purpose registers r0 - r31.
 461    r: [32]u32,
 462    pc: u32,
 463
 464    pub inline fn current() Hexagon {
 465        var ctx: Hexagon = undefined;
 466        asm volatile (
 467            \\ memw(r0 + #0) = r0
 468            \\ memw(r0 + #4) = r1
 469            \\ memw(r0 + #8) = r2
 470            \\ memw(r0 + #12) = r3
 471            \\ memw(r0 + #16) = r4
 472            \\ memw(r0 + #20) = r5
 473            \\ memw(r0 + #24) = r6
 474            \\ memw(r0 + #28) = r7
 475            \\ memw(r0 + #32) = r8
 476            \\ memw(r0 + #36) = r9
 477            \\ memw(r0 + #40) = r10
 478            \\ memw(r0 + #44) = r11
 479            \\ memw(r0 + #48) = r12
 480            \\ memw(r0 + #52) = r13
 481            \\ memw(r0 + #56) = r14
 482            \\ memw(r0 + #60) = r15
 483            \\ memw(r0 + #64) = r16
 484            \\ memw(r0 + #68) = r17
 485            \\ memw(r0 + #72) = r18
 486            \\ memw(r0 + #76) = r19
 487            \\ memw(r0 + #80) = r20
 488            \\ memw(r0 + #84) = r21
 489            \\ memw(r0 + #88) = r22
 490            \\ memw(r0 + #92) = r23
 491            \\ memw(r0 + #96) = r24
 492            \\ memw(r0 + #100) = r25
 493            \\ memw(r0 + #104) = r26
 494            \\ memw(r0 + #108) = r27
 495            \\ memw(r0 + #112) = r28
 496            \\ memw(r0 + #116) = r29
 497            \\ memw(r0 + #120) = r30
 498            \\ memw(r0 + #124) = r31
 499            \\ r1 = pc
 500            \\ memw(r0 + #128) = r1
 501            :
 502            : [ctx] "{r0}" (&ctx),
 503            : .{ .r1 = true, .memory = true });
 504        return ctx;
 505    }
 506
 507    pub fn getFp(ctx: *const Hexagon) u32 {
 508        return ctx.r[30];
 509    }
 510    pub fn getPc(ctx: *const Hexagon) u32 {
 511        return ctx.pc;
 512    }
 513
 514    pub fn dwarfRegisterBytes(ctx: *Hexagon, register_num: u16) DwarfRegisterError![]u8 {
 515        // Sourced from LLVM's HexagonRegisterInfo.td, which disagrees with LLDB...
 516        switch (register_num) {
 517            0...31 => return @ptrCast(&ctx.r[register_num]),
 518            76 => return @ptrCast(&ctx.pc),
 519
 520            // This is probably covering some numbers that aren't actually mapped, but seriously,
 521            // look at that file. I really can't be bothered to make it more precise.
 522            32...75 => return error.UnsupportedRegister,
 523            77...259 => return error.UnsupportedRegister,
 524            // 999999...1000030 => return error.UnsupportedRegister,
 525            // 9999999...10000030 => return error.UnsupportedRegister,
 526
 527            else => return error.InvalidRegister,
 528        }
 529    }
 530};
 531
 532/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 533const Kvx = extern struct {
 534    r: [64]u64,
 535    ra: u64,
 536    pc: u64,
 537
 538    pub inline fn current() Kvx {
 539        var ctx: Kvx = undefined;
 540        asm volatile (
 541            \\ so (0)[$r32] = $r0r1r2r3
 542            \\ ;;
 543            \\ so (32)[$r32] = $r4r5r6r7
 544            \\ ;;
 545            \\ so (64)[$r32] = $r8r9r10r11
 546            \\ ;;
 547            \\ so (96)[$r32] = $r12r13r14r15
 548            \\ ;;
 549            \\ so (128)[$r32] = $r16r17r18r19
 550            \\ ;;
 551            \\ so (160)[$r32] = $r20r21r22r23
 552            \\ ;;
 553            \\ so (192)[$r32] = $r24r25r26r27
 554            \\ ;;
 555            \\ so (224)[$r32] = $r28r29r30r31
 556            \\ ;;
 557            \\ so (256)[$r32] = $r32r33r34r35
 558            \\ ;;
 559            \\ so (288)[$r32] = $r36r37r38r39
 560            \\ ;;
 561            \\ so (320)[$r32] = $r40r41r42r43
 562            \\ ;;
 563            \\ so (352)[$r32] = $r44r45r46r47
 564            \\ ;;
 565            \\ so (384)[$r32] = $r48r49r50r51
 566            \\ ;;
 567            \\ so (416)[$r32] = $r52r53r54r55
 568            \\ ;;
 569            \\ so (448)[$r32] = $r56r57r58r59
 570            \\ get $r34 = $pc
 571            \\ ;;
 572            \\ so (480)[$r32] = $r60r61r62r63
 573            \\ get $r35 = $ra
 574            \\ ;;
 575            \\ sq (512)[$r32] = $r34r35
 576            :
 577            : [ctx] "{r32}" (&ctx),
 578            : .{ .r34 = true, .r35 = true, .memory = true });
 579        return ctx;
 580    }
 581
 582    pub fn getFp(ctx: *const Kvx) u64 {
 583        return ctx.r[14];
 584    }
 585    pub fn getPc(ctx: *const Kvx) u64 {
 586        return ctx.pc;
 587    }
 588
 589    pub fn dwarfRegisterBytes(ctx: *Kvx, register_num: u16) DwarfRegisterError![]u8 {
 590        switch (register_num) {
 591            0...63 => return @ptrCast(&ctx.r[register_num]),
 592            64 => return @ptrCast(&ctx.pc),
 593            67 => return @ptrCast(&ctx.ra),
 594
 595            65...66 => return error.UnsupportedRegister, // SFRs
 596            68...255 => return error.UnsupportedRegister, // SFRs
 597            256...767 => return error.UnsupportedRegister, // XCRs
 598
 599            else => return error.InvalidRegister,
 600        }
 601    }
 602};
 603
 604/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 605const Lanai = extern struct {
 606    r: [32]u32,
 607
 608    pub inline fn current() Lanai {
 609        var ctx: Lanai = undefined;
 610        asm volatile (
 611            \\ st %%r0, 0[r9]
 612            \\ st %%r1, 4[r9]
 613            \\ st %%r2, 8[r9]
 614            \\ st %%r3, 12[r9]
 615            \\ st %%r4, 16[r9]
 616            \\ st %%r5, 20[r9]
 617            \\ st %%r6, 24[r9]
 618            \\ st %%r7, 28[r9]
 619            \\ st %%r8, 32[r9]
 620            \\ st %%r9, 36[r9]
 621            \\ st %%r10, 40[r9]
 622            \\ st %%r11, 44[r9]
 623            \\ st %%r12, 48[r9]
 624            \\ st %%r13, 52[r9]
 625            \\ st %%r14, 56[r9]
 626            \\ st %%r15, 60[r9]
 627            \\ st %%r16, 64[r9]
 628            \\ st %%r17, 68[r9]
 629            \\ st %%r18, 72[r9]
 630            \\ st %%r19, 76[r9]
 631            \\ st %%r20, 80[r9]
 632            \\ st %%r21, 84[r9]
 633            \\ st %%r22, 88[r9]
 634            \\ st %%r23, 92[r9]
 635            \\ st %%r24, 96[r9]
 636            \\ st %%r25, 100[r9]
 637            \\ st %%r26, 104[r9]
 638            \\ st %%r27, 108[r9]
 639            \\ st %%r28, 112[r9]
 640            \\ st %%r29, 116[r9]
 641            \\ st %%r30, 120[r9]
 642            \\ st %%r31, 124[r9]
 643            :
 644            : [ctx] "{r9}" (&ctx),
 645            : .{ .memory = true });
 646        return ctx;
 647    }
 648
 649    pub fn getFp(ctx: *const Lanai) u32 {
 650        return ctx.r[5];
 651    }
 652    pub fn getPc(ctx: *const Lanai) u32 {
 653        return ctx.r[2];
 654    }
 655
 656    pub fn dwarfRegisterBytes(ctx: *Lanai, register_num: u16) DwarfRegisterError![]u8 {
 657        switch (register_num) {
 658            0...31 => return @ptrCast(&ctx.s[register_num]),
 659
 660            else => return error.InvalidRegister,
 661        }
 662    }
 663};
 664
 665/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 666const LoongArch = extern struct {
 667    /// The numbered general-purpose registers r0 - r31. r0 must be zero.
 668    r: [32]Gpr,
 669    pc: Gpr,
 670
 671    pub const Gpr = if (native_arch == .loongarch64) u64 else u32;
 672
 673    pub inline fn current() LoongArch {
 674        var ctx: LoongArch = undefined;
 675        asm volatile (if (Gpr == u64)
 676                \\ st.d $zero, $t0, 0
 677                \\ st.d $ra, $t0, 8
 678                \\ st.d $tp, $t0, 16
 679                \\ st.d $sp, $t0, 24
 680                \\ st.d $a0, $t0, 32
 681                \\ st.d $a1, $t0, 40
 682                \\ st.d $a2, $t0, 48
 683                \\ st.d $a3, $t0, 56
 684                \\ st.d $a4, $t0, 64
 685                \\ st.d $a5, $t0, 72
 686                \\ st.d $a6, $t0, 80
 687                \\ st.d $a7, $t0, 88
 688                \\ st.d $t0, $t0, 96
 689                \\ st.d $t1, $t0, 104
 690                \\ st.d $t2, $t0, 112
 691                \\ st.d $t3, $t0, 120
 692                \\ st.d $t4, $t0, 128
 693                \\ st.d $t5, $t0, 136
 694                \\ st.d $t6, $t0, 144
 695                \\ st.d $t7, $t0, 152
 696                \\ st.d $t8, $t0, 160
 697                \\ st.d $r21, $t0, 168
 698                \\ st.d $fp, $t0, 176
 699                \\ st.d $s0, $t0, 184
 700                \\ st.d $s1, $t0, 192
 701                \\ st.d $s2, $t0, 200
 702                \\ st.d $s3, $t0, 208
 703                \\ st.d $s4, $t0, 216
 704                \\ st.d $s5, $t0, 224
 705                \\ st.d $s6, $t0, 232
 706                \\ st.d $s7, $t0, 240
 707                \\ st.d $s8, $t0, 248
 708                \\ bl 1f
 709                \\1:
 710                \\ st.d $ra, $t0, 256
 711            else
 712                \\ st.w $zero, $t0, 0
 713                \\ st.w $ra, $t0, 4
 714                \\ st.w $tp, $t0, 8
 715                \\ st.w $sp, $t0, 12
 716                \\ st.w $a0, $t0, 16
 717                \\ st.w $a1, $t0, 20
 718                \\ st.w $a2, $t0, 24
 719                \\ st.w $a3, $t0, 28
 720                \\ st.w $a4, $t0, 32
 721                \\ st.w $a5, $t0, 36
 722                \\ st.w $a6, $t0, 40
 723                \\ st.w $a7, $t0, 44
 724                \\ st.w $t0, $t0, 48
 725                \\ st.w $t1, $t0, 52
 726                \\ st.w $t2, $t0, 56
 727                \\ st.w $t3, $t0, 60
 728                \\ st.w $t4, $t0, 64
 729                \\ st.w $t5, $t0, 68
 730                \\ st.w $t6, $t0, 72
 731                \\ st.w $t7, $t0, 76
 732                \\ st.w $t8, $t0, 80
 733                \\ st.w $r21, $t0, 84
 734                \\ st.w $fp, $t0, 88
 735                \\ st.w $s0, $t0, 92
 736                \\ st.w $s1, $t0, 96
 737                \\ st.w $s2, $t0, 100
 738                \\ st.w $s3, $t0, 104
 739                \\ st.w $s4, $t0, 108
 740                \\ st.w $s5, $t0, 112
 741                \\ st.w $s6, $t0, 116
 742                \\ st.w $s7, $t0, 120
 743                \\ st.w $s8, $t0, 124
 744                \\ bl 1f
 745                \\1:
 746                \\ st.w $ra, $t0, 128
 747            :
 748            : [ctx] "{$r12}" (&ctx),
 749            : .{ .r1 = true, .memory = true });
 750        return ctx;
 751    }
 752
 753    pub fn getFp(ctx: *const LoongArch) Gpr {
 754        return ctx.r[22];
 755    }
 756    pub fn getPc(ctx: *const LoongArch) Gpr {
 757        return ctx.pc;
 758    }
 759
 760    pub fn dwarfRegisterBytes(ctx: *LoongArch, register_num: u16) DwarfRegisterError![]u8 {
 761        switch (register_num) {
 762            0...31 => return @ptrCast(&ctx.r[register_num]),
 763            64 => return @ptrCast(&ctx.pc),
 764
 765            32...63 => return error.UnsupportedRegister, // f0 - f31
 766
 767            else => return error.InvalidRegister,
 768        }
 769    }
 770};
 771
 772/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 773const M68k = extern struct {
 774    /// The numbered data registers d0 - d7.
 775    d: [8]u32,
 776    /// The numbered address registers a0 - a7.
 777    a: [8]u32,
 778    pc: u32,
 779
 780    pub inline fn current() M68k {
 781        var ctx: M68k = undefined;
 782        asm volatile (
 783            \\ movem.l %%d0 - %%a7, (%%a0)
 784            \\ lea.l (%%pc), %%a1
 785            \\ move.l %%a1, (%%a0, 64)
 786            :
 787            : [ctx] "{a0}" (&ctx),
 788            : .{ .a1 = true, .memory = true });
 789        return ctx;
 790    }
 791
 792    pub fn getFp(ctx: *const M68k) u32 {
 793        return ctx.a[6];
 794    }
 795    pub fn getPc(ctx: *const M68k) u32 {
 796        return ctx.pc;
 797    }
 798
 799    pub fn dwarfRegisterBytes(ctx: *M68k, register_num: u16) DwarfRegisterError![]u8 {
 800        switch (register_num) {
 801            0...7 => return @ptrCast(&ctx.d[register_num]),
 802            8...15 => return @ptrCast(&ctx.a[register_num - 8]),
 803            26 => return @ptrCast(&ctx.pc),
 804
 805            16...23 => return error.UnsupportedRegister, // fp0 - fp7
 806            24...25 => return error.UnsupportedRegister, // Return columns in GCC...?
 807
 808            else => return error.InvalidRegister,
 809        }
 810    }
 811};
 812
 813/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 814const Mips = extern struct {
 815    /// The numbered general-purpose registers r0 - r31. r0 must be zero.
 816    r: [32]Gpr,
 817    pc: Gpr,
 818
 819    pub const Gpr = if (native_arch.isMIPS64()) u64 else u32;
 820
 821    pub inline fn current() Mips {
 822        var ctx: Mips = undefined;
 823        asm volatile (if (Gpr == u64)
 824                \\ .set push
 825                \\ .set noat
 826                \\ .set noreorder
 827                \\ .set nomacro
 828                \\ sd $zero, 0($t0)
 829                \\ sd $at, 8($t0)
 830                \\ sd $v0, 16($t0)
 831                \\ sd $v1, 24($t0)
 832                \\ sd $a0, 32($t0)
 833                \\ sd $a1, 40($t0)
 834                \\ sd $a2, 48($t0)
 835                \\ sd $a3, 56($t0)
 836                \\ sd $a4, 64($t0)
 837                \\ sd $a5, 72($t0)
 838                \\ sd $a6, 80($t0)
 839                \\ sd $a7, 88($t0)
 840                \\ sd $t0, 96($t0)
 841                \\ sd $t1, 104($t0)
 842                \\ sd $t2, 112($t0)
 843                \\ sd $t3, 120($t0)
 844                \\ sd $s0, 128($t0)
 845                \\ sd $s1, 136($t0)
 846                \\ sd $s2, 144($t0)
 847                \\ sd $s3, 152($t0)
 848                \\ sd $s4, 160($t0)
 849                \\ sd $s5, 168($t0)
 850                \\ sd $s6, 176($t0)
 851                \\ sd $s7, 184($t0)
 852                \\ sd $t8, 192($t0)
 853                \\ sd $t9, 200($t0)
 854                \\ sd $k0, 208($t0)
 855                \\ sd $k1, 216($t0)
 856                \\ sd $gp, 224($t0)
 857                \\ sd $sp, 232($t0)
 858                \\ sd $fp, 240($t0)
 859                \\ sd $ra, 248($t0)
 860                \\ bal 1f
 861                \\1:
 862                \\ sd $ra, 256($t0)
 863                \\ .set pop
 864            else
 865                \\ .set push
 866                \\ .set noat
 867                \\ .set noreorder
 868                \\ .set nomacro
 869                \\ sw $zero, 0($t4)
 870                \\ sw $at, 4($t4)
 871                \\ sw $v0, 8($t4)
 872                \\ sw $v1, 12($t4)
 873                \\ sw $a0, 16($t4)
 874                \\ sw $a1, 20($t4)
 875                \\ sw $a2, 24($t4)
 876                \\ sw $a3, 28($t4)
 877                \\ sw $t0, 32($t4)
 878                \\ sw $t1, 36($t4)
 879                \\ sw $t2, 40($t4)
 880                \\ sw $t3, 44($t4)
 881                \\ sw $t4, 48($t4)
 882                \\ sw $t5, 52($t4)
 883                \\ sw $t6, 56($t4)
 884                \\ sw $t7, 60($t4)
 885                \\ sw $s0, 64($t4)
 886                \\ sw $s1, 68($t4)
 887                \\ sw $s2, 72($t4)
 888                \\ sw $s3, 76($t4)
 889                \\ sw $s4, 80($t4)
 890                \\ sw $s5, 84($t4)
 891                \\ sw $s6, 88($t4)
 892                \\ sw $s7, 92($t4)
 893                \\ sw $t8, 96($t4)
 894                \\ sw $t9, 100($t4)
 895                \\ sw $k0, 104($t4)
 896                \\ sw $k1, 108($t4)
 897                \\ sw $gp, 112($t4)
 898                \\ sw $sp, 116($t4)
 899                \\ sw $fp, 120($t4)
 900                \\ sw $ra, 124($t4)
 901                \\ bal 1f
 902                \\1:
 903                \\ sw $ra, 128($t4)
 904                \\ .set pop
 905            :
 906            : [ctx] "{$12}" (&ctx),
 907            : .{ .r31 = true, .memory = true });
 908        return ctx;
 909    }
 910
 911    pub fn getFp(ctx: *const Mips) usize {
 912        // On N32, `Gpr` is 64 bits but `usize` is 32 bits.
 913        return @intCast(ctx.r[30]);
 914    }
 915    pub fn getPc(ctx: *const Mips) usize {
 916        // On N32, `Gpr` is 64 bits but `usize` is 32 bits.
 917        return @intCast(ctx.pc);
 918    }
 919
 920    pub fn dwarfRegisterBytes(ctx: *Mips, register_num: u16) DwarfRegisterError![]u8 {
 921        switch (register_num) {
 922            0...31 => return @ptrCast(&ctx.r[register_num]),
 923            66 => return @ptrCast(&ctx.pc),
 924
 925            // Who the hell knows what numbers exist for this architecture? What's an ABI
 926            // specification anyway? We don't need that nonsense.
 927            32...63 => return error.UnsupportedRegister, // f0 - f31, w0 - w31
 928            64 => return error.UnsupportedRegister, // hi0 (ac0)
 929            65 => return error.UnsupportedRegister, // lo0 (ac0)
 930            176 => return error.UnsupportedRegister, // hi1 (ac1)
 931            177 => return error.UnsupportedRegister, // lo1 (ac1)
 932            178 => return error.UnsupportedRegister, // hi2 (ac2)
 933            179 => return error.UnsupportedRegister, // lo2 (ac2)
 934            180 => return error.UnsupportedRegister, // hi3 (ac3)
 935            181 => return error.UnsupportedRegister, // lo3 (ac3)
 936
 937            else => return error.InvalidRegister,
 938        }
 939    }
 940};
 941
 942/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
 943const Or1k = extern struct {
 944    /// The numbered general-purpose registers r0 - r31.
 945    r: [32]u32,
 946    pc: u32,
 947
 948    pub inline fn current() Or1k {
 949        var ctx: Or1k = undefined;
 950        asm volatile (
 951            \\ l.sw 0(r15), r0
 952            \\ l.sw 4(r15), r1
 953            \\ l.sw 8(r15), r2
 954            \\ l.sw 12(r15), r3
 955            \\ l.sw 16(r15), r4
 956            \\ l.sw 20(r15), r5
 957            \\ l.sw 24(r15), r6
 958            \\ l.sw 28(r15), r7
 959            \\ l.sw 32(r15), r8
 960            \\ l.sw 36(r15), r9
 961            \\ l.sw 40(r15), r10
 962            \\ l.sw 44(r15), r11
 963            \\ l.sw 48(r15), r12
 964            \\ l.sw 52(r15), r13
 965            \\ l.sw 56(r15), r14
 966            \\ l.sw 60(r15), r15
 967            \\ l.sw 64(r15), r16
 968            \\ l.sw 68(r15), r17
 969            \\ l.sw 72(r15), r18
 970            \\ l.sw 76(r15), r19
 971            \\ l.sw 80(r15), r20
 972            \\ l.sw 84(r15), r21
 973            \\ l.sw 88(r15), r22
 974            \\ l.sw 92(r15), r23
 975            \\ l.sw 96(r15), r24
 976            \\ l.sw 100(r15), r25
 977            \\ l.sw 104(r15), r26
 978            \\ l.sw 108(r15), r27
 979            \\ l.sw 112(r15), r28
 980            \\ l.sw 116(r15), r29
 981            \\ l.sw 120(r15), r30
 982            \\ l.sw 124(r15), r31
 983            \\ l.jal 1f
 984            \\1:
 985            \\ l.sw 128(r15), r9
 986            :
 987            : [ctx] "{r15}" (&ctx),
 988            : .{ .r9 = true, .memory = true });
 989        return ctx;
 990    }
 991
 992    pub fn getFp(ctx: *const Or1k) u32 {
 993        return ctx.r[2];
 994    }
 995    pub fn getPc(ctx: *const Or1k) u32 {
 996        return ctx.pc;
 997    }
 998
 999    pub fn dwarfRegisterBytes(ctx: *Or1k, register_num: u16) DwarfRegisterError![]u8 {
1000        switch (register_num) {
1001            0...31 => return @ptrCast(&ctx.r[register_num]),
1002            35 => return @ptrCast(&ctx.pc),
1003
1004            else => return error.InvalidRegister,
1005        }
1006    }
1007};
1008
1009/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
1010const Powerpc = extern struct {
1011    /// The numbered general-purpose registers r0 - r31.
1012    r: [32]Gpr,
1013    pc: Gpr,
1014    lr: Gpr,
1015
1016    pub const Gpr = if (native_arch.isPowerPC64()) u64 else u32;
1017
1018    pub inline fn current() Powerpc {
1019        var ctx: Powerpc = undefined;
1020        asm volatile (if (Gpr == u64)
1021                \\ std 0, 0(10)
1022                \\ std 1, 8(10)
1023                \\ std 2, 16(10)
1024                \\ std 3, 24(10)
1025                \\ std 4, 32(10)
1026                \\ std 5, 40(10)
1027                \\ std 6, 48(10)
1028                \\ std 7, 56(10)
1029                \\ std 8, 64(10)
1030                \\ std 9, 72(10)
1031                \\ std 10, 80(10)
1032                \\ std 11, 88(10)
1033                \\ std 12, 96(10)
1034                \\ std 13, 104(10)
1035                \\ std 14, 112(10)
1036                \\ std 15, 120(10)
1037                \\ std 16, 128(10)
1038                \\ std 17, 136(10)
1039                \\ std 18, 144(10)
1040                \\ std 19, 152(10)
1041                \\ std 20, 160(10)
1042                \\ std 21, 168(10)
1043                \\ std 22, 176(10)
1044                \\ std 23, 184(10)
1045                \\ std 24, 192(10)
1046                \\ std 25, 200(10)
1047                \\ std 26, 208(10)
1048                \\ std 27, 216(10)
1049                \\ std 28, 224(10)
1050                \\ std 29, 232(10)
1051                \\ std 30, 240(10)
1052                \\ std 31, 248(10)
1053                \\ mflr 8
1054                \\ std 8, 264(10)
1055                \\ bl 1f
1056                \\1:
1057                \\ mflr 8
1058                \\ std 8, 256(10)
1059            else
1060                \\ stw 0, 0(10)
1061                \\ stw 1, 4(10)
1062                \\ stw 2, 8(10)
1063                \\ stw 3, 12(10)
1064                \\ stw 4, 16(10)
1065                \\ stw 5, 20(10)
1066                \\ stw 6, 24(10)
1067                \\ stw 7, 28(10)
1068                \\ stw 8, 32(10)
1069                \\ stw 9, 36(10)
1070                \\ stw 10, 40(10)
1071                \\ stw 11, 44(10)
1072                \\ stw 12, 48(10)
1073                \\ stw 13, 52(10)
1074                \\ stw 14, 56(10)
1075                \\ stw 15, 60(10)
1076                \\ stw 16, 64(10)
1077                \\ stw 17, 68(10)
1078                \\ stw 18, 72(10)
1079                \\ stw 19, 76(10)
1080                \\ stw 20, 80(10)
1081                \\ stw 21, 84(10)
1082                \\ stw 22, 88(10)
1083                \\ stw 23, 92(10)
1084                \\ stw 24, 96(10)
1085                \\ stw 25, 100(10)
1086                \\ stw 26, 104(10)
1087                \\ stw 27, 108(10)
1088                \\ stw 28, 112(10)
1089                \\ stw 29, 116(10)
1090                \\ stw 30, 120(10)
1091                \\ stw 31, 124(10)
1092                \\ mflr 8
1093                \\ stw 8, 132(10)
1094                \\ bl 1f
1095                \\1:
1096                \\ mflr 8
1097                \\ stw 8, 128(10)
1098            :
1099            : [ctx] "{r10}" (&ctx),
1100            : .{ .r8 = true, .lr = true, .memory = true });
1101        return ctx;
1102    }
1103
1104    pub fn getFp(ctx: *const Powerpc) Gpr {
1105        return ctx.r[1];
1106    }
1107    pub fn getPc(ctx: *const Powerpc) Gpr {
1108        return ctx.pc;
1109    }
1110
1111    pub fn dwarfRegisterBytes(ctx: *Powerpc, register_num: u16) DwarfRegisterError![]u8 {
1112        // References:
1113        //
1114        // * System V Application Binary Interface - PowerPC Processor Supplement §3-46
1115        // * Power Architecture 32-bit Application Binary Interface Supplement 1.0 - Linux & Embedded §3.4
1116        // * 64-bit ELF V2 ABI Specification - Power Architecture Revision 1.5 §2.4
1117        //
1118        // Are we having fun yet?
1119
1120        if (Gpr == u64) switch (register_num) {
1121            65 => return @ptrCast(&ctx.lr), // lr
1122
1123            66 => return error.UnsupportedRegister, // ctr
1124            68...75 => return error.UnsupportedRegister, // cr0 - cr7
1125            76 => return error.UnsupportedRegister, // xer
1126            77...108 => return error.UnsupportedRegister, // vr0 - vr31
1127            109 => return error.UnsupportedRegister, // vrsave (LLVM)
1128            110 => return error.UnsupportedRegister, // vscr
1129            114 => return error.UnsupportedRegister, // tfhar
1130            115 => return error.UnsupportedRegister, // tfiar
1131            116 => return error.UnsupportedRegister, // texasr
1132
1133            else => {},
1134        } else switch (register_num) {
1135            65 => return @ptrCast(&ctx.lr), // fpscr (SVR4 / EABI), or lr if you ask LLVM
1136            108 => return @ptrCast(&ctx.lr),
1137
1138            64 => return error.UnsupportedRegister, // cr
1139            66 => return error.UnsupportedRegister, // msr (SVR4 / EABI), or ctr if you ask LLVM
1140            68...75 => return error.UnsupportedRegister, // cr0 - cr7 if you ask LLVM
1141            76 => return error.UnsupportedRegister, // xer if you ask LLVM
1142            99 => return error.UnsupportedRegister, // acc
1143            100 => return error.UnsupportedRegister, // mq
1144            101 => return error.UnsupportedRegister, // xer
1145            102...107 => return error.UnsupportedRegister, // SPRs
1146            109 => return error.UnsupportedRegister, // ctr
1147            110...111 => return error.UnsupportedRegister, // SPRs
1148            112 => return error.UnsupportedRegister, // spefscr
1149            113...1123 => return error.UnsupportedRegister, // SPRs
1150            1124...1155 => return error.UnsupportedRegister, // SPE v0 - v31
1151            1200...1231 => return error.UnsupportedRegister, // SPE upper r0 - r31
1152            3072...4095 => return error.UnsupportedRegister, // DCRs
1153            4096...5120 => return error.UnsupportedRegister, // PMRs
1154
1155            else => {},
1156        }
1157
1158        switch (register_num) {
1159            0...31 => return @ptrCast(&ctx.r[register_num]),
1160            67 => return @ptrCast(&ctx.pc),
1161
1162            32...63 => return error.UnsupportedRegister, // f0 - f31
1163
1164            else => return error.InvalidRegister,
1165        }
1166    }
1167};
1168
1169/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
1170const Riscv = extern struct {
1171    /// The numbered general-purpose registers r0 - r31. r0 must be zero.
1172    x: [32]Gpr,
1173    pc: Gpr,
1174
1175    pub const Gpr = if (native_arch.isRiscv64()) u64 else u32;
1176
1177    pub inline fn current() Riscv {
1178        var ctx: Riscv = undefined;
1179        asm volatile (if (Gpr == u64)
1180                \\ sd zero, 0(t0)
1181                \\ sd ra, 8(t0)
1182                \\ sd sp, 16(t0)
1183                \\ sd gp, 24(t0)
1184                \\ sd tp, 32(t0)
1185                \\ sd t0, 40(t0)
1186                \\ sd t1, 48(t0)
1187                \\ sd t2, 56(t0)
1188                \\ sd s0, 64(t0)
1189                \\ sd s1, 72(t0)
1190                \\ sd a0, 80(t0)
1191                \\ sd a1, 88(t0)
1192                \\ sd a2, 96(t0)
1193                \\ sd a3, 104(t0)
1194                \\ sd a4, 112(t0)
1195                \\ sd a5, 120(t0)
1196                \\ sd a6, 128(t0)
1197                \\ sd a7, 136(t0)
1198                \\ sd s2, 144(t0)
1199                \\ sd s3, 152(t0)
1200                \\ sd s4, 160(t0)
1201                \\ sd s5, 168(t0)
1202                \\ sd s6, 176(t0)
1203                \\ sd s7, 184(t0)
1204                \\ sd s8, 192(t0)
1205                \\ sd s9, 200(t0)
1206                \\ sd s10, 208(t0)
1207                \\ sd s11, 216(t0)
1208                \\ sd t3, 224(t0)
1209                \\ sd t4, 232(t0)
1210                \\ sd t5, 240(t0)
1211                \\ sd t6, 248(t0)
1212                \\ jal ra, 1f
1213                \\1:
1214                \\ sd ra, 256(t0)
1215            else
1216                \\ sw zero, 0(t0)
1217                \\ sw ra, 4(t0)
1218                \\ sw sp, 8(t0)
1219                \\ sw gp, 12(t0)
1220                \\ sw tp, 16(t0)
1221                \\ sw t0, 20(t0)
1222                \\ sw t1, 24(t0)
1223                \\ sw t2, 28(t0)
1224                \\ sw s0, 32(t0)
1225                \\ sw s1, 36(t0)
1226                \\ sw a0, 40(t0)
1227                \\ sw a1, 44(t0)
1228                \\ sw a2, 48(t0)
1229                \\ sw a3, 52(t0)
1230                \\ sw a4, 56(t0)
1231                \\ sw a5, 60(t0)
1232                \\ sw a6, 64(t0)
1233                \\ sw a7, 68(t0)
1234                \\ sw s2, 72(t0)
1235                \\ sw s3, 76(t0)
1236                \\ sw s4, 80(t0)
1237                \\ sw s5, 84(t0)
1238                \\ sw s6, 88(t0)
1239                \\ sw s7, 92(t0)
1240                \\ sw s8, 96(t0)
1241                \\ sw s9, 100(t0)
1242                \\ sw s10, 104(t0)
1243                \\ sw s11, 108(t0)
1244                \\ sw t3, 112(t0)
1245                \\ sw t4, 116(t0)
1246                \\ sw t5, 120(t0)
1247                \\ sw t6, 124(t0)
1248                \\ jal ra, 1f
1249                \\1:
1250                \\ sw ra, 128(t0)
1251            :
1252            : [ctx] "{t0}" (&ctx),
1253            : .{ .x1 = true, .memory = true });
1254        return ctx;
1255    }
1256
1257    pub fn getFp(ctx: *const Riscv) Gpr {
1258        return ctx.x[8];
1259    }
1260    pub fn getPc(ctx: *const Riscv) Gpr {
1261        return ctx.pc;
1262    }
1263
1264    pub fn dwarfRegisterBytes(ctx: *Riscv, register_num: u16) DwarfRegisterError![]u8 {
1265        switch (register_num) {
1266            0...31 => return @ptrCast(&ctx.x[register_num]),
1267            65 => return @ptrCast(&ctx.pc),
1268
1269            32...63 => return error.UnsupportedRegister, // f0 - f31
1270            64 => return error.UnsupportedRegister, // Alternate Frame Return Column
1271            96...127 => return error.UnsupportedRegister, // v0 - v31
1272            3072...4095 => return error.UnsupportedRegister, // Custom extensions
1273            4096...8191 => return error.UnsupportedRegister, // CSRs
1274
1275            else => return error.InvalidRegister,
1276        }
1277    }
1278};
1279
1280/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
1281const S390x = extern struct {
1282    /// The numbered general-purpose registers r0 - r15.
1283    r: [16]u64,
1284    /// The program counter.
1285    psw: extern struct {
1286        mask: u64,
1287        addr: u64,
1288    },
1289
1290    pub inline fn current() S390x {
1291        var ctx: S390x = undefined;
1292        asm volatile (
1293            \\ stmg %%r0, %%r15, 0(%%r2)
1294            \\ epsw %%r0, %%r1
1295            \\ stm %%r0, %%r1, 128(%%r2)
1296            \\ larl %%r0, .
1297            \\ stg %%r0, 136(%%r2)
1298            :
1299            : [ctx] "{r2}" (&ctx),
1300            : .{ .r0 = true, .r1 = true, .memory = true });
1301        return ctx;
1302    }
1303
1304    pub fn getFp(ctx: *const S390x) u64 {
1305        return ctx.r[11];
1306    }
1307    pub fn getPc(ctx: *const S390x) u64 {
1308        return ctx.psw.addr;
1309    }
1310
1311    pub fn dwarfRegisterBytes(ctx: *S390x, register_num: u16) DwarfRegisterError![]u8 {
1312        switch (register_num) {
1313            0...15 => return @ptrCast(&ctx.r[register_num]),
1314            64 => return @ptrCast(&ctx.psw.mask),
1315            65 => return @ptrCast(&ctx.psw.addr),
1316
1317            16...31 => return error.UnsupportedRegister, // f0 - f15
1318            32...47 => return error.UnsupportedRegister, // cr0 - cr15
1319            48...63 => return error.UnsupportedRegister, // a0 - a15
1320            66...67 => return error.UnsupportedRegister, // z/OS stuff???
1321            68...83 => return error.UnsupportedRegister, // v16 - v31
1322
1323            else => return error.InvalidRegister,
1324        }
1325    }
1326};
1327
1328/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
1329const Sparc = extern struct {
1330    g: [8]Gpr,
1331    o: [8]Gpr,
1332    l: [8]Gpr,
1333    i: [8]Gpr,
1334    pc: Gpr,
1335
1336    pub const Gpr = if (native_arch == .sparc64) u64 else u32;
1337
1338    pub inline fn current() Sparc {
1339        flushWindows();
1340
1341        var ctx: Sparc = undefined;
1342        asm volatile (if (Gpr == u64)
1343                \\ stx %g0, [%l0 + 0]
1344                \\ stx %g1, [%l0 + 8]
1345                \\ stx %g2, [%l0 + 16]
1346                \\ stx %g3, [%l0 + 24]
1347                \\ stx %g4, [%l0 + 32]
1348                \\ stx %g5, [%l0 + 40]
1349                \\ stx %g6, [%l0 + 48]
1350                \\ stx %g7, [%l0 + 56]
1351                \\ stx %o0, [%l0 + 64]
1352                \\ stx %o1, [%l0 + 72]
1353                \\ stx %o2, [%l0 + 80]
1354                \\ stx %o3, [%l0 + 88]
1355                \\ stx %o4, [%l0 + 96]
1356                \\ stx %o5, [%l0 + 104]
1357                \\ stx %o6, [%l0 + 112]
1358                \\ stx %o7, [%l0 + 120]
1359                \\ stx %l0, [%l0 + 128]
1360                \\ stx %l1, [%l0 + 136]
1361                \\ stx %l2, [%l0 + 144]
1362                \\ stx %l3, [%l0 + 152]
1363                \\ stx %l4, [%l0 + 160]
1364                \\ stx %l5, [%l0 + 168]
1365                \\ stx %l6, [%l0 + 176]
1366                \\ stx %l7, [%l0 + 184]
1367                \\ stx %i0, [%l0 + 192]
1368                \\ stx %i1, [%l0 + 200]
1369                \\ stx %i2, [%l0 + 208]
1370                \\ stx %i3, [%l0 + 216]
1371                \\ stx %i4, [%l0 + 224]
1372                \\ stx %i5, [%l0 + 232]
1373                \\ stx %i6, [%l0 + 240]
1374                \\ stx %i7, [%l0 + 248]
1375                \\ call 1f
1376                \\1:
1377                \\ stx %o7, [%l0 + 256]
1378            else
1379                \\ std %g0, [%l0 + 0]
1380                \\ std %g2, [%l0 + 8]
1381                \\ std %g4, [%l0 + 16]
1382                \\ std %g6, [%l0 + 24]
1383                \\ std %o0, [%l0 + 32]
1384                \\ std %o2, [%l0 + 40]
1385                \\ std %o4, [%l0 + 48]
1386                \\ std %o6, [%l0 + 56]
1387                \\ std %l0, [%l0 + 64]
1388                \\ std %l2, [%l0 + 72]
1389                \\ std %l4, [%l0 + 80]
1390                \\ std %l6, [%l0 + 88]
1391                \\ std %i0, [%l0 + 96]
1392                \\ std %i2, [%l0 + 104]
1393                \\ std %i4, [%l0 + 112]
1394                \\ std %i6, [%l0 + 120]
1395                \\ call 1f
1396                \\1:
1397                \\ st %o7, [%l0 + 128]
1398            :
1399            : [ctx] "{l0}" (&ctx),
1400            : .{ .o7 = true, .memory = true });
1401        return ctx;
1402    }
1403
1404    noinline fn flushWindows() void {
1405        // Flush all register windows except the current one (hence `noinline`). This ensures that
1406        // we actually see meaningful data on the stack when we walk the frame chain.
1407        if (comptime builtin.target.cpu.has(.sparc, .v9))
1408            asm volatile ("flushw" ::: .{ .memory = true })
1409        else
1410            asm volatile ("ta 3" ::: .{ .memory = true }); // ST_FLUSH_WINDOWS
1411    }
1412
1413    pub fn getFp(ctx: *const Sparc) Gpr {
1414        return ctx.i[6];
1415    }
1416    pub fn getPc(ctx: *const Sparc) Gpr {
1417        return ctx.pc;
1418    }
1419
1420    pub fn dwarfRegisterBytes(ctx: *Sparc, register_num: u16) DwarfRegisterError![]u8 {
1421        switch (register_num) {
1422            0...7 => return @ptrCast(&ctx.g[register_num]),
1423            8...15 => return @ptrCast(&ctx.o[register_num - 8]),
1424            16...23 => return @ptrCast(&ctx.l[register_num - 16]),
1425            24...31 => return @ptrCast(&ctx.i[register_num - 24]),
1426            32 => return @ptrCast(&ctx.pc),
1427
1428            else => return error.InvalidRegister,
1429        }
1430    }
1431};
1432
1433/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
1434const Ve = extern struct {
1435    s: [64]u64,
1436    ic: u64,
1437
1438    pub inline fn current() Ve {
1439        var ctx: Ve = undefined;
1440        asm volatile (
1441            \\ st %%s0, 0(, %%s8)
1442            \\ st %%s1, 8(, %%s8)
1443            \\ st %%s2, 16(, %%s8)
1444            \\ st %%s3, 24(, %%s8)
1445            \\ st %%s4, 32(, %%s8)
1446            \\ st %%s5, 40(, %%s8)
1447            \\ st %%s6, 48(, %%s8)
1448            \\ st %%s7, 56(, %%s8)
1449            \\ st %%s8, 64(, %%s8)
1450            \\ st %%s9, 72(, %%s8)
1451            \\ st %%s10, 80(, %%s8)
1452            \\ st %%s11, 88(, %%s8)
1453            \\ st %%s12, 96(, %%s8)
1454            \\ st %%s13, 104(, %%s8)
1455            \\ st %%s14, 112(, %%s8)
1456            \\ st %%s15, 120(, %%s8)
1457            \\ st %%s16, 128(, %%s8)
1458            \\ st %%s17, 136(, %%s8)
1459            \\ st %%s18, 144(, %%s8)
1460            \\ st %%s19, 152(, %%s8)
1461            \\ st %%s20, 160(, %%s8)
1462            \\ st %%s21, 168(, %%s8)
1463            \\ st %%s22, 176(, %%s8)
1464            \\ st %%s23, 184(, %%s8)
1465            \\ st %%s24, 192(, %%s8)
1466            \\ st %%s25, 200(, %%s8)
1467            \\ st %%s26, 208(, %%s8)
1468            \\ st %%s27, 216(, %%s8)
1469            \\ st %%s28, 224(, %%s8)
1470            \\ st %%s29, 232(, %%s8)
1471            \\ st %%s30, 240(, %%s8)
1472            \\ st %%s31, 248(, %%s8)
1473            \\ st %%s32, 256(, %%s8)
1474            \\ st %%s33, 264(, %%s8)
1475            \\ st %%s34, 272(, %%s8)
1476            \\ st %%s35, 280(, %%s8)
1477            \\ st %%s36, 288(, %%s8)
1478            \\ st %%s37, 296(, %%s8)
1479            \\ st %%s38, 304(, %%s8)
1480            \\ st %%s39, 312(, %%s8)
1481            \\ st %%s40, 320(, %%s8)
1482            \\ st %%s41, 328(, %%s8)
1483            \\ st %%s42, 336(, %%s8)
1484            \\ st %%s43, 344(, %%s8)
1485            \\ st %%s44, 352(, %%s8)
1486            \\ st %%s45, 360(, %%s8)
1487            \\ st %%s46, 368(, %%s8)
1488            \\ st %%s47, 376(, %%s8)
1489            \\ st %%s48, 384(, %%s8)
1490            \\ st %%s49, 392(, %%s8)
1491            \\ st %%s50, 400(, %%s8)
1492            \\ st %%s51, 408(, %%s8)
1493            \\ st %%s52, 416(, %%s8)
1494            \\ st %%s53, 424(, %%s8)
1495            \\ st %%s54, 432(, %%s8)
1496            \\ st %%s55, 440(, %%s8)
1497            \\ st %%s56, 448(, %%s8)
1498            \\ st %%s57, 456(, %%s8)
1499            \\ st %%s58, 464(, %%s8)
1500            \\ st %%s59, 472(, %%s8)
1501            \\ st %%s60, 480(, %%s8)
1502            \\ st %%s61, 488(, %%s8)
1503            \\ st %%s62, 496(, %%s8)
1504            \\ st %%s63, 504(, %%s8)
1505            \\ br.l 1f
1506            \\1:
1507            \\ st %%lr, 512(, %%s8)
1508            :
1509            : [ctx] "{s8}" (&ctx),
1510            : .{ .s10 = true, .memory = true });
1511        return ctx;
1512    }
1513
1514    pub fn getFp(ctx: *const Ve) u64 {
1515        return ctx.s[9];
1516    }
1517    pub fn getPc(ctx: *const Ve) u64 {
1518        return ctx.ic;
1519    }
1520
1521    pub fn dwarfRegisterBytes(ctx: *Ve, register_num: u16) DwarfRegisterError![]u8 {
1522        switch (register_num) {
1523            0...63 => return @ptrCast(&ctx.s[register_num]),
1524            144 => return @ptrCast(&ctx.ic),
1525
1526            64...127 => return error.UnsupportedRegister, // v0 - v63
1527            128...143 => return error.UnsupportedRegister, // vm0 - vm15
1528
1529            else => return error.InvalidRegister,
1530        }
1531    }
1532};
1533
1534const X86_16 = struct {
1535    pub const Register = enum {
1536        // zig fmt: off
1537        sp, bp, ss,
1538        ip, cs,
1539        // zig fmt: on
1540    };
1541
1542    regs: std.enums.EnumArray(Register, u16),
1543
1544    pub inline fn current() X86_16 {
1545        var ctx: X86_16 = undefined;
1546        asm volatile (
1547            \\ movw %%sp, 0x00(%%di)
1548            \\ movw %%bp, 0x02(%%di)
1549            \\ movw %%ss, 0x04(%%di)
1550            \\ pushw %%cs
1551            \\ call 1f
1552            \\1:
1553            \\ popw 0x06(%%di)
1554            \\ popw 0x08(%%di)
1555            :
1556            : [gprs] "{di}" (&ctx.regs.values),
1557            : .{ .memory = true });
1558        return ctx;
1559    }
1560
1561    pub fn getFp(ctx: *const X86_16) u16 {
1562        return ctx.regs.get(.bp);
1563    }
1564    pub fn getPc(ctx: *const X86_16) u16 {
1565        return ctx.regs.get(.ip);
1566    }
1567
1568    // NOTE: There doesn't seem to be any standard for DWARF x86-16 so we'll just reuse the ones for x86.
1569    pub fn dwarfRegisterBytes(ctx: *X86_16, register_num: u16) DwarfRegisterError![]u8 {
1570        switch (register_num) {
1571            4 => return @ptrCast(ctx.regs.getPtr(.sp)),
1572            5 => return @ptrCast(ctx.regs.getPtr(.bp)),
1573            6 => return @ptrCast(ctx.regs.getPtr(.ip)),
1574            41 => return @ptrCast(ctx.regs.getPtr(.cs)),
1575            42 => return @ptrCast(ctx.regs.getPtr(.ss)),
1576            else => return error.InvalidRegister,
1577        }
1578    }
1579};
1580
1581const X86 = struct {
1582    /// The first 8 registers here intentionally match the order of registers in the x86 instruction
1583    /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings,
1584    /// among other things.
1585    pub const Gpr = enum {
1586        // zig fmt: off
1587        eax, ecx, edx, ebx,
1588        esp, ebp, esi, edi,
1589        eip,
1590        // zig fmt: on
1591    };
1592    gprs: std.enums.EnumArray(Gpr, u32),
1593
1594    pub inline fn current() X86 {
1595        var ctx: X86 = undefined;
1596        asm volatile (
1597            \\ movl %%eax, 0x00(%%edi)
1598            \\ movl %%ecx, 0x04(%%edi)
1599            \\ movl %%edx, 0x08(%%edi)
1600            \\ movl %%ebx, 0x0c(%%edi)
1601            \\ movl %%esp, 0x10(%%edi)
1602            \\ movl %%ebp, 0x14(%%edi)
1603            \\ movl %%esi, 0x18(%%edi)
1604            \\ movl %%edi, 0x1c(%%edi)
1605            \\ call 1f
1606            \\1:
1607            \\ popl 0x20(%%edi)
1608            :
1609            : [gprs] "{edi}" (&ctx.gprs.values),
1610            : .{ .memory = true });
1611        return ctx;
1612    }
1613
1614    pub fn getFp(ctx: *const X86) u32 {
1615        return ctx.gprs.get(.ebp);
1616    }
1617    pub fn getPc(ctx: *const X86) u32 {
1618        return ctx.gprs.get(.eip);
1619    }
1620
1621    pub fn dwarfRegisterBytes(ctx: *X86, register_num: u16) DwarfRegisterError![]u8 {
1622        // System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.1
1623        //   § 2.4.2 "DWARF Register Number Mapping"
1624        switch (register_num) {
1625            // The order of `Gpr` intentionally matches DWARF's mappings.
1626            //
1627            // x86-macos sometimes uses different mappings (ebp and esp are reversed when the unwind
1628            // information is from `__eh_frame`). This deviation is not considered here, because
1629            // x86-macos is a deprecated target which is not supported by the Zig Standard Library.
1630            0...8 => return @ptrCast(&ctx.gprs.values[register_num]),
1631
1632            9 => return error.UnsupportedRegister, // eflags
1633            11...18 => return error.UnsupportedRegister, // st0 - st7
1634            21...28 => return error.UnsupportedRegister, // xmm0 - xmm7
1635            29...36 => return error.UnsupportedRegister, // mm0 - mm7
1636            39 => return error.UnsupportedRegister, // mxcsr
1637            40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
1638            48 => return error.UnsupportedRegister, // tr
1639            49 => return error.UnsupportedRegister, // ldtr
1640            93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
1641
1642            else => return error.InvalidRegister,
1643        }
1644    }
1645};
1646
1647const X86_64 = struct {
1648    /// The order here intentionally matches the order of the DWARF register mappings. It's unclear
1649    /// where those mappings actually originated from---the ordering of the first 4 registers seems
1650    /// quite unusual---but it is currently convenient for us to match DWARF.
1651    pub const Gpr = enum {
1652        // zig fmt: off
1653        rax, rdx, rcx, rbx,
1654        rsi, rdi, rbp, rsp,
1655        r8,  r9,  r10, r11,
1656        r12, r13, r14, r15,
1657        rip,
1658        // zig fmt: on
1659    };
1660    gprs: std.enums.EnumArray(Gpr, u64),
1661
1662    pub inline fn current() X86_64 {
1663        var ctx: X86_64 = undefined;
1664        asm volatile (
1665            \\ movq %%rax, 0x00(%%rdi)
1666            \\ movq %%rdx, 0x08(%%rdi)
1667            \\ movq %%rcx, 0x10(%%rdi)
1668            \\ movq %%rbx, 0x18(%%rdi)
1669            \\ movq %%rsi, 0x20(%%rdi)
1670            \\ movq %%rdi, 0x28(%%rdi)
1671            \\ movq %%rbp, 0x30(%%rdi)
1672            \\ movq %%rsp, 0x38(%%rdi)
1673            \\ movq %%r8,  0x40(%%rdi)
1674            \\ movq %%r9,  0x48(%%rdi)
1675            \\ movq %%r10, 0x50(%%rdi)
1676            \\ movq %%r11, 0x58(%%rdi)
1677            \\ movq %%r12, 0x60(%%rdi)
1678            \\ movq %%r13, 0x68(%%rdi)
1679            \\ movq %%r14, 0x70(%%rdi)
1680            \\ movq %%r15, 0x78(%%rdi)
1681            \\ leaq (%%rip), %%rax
1682            \\ movq %%rax, 0x80(%%rdi)
1683            :
1684            : [gprs] "{rdi}" (&ctx.gprs.values),
1685            : .{ .rax = true, .memory = true });
1686        return ctx;
1687    }
1688
1689    pub fn getFp(ctx: *const X86_64) usize {
1690        // On x32, registers are 64 bits but `usize` is 32 bits.
1691        return @intCast(ctx.gprs.get(.rbp));
1692    }
1693    pub fn getPc(ctx: *const X86_64) usize {
1694        // On x32, registers are 64 bits but `usize` is 32 bits.
1695        return @intCast(ctx.gprs.get(.rip));
1696    }
1697
1698    pub fn dwarfRegisterBytes(ctx: *X86_64, register_num: u16) DwarfRegisterError![]u8 {
1699        // System V Application Binary Interface AMD64 Architecture Processor Supplement
1700        //   § 3.6.2 "DWARF Register Number Mapping"
1701        switch (register_num) {
1702            // The order of `Gpr` intentionally matches DWARF's mappings.
1703            0...16 => return @ptrCast(&ctx.gprs.values[register_num]),
1704
1705            17...32 => return error.UnsupportedRegister, // xmm0 - xmm15
1706            33...40 => return error.UnsupportedRegister, // st0 - st7
1707            41...48 => return error.UnsupportedRegister, // mm0 - mm7
1708            49 => return error.UnsupportedRegister, // rflags
1709            50...55 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
1710            58...59 => return error.UnsupportedRegister, // fs.base, gs.base
1711            62 => return error.UnsupportedRegister, // tr
1712            63 => return error.UnsupportedRegister, // ldtr
1713            64 => return error.UnsupportedRegister, // mxcsr
1714            65 => return error.UnsupportedRegister, // fcw
1715            66 => return error.UnsupportedRegister, // fsw
1716            67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512)
1717            118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
1718            130...145 => return error.UnsupportedRegister, // r16 - r31 (APX)
1719
1720            else => return error.InvalidRegister,
1721        }
1722    }
1723};
1724
1725/// The native operating system's `ucontext_t` as seen in the third argument to signal handlers.
1726///
1727/// These are dramatically simplified since we only need general-purpose registers and don't care
1728/// about all the complicated extension state (floating point, vector, etc). This means that these
1729/// structures are almost all shorter than the real ones, which is safe because we only access them
1730/// through a pointer.
1731///
1732/// Some effort is made to have structures for the same architecture use the same access pattern,
1733/// e.g. `uc.mcontext.x` for `aarch64-linux` and `aarch64-freebsd` even though that's not quite how
1734/// they're declared and spelled in the C headers for both targets. Similarly, registers are typed
1735/// as unsigned everywhere even if that's not how they're declared in the C headers.
1736const signal_ucontext_t = switch (native_os) {
1737    .linux => switch (native_arch) {
1738        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/alpha/include/asm/ucontext.h
1739        .alpha => extern struct {
1740            _flags: u64,
1741            _link: ?*signal_ucontext_t,
1742            _osf_sigmask: u64,
1743            _stack: std.os.linux.stack_t,
1744            // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/alpha/include/uapi/asm/sigcontext.h
1745            mcontext: extern struct {
1746                _onstack: i64,
1747                _mask: i64,
1748                pc: u64,
1749                _ps: i64,
1750                r: [32]u64,
1751            },
1752        },
1753        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/arm64/include/uapi/asm/ucontext.h
1754        .aarch64,
1755        .aarch64_be,
1756        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/loongarch/include/uapi/asm/ucontext.h
1757        .loongarch64,
1758        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/powerpc/include/uapi/asm/ucontext.h
1759        .powerpc64,
1760        .powerpc64le,
1761        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/riscv/include/uapi/asm/ucontext.h
1762        .riscv32,
1763        .riscv64,
1764        => extern struct {
1765            _flags: usize,
1766            _link: ?*signal_ucontext_t,
1767            _stack: std.os.linux.stack_t,
1768            _sigmask: std.os.linux.sigset_t,
1769            _unused: [120]u8,
1770            mcontext: switch (native_arch) {
1771                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/arm64/include/uapi/asm/sigcontext.h
1772                .aarch64, .aarch64_be => extern struct {
1773                    _fault_address: u64 align(16),
1774                    x: [30]u64,
1775                    lr: u64,
1776                    sp: u64,
1777                    pc: u64,
1778                },
1779                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/loongarch/include/uapi/asm/sigcontext.h
1780                .loongarch64 => extern struct {
1781                    pc: u64 align(16),
1782                    r: [32]u64,
1783                },
1784                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/powerpc/include/uapi/asm/sigcontext.h
1785                .powerpc64, .powerpc64le => extern struct {
1786                    _unused: [4]u64,
1787                    _signal: i32,
1788                    _pad: i32,
1789                    _handler: u64,
1790                    _oldmask: u64,
1791                    _regs: ?*anyopaque,
1792                    r: [32]u64,
1793                    pc: u64,
1794                    _msr: u64,
1795                    _orig_r3: u64,
1796                    _ctr: u64,
1797                    lr: u64,
1798                },
1799                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/riscv/include/uapi/asm/sigcontext.h
1800                .riscv32, .riscv64 => extern struct {
1801                    pc: usize align(16),
1802                    ra_sp_gp_tp: [4]usize,
1803                    t0_2: [3]usize,
1804                    s0_1: [2]usize,
1805                    a: [8]usize,
1806                    s2_11: [10]usize,
1807                    t3_6: [4]usize,
1808                },
1809                else => unreachable,
1810            },
1811        },
1812        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/include/uapi/asm-generic/ucontext.h
1813        .arc,
1814        .arceb,
1815        .arm,
1816        .armeb,
1817        .thumb,
1818        .thumbeb,
1819        .csky,
1820        .hexagon,
1821        .m68k,
1822        .mips,
1823        .mipsel,
1824        .mips64,
1825        .mips64el,
1826        .or1k,
1827        .s390x,
1828        .x86,
1829        .x86_64,
1830        .xtensa,
1831        .xtensaeb,
1832        => extern struct {
1833            _flags: usize,
1834            _link: ?*signal_ucontext_t,
1835            _stack: std.os.linux.stack_t,
1836            mcontext: switch (native_arch) {
1837                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/arc/include/uapi/asm/sigcontext.h
1838                .arc, .arceb => extern struct {
1839                    _pad1: u32,
1840                    _bta: u32,
1841                    _lp: extern struct {
1842                        _start: u32,
1843                        _end: u32,
1844                        _count: u32,
1845                    },
1846                    _status32: u32,
1847                    pcl: u32,
1848                    r31: u32,
1849                    r27_26: [2]u32,
1850                    r12_0: [13]u32,
1851                    r28: u32,
1852                    _pad2: u32,
1853                    r25_13: [13]u32,
1854                    _efa: u32,
1855                    _stop_pc: u32,
1856                    r30: u32,
1857                },
1858                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/arm/include/uapi/asm/sigcontext.h
1859                .arm, .armeb, .thumb, .thumbeb => extern struct {
1860                    _trap_no: u32,
1861                    _error_code: u32,
1862                    _oldmask: u32,
1863                    r: [15]u32,
1864                    pc: u32,
1865                },
1866                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/csky/include/uapi/asm/sigcontext.h
1867                .csky => extern struct {
1868                    r31: u32,
1869                    r15: u32,
1870                    pc: u32,
1871                    _sr: u32,
1872                    r14: u32,
1873                    _orig_a0: u32,
1874                    r0_13: [14]u32,
1875                    r16_30: [15]u32,
1876                },
1877                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/hexagon/include/uapi/asm/sigcontext.h
1878                .hexagon => extern struct {
1879                    r: [32]u32 align(8),
1880                    _salc: [2]extern struct {
1881                        _sa: u32,
1882                        _lc: u32,
1883                    },
1884                    _m: [2]u32,
1885                    _usr: u32,
1886                    _p: u32,
1887                    _gp: u32,
1888                    _ugp: u32,
1889                    pc: u32,
1890                },
1891                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/parisc/include/uapi/asm/sigcontext.h
1892                .hppa => extern struct {
1893                    _flags: u32,
1894                    _psw: u32,
1895                    r1_19: [19]u32,
1896                    r20: u32,
1897                    r21: u32,
1898                    r22: u32,
1899                    r23_29: [7]u32,
1900                    r30: u32,
1901                    r31: u32,
1902                    _fr: [32]f64,
1903                    _iasq: [2]u32,
1904                    iaoq: [2]u32,
1905                },
1906                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/m68k/include/asm/ucontext.h
1907                .m68k => extern struct {
1908                    _version: i32,
1909                    d: [8]u32,
1910                    a: [8]u32,
1911                    pc: u32,
1912                },
1913                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/microblaze/include/uapi/asm/sigcontext.h
1914                .microblaze, .microblazeel => extern struct {
1915                    r: [32]u32,
1916                    pc: u32,
1917                },
1918                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/mips/include/uapi/asm/sigcontext.h
1919                .mips, .mipsel => extern struct {
1920                    _regmask: u32,
1921                    _status: u32,
1922                    // ??? A spectacularly failed attempt to be future-proof?
1923                    pc: u64,
1924                    r: [32]u64,
1925                },
1926                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/mips/include/uapi/asm/sigcontext.h
1927                .mips64, .mips64el => extern struct {
1928                    r: [32]u64,
1929                    _fpregs: [32]u64,
1930                    _hi: [4]u64,
1931                    _lo: [4]u64,
1932                    pc: u64,
1933                },
1934                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/openrisc/include/uapi/asm/sigcontext.h
1935                .or1k => extern struct {
1936                    r: [32]u32,
1937                    pc: u32,
1938                },
1939                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/s390/include/uapi/asm/sigcontext.h
1940                .s390x => extern struct {
1941                    psw: extern struct {
1942                        mask: u64,
1943                        addr: u64,
1944                    },
1945                    r: [16]u64,
1946                },
1947                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/sh/include/uapi/asm/sigcontext.h
1948                .sh, .sheb => extern struct {
1949                    _oldmask: u32,
1950                    r: [16]u32,
1951                    pc: u32,
1952                    pr: u32,
1953                },
1954                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/x86/include/uapi/asm/sigcontext.h
1955                .x86 => extern struct {
1956                    _gs: u32,
1957                    _fs: u32,
1958                    _es: u32,
1959                    _ds: u32,
1960                    edi: u32,
1961                    esi: u32,
1962                    ebp: u32,
1963                    esp: u32,
1964                    ebx: u32,
1965                    edx: u32,
1966                    ecx: u32,
1967                    eax: u32,
1968                    _trapno: u32,
1969                    _err: u32,
1970                    eip: u32,
1971                },
1972                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/x86/include/uapi/asm/sigcontext.h
1973                .x86_64 => extern struct {
1974                    r8: u64,
1975                    r9: u64,
1976                    r10: u64,
1977                    r11: u64,
1978                    r12: u64,
1979                    r13: u64,
1980                    r14: u64,
1981                    r15: u64,
1982                    rdi: u64,
1983                    rsi: u64,
1984                    rbp: u64,
1985                    rbx: u64,
1986                    rdx: u64,
1987                    rax: u64,
1988                    rcx: u64,
1989                    rsp: u64,
1990                    rip: u64,
1991                },
1992                // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/xtensa/include/uapi/asm/sigcontext.h
1993                .xtensa, .xtensaeb => extern struct {
1994                    pc: u32,
1995                    _ps: u32,
1996                    _l: extern struct {
1997                        _beg: u32,
1998                        _end: u32,
1999                        _count: u32,
2000                    },
2001                    _sar: u32,
2002                    _acc: extern struct {
2003                        _lo: u32,
2004                        _hi: u32,
2005                    },
2006                    a: [16]u32,
2007                },
2008                else => unreachable,
2009            },
2010        },
2011        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/powerpc/include/uapi/asm/ucontext.h
2012        .powerpc, .powerpcle => extern struct {
2013            _flags: u32,
2014            _link: ?*signal_ucontext_t,
2015            _stack: std.os.linux.stack_t,
2016            _pad1: [7]i32,
2017            _regs: ?*anyopaque,
2018            _sigmask: std.os.linux.sigset_t,
2019            _unused: [120]u8,
2020            _pad2: [3]i32,
2021            mcontext: extern struct {
2022                r: [32]u32 align(16),
2023                pc: u32,
2024                _msr: u32,
2025                _orig_r3: u32,
2026                _ctr: u32,
2027                lr: u32,
2028            },
2029        },
2030        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/sparc/kernel/signal_32.c#L48-L49
2031        .sparc => extern struct {
2032            // Not actually a `ucontext_t` at all because, uh, reasons?
2033
2034            _info: std.os.linux.siginfo_t,
2035            mcontext: extern struct {
2036                _psr: u32,
2037                pc: u32,
2038                _npc: u32,
2039                _y: u32,
2040                g: [8]u32,
2041                o: [8]u32,
2042            },
2043        },
2044        // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/sparc/kernel/signal_64.c#L247-L248
2045        .sparc64 => extern struct {
2046            // Ditto...
2047
2048            _info: std.os.linux.siginfo_t,
2049            mcontext: extern struct {
2050                g: [8]u64,
2051                o: [8]u64,
2052                _tstate: u64,
2053                pc: u64,
2054            },
2055        },
2056        else => unreachable,
2057    },
2058    // https://github.com/freebsd/freebsd-src/blob/55c28005f544282b984ae0e15dacd0c108d8ab12/sys/sys/_ucontext.h
2059    .freebsd => extern struct {
2060        _sigmask: std.c.sigset_t,
2061        mcontext: switch (native_arch) {
2062            // https://github.com/freebsd/freebsd-src/blob/55c28005f544282b984ae0e15dacd0c108d8ab12/sys/arm64/include/ucontext.h
2063            .aarch64 => extern struct {
2064                x: [30]u64 align(16),
2065                lr: u64,
2066                sp: u64,
2067                pc: u64,
2068            },
2069            // https://github.com/freebsd/freebsd-src/blob/55c28005f544282b984ae0e15dacd0c108d8ab12/sys/arm/include/ucontext.h
2070            .arm => extern struct {
2071                r: [15]u32,
2072                pc: u32,
2073            },
2074            // https://github.com/freebsd/freebsd-src/blob/55c28005f544282b984ae0e15dacd0c108d8ab12/sys/powerpc/include/ucontext.h
2075            .powerpc64, .powerpc64le => extern struct {
2076                _vers: i32 align(16),
2077                _flags: i32,
2078                _onstack: i32,
2079                _len: i32,
2080                _avec: [32 * 2]u64,
2081                _av: [2]u32,
2082                r: [32]u64,
2083                lr: u64,
2084                _cr: u64,
2085                _xer: u64,
2086                _ctr: u64,
2087                pc: u64,
2088            },
2089            // https://github.com/freebsd/freebsd-src/blob/55c28005f544282b984ae0e15dacd0c108d8ab12/sys/riscv/include/ucontext.h
2090            .riscv64 => extern struct {
2091                ra_sp_gp_tp: [4]u64,
2092                t0_2: [3]u64,
2093                t3_6: [4]u64,
2094                s0_1: [2]u64,
2095                s2_11: [10]u64,
2096                a: [8]u64,
2097                pc: u64,
2098            },
2099            // https://github.com/freebsd/freebsd-src/blob/55c28005f544282b984ae0e15dacd0c108d8ab12/sys/x86/include/ucontext.h
2100            .x86_64 => extern struct {
2101                _onstack: i64,
2102                rdi: u64,
2103                rsi: u64,
2104                rdx: u64,
2105                rcx: u64,
2106                r8: u64,
2107                r9: u64,
2108                rax: u64,
2109                rbx: u64,
2110                rbp: u64,
2111                r10: u64,
2112                r11: u64,
2113                r12: u64,
2114                r13: u64,
2115                r14: u64,
2116                r15: u64,
2117                _trapno: i32,
2118                _fs: i16,
2119                _gs: i16,
2120                _addr: i64,
2121                _flags: i32,
2122                _es: i16,
2123                _ds: i16,
2124                _err: i64,
2125                rip: u64,
2126                _cs: i64,
2127                _rflags: i64,
2128                rsp: u64,
2129            },
2130            else => unreachable,
2131        },
2132    },
2133    // https://github.com/ziglang/zig/blob/60be67d3c0ba6ae15fa7115596734ab1e74fbcd3/lib/libc/include/any-macos-any/sys/_types/_ucontext.h
2134    .driverkit, .ios, .maccatalyst, .macos, .tvos, .watchos, .visionos => extern struct {
2135        _onstack: i32,
2136        _sigmask: std.c.sigset_t,
2137        _stack: std.c.stack_t,
2138        _link: ?*signal_ucontext_t,
2139        _mcsize: u64,
2140        mcontext: *switch (native_arch) {
2141            // https://github.com/ziglang/zig/blob/60be67d3c0ba6ae15fa7115596734ab1e74fbcd3/lib/libc/include/any-macos-any/arm/_mcontext.h
2142            // https://github.com/ziglang/zig/blob/60be67d3c0ba6ae15fa7115596734ab1e74fbcd3/lib/libc/include/any-macos-any/mach/arm/_structs.h
2143            .aarch64 => extern struct {
2144                _far: u64 align(16),
2145                _esr: u64,
2146                x: [30]u64,
2147                lr: u64,
2148                sp: u64,
2149                pc: u64,
2150            },
2151            // https://github.com/ziglang/zig/blob/60be67d3c0ba6ae15fa7115596734ab1e74fbcd3/lib/libc/include/any-macos-any/i386/_mcontext.h
2152            // https://github.com/ziglang/zig/blob/60be67d3c0ba6ae15fa7115596734ab1e74fbcd3/lib/libc/include/any-macos-any/mach/i386/_structs.h
2153            .x86_64 => extern struct {
2154                _trapno: u16,
2155                _cpu: u16,
2156                _err: u32,
2157                _faultvaddr: u64,
2158                rax: u64,
2159                rbx: u64,
2160                rcx: u64,
2161                rdx: u64,
2162                rdi: u64,
2163                rsi: u64,
2164                rbp: u64,
2165                rsp: u64,
2166                r8: u64,
2167                r9: u64,
2168                r10: u64,
2169                r11: u64,
2170                r12: u64,
2171                r13: u64,
2172                r14: u64,
2173                r15: u64,
2174                rip: u64,
2175            },
2176            else => unreachable,
2177        },
2178    },
2179    // https://github.com/illumos/illumos-gate/blob/d4ce137bba3bd16823db6374d9e9a643264ce245/usr/src/uts/intel/sys/ucontext.h
2180    .illumos => extern struct {
2181        _flags: usize,
2182        _link: ?*signal_ucontext_t,
2183        _sigmask: std.c.sigset_t,
2184        _stack: std.c.stack_t,
2185        mcontext: switch (native_arch) {
2186            // https://github.com/illumos/illumos-gate/blob/d4ce137bba3bd16823db6374d9e9a643264ce245/usr/src/uts/intel/sys/mcontext.h
2187            .x86 => extern struct {
2188                _gs: u32,
2189                _fs: u32,
2190                _es: u32,
2191                _ds: u32,
2192                edi: u32,
2193                esi: u32,
2194                ebp: u32,
2195                esp: u32,
2196                ebx: u32,
2197                edx: u32,
2198                ecx: u32,
2199                eax: u32,
2200                _trapno: i32,
2201                _err: i32,
2202                eip: u32,
2203            },
2204            // https://github.com/illumos/illumos-gate/blob/d4ce137bba3bd16823db6374d9e9a643264ce245/usr/src/uts/intel/sys/mcontext.h
2205            .x86_64 => extern struct {
2206                r15: u64 align(16),
2207                r14: u64,
2208                r13: u64,
2209                r12: u64,
2210                r11: u64,
2211                r10: u64,
2212                r9: u64,
2213                r8: u64,
2214                rdi: u64,
2215                rsi: u64,
2216                rbp: u64,
2217                rbx: u64,
2218                rdx: u64,
2219                rcx: u64,
2220                rax: u64,
2221                _trapno: i64,
2222                _err: i64,
2223                rip: u64,
2224                _cs: i64,
2225                _rflags: i64,
2226                rsp: u64,
2227            },
2228            else => unreachable,
2229        },
2230    },
2231    .openbsd => switch (native_arch) {
2232        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/arm64/include/signal.h
2233        .aarch64 => extern struct {
2234            _unused: i32,
2235            _mask: i32,
2236            mcontext: extern struct {
2237                sp: u64,
2238                lr: u64,
2239                pc: u64,
2240                _spsr: u64,
2241                x: [30]u64,
2242            },
2243        },
2244        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/alpha/include/signal.h
2245        .alpha => extern struct {
2246            _cookie: i64,
2247            _mask: i64,
2248            pc: u64,
2249            _ps: i64,
2250            r: [32]u64,
2251        },
2252        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/arm/include/signal.h
2253        .arm => extern struct {
2254            _cookie: i32,
2255            _mask: i32,
2256            mcontext: extern struct {
2257                _spsr: u32 align(8),
2258                r: [15]u32,
2259                _svc_lr: u32,
2260                pc: u32,
2261            },
2262        },
2263        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/hppa/include/signal.h
2264        .hppa => extern struct {
2265            _unused: u32,
2266            _mask: i32,
2267            _fp: u32,
2268            iaoq: [2]u32,
2269            _resv: [2]u32,
2270            r22: u32,
2271            r21: u32,
2272            r30: u32,
2273            r20: u32,
2274            _sar: u32,
2275            r1_19: [19]u32,
2276            r23_29: [7]u32,
2277            r31: u32,
2278        },
2279        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/mips64/include/signal.h
2280        .mips64, .mips64el => extern struct {
2281            _cookie: i64,
2282            _mask: i64,
2283            mcontext: extern struct {
2284                pc: u64,
2285                r: [32]u64,
2286            },
2287        },
2288        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/powerpc/include/signal.h
2289        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/powerpc64/include/signal.h
2290        .powerpc, .powerpc64 => extern struct {
2291            _cookie: isize,
2292            _mask: i32,
2293            mcontext: extern struct {
2294                r: [32]usize,
2295                lr: usize,
2296                _cr: usize,
2297                _xer: usize,
2298                _ctr: usize,
2299                pc: usize,
2300            },
2301        },
2302        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/riscv64/include/signal.h
2303        .riscv64 => extern struct {
2304            _unused: i32,
2305            _mask: i32,
2306            mcontext: extern struct {
2307                ra_sp_gp_tp: [4]u64,
2308                t0_2: [3]u64,
2309                t3_6: [4]u64,
2310                s0_1: [2]u64,
2311                s2_11: [10]u64,
2312                a: [8]u64,
2313                pc: u64,
2314            },
2315        },
2316        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/sparc64/include/signal.h
2317        .sparc64 => @compileError("sparc64-openbsd ucontext_t missing"),
2318        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/sh/include/signal.h
2319        .sh, .sheb => extern struct {
2320            pc: u32,
2321            _sr: i32,
2322            _gbr: i32,
2323            _macl: i32,
2324            _mach: i32,
2325            pr: u32,
2326            r13_0: [14]u32,
2327            r15: u32,
2328            r14: u32,
2329        },
2330        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/i386/include/signal.h
2331        .x86 => extern struct {
2332            mcontext: extern struct {
2333                _gs: i32,
2334                _fs: i32,
2335                _es: i32,
2336                _ds: i32,
2337                edi: u32,
2338                esi: u32,
2339                ebp: u32,
2340                ebx: u32,
2341                edx: u32,
2342                ecx: u32,
2343                eax: u32,
2344                eip: u32,
2345                _cs: i32,
2346                _eflags: i32,
2347                esp: u32,
2348            },
2349        },
2350        // https://github.com/openbsd/src/blob/42468faed8369d07ae49ae02dd71ec34f59b66cd/sys/arch/amd64/include/signal.h
2351        .x86_64 => extern struct {
2352            mcontext: extern struct {
2353                rdi: u64,
2354                rsi: u64,
2355                rdx: u64,
2356                rcx: u64,
2357                r8: u64,
2358                r9: u64,
2359                r10: u64,
2360                r11: u64,
2361                r12: u64,
2362                r13: u64,
2363                r14: u64,
2364                r15: u64,
2365                rbp: u64,
2366                rbx: u64,
2367                rax: u64,
2368                _gs: i64,
2369                _fs: i64,
2370                _es: i64,
2371                _ds: i64,
2372                _trapno: i64,
2373                _err: i64,
2374                rip: u64,
2375                _cs: i64,
2376                _rflags: i64,
2377                rsp: u64,
2378            },
2379        },
2380        else => unreachable,
2381    },
2382    // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/sys/ucontext.h
2383    .netbsd => extern struct {
2384        _flags: u32,
2385        _link: ?*signal_ucontext_t,
2386        _sigmask: std.c.sigset_t,
2387        _stack: std.c.stack_t,
2388        mcontext: switch (native_arch) {
2389            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/arm/include/mcontext.h
2390            .aarch64, .aarch64_be => extern struct {
2391                x: [30]u64 align(16),
2392                lr: u64,
2393                sp: u64,
2394                pc: u64,
2395            },
2396            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/alpha/include/mcontext.h
2397            .alpha => extern struct {
2398                r: [32]u64,
2399                pc: u64,
2400            },
2401            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/arm/include/mcontext.h
2402            .arm, .armeb => extern struct {
2403                r: [15]u32 align(8),
2404                pc: u32,
2405            },
2406            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/m68k/include/mcontext.h
2407            .m68k => extern struct {
2408                d: [8]u32,
2409                a: [8]u32,
2410                pc: u32,
2411            },
2412            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/mips/include/mcontext.h
2413            .mips, .mipsel => extern struct {
2414                r: [32]u32 align(8),
2415                _lo: i32,
2416                _hi: i32,
2417                _cause: i32,
2418                pc: u32,
2419            },
2420            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/mips/include/mcontext.h
2421            .mips64, .mips64el => @compileError("https://github.com/ziglang/zig/issues/23765#issuecomment-2880386178"),
2422            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/powerpc/include/mcontext.h
2423            .powerpc => extern struct {
2424                r: [32]u32 align(16),
2425                _cr: i32,
2426                lr: u32,
2427                pc: u32,
2428            },
2429            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/sparc/include/mcontext.h
2430            .sparc => @compileError("sparc-netbsd mcontext_t missing"),
2431            .sparc64 => @compileError("sparc64-netbsd mcontext_t missing"),
2432            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/sh3/include/mcontext.h
2433            .sh, .sheb => extern struct {
2434                _gbr: i32,
2435                pc: u32,
2436                _sr: i32,
2437                _macl: i32,
2438                _mach: i32,
2439                pr: u32,
2440                r14: u32,
2441                r13_0: [14]u32,
2442                r15: u32,
2443            },
2444            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/i386/include/mcontext.h
2445            .x86 => extern struct {
2446                _gs: i32,
2447                _fs: i32,
2448                _es: i32,
2449                _ds: i32,
2450                edi: u32,
2451                esi: u32,
2452                ebp: u32,
2453                esp: u32,
2454                ebx: u32,
2455                edx: u32,
2456                ecx: u32,
2457                eax: u32,
2458                _trapno: i32,
2459                _err: i32,
2460                eip: u32,
2461            },
2462            // https://github.com/NetBSD/src/blob/861008c62187bf7bc0aac4d81e52ed6eee4d0c74/sys/arch/amd64/include/mcontext.h
2463            .x86_64 => extern struct {
2464                rdi: u64,
2465                rsi: u64,
2466                rdx: u64,
2467                rcx: u64,
2468                r8: u64,
2469                r9: u64,
2470                r10: u64,
2471                r11: u64,
2472                r12: u64,
2473                r13: u64,
2474                r14: u64,
2475                r15: u64,
2476                rbp: u64,
2477                rbx: u64,
2478                rax: u64,
2479                _gs: i64,
2480                _fs: i64,
2481                _es: i64,
2482                _ds: i64,
2483                _trapno: i64,
2484                _err: i64,
2485                rip: u64,
2486                _cs: i64,
2487                _rflags: i64,
2488                rsp: u64,
2489            },
2490            else => unreachable,
2491        },
2492    },
2493    // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/3de1e9d36269616d22237f19d60a737a41271ab5/sys/sys/_ucontext.h
2494    .dragonfly => extern struct {
2495        _sigmask: std.c.sigset_t,
2496        mcontext: switch (native_arch) {
2497            // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/3de1e9d36269616d22237f19d60a737a41271ab5/sys/cpu/x86_64/include/ucontext.h
2498            .x86_64 => extern struct {
2499                _onstack: i64 align(64),
2500                rdi: u64,
2501                rsi: u64,
2502                rdx: u64,
2503                rcx: u64,
2504                r8: u64,
2505                r9: u64,
2506                rax: u64,
2507                rbx: u64,
2508                rbp: u64,
2509                r10: u64,
2510                r11: u64,
2511                r12: u64,
2512                r13: u64,
2513                r14: u64,
2514                r15: u64,
2515                _xflags: i64,
2516                _trapno: i64,
2517                _addr: i64,
2518                _flags: i64,
2519                _err: i64,
2520                rip: u64,
2521                _cs: i64,
2522                _rflags: i64,
2523                rsp: u64,
2524            },
2525            else => unreachable,
2526        },
2527    },
2528    // https://github.com/SerenityOS/serenity/blob/103d6a07de9e28f3c94dfa2351b9af76a49ba6e6/Kernel/API/POSIX/ucontext.h
2529    .serenity => extern struct {
2530        _link: ?*signal_ucontext_t,
2531        _sigmask: std.c.sigset_t,
2532        _stack: std.c.stack_t,
2533        mcontext: switch (native_arch) {
2534            // https://github.com/SerenityOS/serenity/blob/103d6a07de9e28f3c94dfa2351b9af76a49ba6e6/Kernel/Arch/aarch64/mcontext.h
2535            .aarch64 => extern struct {
2536                x: [30]u64,
2537                lr: u64,
2538                sp: u64,
2539                pc: u64,
2540            },
2541            // https://github.com/SerenityOS/serenity/blob/103d6a07de9e28f3c94dfa2351b9af76a49ba6e6/Kernel/Arch/riscv64/mcontext.h
2542            .riscv64 => extern struct {
2543                ra_sp_gp_tp: [4]u64,
2544                t0_2: [3]u64,
2545                s0_1: [2]u64,
2546                a: [8]u64,
2547                s2_11: [10]u64,
2548                t3_6: [4]u64,
2549                pc: u64,
2550            },
2551            // https://github.com/SerenityOS/serenity/blob/103d6a07de9e28f3c94dfa2351b9af76a49ba6e6/Kernel/Arch/x86_64/mcontext.h
2552            .x86_64 => extern struct {
2553                rax: u64,
2554                rcx: u64,
2555                rdx: u64,
2556                rbx: u64,
2557                rsp: u64,
2558                rbp: u64,
2559                rsi: u64,
2560                rdi: u64,
2561                rip: u64,
2562                r8: u64,
2563                r9: u64,
2564                r10: u64,
2565                r11: u64,
2566                r12: u64,
2567                r13: u64,
2568                r14: u64,
2569                r15: u64,
2570            },
2571            else => unreachable,
2572        },
2573    },
2574    // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/signal.h#L356
2575    .haiku => extern struct {
2576        _link: ?*signal_ucontext_t,
2577        _sigmask: std.c.sigset_t,
2578        _stack: std.c.stack_t,
2579        mcontext: switch (native_arch) {
2580            // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/arch/arm/signal.h
2581            .arm => extern struct {
2582                r: [15]u32 align(8),
2583                pc: u32,
2584            },
2585            // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/arch/arm64/signal.h
2586            .aarch64 => extern struct {
2587                x: [30]u64 align(16),
2588                lr: u64,
2589                sp: u64,
2590                pc: u64,
2591            },
2592            // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/arch/m68k/signal.h
2593            .m68k => extern struct {
2594                pc: u32 align(8),
2595                d: [8]u32,
2596                a: [8]u32,
2597            },
2598            // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/arch/ppc/signal.h
2599            .powerpc => extern struct {
2600                pc: u32 align(8),
2601                r: [13]u32, // Um, are you okay, Haiku?
2602                _f: [14]f64,
2603                _reserved: u32,
2604                _fpscr: u32,
2605                _ctr: u32,
2606                _xer: u32,
2607                _cr: u32,
2608                _msr: u32,
2609                lr: u32,
2610            },
2611            // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/arch/riscv64/signal.h
2612            .riscv64 => extern struct {
2613                ra_sp_gp_tp: [4]u64,
2614                t0_2: [3]u64,
2615                s0_1: [2]u64,
2616                a: [8]u64,
2617                s2_11: [10]u64,
2618                t3_6: [4]u64,
2619                pc: u64,
2620            },
2621            // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/arch/sparc64/signal.h
2622            .sparc64 => @compileError("sparc64-haiku mcontext_t missing"),
2623            // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/arch/x86/signal.h
2624            .x86 => extern struct {
2625                eip: u32,
2626                _eflags: u32,
2627                eax: u32,
2628                ecx: u32,
2629                edx: u32,
2630                esp: u32,
2631                ebp: u32,
2632                _reserved: u32,
2633                _xregs: extern struct {
2634                    _fp_control: u16,
2635                    _fp_status: u16,
2636                    _fp_tag: u16,
2637                    _fp_opcode: u16,
2638                    _fp_eip: u32,
2639                    _fp_cs: u16,
2640                    _reserved1: u16,
2641                    _fp_datap: u32,
2642                    _fp_ds: u16,
2643                    _reserved2: u16,
2644                    _mxcsr: u32,
2645                    _mxcsr_mask: u32,
2646                    _mmx: [8][16]u8,
2647                    _xmmx: [8][16]u8,
2648                    _reserved3: [176]u8,
2649                    _fault_address: u32,
2650                    _error_code: u32,
2651                    _cs: u16,
2652                    _ds: u16,
2653                    _es: u16,
2654                    _fs: u16,
2655                    _gs: u16,
2656                    _ss: u16,
2657                    _trap_number: u8,
2658                    _reserved4: [27]u8,
2659                    _format: u32,
2660                },
2661                edi: u32,
2662                esi: u32,
2663                ebx: u32,
2664            },
2665            // https://github.com/haiku/haiku/blob/47538c534fe0aadc626c09d121773fee8ea10d71/headers/posix/arch/x86_64/signal.h
2666            .x86_64 => extern struct {
2667                rax: u64,
2668                rbx: u64,
2669                rcx: u64,
2670                rdx: u64,
2671                rdi: u64,
2672                rsi: u64,
2673                rbp: u64,
2674                r8: u64,
2675                r9: u64,
2676                r10: u64,
2677                r11: u64,
2678                r12: u64,
2679                r13: u64,
2680                r14: u64,
2681                r15: u64,
2682                rsp: u64,
2683                rip: u64,
2684            },
2685            else => unreachable,
2686        },
2687    },
2688    else => void,
2689};
2690
2691const std = @import("../std.zig");
2692const root = @import("root");
2693const builtin = @import("builtin");
2694const native_arch = @import("builtin").target.cpu.arch;
2695const native_os = @import("builtin").target.os.tag;