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