| ... | ... | @@ -5,13 +5,19 @@ pub const Native = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "CpuCont |
| 5 | 5 | root.debug.CpuContext |
| 6 | 6 | else switch (native_arch) { |
| 7 | 7 | .aarch64, .aarch64_be => Aarch64, |
| 8 | .arc => Arc, |
| 8 | 9 | .arm, .armeb, .thumb, .thumbeb => Arm, |
| 10 | .csky => Csky, |
| 9 | 11 | .hexagon => Hexagon, |
| 12 | .lanai => Lanai, |
| 10 | 13 | .loongarch32, .loongarch64 => LoongArch, |
| 14 | .m68k => M68k, |
| 11 | 15 | .mips, .mipsel, .mips64, .mips64el => Mips, |
| 16 | .or1k => Or1k, |
| 12 | 17 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => Powerpc, |
| 13 | 18 | .sparc, .sparc64 => Sparc, |
| 14 | 19 | .riscv32, .riscv32be, .riscv64, .riscv64be => Riscv, |
| 20 | .ve => Ve, |
| 15 | 21 | .s390x => S390x, |
| 16 | 22 | .x86 => X86, |
| 17 | 23 | .x86_64 => X86_64, |
| ... | ... | @@ -30,7 +36,20 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { |
| 30 | 36 | const uc: *const signal_ucontext_t = @ptrCast(@alignCast(ctx_ptr)); |
| 31 | 37 | |
| 32 | 38 | // Deal with some special cases first. |
| 33 | | if (native_arch.isMIPS32() and native_os == .linux) { |
| 39 | if (native_arch == .arc and native_os == .linux) { |
| 40 | var native: Native = .{ |
| 41 | .r = [_]u32{ uc.mcontext.r31, uc.mcontext.r30, 0, uc.mcontext.r28 } ++ |
| 42 | uc.mcontext.r27_26 ++ |
| 43 | uc.mcontext.r25_13 ++ |
| 44 | uc.mcontext.r12_0, |
| 45 | .pcl = uc.mcontext.pcl, |
| 46 | }; |
| 47 | |
| 48 | // I have no idea why the kernel is storing these registers in such a bizarre order... |
| 49 | std.mem.reverse(native.r[0..]); |
| 50 | |
| 51 | return native; |
| 52 | } else if (native_arch.isMIPS32() and native_os == .linux) { |
| 34 | 53 | // The O32 kABI uses 64-bit fields for some reason. |
| 35 | 54 | return .{ |
| 36 | 55 | .r = s: { |
| ... | ... | @@ -72,10 +91,22 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { |
| 72 | 91 | .sp = uc.mcontext.sp, |
| 73 | 92 | .pc = uc.mcontext.pc, |
| 74 | 93 | }, |
| 94 | .csky => .{ |
| 95 | .r = uc.mcontext.r0_13 ++ |
| 96 | [_]u32{ uc.mcontext.r14, uc.mcontext.r15 } ++ |
| 97 | uc.mcontext.r16_30 ++ |
| 98 | [_]u32{uc.mcontext.r31}, |
| 99 | .pc = uc.mcontext.pc, |
| 100 | }, |
| 75 | 101 | .hexagon, .loongarch32, .loongarch64, .mips, .mipsel, .mips64, .mips64el, .or1k => .{ |
| 76 | 102 | .r = uc.mcontext.r, |
| 77 | 103 | .pc = uc.mcontext.pc, |
| 78 | 104 | }, |
| 105 | .m68k => .{ |
| 106 | .d = uc.mcontext.d, |
| 107 | .a = uc.mcontext.a, |
| 108 | .pc = uc.mcontext.pc, |
| 109 | }, |
| 79 | 110 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => .{ |
| 80 | 111 | .r = uc.mcontext.r, |
| 81 | 112 | .pc = uc.mcontext.pc, |
| ... | ... | @@ -181,129 +212,124 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native { |
| 181 | 212 | }; |
| 182 | 213 | } |
| 183 | 214 | |
| 184 | | const X86 = struct { |
| 185 | | /// The first 8 registers here intentionally match the order of registers in the x86 instruction |
| 186 | | /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings, |
| 187 | | /// among other things. |
| 188 | | pub const Gpr = enum { |
| 189 | | // zig fmt: off |
| 190 | | eax, ecx, edx, ebx, |
| 191 | | esp, ebp, esi, edi, |
| 192 | | eip, |
| 193 | | // zig fmt: on |
| 194 | | }; |
| 195 | | gprs: std.enums.EnumArray(Gpr, u32), |
| 215 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 216 | const Aarch64 = extern struct { |
| 217 | /// The numbered general-purpose registers X0 - X30. |
| 218 | x: [31]u64, |
| 219 | sp: u64, |
| 220 | pc: u64, |
| 196 | 221 | |
| 197 | | pub inline fn current() X86 { |
| 198 | | var ctx: X86 = undefined; |
| 222 | pub inline fn current() Aarch64 { |
| 223 | var ctx: Aarch64 = undefined; |
| 199 | 224 | asm volatile ( |
| 200 | | \\movl %%eax, 0x00(%%edi) |
| 201 | | \\movl %%ecx, 0x04(%%edi) |
| 202 | | \\movl %%edx, 0x08(%%edi) |
| 203 | | \\movl %%ebx, 0x0c(%%edi) |
| 204 | | \\movl %%esp, 0x10(%%edi) |
| 205 | | \\movl %%ebp, 0x14(%%edi) |
| 206 | | \\movl %%esi, 0x18(%%edi) |
| 207 | | \\movl %%edi, 0x1c(%%edi) |
| 208 | | \\call 1f |
| 209 | | \\1: |
| 210 | | \\popl 0x20(%%edi) |
| 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] |
| 211 | 245 | : |
| 212 | | : [gprs] "{edi}" (&ctx.gprs.values), |
| 213 | | : .{ .memory = true }); |
| 246 | : [ctx] "{x0}" (&ctx), |
| 247 | : .{ .x1 = true, .memory = true }); |
| 214 | 248 | return ctx; |
| 215 | 249 | } |
| 216 | 250 | |
| 217 | | pub fn dwarfRegisterBytes(ctx: *X86, register_num: u16) DwarfRegisterError![]u8 { |
| 218 | | // System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.1 |
| 219 | | // § 2.4.2 "DWARF Register Number Mapping" |
| 251 | pub fn dwarfRegisterBytes(ctx: *Aarch64, register_num: u16) DwarfRegisterError![]u8 { |
| 252 | // DWARF for the Arm(r) 64-bit Architecture (AArch64) § 4.1 "DWARF register names" |
| 220 | 253 | switch (register_num) { |
| 221 | | // The order of `Gpr` intentionally matches DWARF's mappings. |
| 222 | | // |
| 223 | | // x86-macos sometimes uses different mappings (ebp and esp are reversed when the unwind |
| 224 | | // information is from `__eh_frame`). This deviation is not considered here, because |
| 225 | | // x86-macos is a deprecated target which is not supported by the Zig Standard Library. |
| 226 | | 0...8 => return @ptrCast(&ctx.gprs.values[register_num]), |
| 254 | 0...30 => return @ptrCast(&ctx.x[register_num]), |
| 255 | 31 => return @ptrCast(&ctx.sp), |
| 256 | 32 => return @ptrCast(&ctx.pc), |
| 227 | 257 | |
| 228 | | 9 => return error.UnsupportedRegister, // eflags |
| 229 | | 11...18 => return error.UnsupportedRegister, // st0 - st7 |
| 230 | | 21...28 => return error.UnsupportedRegister, // xmm0 - xmm7 |
| 231 | | 29...36 => return error.UnsupportedRegister, // mm0 - mm7 |
| 232 | | 39 => return error.UnsupportedRegister, // mxcsr |
| 233 | | 40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs |
| 234 | | 48 => return error.UnsupportedRegister, // tr |
| 235 | | 49 => return error.UnsupportedRegister, // ldtr |
| 236 | | 93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512) |
| 258 | 33 => return error.UnsupportedRegister, // ELR_mode |
| 259 | 34 => return error.UnsupportedRegister, // RA_SIGN_STATE |
| 260 | 35 => return error.UnsupportedRegister, // TPIDRRO_ELO |
| 261 | 36 => return error.UnsupportedRegister, // TPIDR_ELO |
| 262 | 37 => return error.UnsupportedRegister, // TPIDR_EL1 |
| 263 | 38 => return error.UnsupportedRegister, // TPIDR_EL2 |
| 264 | 39 => return error.UnsupportedRegister, // TPIDR_EL3 |
| 265 | 40...45 => return error.UnsupportedRegister, // Reserved |
| 266 | 46 => return error.UnsupportedRegister, // VG |
| 267 | 47 => return error.UnsupportedRegister, // FFR |
| 268 | 48...63 => return error.UnsupportedRegister, // P0 - P15 |
| 269 | 64...95 => return error.UnsupportedRegister, // V0 - V31 |
| 270 | 96...127 => return error.UnsupportedRegister, // Z0 - Z31 |
| 237 | 271 | |
| 238 | 272 | else => return error.InvalidRegister, |
| 239 | 273 | } |
| 240 | 274 | } |
| 241 | 275 | }; |
| 242 | 276 | |
| 243 | | const X86_64 = struct { |
| 244 | | /// The order here intentionally matches the order of the DWARF register mappings. It's unclear |
| 245 | | /// where those mappings actually originated from---the ordering of the first 4 registers seems |
| 246 | | /// quite unusual---but it is currently convenient for us to match DWARF. |
| 247 | | pub const Gpr = enum { |
| 248 | | // zig fmt: off |
| 249 | | rax, rdx, rcx, rbx, |
| 250 | | rsi, rdi, rbp, rsp, |
| 251 | | r8, r9, r10, r11, |
| 252 | | r12, r13, r14, r15, |
| 253 | | rip, |
| 254 | | // zig fmt: on |
| 255 | | }; |
| 256 | | gprs: std.enums.EnumArray(Gpr, u64), |
| 277 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 278 | const Arc = extern struct { |
| 279 | /// The numbered general-purpose registers r0 - r31. |
| 280 | r: [32]u32, |
| 281 | pcl: u32, |
| 257 | 282 | |
| 258 | | pub inline fn current() X86_64 { |
| 259 | | var ctx: X86_64 = undefined; |
| 283 | pub inline fn current() Arc { |
| 284 | var ctx: Arc = undefined; |
| 260 | 285 | asm volatile ( |
| 261 | | \\movq %%rax, 0x00(%%rdi) |
| 262 | | \\movq %%rdx, 0x08(%%rdi) |
| 263 | | \\movq %%rcx, 0x10(%%rdi) |
| 264 | | \\movq %%rbx, 0x18(%%rdi) |
| 265 | | \\movq %%rsi, 0x20(%%rdi) |
| 266 | | \\movq %%rdi, 0x28(%%rdi) |
| 267 | | \\movq %%rbp, 0x30(%%rdi) |
| 268 | | \\movq %%rsp, 0x38(%%rdi) |
| 269 | | \\movq %%r8, 0x40(%%rdi) |
| 270 | | \\movq %%r9, 0x48(%%rdi) |
| 271 | | \\movq %%r10, 0x50(%%rdi) |
| 272 | | \\movq %%r11, 0x58(%%rdi) |
| 273 | | \\movq %%r12, 0x60(%%rdi) |
| 274 | | \\movq %%r13, 0x68(%%rdi) |
| 275 | | \\movq %%r14, 0x70(%%rdi) |
| 276 | | \\movq %%r15, 0x78(%%rdi) |
| 277 | | \\leaq (%%rip), %%rax |
| 278 | | \\movq %%rax, 0x80(%%rdi) |
| 279 | | \\movq 0x00(%%rdi), %%rax |
| 286 | \\ st r0, [r8, 0] |
| 287 | \\ st r1, [r8, 4] |
| 288 | \\ st r2, [r8, 8] |
| 289 | \\ st r3, [r8, 12] |
| 290 | \\ st r4, [r8, 16] |
| 291 | \\ st r5, [r8, 20] |
| 292 | \\ st r6, [r8, 24] |
| 293 | \\ st r7, [r8, 28] |
| 294 | \\ st r8, [r8, 32] |
| 295 | \\ st r9, [r8, 36] |
| 296 | \\ st r10, [r8, 40] |
| 297 | \\ st r11, [r8, 44] |
| 298 | \\ st r12, [r8, 48] |
| 299 | \\ st r13, [r8, 52] |
| 300 | \\ st r14, [r8, 56] |
| 301 | \\ st r15, [r8, 60] |
| 302 | \\ st r16, [r8, 64] |
| 303 | \\ st r17, [r8, 68] |
| 304 | \\ st r18, [r8, 72] |
| 305 | \\ st r19, [r8, 76] |
| 306 | \\ st r20, [r8, 80] |
| 307 | \\ st r21, [r8, 84] |
| 308 | \\ st r22, [r8, 88] |
| 309 | \\ st r23, [r8, 92] |
| 310 | \\ st r24, [r8, 96] |
| 311 | \\ st r25, [r8, 100] |
| 312 | \\ st r26, [r8, 104] |
| 313 | \\ st r27, [r8, 108] |
| 314 | \\ st r28, [r8, 112] |
| 315 | \\ st r29, [r8, 116] |
| 316 | \\ st r30, [r8, 120] |
| 317 | \\ st r31, [r8, 124] |
| 318 | \\ st pcl, [r8, 128] |
| 280 | 319 | : |
| 281 | | : [gprs] "{rdi}" (&ctx.gprs.values), |
| 320 | : [ctx] "{r8}" (&ctx), |
| 282 | 321 | : .{ .memory = true }); |
| 283 | 322 | return ctx; |
| 284 | 323 | } |
| 285 | 324 | |
| 286 | | pub fn dwarfRegisterBytes(ctx: *X86_64, register_num: u16) DwarfRegisterError![]u8 { |
| 287 | | // System V Application Binary Interface AMD64 Architecture Processor Supplement |
| 288 | | // § 3.6.2 "DWARF Register Number Mapping" |
| 325 | pub fn dwarfRegisterBytes(ctx: *Arc, register_num: u16) DwarfRegisterError![]u8 { |
| 289 | 326 | switch (register_num) { |
| 290 | | // The order of `Gpr` intentionally matches DWARF's mappings. |
| 291 | | 0...16 => return @ptrCast(&ctx.gprs.values[register_num]), |
| 327 | 0...31 => return @ptrCast(&ctx.r[register_num]), |
| 328 | 160 => return @ptrCast(&ctx.pcl), |
| 292 | 329 | |
| 293 | | 17...32 => return error.UnsupportedRegister, // xmm0 - xmm15 |
| 294 | | 33...40 => return error.UnsupportedRegister, // st0 - st7 |
| 295 | | 41...48 => return error.UnsupportedRegister, // mm0 - mm7 |
| 296 | | 49 => return error.UnsupportedRegister, // rflags |
| 297 | | 50...55 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs |
| 298 | | 58...59 => return error.UnsupportedRegister, // fs.base, gs.base |
| 299 | | 62 => return error.UnsupportedRegister, // tr |
| 300 | | 63 => return error.UnsupportedRegister, // ldtr |
| 301 | | 64 => return error.UnsupportedRegister, // mxcsr |
| 302 | | 65 => return error.UnsupportedRegister, // fcw |
| 303 | | 66 => return error.UnsupportedRegister, // fsw |
| 304 | | 67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512) |
| 305 | | 118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512) |
| 306 | | 130...145 => return error.UnsupportedRegister, // r16 - r31 (APX) |
| 330 | 32...57 => return error.UnsupportedRegister, // Extension Core Registers |
| 331 | 58...127 => return error.UnsupportedRegister, // Reserved |
| 332 | 128...159 => return error.UnsupportedRegister, // f0 - f31 |
| 307 | 333 | |
| 308 | 334 | else => return error.InvalidRegister, |
| 309 | 335 | } |
| ... | ... | @@ -317,11 +343,11 @@ const Arm = struct { |
| 317 | 343 | pub inline fn current() Arm { |
| 318 | 344 | var ctx: Arm = undefined; |
| 319 | 345 | asm volatile ( |
| 320 | | \\// For compatibility with Thumb, we can't write r13 (sp) or r15 (pc) with stm. |
| 321 | | \\stm r0, {r0-r12} |
| 322 | | \\str r13, [r0, #0x34] |
| 323 | | \\str r14, [r0, #0x38] |
| 324 | | \\str r15, [r0, #0x3c] |
| 346 | \\ // For compatibility with Thumb, we can't write r13 (sp) or r15 (pc) with stm. |
| 347 | \\ stm r0, {r0-r12} |
| 348 | \\ str r13, [r0, #0x34] |
| 349 | \\ str r14, [r0, #0x38] |
| 350 | \\ str r15, [r0, #0x3c] |
| 325 | 351 | : |
| 326 | 352 | : [r] "{r0}" (&ctx.r), |
| 327 | 353 | : .{ .memory = true }); |
| ... | ... | @@ -369,62 +395,30 @@ const Arm = struct { |
| 369 | 395 | }; |
| 370 | 396 | |
| 371 | 397 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 372 | | const Aarch64 = extern struct { |
| 373 | | /// The numbered general-purpose registers X0 - X30. |
| 374 | | x: [31]u64, |
| 375 | | sp: u64, |
| 376 | | pc: u64, |
| 398 | const Csky = extern struct { |
| 399 | /// The numbered general-purpose registers r0 - r31. |
| 400 | r: [32]u32, |
| 401 | pc: u32, |
| 377 | 402 | |
| 378 | | pub inline fn current() Aarch64 { |
| 379 | | var ctx: Aarch64 = undefined; |
| 403 | pub inline fn current() Csky { |
| 404 | var ctx: Csky = undefined; |
| 380 | 405 | asm volatile ( |
| 381 | | \\stp x0, x1, [x0, #0x000] |
| 382 | | \\stp x2, x3, [x0, #0x010] |
| 383 | | \\stp x4, x5, [x0, #0x020] |
| 384 | | \\stp x6, x7, [x0, #0x030] |
| 385 | | \\stp x8, x9, [x0, #0x040] |
| 386 | | \\stp x10, x11, [x0, #0x050] |
| 387 | | \\stp x12, x13, [x0, #0x060] |
| 388 | | \\stp x14, x15, [x0, #0x070] |
| 389 | | \\stp x16, x17, [x0, #0x080] |
| 390 | | \\stp x18, x19, [x0, #0x090] |
| 391 | | \\stp x20, x21, [x0, #0x0a0] |
| 392 | | \\stp x22, x23, [x0, #0x0b0] |
| 393 | | \\stp x24, x25, [x0, #0x0c0] |
| 394 | | \\stp x26, x27, [x0, #0x0d0] |
| 395 | | \\stp x28, x29, [x0, #0x0e0] |
| 396 | | \\str x30, [x0, #0x0f0] |
| 397 | | \\mov x1, sp |
| 398 | | \\str x1, [x0, #0x0f8] |
| 399 | | \\adr x1, . |
| 400 | | \\str x1, [x0, #0x100] |
| 401 | | \\ldr x1, [x0, #0x008] |
| 406 | \\ stm r0-r31, (t0) |
| 407 | \\ grs t1, 1f |
| 408 | \\1: |
| 409 | \\ st32.w t1, (t0, 128) |
| 402 | 410 | : |
| 403 | | : [gprs] "{x0}" (&ctx), |
| 404 | | : .{ .memory = true }); |
| 411 | : [ctx] "{r12}" (&ctx), |
| 412 | : .{ .r13 = true, .memory = true }); |
| 405 | 413 | return ctx; |
| 406 | 414 | } |
| 407 | 415 | |
| 408 | | pub fn dwarfRegisterBytes(ctx: *Aarch64, register_num: u16) DwarfRegisterError![]u8 { |
| 409 | | // DWARF for the Arm(r) 64-bit Architecture (AArch64) § 4.1 "DWARF register names" |
| 416 | pub fn dwarfRegisterBytes(ctx: *Csky, register_num: u16) DwarfRegisterError![]u8 { |
| 410 | 417 | switch (register_num) { |
| 411 | | 0...30 => return @ptrCast(&ctx.x[register_num]), |
| 412 | | 31 => return @ptrCast(&ctx.sp), |
| 413 | | 32 => return @ptrCast(&ctx.pc), |
| 418 | 0...31 => return @ptrCast(&ctx.r[register_num]), |
| 419 | 64 => return @ptrCast(&ctx.pc), |
| 414 | 420 | |
| 415 | | 33 => return error.UnsupportedRegister, // ELR_mode |
| 416 | | 34 => return error.UnsupportedRegister, // RA_SIGN_STATE |
| 417 | | 35 => return error.UnsupportedRegister, // TPIDRRO_ELO |
| 418 | | 36 => return error.UnsupportedRegister, // TPIDR_ELO |
| 419 | | 37 => return error.UnsupportedRegister, // TPIDR_EL1 |
| 420 | | 38 => return error.UnsupportedRegister, // TPIDR_EL2 |
| 421 | | 39 => return error.UnsupportedRegister, // TPIDR_EL3 |
| 422 | | 40...45 => return error.UnsupportedRegister, // Reserved |
| 423 | | 46 => return error.UnsupportedRegister, // VG |
| 424 | | 47 => return error.UnsupportedRegister, // FFR |
| 425 | | 48...63 => return error.UnsupportedRegister, // P0 - P15 |
| 426 | | 64...95 => return error.UnsupportedRegister, // V0 - V31 |
| 427 | | 96...127 => return error.UnsupportedRegister, // Z0 - Z31 |
| 421 | 32...63 => return error.UnsupportedRegister, // f0 - f31 |
| 428 | 422 | |
| 429 | 423 | else => return error.InvalidRegister, |
| 430 | 424 | } |
| ... | ... | @@ -474,10 +468,9 @@ const Hexagon = extern struct { |
| 474 | 468 | \\ memw(r0 + #124) = r31 |
| 475 | 469 | \\ r1 = pc |
| 476 | 470 | \\ memw(r0 + #128) = r1 |
| 477 | | \\ r1 = memw(r0 + #4) |
| 478 | 471 | : |
| 479 | | : [gprs] "{r0}" (&ctx), |
| 480 | | : .{ .memory = true }); |
| 472 | : [ctx] "{r0}" (&ctx), |
| 473 | : .{ .r1 = true, .memory = true }); |
| 481 | 474 | return ctx; |
| 482 | 475 | } |
| 483 | 476 | |
| ... | ... | @@ -499,6 +492,60 @@ const Hexagon = extern struct { |
| 499 | 492 | } |
| 500 | 493 | }; |
| 501 | 494 | |
| 495 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 496 | const Lanai = extern struct { |
| 497 | r: [32]u32, |
| 498 | |
| 499 | pub inline fn current() Lanai { |
| 500 | var ctx: Lanai = undefined; |
| 501 | asm volatile ( |
| 502 | \\ st %%r0, 0[r9] |
| 503 | \\ st %%r1, 4[r9] |
| 504 | \\ st %%r2, 8[r9] |
| 505 | \\ st %%r3, 12[r9] |
| 506 | \\ st %%r4, 16[r9] |
| 507 | \\ st %%r5, 20[r9] |
| 508 | \\ st %%r6, 24[r9] |
| 509 | \\ st %%r7, 28[r9] |
| 510 | \\ st %%r8, 32[r9] |
| 511 | \\ st %%r9, 36[r9] |
| 512 | \\ st %%r10, 40[r9] |
| 513 | \\ st %%r11, 44[r9] |
| 514 | \\ st %%r12, 48[r9] |
| 515 | \\ st %%r13, 52[r9] |
| 516 | \\ st %%r14, 56[r9] |
| 517 | \\ st %%r15, 60[r9] |
| 518 | \\ st %%r16, 64[r9] |
| 519 | \\ st %%r17, 68[r9] |
| 520 | \\ st %%r18, 72[r9] |
| 521 | \\ st %%r19, 76[r9] |
| 522 | \\ st %%r20, 80[r9] |
| 523 | \\ st %%r21, 84[r9] |
| 524 | \\ st %%r22, 88[r9] |
| 525 | \\ st %%r23, 92[r9] |
| 526 | \\ st %%r24, 96[r9] |
| 527 | \\ st %%r25, 100[r9] |
| 528 | \\ st %%r26, 104[r9] |
| 529 | \\ st %%r27, 108[r9] |
| 530 | \\ st %%r28, 112[r9] |
| 531 | \\ st %%r29, 116[r9] |
| 532 | \\ st %%r30, 120[r9] |
| 533 | \\ st %%r31, 124[r9] |
| 534 | : |
| 535 | : [ctx] "{r9}" (&ctx), |
| 536 | : .{ .memory = true }); |
| 537 | return ctx; |
| 538 | } |
| 539 | |
| 540 | pub fn dwarfRegisterBytes(ctx: *Lanai, register_num: u16) DwarfRegisterError![]u8 { |
| 541 | switch (register_num) { |
| 542 | 0...31 => return @ptrCast(&ctx.s[register_num]), |
| 543 | |
| 544 | else => return error.InvalidRegister, |
| 545 | } |
| 546 | } |
| 547 | }; |
| 548 | |
| 502 | 549 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 503 | 550 | const LoongArch = extern struct { |
| 504 | 551 | /// The numbered general-purpose registers r0 - r31. r0 must be zero. |
| ... | ... | @@ -545,7 +592,6 @@ const LoongArch = extern struct { |
| 545 | 592 | \\ bl 1f |
| 546 | 593 | \\1: |
| 547 | 594 | \\ st.d $ra, $t0, 256 |
| 548 | | \\ ld.d $ra, $t0, 8 |
| 549 | 595 | else |
| 550 | 596 | \\ st.w $zero, $t0, 0 |
| 551 | 597 | \\ st.w $ra, $t0, 4 |
| ... | ... | @@ -582,10 +628,9 @@ const LoongArch = extern struct { |
| 582 | 628 | \\ bl 1f |
| 583 | 629 | \\1: |
| 584 | 630 | \\ st.w $ra, $t0, 128 |
| 585 | | \\ ld.w $ra, $t0, 4 |
| 586 | 631 | : |
| 587 | | : [gprs] "{$r12}" (&ctx), |
| 588 | | : .{ .memory = true }); |
| 632 | : [ctx] "{$r12}" (&ctx), |
| 633 | : .{ .r1 = true, .memory = true }); |
| 589 | 634 | return ctx; |
| 590 | 635 | } |
| 591 | 636 | |
| ... | ... | @@ -601,6 +646,40 @@ const LoongArch = extern struct { |
| 601 | 646 | } |
| 602 | 647 | }; |
| 603 | 648 | |
| 649 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 650 | const M68k = extern struct { |
| 651 | /// The numbered data registers d0 - d7. |
| 652 | d: [8]u32, |
| 653 | /// The numbered address registers a0 - a7. |
| 654 | a: [8]u32, |
| 655 | pc: u32, |
| 656 | |
| 657 | pub inline fn current() M68k { |
| 658 | var ctx: M68k = undefined; |
| 659 | asm volatile ( |
| 660 | \\ movem.l %%d0 - %%a7, (%%a0) |
| 661 | \\ lea.l (%%pc), %%a1 |
| 662 | \\ move.l %%a1, (%%a0, 64) |
| 663 | : |
| 664 | : [ctx] "{a0}" (&ctx), |
| 665 | : .{ .a1 = true, .memory = true }); |
| 666 | return ctx; |
| 667 | } |
| 668 | |
| 669 | pub fn dwarfRegisterBytes(ctx: *M68k, register_num: u16) DwarfRegisterError![]u8 { |
| 670 | switch (register_num) { |
| 671 | 0...7 => return @ptrCast(&ctx.d[register_num]), |
| 672 | 8...15 => return @ptrCast(&ctx.a[register_num - 8]), |
| 673 | 26 => return @ptrCast(&ctx.pc), |
| 674 | |
| 675 | 16...23 => return error.UnsupportedRegister, // fp0 - fp7 |
| 676 | 24...25 => return error.UnsupportedRegister, // Return columns in GCC...? |
| 677 | |
| 678 | else => return error.InvalidRegister, |
| 679 | } |
| 680 | } |
| 681 | }; |
| 682 | |
| 604 | 683 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 605 | 684 | const Mips = extern struct { |
| 606 | 685 | /// The numbered general-purpose registers r0 - r31. r0 must be zero. |
| ... | ... | @@ -651,7 +730,6 @@ const Mips = extern struct { |
| 651 | 730 | \\ bal 1f |
| 652 | 731 | \\1: |
| 653 | 732 | \\ sd $ra, 256($t0) |
| 654 | | \\ ld $ra, 248($t0) |
| 655 | 733 | \\ .set pop |
| 656 | 734 | else |
| 657 | 735 | \\ .set push |
| ... | ... | @@ -693,11 +771,10 @@ const Mips = extern struct { |
| 693 | 771 | \\ bal 1f |
| 694 | 772 | \\1: |
| 695 | 773 | \\ sw $ra, 128($t4) |
| 696 | | \\ lw $ra, 124($t4) |
| 697 | 774 | \\ .set pop |
| 698 | 775 | : |
| 699 | | : [gprs] "{$12}" (&ctx), |
| 700 | | : .{ .memory = true }); |
| 776 | : [ctx] "{$12}" (&ctx), |
| 777 | : .{ .r31 = true, .memory = true }); |
| 701 | 778 | return ctx; |
| 702 | 779 | } |
| 703 | 780 | |
| ... | ... | @@ -723,6 +800,66 @@ const Mips = extern struct { |
| 723 | 800 | } |
| 724 | 801 | }; |
| 725 | 802 | |
| 803 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 804 | const Or1k = extern struct { |
| 805 | /// The numbered general-purpose registers r0 - r31. |
| 806 | r: [32]u32, |
| 807 | pc: u32, |
| 808 | |
| 809 | pub inline fn current() Or1k { |
| 810 | var ctx: Or1k = undefined; |
| 811 | asm volatile ( |
| 812 | \\ l.sw 0(r15), r0 |
| 813 | \\ l.sw 4(r15), r1 |
| 814 | \\ l.sw 8(r15), r2 |
| 815 | \\ l.sw 12(r15), r3 |
| 816 | \\ l.sw 16(r15), r4 |
| 817 | \\ l.sw 20(r15), r5 |
| 818 | \\ l.sw 24(r15), r6 |
| 819 | \\ l.sw 28(r15), r7 |
| 820 | \\ l.sw 32(r15), r8 |
| 821 | \\ l.sw 36(r15), r9 |
| 822 | \\ l.sw 40(r15), r10 |
| 823 | \\ l.sw 44(r15), r11 |
| 824 | \\ l.sw 48(r15), r12 |
| 825 | \\ l.sw 52(r15), r13 |
| 826 | \\ l.sw 56(r15), r14 |
| 827 | \\ l.sw 60(r15), r15 |
| 828 | \\ l.sw 64(r15), r16 |
| 829 | \\ l.sw 68(r15), r17 |
| 830 | \\ l.sw 72(r15), r18 |
| 831 | \\ l.sw 76(r15), r19 |
| 832 | \\ l.sw 80(r15), r20 |
| 833 | \\ l.sw 84(r15), r21 |
| 834 | \\ l.sw 88(r15), r22 |
| 835 | \\ l.sw 92(r15), r23 |
| 836 | \\ l.sw 96(r15), r24 |
| 837 | \\ l.sw 100(r15), r25 |
| 838 | \\ l.sw 104(r15), r26 |
| 839 | \\ l.sw 108(r15), r27 |
| 840 | \\ l.sw 112(r15), r28 |
| 841 | \\ l.sw 116(r15), r29 |
| 842 | \\ l.sw 120(r15), r30 |
| 843 | \\ l.sw 124(r15), r31 |
| 844 | \\ l.jal 1f |
| 845 | \\1: |
| 846 | \\ l.sw 128(r15), r9 |
| 847 | : |
| 848 | : [ctx] "{r15}" (&ctx), |
| 849 | : .{ .r9 = true, .memory = true }); |
| 850 | return ctx; |
| 851 | } |
| 852 | |
| 853 | pub fn dwarfRegisterBytes(ctx: *Or1k, register_num: u16) DwarfRegisterError![]u8 { |
| 854 | switch (register_num) { |
| 855 | 0...31 => return @ptrCast(&ctx.r[register_num]), |
| 856 | 35 => return @ptrCast(&ctx.pc), |
| 857 | |
| 858 | else => return error.InvalidRegister, |
| 859 | } |
| 860 | } |
| 861 | }; |
| 862 | |
| 726 | 863 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 727 | 864 | const Powerpc = extern struct { |
| 728 | 865 | /// The numbered general-purpose registers r0 - r31. |
| ... | ... | @@ -773,7 +910,6 @@ const Powerpc = extern struct { |
| 773 | 910 | \\1: |
| 774 | 911 | \\ mflr 8 |
| 775 | 912 | \\ std 8, 256(10) |
| 776 | | \\ ld 8, 64(10) |
| 777 | 913 | else |
| 778 | 914 | \\ stw 0, 0(10) |
| 779 | 915 | \\ stw 1, 4(10) |
| ... | ... | @@ -813,10 +949,9 @@ const Powerpc = extern struct { |
| 813 | 949 | \\1: |
| 814 | 950 | \\ mflr 8 |
| 815 | 951 | \\ stw 8, 128(10) |
| 816 | | \\ lwz 8, 32(10) |
| 817 | 952 | : |
| 818 | | : [gprs] "{r10}" (&ctx), |
| 819 | | : .{ .lr = true, .memory = true }); |
| 953 | : [ctx] "{r10}" (&ctx), |
| 954 | : .{ .r8 = true, .lr = true, .memory = true }); |
| 820 | 955 | return ctx; |
| 821 | 956 | } |
| 822 | 957 | |
| ... | ... | @@ -879,104 +1014,6 @@ const Powerpc = extern struct { |
| 879 | 1014 | } |
| 880 | 1015 | }; |
| 881 | 1016 | |
| 882 | | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 883 | | const Sparc = extern struct { |
| 884 | | g: [8]Gpr, |
| 885 | | o: [8]Gpr, |
| 886 | | l: [8]Gpr, |
| 887 | | i: [8]Gpr, |
| 888 | | pc: Gpr, |
| 889 | | |
| 890 | | pub const Gpr = if (native_arch == .sparc64) u64 else u32; |
| 891 | | |
| 892 | | pub inline fn current() Sparc { |
| 893 | | flushWindows(); |
| 894 | | |
| 895 | | var ctx: Sparc = undefined; |
| 896 | | asm volatile (if (Gpr == u64) |
| 897 | | \\ stx %g0, [%l0 + 0] |
| 898 | | \\ stx %g1, [%l0 + 8] |
| 899 | | \\ stx %g2, [%l0 + 16] |
| 900 | | \\ stx %g3, [%l0 + 24] |
| 901 | | \\ stx %g4, [%l0 + 32] |
| 902 | | \\ stx %g5, [%l0 + 40] |
| 903 | | \\ stx %g6, [%l0 + 48] |
| 904 | | \\ stx %g7, [%l0 + 56] |
| 905 | | \\ stx %o0, [%l0 + 64] |
| 906 | | \\ stx %o1, [%l0 + 72] |
| 907 | | \\ stx %o2, [%l0 + 80] |
| 908 | | \\ stx %o3, [%l0 + 88] |
| 909 | | \\ stx %o4, [%l0 + 96] |
| 910 | | \\ stx %o5, [%l0 + 104] |
| 911 | | \\ stx %o6, [%l0 + 112] |
| 912 | | \\ stx %o7, [%l0 + 120] |
| 913 | | \\ stx %l0, [%l0 + 128] |
| 914 | | \\ stx %l1, [%l0 + 136] |
| 915 | | \\ stx %l2, [%l0 + 144] |
| 916 | | \\ stx %l3, [%l0 + 152] |
| 917 | | \\ stx %l4, [%l0 + 160] |
| 918 | | \\ stx %l5, [%l0 + 168] |
| 919 | | \\ stx %l6, [%l0 + 176] |
| 920 | | \\ stx %l7, [%l0 + 184] |
| 921 | | \\ stx %i0, [%l0 + 192] |
| 922 | | \\ stx %i1, [%l0 + 200] |
| 923 | | \\ stx %i2, [%l0 + 208] |
| 924 | | \\ stx %i3, [%l0 + 216] |
| 925 | | \\ stx %i4, [%l0 + 224] |
| 926 | | \\ stx %i5, [%l0 + 232] |
| 927 | | \\ stx %i6, [%l0 + 240] |
| 928 | | \\ stx %i7, [%l0 + 248] |
| 929 | | \\ call 1f |
| 930 | | \\ stx %o7, [%l0 + 256] |
| 931 | | \\1: |
| 932 | | else |
| 933 | | \\ std %g0, [%l0 + 0] |
| 934 | | \\ std %g2, [%l0 + 8] |
| 935 | | \\ std %g4, [%l0 + 16] |
| 936 | | \\ std %g6, [%l0 + 24] |
| 937 | | \\ std %o0, [%l0 + 32] |
| 938 | | \\ std %o2, [%l0 + 40] |
| 939 | | \\ std %o4, [%l0 + 48] |
| 940 | | \\ std %o6, [%l0 + 56] |
| 941 | | \\ std %l0, [%l0 + 64] |
| 942 | | \\ std %l2, [%l0 + 72] |
| 943 | | \\ std %l4, [%l0 + 80] |
| 944 | | \\ std %l6, [%l0 + 88] |
| 945 | | \\ std %i0, [%l0 + 96] |
| 946 | | \\ std %i2, [%l0 + 104] |
| 947 | | \\ std %i4, [%l0 + 112] |
| 948 | | \\ std %i6, [%l0 + 120] |
| 949 | | \\ call 1f |
| 950 | | \\ st %o7, [%l0 + 128] |
| 951 | | \\1: |
| 952 | | : |
| 953 | | : [gprs] "{l0}" (&ctx), |
| 954 | | : .{ .o7 = true, .memory = true }); |
| 955 | | return ctx; |
| 956 | | } |
| 957 | | |
| 958 | | noinline fn flushWindows() void { |
| 959 | | // Flush all register windows except the current one (hence `noinline`). This ensures that |
| 960 | | // we actually see meaningful data on the stack when we walk the frame chain. |
| 961 | | if (comptime builtin.target.cpu.has(.sparc, .v9)) |
| 962 | | asm volatile ("flushw" ::: .{ .memory = true }) |
| 963 | | else |
| 964 | | asm volatile ("ta 3" ::: .{ .memory = true }); // ST_FLUSH_WINDOWS |
| 965 | | } |
| 966 | | |
| 967 | | pub fn dwarfRegisterBytes(ctx: *Sparc, register_num: u16) DwarfRegisterError![]u8 { |
| 968 | | switch (register_num) { |
| 969 | | 0...7 => return @ptrCast(&ctx.g[register_num]), |
| 970 | | 8...15 => return @ptrCast(&ctx.o[register_num - 8]), |
| 971 | | 16...23 => return @ptrCast(&ctx.l[register_num - 16]), |
| 972 | | 24...31 => return @ptrCast(&ctx.i[register_num - 24]), |
| 973 | | 32 => return @ptrCast(&ctx.pc), |
| 974 | | |
| 975 | | else => return error.InvalidRegister, |
| 976 | | } |
| 977 | | } |
| 978 | | }; |
| 979 | | |
| 980 | 1017 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 981 | 1018 | const Riscv = extern struct { |
| 982 | 1019 | /// The numbered general-purpose registers r0 - r31. r0 must be zero. |
| ... | ... | @@ -1023,7 +1060,6 @@ const Riscv = extern struct { |
| 1023 | 1060 | \\ jal ra, 1f |
| 1024 | 1061 | \\1: |
| 1025 | 1062 | \\ sd ra, 256(t0) |
| 1026 | | \\ ld ra, 8(t0) |
| 1027 | 1063 | else |
| 1028 | 1064 | \\ sw zero, 0(t0) |
| 1029 | 1065 | \\ sw ra, 4(t0) |
| ... | ... | @@ -1060,10 +1096,9 @@ const Riscv = extern struct { |
| 1060 | 1096 | \\ jal ra, 1f |
| 1061 | 1097 | \\1: |
| 1062 | 1098 | \\ sw ra, 128(t0) |
| 1063 | | \\ lw ra, 4(t0) |
| 1064 | 1099 | : |
| 1065 | | : [gprs] "{t0}" (&ctx), |
| 1066 | | : .{ .memory = true }); |
| 1100 | : [ctx] "{t0}" (&ctx), |
| 1101 | : .{ .x1 = true, .memory = true }); |
| 1067 | 1102 | return ctx; |
| 1068 | 1103 | } |
| 1069 | 1104 | |
| ... | ... | @@ -1101,11 +1136,9 @@ const S390x = extern struct { |
| 1101 | 1136 | \\ stm %%r0, %%r1, 128(%%r2) |
| 1102 | 1137 | \\ larl %%r0, . |
| 1103 | 1138 | \\ stg %%r0, 136(%%r2) |
| 1104 | | \\ lg %%r0, 0(%%r2) |
| 1105 | | \\ lg %%r1, 8(%%r2) |
| 1106 | 1139 | : |
| 1107 | | : [gprs] "{r2}" (&ctx), |
| 1108 | | : .{ .memory = true }); |
| 1140 | : [ctx] "{r2}" (&ctx), |
| 1141 | : .{ .r0 = true, .r1 = true, .memory = true }); |
| 1109 | 1142 | return ctx; |
| 1110 | 1143 | } |
| 1111 | 1144 | |
| ... | ... | @@ -1126,6 +1159,326 @@ const S390x = extern struct { |
| 1126 | 1159 | } |
| 1127 | 1160 | }; |
| 1128 | 1161 | |
| 1162 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 1163 | const Sparc = extern struct { |
| 1164 | g: [8]Gpr, |
| 1165 | o: [8]Gpr, |
| 1166 | l: [8]Gpr, |
| 1167 | i: [8]Gpr, |
| 1168 | pc: Gpr, |
| 1169 | |
| 1170 | pub const Gpr = if (native_arch == .sparc64) u64 else u32; |
| 1171 | |
| 1172 | pub inline fn current() Sparc { |
| 1173 | flushWindows(); |
| 1174 | |
| 1175 | var ctx: Sparc = undefined; |
| 1176 | asm volatile (if (Gpr == u64) |
| 1177 | \\ stx %g0, [%l0 + 0] |
| 1178 | \\ stx %g1, [%l0 + 8] |
| 1179 | \\ stx %g2, [%l0 + 16] |
| 1180 | \\ stx %g3, [%l0 + 24] |
| 1181 | \\ stx %g4, [%l0 + 32] |
| 1182 | \\ stx %g5, [%l0 + 40] |
| 1183 | \\ stx %g6, [%l0 + 48] |
| 1184 | \\ stx %g7, [%l0 + 56] |
| 1185 | \\ stx %o0, [%l0 + 64] |
| 1186 | \\ stx %o1, [%l0 + 72] |
| 1187 | \\ stx %o2, [%l0 + 80] |
| 1188 | \\ stx %o3, [%l0 + 88] |
| 1189 | \\ stx %o4, [%l0 + 96] |
| 1190 | \\ stx %o5, [%l0 + 104] |
| 1191 | \\ stx %o6, [%l0 + 112] |
| 1192 | \\ stx %o7, [%l0 + 120] |
| 1193 | \\ stx %l0, [%l0 + 128] |
| 1194 | \\ stx %l1, [%l0 + 136] |
| 1195 | \\ stx %l2, [%l0 + 144] |
| 1196 | \\ stx %l3, [%l0 + 152] |
| 1197 | \\ stx %l4, [%l0 + 160] |
| 1198 | \\ stx %l5, [%l0 + 168] |
| 1199 | \\ stx %l6, [%l0 + 176] |
| 1200 | \\ stx %l7, [%l0 + 184] |
| 1201 | \\ stx %i0, [%l0 + 192] |
| 1202 | \\ stx %i1, [%l0 + 200] |
| 1203 | \\ stx %i2, [%l0 + 208] |
| 1204 | \\ stx %i3, [%l0 + 216] |
| 1205 | \\ stx %i4, [%l0 + 224] |
| 1206 | \\ stx %i5, [%l0 + 232] |
| 1207 | \\ stx %i6, [%l0 + 240] |
| 1208 | \\ stx %i7, [%l0 + 248] |
| 1209 | \\ call 1f |
| 1210 | \\1: |
| 1211 | \\ stx %o7, [%l0 + 256] |
| 1212 | else |
| 1213 | \\ std %g0, [%l0 + 0] |
| 1214 | \\ std %g2, [%l0 + 8] |
| 1215 | \\ std %g4, [%l0 + 16] |
| 1216 | \\ std %g6, [%l0 + 24] |
| 1217 | \\ std %o0, [%l0 + 32] |
| 1218 | \\ std %o2, [%l0 + 40] |
| 1219 | \\ std %o4, [%l0 + 48] |
| 1220 | \\ std %o6, [%l0 + 56] |
| 1221 | \\ std %l0, [%l0 + 64] |
| 1222 | \\ std %l2, [%l0 + 72] |
| 1223 | \\ std %l4, [%l0 + 80] |
| 1224 | \\ std %l6, [%l0 + 88] |
| 1225 | \\ std %i0, [%l0 + 96] |
| 1226 | \\ std %i2, [%l0 + 104] |
| 1227 | \\ std %i4, [%l0 + 112] |
| 1228 | \\ std %i6, [%l0 + 120] |
| 1229 | \\ call 1f |
| 1230 | \\1: |
| 1231 | \\ st %o7, [%l0 + 128] |
| 1232 | : |
| 1233 | : [ctx] "{l0}" (&ctx), |
| 1234 | : .{ .o7 = true, .memory = true }); |
| 1235 | return ctx; |
| 1236 | } |
| 1237 | |
| 1238 | noinline fn flushWindows() void { |
| 1239 | // Flush all register windows except the current one (hence `noinline`). This ensures that |
| 1240 | // we actually see meaningful data on the stack when we walk the frame chain. |
| 1241 | if (comptime builtin.target.cpu.has(.sparc, .v9)) |
| 1242 | asm volatile ("flushw" ::: .{ .memory = true }) |
| 1243 | else |
| 1244 | asm volatile ("ta 3" ::: .{ .memory = true }); // ST_FLUSH_WINDOWS |
| 1245 | } |
| 1246 | |
| 1247 | pub fn dwarfRegisterBytes(ctx: *Sparc, register_num: u16) DwarfRegisterError![]u8 { |
| 1248 | switch (register_num) { |
| 1249 | 0...7 => return @ptrCast(&ctx.g[register_num]), |
| 1250 | 8...15 => return @ptrCast(&ctx.o[register_num - 8]), |
| 1251 | 16...23 => return @ptrCast(&ctx.l[register_num - 16]), |
| 1252 | 24...31 => return @ptrCast(&ctx.i[register_num - 24]), |
| 1253 | 32 => return @ptrCast(&ctx.pc), |
| 1254 | |
| 1255 | else => return error.InvalidRegister, |
| 1256 | } |
| 1257 | } |
| 1258 | }; |
| 1259 | |
| 1260 | /// This is an `extern struct` so that inline assembly in `current` can use field offsets. |
| 1261 | const Ve = extern struct { |
| 1262 | s: [64]u64, |
| 1263 | ic: u64, |
| 1264 | |
| 1265 | pub inline fn current() Ve { |
| 1266 | var ctx: Ve = undefined; |
| 1267 | asm volatile ( |
| 1268 | \\ st %%s0, 0(, %%s8) |
| 1269 | \\ st %%s1, 8(, %%s8) |
| 1270 | \\ st %%s2, 16(, %%s8) |
| 1271 | \\ st %%s3, 24(, %%s8) |
| 1272 | \\ st %%s4, 32(, %%s8) |
| 1273 | \\ st %%s5, 40(, %%s8) |
| 1274 | \\ st %%s6, 48(, %%s8) |
| 1275 | \\ st %%s7, 56(, %%s8) |
| 1276 | \\ st %%s8, 64(, %%s8) |
| 1277 | \\ st %%s9, 72(, %%s8) |
| 1278 | \\ st %%s10, 80(, %%s8) |
| 1279 | \\ st %%s11, 88(, %%s8) |
| 1280 | \\ st %%s12, 96(, %%s8) |
| 1281 | \\ st %%s13, 104(, %%s8) |
| 1282 | \\ st %%s14, 112(, %%s8) |
| 1283 | \\ st %%s15, 120(, %%s8) |
| 1284 | \\ st %%s16, 128(, %%s8) |
| 1285 | \\ st %%s17, 136(, %%s8) |
| 1286 | \\ st %%s18, 144(, %%s8) |
| 1287 | \\ st %%s19, 152(, %%s8) |
| 1288 | \\ st %%s20, 160(, %%s8) |
| 1289 | \\ st %%s21, 168(, %%s8) |
| 1290 | \\ st %%s22, 176(, %%s8) |
| 1291 | \\ st %%s23, 184(, %%s8) |
| 1292 | \\ st %%s24, 192(, %%s8) |
| 1293 | \\ st %%s25, 200(, %%s8) |
| 1294 | \\ st %%s26, 208(, %%s8) |
| 1295 | \\ st %%s27, 216(, %%s8) |
| 1296 | \\ st %%s28, 224(, %%s8) |
| 1297 | \\ st %%s29, 232(, %%s8) |
| 1298 | \\ st %%s30, 240(, %%s8) |
| 1299 | \\ st %%s31, 248(, %%s8) |
| 1300 | \\ st %%s32, 256(, %%s8) |
| 1301 | \\ st %%s33, 264(, %%s8) |
| 1302 | \\ st %%s34, 272(, %%s8) |
| 1303 | \\ st %%s35, 280(, %%s8) |
| 1304 | \\ st %%s36, 288(, %%s8) |
| 1305 | \\ st %%s37, 296(, %%s8) |
| 1306 | \\ st %%s38, 304(, %%s8) |
| 1307 | \\ st %%s39, 312(, %%s8) |
| 1308 | \\ st %%s40, 320(, %%s8) |
| 1309 | \\ st %%s41, 328(, %%s8) |
| 1310 | \\ st %%s42, 336(, %%s8) |
| 1311 | \\ st %%s43, 344(, %%s8) |
| 1312 | \\ st %%s44, 352(, %%s8) |
| 1313 | \\ st %%s45, 360(, %%s8) |
| 1314 | \\ st %%s46, 368(, %%s8) |
| 1315 | \\ st %%s47, 376(, %%s8) |
| 1316 | \\ st %%s48, 384(, %%s8) |
| 1317 | \\ st %%s49, 392(, %%s8) |
| 1318 | \\ st %%s50, 400(, %%s8) |
| 1319 | \\ st %%s51, 408(, %%s8) |
| 1320 | \\ st %%s52, 416(, %%s8) |
| 1321 | \\ st %%s53, 424(, %%s8) |
| 1322 | \\ st %%s54, 432(, %%s8) |
| 1323 | \\ st %%s55, 440(, %%s8) |
| 1324 | \\ st %%s56, 448(, %%s8) |
| 1325 | \\ st %%s57, 456(, %%s8) |
| 1326 | \\ st %%s58, 464(, %%s8) |
| 1327 | \\ st %%s59, 472(, %%s8) |
| 1328 | \\ st %%s60, 480(, %%s8) |
| 1329 | \\ st %%s61, 488(, %%s8) |
| 1330 | \\ st %%s62, 496(, %%s8) |
| 1331 | \\ st %%s63, 504(, %%s8) |
| 1332 | \\ br.l 1f |
| 1333 | \\1: |
| 1334 | \\ st %%lr, 512(, %%s8) |
| 1335 | : |
| 1336 | : [ctx] "{s8}" (&ctx), |
| 1337 | : .{ .s10 = true, .memory = true }); |
| 1338 | return ctx; |
| 1339 | } |
| 1340 | |
| 1341 | pub fn dwarfRegisterBytes(ctx: *Ve, register_num: u16) DwarfRegisterError![]u8 { |
| 1342 | switch (register_num) { |
| 1343 | 0...63 => return @ptrCast(&ctx.s[register_num]), |
| 1344 | 144 => return @ptrCast(&ctx.ic), |
| 1345 | |
| 1346 | 64...127 => return error.UnsupportedRegister, // v0 - v63 |
| 1347 | 128...143 => return error.UnsupportedRegister, // vm0 - vm15 |
| 1348 | |
| 1349 | else => return error.InvalidRegister, |
| 1350 | } |
| 1351 | } |
| 1352 | }; |
| 1353 | |
| 1354 | const X86 = struct { |
| 1355 | /// The first 8 registers here intentionally match the order of registers in the x86 instruction |
| 1356 | /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings, |
| 1357 | /// among other things. |
| 1358 | pub const Gpr = enum { |
| 1359 | // zig fmt: off |
| 1360 | eax, ecx, edx, ebx, |
| 1361 | esp, ebp, esi, edi, |
| 1362 | eip, |
| 1363 | // zig fmt: on |
| 1364 | }; |
| 1365 | gprs: std.enums.EnumArray(Gpr, u32), |
| 1366 | |
| 1367 | pub inline fn current() X86 { |
| 1368 | var ctx: X86 = undefined; |
| 1369 | asm volatile ( |
| 1370 | \\ movl %%eax, 0x00(%%edi) |
| 1371 | \\ movl %%ecx, 0x04(%%edi) |
| 1372 | \\ movl %%edx, 0x08(%%edi) |
| 1373 | \\ movl %%ebx, 0x0c(%%edi) |
| 1374 | \\ movl %%esp, 0x10(%%edi) |
| 1375 | \\ movl %%ebp, 0x14(%%edi) |
| 1376 | \\ movl %%esi, 0x18(%%edi) |
| 1377 | \\ movl %%edi, 0x1c(%%edi) |
| 1378 | \\ call 1f |
| 1379 | \\1: |
| 1380 | \\ popl 0x20(%%edi) |
| 1381 | : |
| 1382 | : [gprs] "{edi}" (&ctx.gprs.values), |
| 1383 | : .{ .memory = true }); |
| 1384 | return ctx; |
| 1385 | } |
| 1386 | |
| 1387 | pub fn dwarfRegisterBytes(ctx: *X86, register_num: u16) DwarfRegisterError![]u8 { |
| 1388 | // System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.1 |
| 1389 | // § 2.4.2 "DWARF Register Number Mapping" |
| 1390 | switch (register_num) { |
| 1391 | // The order of `Gpr` intentionally matches DWARF's mappings. |
| 1392 | // |
| 1393 | // x86-macos sometimes uses different mappings (ebp and esp are reversed when the unwind |
| 1394 | // information is from `__eh_frame`). This deviation is not considered here, because |
| 1395 | // x86-macos is a deprecated target which is not supported by the Zig Standard Library. |
| 1396 | 0...8 => return @ptrCast(&ctx.gprs.values[register_num]), |
| 1397 | |
| 1398 | 9 => return error.UnsupportedRegister, // eflags |
| 1399 | 11...18 => return error.UnsupportedRegister, // st0 - st7 |
| 1400 | 21...28 => return error.UnsupportedRegister, // xmm0 - xmm7 |
| 1401 | 29...36 => return error.UnsupportedRegister, // mm0 - mm7 |
| 1402 | 39 => return error.UnsupportedRegister, // mxcsr |
| 1403 | 40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs |
| 1404 | 48 => return error.UnsupportedRegister, // tr |
| 1405 | 49 => return error.UnsupportedRegister, // ldtr |
| 1406 | 93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512) |
| 1407 | |
| 1408 | else => return error.InvalidRegister, |
| 1409 | } |
| 1410 | } |
| 1411 | }; |
| 1412 | |
| 1413 | const X86_64 = struct { |
| 1414 | /// The order here intentionally matches the order of the DWARF register mappings. It's unclear |
| 1415 | /// where those mappings actually originated from---the ordering of the first 4 registers seems |
| 1416 | /// quite unusual---but it is currently convenient for us to match DWARF. |
| 1417 | pub const Gpr = enum { |
| 1418 | // zig fmt: off |
| 1419 | rax, rdx, rcx, rbx, |
| 1420 | rsi, rdi, rbp, rsp, |
| 1421 | r8, r9, r10, r11, |
| 1422 | r12, r13, r14, r15, |
| 1423 | rip, |
| 1424 | // zig fmt: on |
| 1425 | }; |
| 1426 | gprs: std.enums.EnumArray(Gpr, u64), |
| 1427 | |
| 1428 | pub inline fn current() X86_64 { |
| 1429 | var ctx: X86_64 = undefined; |
| 1430 | asm volatile ( |
| 1431 | \\ movq %%rax, 0x00(%%rdi) |
| 1432 | \\ movq %%rdx, 0x08(%%rdi) |
| 1433 | \\ movq %%rcx, 0x10(%%rdi) |
| 1434 | \\ movq %%rbx, 0x18(%%rdi) |
| 1435 | \\ movq %%rsi, 0x20(%%rdi) |
| 1436 | \\ movq %%rdi, 0x28(%%rdi) |
| 1437 | \\ movq %%rbp, 0x30(%%rdi) |
| 1438 | \\ movq %%rsp, 0x38(%%rdi) |
| 1439 | \\ movq %%r8, 0x40(%%rdi) |
| 1440 | \\ movq %%r9, 0x48(%%rdi) |
| 1441 | \\ movq %%r10, 0x50(%%rdi) |
| 1442 | \\ movq %%r11, 0x58(%%rdi) |
| 1443 | \\ movq %%r12, 0x60(%%rdi) |
| 1444 | \\ movq %%r13, 0x68(%%rdi) |
| 1445 | \\ movq %%r14, 0x70(%%rdi) |
| 1446 | \\ movq %%r15, 0x78(%%rdi) |
| 1447 | \\ leaq (%%rip), %%rax |
| 1448 | \\ movq %%rax, 0x80(%%rdi) |
| 1449 | : |
| 1450 | : [gprs] "{rdi}" (&ctx.gprs.values), |
| 1451 | : .{ .rax = true, .memory = true }); |
| 1452 | return ctx; |
| 1453 | } |
| 1454 | |
| 1455 | pub fn dwarfRegisterBytes(ctx: *X86_64, register_num: u16) DwarfRegisterError![]u8 { |
| 1456 | // System V Application Binary Interface AMD64 Architecture Processor Supplement |
| 1457 | // § 3.6.2 "DWARF Register Number Mapping" |
| 1458 | switch (register_num) { |
| 1459 | // The order of `Gpr` intentionally matches DWARF's mappings. |
| 1460 | 0...16 => return @ptrCast(&ctx.gprs.values[register_num]), |
| 1461 | |
| 1462 | 17...32 => return error.UnsupportedRegister, // xmm0 - xmm15 |
| 1463 | 33...40 => return error.UnsupportedRegister, // st0 - st7 |
| 1464 | 41...48 => return error.UnsupportedRegister, // mm0 - mm7 |
| 1465 | 49 => return error.UnsupportedRegister, // rflags |
| 1466 | 50...55 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs |
| 1467 | 58...59 => return error.UnsupportedRegister, // fs.base, gs.base |
| 1468 | 62 => return error.UnsupportedRegister, // tr |
| 1469 | 63 => return error.UnsupportedRegister, // ldtr |
| 1470 | 64 => return error.UnsupportedRegister, // mxcsr |
| 1471 | 65 => return error.UnsupportedRegister, // fcw |
| 1472 | 66 => return error.UnsupportedRegister, // fsw |
| 1473 | 67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512) |
| 1474 | 118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512) |
| 1475 | 130...145 => return error.UnsupportedRegister, // r16 - r31 (APX) |
| 1476 | |
| 1477 | else => return error.InvalidRegister, |
| 1478 | } |
| 1479 | } |
| 1480 | }; |
| 1481 | |
| 1129 | 1482 | /// The native operating system's `ucontext_t` as seen in the third argument to signal handlers. |
| 1130 | 1483 | /// |
| 1131 | 1484 | /// These are dramatically simplified since we only need general-purpose registers and don't care |
| ... | ... | @@ -1227,7 +1580,7 @@ const signal_ucontext_t = switch (native_os) { |
| 1227 | 1580 | _count: u32, |
| 1228 | 1581 | }, |
| 1229 | 1582 | _status32: u32, |
| 1230 | | pc: u32, |
| 1583 | pcl: u32, |
| 1231 | 1584 | r31: u32, |
| 1232 | 1585 | r27_26: [2]u32, |
| 1233 | 1586 | r12_0: [13]u32, |