| ... | @@ -212,129 +212,63 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native { | ... | @@ -212,129 +212,63 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native { |
| 212 | }; | 212 | }; |
| 213 | } | 213 | } |
| 214 | | 214 | |
| 215 | const X86 = struct { | 215 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 216 | /// The first 8 registers here intentionally match the order of registers in the x86 instruction | 216 | const Aarch64 = extern struct { |
| 217 | /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings, | 217 | /// The numbered general-purpose registers X0 - X30. |
| 218 | /// among other things. | 218 | x: [31]u64, |
| 219 | pub const Gpr = enum { | 219 | sp: u64, |
| 220 | // zig fmt: off | 220 | pc: u64, |
| 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 | | | |
| 274 | const 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), | | |
| 288 | | 221 | |
| 289 | pub inline fn current() X86_64 { | 222 | pub inline fn current() Aarch64 { |
| 290 | var ctx: X86_64 = undefined; | 223 | var ctx: Aarch64 = undefined; |
| 291 | asm volatile ( | 224 | asm volatile ( |
| 292 | \\movq %%rax, 0x00(%%rdi) | 225 | \\ stp x0, x1, [x0, #0x000] |
| 293 | \\movq %%rdx, 0x08(%%rdi) | 226 | \\ stp x2, x3, [x0, #0x010] |
| 294 | \\movq %%rcx, 0x10(%%rdi) | 227 | \\ stp x4, x5, [x0, #0x020] |
| 295 | \\movq %%rbx, 0x18(%%rdi) | 228 | \\ stp x6, x7, [x0, #0x030] |
| 296 | \\movq %%rsi, 0x20(%%rdi) | 229 | \\ stp x8, x9, [x0, #0x040] |
| 297 | \\movq %%rdi, 0x28(%%rdi) | 230 | \\ stp x10, x11, [x0, #0x050] |
| 298 | \\movq %%rbp, 0x30(%%rdi) | 231 | \\ stp x12, x13, [x0, #0x060] |
| 299 | \\movq %%rsp, 0x38(%%rdi) | 232 | \\ stp x14, x15, [x0, #0x070] |
| 300 | \\movq %%r8, 0x40(%%rdi) | 233 | \\ stp x16, x17, [x0, #0x080] |
| 301 | \\movq %%r9, 0x48(%%rdi) | 234 | \\ stp x18, x19, [x0, #0x090] |
| 302 | \\movq %%r10, 0x50(%%rdi) | 235 | \\ stp x20, x21, [x0, #0x0a0] |
| 303 | \\movq %%r11, 0x58(%%rdi) | 236 | \\ stp x22, x23, [x0, #0x0b0] |
| 304 | \\movq %%r12, 0x60(%%rdi) | 237 | \\ stp x24, x25, [x0, #0x0c0] |
| 305 | \\movq %%r13, 0x68(%%rdi) | 238 | \\ stp x26, x27, [x0, #0x0d0] |
| 306 | \\movq %%r14, 0x70(%%rdi) | 239 | \\ stp x28, x29, [x0, #0x0e0] |
| 307 | \\movq %%r15, 0x78(%%rdi) | 240 | \\ str x30, [x0, #0x0f0] |
| 308 | \\leaq (%%rip), %%rax | 241 | \\ mov x1, sp |
| 309 | \\movq %%rax, 0x80(%%rdi) | 242 | \\ str x1, [x0, #0x0f8] |
| 310 | \\movq 0x00(%%rdi), %%rax | 243 | \\ adr x1, . |
| | 244 | \\ str x1, [x0, #0x100] |
| | 245 | \\ ldr x1, [x0, #0x008] |
| 311 | : | 246 | : |
| 312 | : [gprs] "{rdi}" (&ctx.gprs.values), | 247 | : [ctx] "{x0}" (&ctx), |
| 313 | : .{ .memory = true }); | 248 | : .{ .memory = true }); |
| 314 | return ctx; | 249 | return ctx; |
| 315 | } | 250 | } |
| 316 | | 251 | |
| 317 | pub fn dwarfRegisterBytes(ctx: *X86_64, register_num: u16) DwarfRegisterError![]u8 { | 252 | pub fn dwarfRegisterBytes(ctx: *Aarch64, register_num: u16) DwarfRegisterError![]u8 { |
| 318 | // System V Application Binary Interface AMD64 Architecture Processor Supplement | 253 | // DWARF for the Arm(r) 64-bit Architecture (AArch64) § 4.1 "DWARF register names" |
| 319 | // § 3.6.2 "DWARF Register Number Mapping" | | |
| 320 | switch (register_num) { | 254 | switch (register_num) { |
| 321 | // The order of `Gpr` intentionally matches DWARF's mappings. | 255 | 0...30 => return @ptrCast(&ctx.x[register_num]), |
| 322 | 0...16 => return @ptrCast(&ctx.gprs.values[register_num]), | 256 | 31 => return @ptrCast(&ctx.sp), |
| | 257 | 32 => return @ptrCast(&ctx.pc), |
| 323 | | 258 | |
| 324 | 17...32 => return error.UnsupportedRegister, // xmm0 - xmm15 | 259 | 33 => return error.UnsupportedRegister, // ELR_mode |
| 325 | 33...40 => return error.UnsupportedRegister, // st0 - st7 | 260 | 34 => return error.UnsupportedRegister, // RA_SIGN_STATE |
| 326 | 41...48 => return error.UnsupportedRegister, // mm0 - mm7 | 261 | 35 => return error.UnsupportedRegister, // TPIDRRO_ELO |
| 327 | 49 => return error.UnsupportedRegister, // rflags | 262 | 36 => return error.UnsupportedRegister, // TPIDR_ELO |
| 328 | 50...55 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs | 263 | 37 => return error.UnsupportedRegister, // TPIDR_EL1 |
| 329 | 58...59 => return error.UnsupportedRegister, // fs.base, gs.base | 264 | 38 => return error.UnsupportedRegister, // TPIDR_EL2 |
| 330 | 62 => return error.UnsupportedRegister, // tr | 265 | 39 => return error.UnsupportedRegister, // TPIDR_EL3 |
| 331 | 63 => return error.UnsupportedRegister, // ldtr | 266 | 40...45 => return error.UnsupportedRegister, // Reserved |
| 332 | 64 => return error.UnsupportedRegister, // mxcsr | 267 | 46 => return error.UnsupportedRegister, // VG |
| 333 | 65 => return error.UnsupportedRegister, // fcw | 268 | 47 => return error.UnsupportedRegister, // FFR |
| 334 | 66 => return error.UnsupportedRegister, // fsw | 269 | 48...63 => return error.UnsupportedRegister, // P0 - P15 |
| 335 | 67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512) | 270 | 64...95 => return error.UnsupportedRegister, // V0 - V31 |
| 336 | 118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512) | 271 | 96...127 => return error.UnsupportedRegister, // Z0 - Z31 |
| 337 | 130...145 => return error.UnsupportedRegister, // r16 - r31 (APX) | | |
| 338 | | 272 | |
| 339 | else => return error.InvalidRegister, | 273 | else => return error.InvalidRegister, |
| 340 | } | 274 | } |
| ... | @@ -410,11 +344,11 @@ const Arm = struct { | ... | @@ -410,11 +344,11 @@ const Arm = struct { |
| 410 | pub inline fn current() Arm { | 344 | pub inline fn current() Arm { |
| 411 | var ctx: Arm = undefined; | 345 | var ctx: Arm = undefined; |
| 412 | asm volatile ( | 346 | asm volatile ( |
| 413 | \\// For compatibility with Thumb, we can't write r13 (sp) or r15 (pc) with stm. | 347 | \\ // For compatibility with Thumb, we can't write r13 (sp) or r15 (pc) with stm. |
| 414 | \\stm r0, {r0-r12} | 348 | \\ stm r0, {r0-r12} |
| 415 | \\str r13, [r0, #0x34] | 349 | \\ str r13, [r0, #0x34] |
| 416 | \\str r14, [r0, #0x38] | 350 | \\ str r14, [r0, #0x38] |
| 417 | \\str r15, [r0, #0x3c] | 351 | \\ str r15, [r0, #0x3c] |
| 418 | : | 352 | : |
| 419 | : [r] "{r0}" (&ctx.r), | 353 | : [r] "{r0}" (&ctx.r), |
| 420 | : .{ .memory = true }); | 354 | : .{ .memory = true }); |
| ... | @@ -461,69 +395,6 @@ const Arm = struct { | ... | @@ -461,69 +395,6 @@ const Arm = struct { |
| 461 | } | 395 | } |
| 462 | }; | 396 | }; |
| 463 | | 397 | |
| 464 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. | | |
| 465 | const 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 | | | |
| 527 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. | 398 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 528 | const Csky = extern struct { | 399 | const Csky = extern struct { |
| 529 | /// The numbered general-purpose registers r0 - r31. | 400 | /// The numbered general-purpose registers r0 - r31. |
| ... | @@ -600,7 +471,7 @@ const Hexagon = extern struct { | ... | @@ -600,7 +471,7 @@ const Hexagon = extern struct { |
| 600 | \\ memw(r0 + #128) = r1 | 471 | \\ memw(r0 + #128) = r1 |
| 601 | \\ r1 = memw(r0 + #4) | 472 | \\ r1 = memw(r0 + #4) |
| 602 | : | 473 | : |
| 603 | : [gprs] "{r0}" (&ctx), | 474 | : [ctx] "{r0}" (&ctx), |
| 604 | : .{ .memory = true }); | 475 | : .{ .memory = true }); |
| 605 | return ctx; | 476 | return ctx; |
| 606 | } | 477 | } |
| ... | @@ -762,7 +633,7 @@ const LoongArch = extern struct { | ... | @@ -762,7 +633,7 @@ const LoongArch = extern struct { |
| 762 | \\ st.w $ra, $t0, 128 | 633 | \\ st.w $ra, $t0, 128 |
| 763 | \\ ld.w $ra, $t0, 4 | 634 | \\ ld.w $ra, $t0, 4 |
| 764 | : | 635 | : |
| 765 | : [gprs] "{$r12}" (&ctx), | 636 | : [ctx] "{$r12}" (&ctx), |
| 766 | : .{ .memory = true }); | 637 | : .{ .memory = true }); |
| 767 | return ctx; | 638 | return ctx; |
| 768 | } | 639 | } |
| ... | @@ -908,7 +779,7 @@ const Mips = extern struct { | ... | @@ -908,7 +779,7 @@ const Mips = extern struct { |
| 908 | \\ lw $ra, 124($t4) | 779 | \\ lw $ra, 124($t4) |
| 909 | \\ .set pop | 780 | \\ .set pop |
| 910 | : | 781 | : |
| 911 | : [gprs] "{$12}" (&ctx), | 782 | : [ctx] "{$12}" (&ctx), |
| 912 | : .{ .memory = true }); | 783 | : .{ .memory = true }); |
| 913 | return ctx; | 784 | return ctx; |
| 914 | } | 785 | } |
| ... | @@ -1087,7 +958,7 @@ const Powerpc = extern struct { | ... | @@ -1087,7 +958,7 @@ const Powerpc = extern struct { |
| 1087 | \\ stw 8, 128(10) | 958 | \\ stw 8, 128(10) |
| 1088 | \\ lwz 8, 32(10) | 959 | \\ lwz 8, 32(10) |
| 1089 | : | 960 | : |
| 1090 | : [gprs] "{r10}" (&ctx), | 961 | : [ctx] "{r10}" (&ctx), |
| 1091 | : .{ .lr = true, .memory = true }); | 962 | : .{ .lr = true, .memory = true }); |
| 1092 | return ctx; | 963 | return ctx; |
| 1093 | } | 964 | } |
| ... | @@ -1151,104 +1022,6 @@ const Powerpc = extern struct { | ... | @@ -1151,104 +1022,6 @@ const Powerpc = extern struct { |
| 1151 | } | 1022 | } |
| 1152 | }; | 1023 | }; |
| 1153 | | 1024 | |
| 1154 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. | | |
| 1155 | const 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 | | | |
| 1252 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. | 1025 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 1253 | const Riscv = extern struct { | 1026 | const Riscv = extern struct { |
| 1254 | /// The numbered general-purpose registers r0 - r31. r0 must be zero. | 1027 | /// The numbered general-purpose registers r0 - r31. r0 must be zero. |
| ... | @@ -1334,7 +1107,7 @@ const Riscv = extern struct { | ... | @@ -1334,7 +1107,7 @@ const Riscv = extern struct { |
| 1334 | \\ sw ra, 128(t0) | 1107 | \\ sw ra, 128(t0) |
| 1335 | \\ lw ra, 4(t0) | 1108 | \\ lw ra, 4(t0) |
| 1336 | : | 1109 | : |
| 1337 | : [gprs] "{t0}" (&ctx), | 1110 | : [ctx] "{t0}" (&ctx), |
| 1338 | : .{ .memory = true }); | 1111 | : .{ .memory = true }); |
| 1339 | return ctx; | 1112 | return ctx; |
| 1340 | } | 1113 | } |
| ... | @@ -1376,7 +1149,7 @@ const S390x = extern struct { | ... | @@ -1376,7 +1149,7 @@ const S390x = extern struct { |
| 1376 | \\ lg %%r0, 0(%%r2) | 1149 | \\ lg %%r0, 0(%%r2) |
| 1377 | \\ lg %%r1, 8(%%r2) | 1150 | \\ lg %%r1, 8(%%r2) |
| 1378 | : | 1151 | : |
| 1379 | : [gprs] "{r2}" (&ctx), | 1152 | : [ctx] "{r2}" (&ctx), |
| 1380 | : .{ .memory = true }); | 1153 | : .{ .memory = true }); |
| 1381 | return ctx; | 1154 | return ctx; |
| 1382 | } | 1155 | } |
| ... | @@ -1398,6 +1171,104 @@ const S390x = extern struct { | ... | @@ -1398,6 +1171,104 @@ const S390x = extern struct { |
| 1398 | } | 1171 | } |
| 1399 | }; | 1172 | }; |
| 1400 | | 1173 | |
| | 1174 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| | 1175 | const 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 | |
| 1401 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. | 1272 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 1402 | const Ve = extern struct { | 1273 | const Ve = extern struct { |
| 1403 | s: [64]u64, | 1274 | s: [64]u64, |
| ... | @@ -1492,6 +1363,135 @@ const Ve = extern struct { | ... | @@ -1492,6 +1363,135 @@ const Ve = extern struct { |
| 1492 | } | 1363 | } |
| 1493 | }; | 1364 | }; |
| 1494 | | 1365 | |
| | 1366 | const 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 | |
| | 1425 | const 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 | |
| 1495 | /// The native operating system's `ucontext_t` as seen in the third argument to signal handlers. | 1495 | /// The native operating system's `ucontext_t` as seen in the third argument to signal handlers. |
| 1496 | /// | 1496 | /// |
| 1497 | /// These are dramatically simplified since we only need general-purpose registers and don't care | 1497 | /// These are dramatically simplified since we only need general-purpose registers and don't care |