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;