authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-10-16 18:51:09+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-10-18 00:36:52+02:00
log1f15e265fe0861cbfad4479c69b79b46158d8d16
treef8919c057585cafe252e0de79129c4f3e735501a
parent4c81a496e7c979755d9fc74734ab740a828c4491
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

std.debug.cpu_context: sort context decls according to switch prongs (NFC)


1 files changed, 286 insertions(+), 286 deletions(-)

lib/std/debug/cpu_context.zig+286-286
......@@ -212,129 +212,63 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native {
212212 };
213213}
214214
215const X86 = struct {
216 /// The first 8 registers here intentionally match the order of registers in the x86 instruction
217 /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings,
218 /// among other things.
219 pub const Gpr = enum {
220 // zig fmt: off
221 eax, ecx, edx, ebx,
222 esp, ebp, esi, edi,
223 eip,
224 // zig fmt: on
225 };
226 gprs: std.enums.EnumArray(Gpr, u32),
227
228 pub inline fn current() X86 {
229 var ctx: X86 = undefined;
230 asm volatile (
231 \\movl %%eax, 0x00(%%edi)
232 \\movl %%ecx, 0x04(%%edi)
233 \\movl %%edx, 0x08(%%edi)
234 \\movl %%ebx, 0x0c(%%edi)
235 \\movl %%esp, 0x10(%%edi)
236 \\movl %%ebp, 0x14(%%edi)
237 \\movl %%esi, 0x18(%%edi)
238 \\movl %%edi, 0x1c(%%edi)
239 \\call 1f
240 \\1:
241 \\popl 0x20(%%edi)
242 :
243 : [gprs] "{edi}" (&ctx.gprs.values),
244 : .{ .memory = true });
245 return ctx;
246 }
247
248 pub fn dwarfRegisterBytes(ctx: *X86, register_num: u16) DwarfRegisterError![]u8 {
249 // System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.1
250 // § 2.4.2 "DWARF Register Number Mapping"
251 switch (register_num) {
252 // The order of `Gpr` intentionally matches DWARF's mappings.
253 //
254 // x86-macos sometimes uses different mappings (ebp and esp are reversed when the unwind
255 // information is from `__eh_frame`). This deviation is not considered here, because
256 // x86-macos is a deprecated target which is not supported by the Zig Standard Library.
257 0...8 => return @ptrCast(&ctx.gprs.values[register_num]),
258
259 9 => return error.UnsupportedRegister, // eflags
260 11...18 => return error.UnsupportedRegister, // st0 - st7
261 21...28 => return error.UnsupportedRegister, // xmm0 - xmm7
262 29...36 => return error.UnsupportedRegister, // mm0 - mm7
263 39 => return error.UnsupportedRegister, // mxcsr
264 40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
265 48 => return error.UnsupportedRegister, // tr
266 49 => return error.UnsupportedRegister, // ldtr
267 93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
268
269 else => return error.InvalidRegister,
270 }
271 }
272};
273
274const X86_64 = struct {
275 /// The order here intentionally matches the order of the DWARF register mappings. It's unclear
276 /// where those mappings actually originated from---the ordering of the first 4 registers seems
277 /// quite unusual---but it is currently convenient for us to match DWARF.
278 pub const Gpr = enum {
279 // zig fmt: off
280 rax, rdx, rcx, rbx,
281 rsi, rdi, rbp, rsp,
282 r8, r9, r10, r11,
283 r12, r13, r14, r15,
284 rip,
285 // zig fmt: on
286 };
287 gprs: std.enums.EnumArray(Gpr, u64),
215/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
216const Aarch64 = extern struct {
217 /// The numbered general-purpose registers X0 - X30.
218 x: [31]u64,
219 sp: u64,
220 pc: u64,
288221
289 pub inline fn current() X86_64 {
290 var ctx: X86_64 = undefined;
222 pub inline fn current() Aarch64 {
223 var ctx: Aarch64 = undefined;
291224 asm volatile (
292 \\movq %%rax, 0x00(%%rdi)
293 \\movq %%rdx, 0x08(%%rdi)
294 \\movq %%rcx, 0x10(%%rdi)
295 \\movq %%rbx, 0x18(%%rdi)
296 \\movq %%rsi, 0x20(%%rdi)
297 \\movq %%rdi, 0x28(%%rdi)
298 \\movq %%rbp, 0x30(%%rdi)
299 \\movq %%rsp, 0x38(%%rdi)
300 \\movq %%r8, 0x40(%%rdi)
301 \\movq %%r9, 0x48(%%rdi)
302 \\movq %%r10, 0x50(%%rdi)
303 \\movq %%r11, 0x58(%%rdi)
304 \\movq %%r12, 0x60(%%rdi)
305 \\movq %%r13, 0x68(%%rdi)
306 \\movq %%r14, 0x70(%%rdi)
307 \\movq %%r15, 0x78(%%rdi)
308 \\leaq (%%rip), %%rax
309 \\movq %%rax, 0x80(%%rdi)
310 \\movq 0x00(%%rdi), %%rax
225 \\ stp x0, x1, [x0, #0x000]
226 \\ stp x2, x3, [x0, #0x010]
227 \\ stp x4, x5, [x0, #0x020]
228 \\ stp x6, x7, [x0, #0x030]
229 \\ stp x8, x9, [x0, #0x040]
230 \\ stp x10, x11, [x0, #0x050]
231 \\ stp x12, x13, [x0, #0x060]
232 \\ stp x14, x15, [x0, #0x070]
233 \\ stp x16, x17, [x0, #0x080]
234 \\ stp x18, x19, [x0, #0x090]
235 \\ stp x20, x21, [x0, #0x0a0]
236 \\ stp x22, x23, [x0, #0x0b0]
237 \\ stp x24, x25, [x0, #0x0c0]
238 \\ stp x26, x27, [x0, #0x0d0]
239 \\ stp x28, x29, [x0, #0x0e0]
240 \\ str x30, [x0, #0x0f0]
241 \\ mov x1, sp
242 \\ str x1, [x0, #0x0f8]
243 \\ adr x1, .
244 \\ str x1, [x0, #0x100]
245 \\ ldr x1, [x0, #0x008]
311246 :
312 : [gprs] "{rdi}" (&ctx.gprs.values),
247 : [ctx] "{x0}" (&ctx),
313248 : .{ .memory = true });
314249 return ctx;
315250 }
316251
317 pub fn dwarfRegisterBytes(ctx: *X86_64, register_num: u16) DwarfRegisterError![]u8 {
318 // System V Application Binary Interface AMD64 Architecture Processor Supplement
319 // § 3.6.2 "DWARF Register Number Mapping"
252 pub fn dwarfRegisterBytes(ctx: *Aarch64, register_num: u16) DwarfRegisterError![]u8 {
253 // DWARF for the Arm(r) 64-bit Architecture (AArch64) § 4.1 "DWARF register names"
320254 switch (register_num) {
321 // The order of `Gpr` intentionally matches DWARF's mappings.
322 0...16 => return @ptrCast(&ctx.gprs.values[register_num]),
255 0...30 => return @ptrCast(&ctx.x[register_num]),
256 31 => return @ptrCast(&ctx.sp),
257 32 => return @ptrCast(&ctx.pc),
323258
324 17...32 => return error.UnsupportedRegister, // xmm0 - xmm15
325 33...40 => return error.UnsupportedRegister, // st0 - st7
326 41...48 => return error.UnsupportedRegister, // mm0 - mm7
327 49 => return error.UnsupportedRegister, // rflags
328 50...55 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
329 58...59 => return error.UnsupportedRegister, // fs.base, gs.base
330 62 => return error.UnsupportedRegister, // tr
331 63 => return error.UnsupportedRegister, // ldtr
332 64 => return error.UnsupportedRegister, // mxcsr
333 65 => return error.UnsupportedRegister, // fcw
334 66 => return error.UnsupportedRegister, // fsw
335 67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512)
336 118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
337 130...145 => return error.UnsupportedRegister, // r16 - r31 (APX)
259 33 => return error.UnsupportedRegister, // ELR_mode
260 34 => return error.UnsupportedRegister, // RA_SIGN_STATE
261 35 => return error.UnsupportedRegister, // TPIDRRO_ELO
262 36 => return error.UnsupportedRegister, // TPIDR_ELO
263 37 => return error.UnsupportedRegister, // TPIDR_EL1
264 38 => return error.UnsupportedRegister, // TPIDR_EL2
265 39 => return error.UnsupportedRegister, // TPIDR_EL3
266 40...45 => return error.UnsupportedRegister, // Reserved
267 46 => return error.UnsupportedRegister, // VG
268 47 => return error.UnsupportedRegister, // FFR
269 48...63 => return error.UnsupportedRegister, // P0 - P15
270 64...95 => return error.UnsupportedRegister, // V0 - V31
271 96...127 => return error.UnsupportedRegister, // Z0 - Z31
338272
339273 else => return error.InvalidRegister,
340274 }
......@@ -410,11 +344,11 @@ const Arm = struct {
410344 pub inline fn current() Arm {
411345 var ctx: Arm = undefined;
412346 asm volatile (
413 \\// For compatibility with Thumb, we can't write r13 (sp) or r15 (pc) with stm.
414 \\stm r0, {r0-r12}
415 \\str r13, [r0, #0x34]
416 \\str r14, [r0, #0x38]
417 \\str r15, [r0, #0x3c]
347 \\ // For compatibility with Thumb, we can't write r13 (sp) or r15 (pc) with stm.
348 \\ stm r0, {r0-r12}
349 \\ str r13, [r0, #0x34]
350 \\ str r14, [r0, #0x38]
351 \\ str r15, [r0, #0x3c]
418352 :
419353 : [r] "{r0}" (&ctx.r),
420354 : .{ .memory = true });
......@@ -461,69 +395,6 @@ const Arm = struct {
461395 }
462396};
463397
464/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
465const Aarch64 = extern struct {
466 /// The numbered general-purpose registers X0 - X30.
467 x: [31]u64,
468 sp: u64,
469 pc: u64,
470
471 pub inline fn current() Aarch64 {
472 var ctx: Aarch64 = undefined;
473 asm volatile (
474 \\stp x0, x1, [x0, #0x000]
475 \\stp x2, x3, [x0, #0x010]
476 \\stp x4, x5, [x0, #0x020]
477 \\stp x6, x7, [x0, #0x030]
478 \\stp x8, x9, [x0, #0x040]
479 \\stp x10, x11, [x0, #0x050]
480 \\stp x12, x13, [x0, #0x060]
481 \\stp x14, x15, [x0, #0x070]
482 \\stp x16, x17, [x0, #0x080]
483 \\stp x18, x19, [x0, #0x090]
484 \\stp x20, x21, [x0, #0x0a0]
485 \\stp x22, x23, [x0, #0x0b0]
486 \\stp x24, x25, [x0, #0x0c0]
487 \\stp x26, x27, [x0, #0x0d0]
488 \\stp x28, x29, [x0, #0x0e0]
489 \\str x30, [x0, #0x0f0]
490 \\mov x1, sp
491 \\str x1, [x0, #0x0f8]
492 \\adr x1, .
493 \\str x1, [x0, #0x100]
494 \\ldr x1, [x0, #0x008]
495 :
496 : [gprs] "{x0}" (&ctx),
497 : .{ .memory = true });
498 return ctx;
499 }
500
501 pub fn dwarfRegisterBytes(ctx: *Aarch64, register_num: u16) DwarfRegisterError![]u8 {
502 // DWARF for the Arm(r) 64-bit Architecture (AArch64) § 4.1 "DWARF register names"
503 switch (register_num) {
504 0...30 => return @ptrCast(&ctx.x[register_num]),
505 31 => return @ptrCast(&ctx.sp),
506 32 => return @ptrCast(&ctx.pc),
507
508 33 => return error.UnsupportedRegister, // ELR_mode
509 34 => return error.UnsupportedRegister, // RA_SIGN_STATE
510 35 => return error.UnsupportedRegister, // TPIDRRO_ELO
511 36 => return error.UnsupportedRegister, // TPIDR_ELO
512 37 => return error.UnsupportedRegister, // TPIDR_EL1
513 38 => return error.UnsupportedRegister, // TPIDR_EL2
514 39 => return error.UnsupportedRegister, // TPIDR_EL3
515 40...45 => return error.UnsupportedRegister, // Reserved
516 46 => return error.UnsupportedRegister, // VG
517 47 => return error.UnsupportedRegister, // FFR
518 48...63 => return error.UnsupportedRegister, // P0 - P15
519 64...95 => return error.UnsupportedRegister, // V0 - V31
520 96...127 => return error.UnsupportedRegister, // Z0 - Z31
521
522 else => return error.InvalidRegister,
523 }
524 }
525};
526
527398/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
528399const Csky = extern struct {
529400 /// The numbered general-purpose registers r0 - r31.
......@@ -600,7 +471,7 @@ const Hexagon = extern struct {
600471 \\ memw(r0 + #128) = r1
601472 \\ r1 = memw(r0 + #4)
602473 :
603 : [gprs] "{r0}" (&ctx),
474 : [ctx] "{r0}" (&ctx),
604475 : .{ .memory = true });
605476 return ctx;
606477 }
......@@ -762,7 +633,7 @@ const LoongArch = extern struct {
762633 \\ st.w $ra, $t0, 128
763634 \\ ld.w $ra, $t0, 4
764635 :
765 : [gprs] "{$r12}" (&ctx),
636 : [ctx] "{$r12}" (&ctx),
766637 : .{ .memory = true });
767638 return ctx;
768639 }
......@@ -908,7 +779,7 @@ const Mips = extern struct {
908779 \\ lw $ra, 124($t4)
909780 \\ .set pop
910781 :
911 : [gprs] "{$12}" (&ctx),
782 : [ctx] "{$12}" (&ctx),
912783 : .{ .memory = true });
913784 return ctx;
914785 }
......@@ -1087,7 +958,7 @@ const Powerpc = extern struct {
1087958 \\ stw 8, 128(10)
1088959 \\ lwz 8, 32(10)
1089960 :
1090 : [gprs] "{r10}" (&ctx),
961 : [ctx] "{r10}" (&ctx),
1091962 : .{ .lr = true, .memory = true });
1092963 return ctx;
1093964 }
......@@ -1151,104 +1022,6 @@ const Powerpc = extern struct {
11511022 }
11521023};
11531024
1154/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
1155const Sparc = extern struct {
1156 g: [8]Gpr,
1157 o: [8]Gpr,
1158 l: [8]Gpr,
1159 i: [8]Gpr,
1160 pc: Gpr,
1161
1162 pub const Gpr = if (native_arch == .sparc64) u64 else u32;
1163
1164 pub inline fn current() Sparc {
1165 flushWindows();
1166
1167 var ctx: Sparc = undefined;
1168 asm volatile (if (Gpr == u64)
1169 \\ stx %g0, [%l0 + 0]
1170 \\ stx %g1, [%l0 + 8]
1171 \\ stx %g2, [%l0 + 16]
1172 \\ stx %g3, [%l0 + 24]
1173 \\ stx %g4, [%l0 + 32]
1174 \\ stx %g5, [%l0 + 40]
1175 \\ stx %g6, [%l0 + 48]
1176 \\ stx %g7, [%l0 + 56]
1177 \\ stx %o0, [%l0 + 64]
1178 \\ stx %o1, [%l0 + 72]
1179 \\ stx %o2, [%l0 + 80]
1180 \\ stx %o3, [%l0 + 88]
1181 \\ stx %o4, [%l0 + 96]
1182 \\ stx %o5, [%l0 + 104]
1183 \\ stx %o6, [%l0 + 112]
1184 \\ stx %o7, [%l0 + 120]
1185 \\ stx %l0, [%l0 + 128]
1186 \\ stx %l1, [%l0 + 136]
1187 \\ stx %l2, [%l0 + 144]
1188 \\ stx %l3, [%l0 + 152]
1189 \\ stx %l4, [%l0 + 160]
1190 \\ stx %l5, [%l0 + 168]
1191 \\ stx %l6, [%l0 + 176]
1192 \\ stx %l7, [%l0 + 184]
1193 \\ stx %i0, [%l0 + 192]
1194 \\ stx %i1, [%l0 + 200]
1195 \\ stx %i2, [%l0 + 208]
1196 \\ stx %i3, [%l0 + 216]
1197 \\ stx %i4, [%l0 + 224]
1198 \\ stx %i5, [%l0 + 232]
1199 \\ stx %i6, [%l0 + 240]
1200 \\ stx %i7, [%l0 + 248]
1201 \\ call 1f
1202 \\ stx %o7, [%l0 + 256]
1203 \\1:
1204 else
1205 \\ std %g0, [%l0 + 0]
1206 \\ std %g2, [%l0 + 8]
1207 \\ std %g4, [%l0 + 16]
1208 \\ std %g6, [%l0 + 24]
1209 \\ std %o0, [%l0 + 32]
1210 \\ std %o2, [%l0 + 40]
1211 \\ std %o4, [%l0 + 48]
1212 \\ std %o6, [%l0 + 56]
1213 \\ std %l0, [%l0 + 64]
1214 \\ std %l2, [%l0 + 72]
1215 \\ std %l4, [%l0 + 80]
1216 \\ std %l6, [%l0 + 88]
1217 \\ std %i0, [%l0 + 96]
1218 \\ std %i2, [%l0 + 104]
1219 \\ std %i4, [%l0 + 112]
1220 \\ std %i6, [%l0 + 120]
1221 \\ call 1f
1222 \\ st %o7, [%l0 + 128]
1223 \\1:
1224 :
1225 : [gprs] "{l0}" (&ctx),
1226 : .{ .o7 = true, .memory = true });
1227 return ctx;
1228 }
1229
1230 noinline fn flushWindows() void {
1231 // Flush all register windows except the current one (hence `noinline`). This ensures that
1232 // we actually see meaningful data on the stack when we walk the frame chain.
1233 if (comptime builtin.target.cpu.has(.sparc, .v9))
1234 asm volatile ("flushw" ::: .{ .memory = true })
1235 else
1236 asm volatile ("ta 3" ::: .{ .memory = true }); // ST_FLUSH_WINDOWS
1237 }
1238
1239 pub fn dwarfRegisterBytes(ctx: *Sparc, register_num: u16) DwarfRegisterError![]u8 {
1240 switch (register_num) {
1241 0...7 => return @ptrCast(&ctx.g[register_num]),
1242 8...15 => return @ptrCast(&ctx.o[register_num - 8]),
1243 16...23 => return @ptrCast(&ctx.l[register_num - 16]),
1244 24...31 => return @ptrCast(&ctx.i[register_num - 24]),
1245 32 => return @ptrCast(&ctx.pc),
1246
1247 else => return error.InvalidRegister,
1248 }
1249 }
1250};
1251
12521025/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
12531026const Riscv = extern struct {
12541027 /// The numbered general-purpose registers r0 - r31. r0 must be zero.
......@@ -1334,7 +1107,7 @@ const Riscv = extern struct {
13341107 \\ sw ra, 128(t0)
13351108 \\ lw ra, 4(t0)
13361109 :
1337 : [gprs] "{t0}" (&ctx),
1110 : [ctx] "{t0}" (&ctx),
13381111 : .{ .memory = true });
13391112 return ctx;
13401113 }
......@@ -1376,7 +1149,7 @@ const S390x = extern struct {
13761149 \\ lg %%r0, 0(%%r2)
13771150 \\ lg %%r1, 8(%%r2)
13781151 :
1379 : [gprs] "{r2}" (&ctx),
1152 : [ctx] "{r2}" (&ctx),
13801153 : .{ .memory = true });
13811154 return ctx;
13821155 }
......@@ -1398,6 +1171,104 @@ const S390x = extern struct {
13981171 }
13991172};
14001173
1174/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
1175const Sparc = extern struct {
1176 g: [8]Gpr,
1177 o: [8]Gpr,
1178 l: [8]Gpr,
1179 i: [8]Gpr,
1180 pc: Gpr,
1181
1182 pub const Gpr = if (native_arch == .sparc64) u64 else u32;
1183
1184 pub inline fn current() Sparc {
1185 flushWindows();
1186
1187 var ctx: Sparc = undefined;
1188 asm volatile (if (Gpr == u64)
1189 \\ stx %g0, [%l0 + 0]
1190 \\ stx %g1, [%l0 + 8]
1191 \\ stx %g2, [%l0 + 16]
1192 \\ stx %g3, [%l0 + 24]
1193 \\ stx %g4, [%l0 + 32]
1194 \\ stx %g5, [%l0 + 40]
1195 \\ stx %g6, [%l0 + 48]
1196 \\ stx %g7, [%l0 + 56]
1197 \\ stx %o0, [%l0 + 64]
1198 \\ stx %o1, [%l0 + 72]
1199 \\ stx %o2, [%l0 + 80]
1200 \\ stx %o3, [%l0 + 88]
1201 \\ stx %o4, [%l0 + 96]
1202 \\ stx %o5, [%l0 + 104]
1203 \\ stx %o6, [%l0 + 112]
1204 \\ stx %o7, [%l0 + 120]
1205 \\ stx %l0, [%l0 + 128]
1206 \\ stx %l1, [%l0 + 136]
1207 \\ stx %l2, [%l0 + 144]
1208 \\ stx %l3, [%l0 + 152]
1209 \\ stx %l4, [%l0 + 160]
1210 \\ stx %l5, [%l0 + 168]
1211 \\ stx %l6, [%l0 + 176]
1212 \\ stx %l7, [%l0 + 184]
1213 \\ stx %i0, [%l0 + 192]
1214 \\ stx %i1, [%l0 + 200]
1215 \\ stx %i2, [%l0 + 208]
1216 \\ stx %i3, [%l0 + 216]
1217 \\ stx %i4, [%l0 + 224]
1218 \\ stx %i5, [%l0 + 232]
1219 \\ stx %i6, [%l0 + 240]
1220 \\ stx %i7, [%l0 + 248]
1221 \\ call 1f
1222 \\ stx %o7, [%l0 + 256]
1223 \\1:
1224 else
1225 \\ std %g0, [%l0 + 0]
1226 \\ std %g2, [%l0 + 8]
1227 \\ std %g4, [%l0 + 16]
1228 \\ std %g6, [%l0 + 24]
1229 \\ std %o0, [%l0 + 32]
1230 \\ std %o2, [%l0 + 40]
1231 \\ std %o4, [%l0 + 48]
1232 \\ std %o6, [%l0 + 56]
1233 \\ std %l0, [%l0 + 64]
1234 \\ std %l2, [%l0 + 72]
1235 \\ std %l4, [%l0 + 80]
1236 \\ std %l6, [%l0 + 88]
1237 \\ std %i0, [%l0 + 96]
1238 \\ std %i2, [%l0 + 104]
1239 \\ std %i4, [%l0 + 112]
1240 \\ std %i6, [%l0 + 120]
1241 \\ call 1f
1242 \\ st %o7, [%l0 + 128]
1243 \\1:
1244 :
1245 : [ctx] "{l0}" (&ctx),
1246 : .{ .o7 = true, .memory = true });
1247 return ctx;
1248 }
1249
1250 noinline fn flushWindows() void {
1251 // Flush all register windows except the current one (hence `noinline`). This ensures that
1252 // we actually see meaningful data on the stack when we walk the frame chain.
1253 if (comptime builtin.target.cpu.has(.sparc, .v9))
1254 asm volatile ("flushw" ::: .{ .memory = true })
1255 else
1256 asm volatile ("ta 3" ::: .{ .memory = true }); // ST_FLUSH_WINDOWS
1257 }
1258
1259 pub fn dwarfRegisterBytes(ctx: *Sparc, register_num: u16) DwarfRegisterError![]u8 {
1260 switch (register_num) {
1261 0...7 => return @ptrCast(&ctx.g[register_num]),
1262 8...15 => return @ptrCast(&ctx.o[register_num - 8]),
1263 16...23 => return @ptrCast(&ctx.l[register_num - 16]),
1264 24...31 => return @ptrCast(&ctx.i[register_num - 24]),
1265 32 => return @ptrCast(&ctx.pc),
1266
1267 else => return error.InvalidRegister,
1268 }
1269 }
1270};
1271
14011272/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
14021273const Ve = extern struct {
14031274 s: [64]u64,
......@@ -1492,6 +1363,135 @@ const Ve = extern struct {
14921363 }
14931364};
14941365
1366const X86 = struct {
1367 /// The first 8 registers here intentionally match the order of registers in the x86 instruction
1368 /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings,
1369 /// among other things.
1370 pub const Gpr = enum {
1371 // zig fmt: off
1372 eax, ecx, edx, ebx,
1373 esp, ebp, esi, edi,
1374 eip,
1375 // zig fmt: on
1376 };
1377 gprs: std.enums.EnumArray(Gpr, u32),
1378
1379 pub inline fn current() X86 {
1380 var ctx: X86 = undefined;
1381 asm volatile (
1382 \\ movl %%eax, 0x00(%%edi)
1383 \\ movl %%ecx, 0x04(%%edi)
1384 \\ movl %%edx, 0x08(%%edi)
1385 \\ movl %%ebx, 0x0c(%%edi)
1386 \\ movl %%esp, 0x10(%%edi)
1387 \\ movl %%ebp, 0x14(%%edi)
1388 \\ movl %%esi, 0x18(%%edi)
1389 \\ movl %%edi, 0x1c(%%edi)
1390 \\ call 1f
1391 \\1:
1392 \\ popl 0x20(%%edi)
1393 :
1394 : [gprs] "{edi}" (&ctx.gprs.values),
1395 : .{ .memory = true });
1396 return ctx;
1397 }
1398
1399 pub fn dwarfRegisterBytes(ctx: *X86, register_num: u16) DwarfRegisterError![]u8 {
1400 // System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.1
1401 // § 2.4.2 "DWARF Register Number Mapping"
1402 switch (register_num) {
1403 // The order of `Gpr` intentionally matches DWARF's mappings.
1404 //
1405 // x86-macos sometimes uses different mappings (ebp and esp are reversed when the unwind
1406 // information is from `__eh_frame`). This deviation is not considered here, because
1407 // x86-macos is a deprecated target which is not supported by the Zig Standard Library.
1408 0...8 => return @ptrCast(&ctx.gprs.values[register_num]),
1409
1410 9 => return error.UnsupportedRegister, // eflags
1411 11...18 => return error.UnsupportedRegister, // st0 - st7
1412 21...28 => return error.UnsupportedRegister, // xmm0 - xmm7
1413 29...36 => return error.UnsupportedRegister, // mm0 - mm7
1414 39 => return error.UnsupportedRegister, // mxcsr
1415 40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
1416 48 => return error.UnsupportedRegister, // tr
1417 49 => return error.UnsupportedRegister, // ldtr
1418 93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
1419
1420 else => return error.InvalidRegister,
1421 }
1422 }
1423};
1424
1425const X86_64 = struct {
1426 /// The order here intentionally matches the order of the DWARF register mappings. It's unclear
1427 /// where those mappings actually originated from---the ordering of the first 4 registers seems
1428 /// quite unusual---but it is currently convenient for us to match DWARF.
1429 pub const Gpr = enum {
1430 // zig fmt: off
1431 rax, rdx, rcx, rbx,
1432 rsi, rdi, rbp, rsp,
1433 r8, r9, r10, r11,
1434 r12, r13, r14, r15,
1435 rip,
1436 // zig fmt: on
1437 };
1438 gprs: std.enums.EnumArray(Gpr, u64),
1439
1440 pub inline fn current() X86_64 {
1441 var ctx: X86_64 = undefined;
1442 asm volatile (
1443 \\ movq %%rax, 0x00(%%rdi)
1444 \\ movq %%rdx, 0x08(%%rdi)
1445 \\ movq %%rcx, 0x10(%%rdi)
1446 \\ movq %%rbx, 0x18(%%rdi)
1447 \\ movq %%rsi, 0x20(%%rdi)
1448 \\ movq %%rdi, 0x28(%%rdi)
1449 \\ movq %%rbp, 0x30(%%rdi)
1450 \\ movq %%rsp, 0x38(%%rdi)
1451 \\ movq %%r8, 0x40(%%rdi)
1452 \\ movq %%r9, 0x48(%%rdi)
1453 \\ movq %%r10, 0x50(%%rdi)
1454 \\ movq %%r11, 0x58(%%rdi)
1455 \\ movq %%r12, 0x60(%%rdi)
1456 \\ movq %%r13, 0x68(%%rdi)
1457 \\ movq %%r14, 0x70(%%rdi)
1458 \\ movq %%r15, 0x78(%%rdi)
1459 \\ leaq (%%rip), %%rax
1460 \\ movq %%rax, 0x80(%%rdi)
1461 \\ movq 0x00(%%rdi), %%rax
1462 :
1463 : [gprs] "{rdi}" (&ctx.gprs.values),
1464 : .{ .memory = true });
1465 return ctx;
1466 }
1467
1468 pub fn dwarfRegisterBytes(ctx: *X86_64, register_num: u16) DwarfRegisterError![]u8 {
1469 // System V Application Binary Interface AMD64 Architecture Processor Supplement
1470 // § 3.6.2 "DWARF Register Number Mapping"
1471 switch (register_num) {
1472 // The order of `Gpr` intentionally matches DWARF's mappings.
1473 0...16 => return @ptrCast(&ctx.gprs.values[register_num]),
1474
1475 17...32 => return error.UnsupportedRegister, // xmm0 - xmm15
1476 33...40 => return error.UnsupportedRegister, // st0 - st7
1477 41...48 => return error.UnsupportedRegister, // mm0 - mm7
1478 49 => return error.UnsupportedRegister, // rflags
1479 50...55 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
1480 58...59 => return error.UnsupportedRegister, // fs.base, gs.base
1481 62 => return error.UnsupportedRegister, // tr
1482 63 => return error.UnsupportedRegister, // ldtr
1483 64 => return error.UnsupportedRegister, // mxcsr
1484 65 => return error.UnsupportedRegister, // fcw
1485 66 => return error.UnsupportedRegister, // fsw
1486 67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512)
1487 118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
1488 130...145 => return error.UnsupportedRegister, // r16 - r31 (APX)
1489
1490 else => return error.InvalidRegister,
1491 }
1492 }
1493};
1494
14951495/// The native operating system's `ucontext_t` as seen in the third argument to signal handlers.
14961496///
14971497/// These are dramatically simplified since we only need general-purpose registers and don't care