authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-10-08 06:29:28+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-10-08 06:29:28+02:00
log2aea7a42b085f1775889f9d49141faa8098221f9
tree2d59b52da1298ca39b0b57867144852ae8da18d3
parente959a86bb92006eea4d0f15cc1c0f82ecccbc58b
parenta54906b46e01f708fb521cb01445808382ef9954
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25493 from alexrp/std-debug-mips-ppc

`std.debug`: MIPS and PowerPC unwind support + some other stuff

9 files changed, 436 insertions(+), 81 deletions(-)

lib/std/debug.zig+2-2
...@@ -623,7 +623,7 @@ pub const StackUnwindOptions = struct {...@@ -623,7 +623,7 @@ pub const StackUnwindOptions = struct {
623/// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`.623/// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`.
624///624///
625/// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it.625/// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it.
626pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace {626pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace {
627 const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} };627 const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} };
628 if (!std.options.allow_stack_tracing) return empty_trace;628 if (!std.options.allow_stack_tracing) return empty_trace;
629 var it = StackIterator.init(options.context) catch return empty_trace;629 var it = StackIterator.init(options.context) catch return empty_trace;
...@@ -661,7 +661,7 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize)...@@ -661,7 +661,7 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize)
661/// Write the current stack trace to `writer`, annotated with source locations.661/// Write the current stack trace to `writer`, annotated with source locations.
662///662///
663/// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing.663/// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing.
664pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void {664pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void {
665 if (!std.options.allow_stack_tracing) {665 if (!std.options.allow_stack_tracing) {
666 tty_config.setColor(writer, .dim) catch {};666 tty_config.setColor(writer, .dim) catch {};
667 try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{});667 try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{});
lib/std/debug/Dwarf.zig+8-2
...@@ -1432,8 +1432,10 @@ pub fn ipRegNum(arch: std.Target.Cpu.Arch) ?u16 {...@@ -1432,8 +1432,10 @@ pub fn ipRegNum(arch: std.Target.Cpu.Arch) ?u16 {
1432 .aarch64, .aarch64_be => 32,1432 .aarch64, .aarch64_be => 32,
1433 .arm, .armeb, .thumb, .thumbeb => 15,1433 .arm, .armeb, .thumb, .thumbeb => 15,
1434 .hexagon => 76,1434 .hexagon => 76,
1435 .loongarch32, .loongarch64 => 32,1435 .loongarch32, .loongarch64 => 64,
1436 .riscv32, .riscv32be, .riscv64, .riscv64be => 32,1436 .mips, .mipsel, .mips64, .mips64el => 66,
1437 .powerpc, .powerpcle, .powerpc64, .powerpc64le => 67,
1438 .riscv32, .riscv32be, .riscv64, .riscv64be => 65,
1437 .s390x => 65,1439 .s390x => 65,
1438 .x86 => 8,1440 .x86 => 8,
1439 .x86_64 => 16,1441 .x86_64 => 16,
...@@ -1447,6 +1449,8 @@ pub fn fpRegNum(arch: std.Target.Cpu.Arch) u16 {...@@ -1447,6 +1449,8 @@ pub fn fpRegNum(arch: std.Target.Cpu.Arch) u16 {
1447 .arm, .armeb, .thumb, .thumbeb => 11,1449 .arm, .armeb, .thumb, .thumbeb => 11,
1448 .hexagon => 30,1450 .hexagon => 30,
1449 .loongarch32, .loongarch64 => 22,1451 .loongarch32, .loongarch64 => 22,
1452 .mips, .mipsel, .mips64, .mips64el => 30,
1453 .powerpc, .powerpcle, .powerpc64, .powerpc64le => 1,
1450 .riscv32, .riscv32be, .riscv64, .riscv64be => 8,1454 .riscv32, .riscv32be, .riscv64, .riscv64be => 8,
1451 .s390x => 11,1455 .s390x => 11,
1452 .x86 => 5,1456 .x86 => 5,
...@@ -1461,6 +1465,8 @@ pub fn spRegNum(arch: std.Target.Cpu.Arch) u16 {...@@ -1461,6 +1465,8 @@ pub fn spRegNum(arch: std.Target.Cpu.Arch) u16 {
1461 .arm, .armeb, .thumb, .thumbeb => 13,1465 .arm, .armeb, .thumb, .thumbeb => 13,
1462 .hexagon => 29,1466 .hexagon => 29,
1463 .loongarch32, .loongarch64 => 3,1467 .loongarch32, .loongarch64 => 3,
1468 .mips, .mipsel, .mips64, .mips64el => 29,
1469 .powerpc, .powerpcle, .powerpc64, .powerpc64le => 1,
1464 .riscv32, .riscv32be, .riscv64, .riscv64be => 2,1470 .riscv32, .riscv32be, .riscv64, .riscv64be => 2,
1465 .s390x => 15,1471 .s390x => 15,
1466 .x86 => 4,1472 .x86 => 4,
lib/std/debug/Dwarf/SelfUnwinder.zig+4-2
...@@ -229,8 +229,10 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE...@@ -229,8 +229,10 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
229 } = switch (rule) {229 } = switch (rule) {
230 .default => val: {230 .default => val: {
231 // The default rule is typically equivalent to `.undefined`, but ABIs may override it.231 // The default rule is typically equivalent to `.undefined`, but ABIs may override it.
232 if (builtin.cpu.arch.isAARCH64() and register >= 19 and register <= 28) {232 switch (builtin.target.cpu.arch) {
233 break :val .same;233 .aarch64, .aarch64_be => if (register >= 19 and register <= 28) break :val .same,
234 .s390x => if (register >= 6 and register <= 15) break :val .same,
235 else => {},
234 }236 }
235 break :val .undefined;237 break :val .undefined;
236 },238 },
lib/std/debug/Dwarf/expression.zig+4-7
...@@ -1160,22 +1160,19 @@ test "basics" {...@@ -1160,22 +1160,19 @@ test "basics" {
11601160
1161 mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);1161 mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);
1162 (try regNative(&cpu_context, fp_reg_num)).* = 1;1162 (try regNative(&cpu_context, fp_reg_num)).* = 1;
1163 (try regNative(&cpu_context, sp_reg_num)).* = 2;1163 (try regNative(&cpu_context, ip_reg_num)).* = 2;
1164 (try regNative(&cpu_context, ip_reg_num)).* = 3;
11651164
1166 try b.writeBreg(writer, fp_reg_num, @as(usize, 100));1165 try b.writeBreg(writer, fp_reg_num, @as(usize, 100));
1167 try b.writeBreg(writer, sp_reg_num, @as(usize, 200));1166 try b.writeBregx(writer, ip_reg_num, @as(usize, 200));
1168 try b.writeBregx(writer, ip_reg_num, @as(usize, 300));1167 try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 300));
1169 try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400));
11701168
1171 _ = try stack_machine.run(program.written(), allocator, context, 0);1169 _ = try stack_machine.run(program.written(), allocator, context, 0);
11721170
1173 const regval_type = stack_machine.stack.pop().?.regval_type;1171 const regval_type = stack_machine.stack.pop().?.regval_type;
1174 try testing.expectEqual(@as(usize, 400), regval_type.type_offset);1172 try testing.expectEqual(@as(usize, 300), regval_type.type_offset);
1175 try testing.expectEqual(@as(u8, @sizeOf(usize)), regval_type.type_size);1173 try testing.expectEqual(@as(u8, @sizeOf(usize)), regval_type.type_size);
1176 try testing.expectEqual(@as(usize, 0xee), regval_type.value);1174 try testing.expectEqual(@as(usize, 0xee), regval_type.value);
11771175
1178 try testing.expectEqual(@as(usize, 303), stack_machine.stack.pop().?.generic);
1179 try testing.expectEqual(@as(usize, 202), stack_machine.stack.pop().?.generic);1176 try testing.expectEqual(@as(usize, 202), stack_machine.stack.pop().?.generic);
1180 try testing.expectEqual(@as(usize, 101), stack_machine.stack.pop().?.generic);1177 try testing.expectEqual(@as(usize, 101), stack_machine.stack.pop().?.generic);
1181 }1178 }
lib/std/debug/SelfInfo/Elf.zig+8
...@@ -99,6 +99,14 @@ pub const can_unwind: bool = s: {...@@ -99,6 +99,14 @@ pub const can_unwind: bool = s: {
99 .aarch64_be,99 .aarch64_be,
100 .hexagon,100 .hexagon,
101 .loongarch64,101 .loongarch64,
102 .mips,
103 .mipsel,
104 .mips64,
105 .mips64el,
106 .powerpc,
107 .powerpcle,
108 .powerpc64,
109 .powerpc64le,
102 .riscv32,110 .riscv32,
103 .riscv64,111 .riscv64,
104 .s390x,112 .s390x,
lib/std/debug/cpu_context.zig+350-61
...@@ -8,6 +8,8 @@ else switch (native_arch) {...@@ -8,6 +8,8 @@ else switch (native_arch) {
8 .arm, .armeb, .thumb, .thumbeb => Arm,8 .arm, .armeb, .thumb, .thumbeb => Arm,
9 .hexagon => Hexagon,9 .hexagon => Hexagon,
10 .loongarch32, .loongarch64 => LoongArch,10 .loongarch32, .loongarch64 => LoongArch,
11 .mips, .mipsel, .mips64, .mips64el => Mips,
12 .powerpc, .powerpcle, .powerpc64, .powerpc64le => Powerpc,
11 .riscv32, .riscv32be, .riscv64, .riscv64be => Riscv,13 .riscv32, .riscv32be, .riscv64, .riscv64be => Riscv,
12 .s390x => S390x,14 .s390x => S390x,
13 .x86 => X86,15 .x86 => X86,
...@@ -196,6 +198,33 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {...@@ -196,6 +198,33 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
196 },198 },
197 else => null,199 else => null,
198 },200 },
201 .mips, .mipsel => switch (builtin.os.tag) {
202 // The O32 kABI uses 64-bit fields for some reason...
203 .linux => .{
204 .r = s: {
205 var regs: [32]Mips.Gpr = undefined;
206 for (uc.mcontext.regs, 0..) |r, i| regs[i] = @truncate(r); // includes r0 (hardwired zero)
207 break :s regs;
208 },
209 .pc = @truncate(uc.mcontext.pc),
210 },
211 else => null,
212 },
213 .mips64, .mips64el => switch (builtin.os.tag) {
214 .linux => .{
215 .r = uc.mcontext.regs, // includes r0 (hardwired zero)
216 .pc = uc.mcontext.pc,
217 },
218 else => null,
219 },
220 .powerpc, .powerpcle, .powerpc64, .powerpc64le => switch (builtin.os.tag) {
221 .linux => .{
222 .r = uc.mcontext.gp_regs[0..32].*,
223 .pc = uc.mcontext.gp_regs[32],
224 .lr = uc.mcontext.gp_regs[36],
225 },
226 else => null,
227 },
199 .riscv32, .riscv64 => switch (builtin.os.tag) {228 .riscv32, .riscv64 => switch (builtin.os.tag) {
200 .linux => .{229 .linux => .{
201 .r = [1]usize{0} ++ uc.mcontext.gregs[1..].*, // r0 position is used for pc; replace with zero230 .r = [1]usize{0} ++ uc.mcontext.gregs[1..].*, // r0 position is used for pc; replace with zero
...@@ -210,7 +239,6 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {...@@ -210,7 +239,6 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
210 .s390x => switch (builtin.os.tag) {239 .s390x => switch (builtin.os.tag) {
211 .linux => .{240 .linux => .{
212 .r = uc.mcontext.gregs,241 .r = uc.mcontext.gregs,
213 .f = uc.mcontext.fregs,
214 .psw = .{242 .psw = .{
215 .mask = uc.mcontext.psw.mask,243 .mask = uc.mcontext.psw.mask,
216 .addr = uc.mcontext.psw.addr,244 .addr = uc.mcontext.psw.addr,
...@@ -269,7 +297,7 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native {...@@ -269,7 +297,7 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native {
269 };297 };
270}298}
271299
272pub const X86 = struct {300const X86 = struct {
273 /// The first 8 registers here intentionally match the order of registers in the x86 instruction301 /// The first 8 registers here intentionally match the order of registers in the x86 instruction
274 /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings,302 /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings,
275 /// among other things.303 /// among other things.
...@@ -313,7 +341,7 @@ pub const X86 = struct {...@@ -313,7 +341,7 @@ pub const X86 = struct {
313 // x86-macos is a deprecated target which is not supported by the Zig Standard Library.341 // x86-macos is a deprecated target which is not supported by the Zig Standard Library.
314 0...8 => return @ptrCast(&ctx.gprs.values[register_num]),342 0...8 => return @ptrCast(&ctx.gprs.values[register_num]),
315343
316 9 => return error.UnsupportedRegister, // rflags344 9 => return error.UnsupportedRegister, // eflags
317 11...18 => return error.UnsupportedRegister, // st0 - st7345 11...18 => return error.UnsupportedRegister, // st0 - st7
318 21...28 => return error.UnsupportedRegister, // xmm0 - xmm7346 21...28 => return error.UnsupportedRegister, // xmm0 - xmm7
319 29...36 => return error.UnsupportedRegister, // mm0 - mm7347 29...36 => return error.UnsupportedRegister, // mm0 - mm7
...@@ -321,14 +349,14 @@ pub const X86 = struct {...@@ -321,14 +349,14 @@ pub const X86 = struct {
321 40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs349 40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
322 48 => return error.UnsupportedRegister, // tr350 48 => return error.UnsupportedRegister, // tr
323 49 => return error.UnsupportedRegister, // ldtr351 49 => return error.UnsupportedRegister, // ldtr
324 93...94 => return error.UnsupportedRegister, // fs.base, gs.base352 93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
325353
326 else => return error.InvalidRegister,354 else => return error.InvalidRegister,
327 }355 }
328 }356 }
329};357};
330358
331pub const X86_64 = struct {359const X86_64 = struct {
332 /// The order here intentionally matches the order of the DWARF register mappings. It's unclear360 /// The order here intentionally matches the order of the DWARF register mappings. It's unclear
333 /// where those mappings actually originated from---the ordering of the first 4 registers seems361 /// where those mappings actually originated from---the ordering of the first 4 registers seems
334 /// quite unusual---but it is currently convenient for us to match DWARF.362 /// quite unusual---but it is currently convenient for us to match DWARF.
...@@ -389,13 +417,16 @@ pub const X86_64 = struct {...@@ -389,13 +417,16 @@ pub const X86_64 = struct {
389 64 => return error.UnsupportedRegister, // mxcsr417 64 => return error.UnsupportedRegister, // mxcsr
390 65 => return error.UnsupportedRegister, // fcw418 65 => return error.UnsupportedRegister, // fcw
391 66 => return error.UnsupportedRegister, // fsw419 66 => return error.UnsupportedRegister, // fsw
420 67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512)
421 118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
422 130...145 => return error.UnsupportedRegister, // r16 - r31 (APX)
392423
393 else => return error.InvalidRegister,424 else => return error.InvalidRegister,
394 }425 }
395 }426 }
396};427};
397428
398pub const Arm = struct {429const Arm = struct {
399 /// The numbered general-purpose registers R0 - R15.430 /// The numbered general-purpose registers R0 - R15.
400 r: [16]u32,431 r: [16]u32,
401432
...@@ -449,7 +480,7 @@ pub const Arm = struct {...@@ -449,7 +480,7 @@ pub const Arm = struct {
449};480};
450481
451/// This is an `extern struct` so that inline assembly in `current` can use field offsets.482/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
452pub const Aarch64 = extern struct {483const Aarch64 = extern struct {
453 /// The numbered general-purpose registers X0 - X30.484 /// The numbered general-purpose registers X0 - X30.
454 x: [31]u64,485 x: [31]u64,
455 sp: u64,486 sp: u64,
...@@ -492,13 +523,13 @@ pub const Aarch64 = extern struct {...@@ -492,13 +523,13 @@ pub const Aarch64 = extern struct {
492 31 => return @ptrCast(&ctx.sp),523 31 => return @ptrCast(&ctx.sp),
493 32 => return @ptrCast(&ctx.pc),524 32 => return @ptrCast(&ctx.pc),
494525
495 33 => return error.UnsupportedRegister, // ELF_mode526 33 => return error.UnsupportedRegister, // ELR_mode
496 34 => return error.UnsupportedRegister, // RA_SIGN_STATE527 34 => return error.UnsupportedRegister, // RA_SIGN_STATE
497 35 => return error.UnsupportedRegister, // TPIDRRO_ELO528 35 => return error.UnsupportedRegister, // TPIDRRO_ELO
498 36 => return error.UnsupportedRegister, // RPIDR_ELO529 36 => return error.UnsupportedRegister, // TPIDR_ELO
499 37 => return error.UnsupportedRegister, // RPIDR_EL1530 37 => return error.UnsupportedRegister, // TPIDR_EL1
500 38 => return error.UnsupportedRegister, // RPIDR_EL2531 38 => return error.UnsupportedRegister, // TPIDR_EL2
501 39 => return error.UnsupportedRegister, // RPIDR_EL3532 39 => return error.UnsupportedRegister, // TPIDR_EL3
502 46 => return error.UnsupportedRegister, // VG533 46 => return error.UnsupportedRegister, // VG
503 47 => return error.UnsupportedRegister, // FFR534 47 => return error.UnsupportedRegister, // FFR
504 48...63 => return error.UnsupportedRegister, // P0 - P15535 48...63 => return error.UnsupportedRegister, // P0 - P15
...@@ -511,7 +542,7 @@ pub const Aarch64 = extern struct {...@@ -511,7 +542,7 @@ pub const Aarch64 = extern struct {
511};542};
512543
513/// This is an `extern struct` so that inline assembly in `current` can use field offsets.544/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
514pub const Hexagon = extern struct {545const Hexagon = extern struct {
515 /// The numbered general-purpose registers r0 - r31.546 /// The numbered general-purpose registers r0 - r31.
516 r: [32]u32,547 r: [32]u32,
517 pc: u32,548 pc: u32,
...@@ -579,14 +610,16 @@ pub const Hexagon = extern struct {...@@ -579,14 +610,16 @@ pub const Hexagon = extern struct {
579};610};
580611
581/// This is an `extern struct` so that inline assembly in `current` can use field offsets.612/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
582pub const LoongArch = extern struct {613const LoongArch = extern struct {
583 /// The numbered general-purpose registers r0 - r31. r0 must be zero.614 /// The numbered general-purpose registers r0 - r31. r0 must be zero.
584 r: [32]usize,615 r: [32]Gpr,
585 pc: usize,616 pc: Gpr,
617
618 pub const Gpr = if (builtin.target.cpu.arch == .loongarch64) u64 else u32;
586619
587 pub inline fn current() LoongArch {620 pub inline fn current() LoongArch {
588 var ctx: LoongArch = undefined;621 var ctx: LoongArch = undefined;
589 asm volatile (if (@sizeOf(usize) == 8)622 asm volatile (if (Gpr == u64)
590 \\ st.d $zero, $t0, 0623 \\ st.d $zero, $t0, 0
591 \\ st.d $ra, $t0, 8624 \\ st.d $ra, $t0, 8
592 \\ st.d $tp, $t0, 16625 \\ st.d $tp, $t0, 16
...@@ -669,7 +702,9 @@ pub const LoongArch = extern struct {...@@ -669,7 +702,9 @@ pub const LoongArch = extern struct {
669 pub fn dwarfRegisterBytes(ctx: *LoongArch, register_num: u16) DwarfRegisterError![]u8 {702 pub fn dwarfRegisterBytes(ctx: *LoongArch, register_num: u16) DwarfRegisterError![]u8 {
670 switch (register_num) {703 switch (register_num) {
671 0...31 => return @ptrCast(&ctx.r[register_num]),704 0...31 => return @ptrCast(&ctx.r[register_num]),
672 32 => return @ptrCast(&ctx.pc),705 64 => return @ptrCast(&ctx.pc),
706
707 32...63 => return error.UnsupportedRegister, // f0 - f31
673708
674 else => return error.InvalidRegister,709 else => return error.InvalidRegister,
675 }710 }
...@@ -677,14 +712,294 @@ pub const LoongArch = extern struct {...@@ -677,14 +712,294 @@ pub const LoongArch = extern struct {
677};712};
678713
679/// This is an `extern struct` so that inline assembly in `current` can use field offsets.714/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
680pub const Riscv = extern struct {715const Mips = extern struct {
681 /// The numbered general-purpose registers r0 - r31. r0 must be zero.716 /// The numbered general-purpose registers r0 - r31. r0 must be zero.
682 r: [32]usize,717 r: [32]Gpr,
683 pc: usize,718 pc: Gpr,
719
720 pub const Gpr = if (builtin.target.cpu.arch.isMIPS64()) u64 else u32;
721
722 pub inline fn current() Mips {
723 var ctx: Mips = undefined;
724 asm volatile (if (Gpr == u64)
725 \\ .set push
726 \\ .set noat
727 \\ .set noreorder
728 \\ .set nomacro
729 \\ sd $zero, 0($t0)
730 \\ sd $at, 8($t0)
731 \\ sd $v0, 16($t0)
732 \\ sd $v1, 24($t0)
733 \\ sd $a0, 32($t0)
734 \\ sd $a1, 40($t0)
735 \\ sd $a2, 48($t0)
736 \\ sd $a3, 56($t0)
737 \\ sd $a4, 64($t0)
738 \\ sd $a5, 72($t0)
739 \\ sd $a6, 80($t0)
740 \\ sd $a7, 88($t0)
741 \\ sd $t0, 96($t0)
742 \\ sd $t1, 104($t0)
743 \\ sd $t2, 112($t0)
744 \\ sd $t3, 120($t0)
745 \\ sd $s0, 128($t0)
746 \\ sd $s1, 136($t0)
747 \\ sd $s2, 144($t0)
748 \\ sd $s3, 152($t0)
749 \\ sd $s4, 160($t0)
750 \\ sd $s5, 168($t0)
751 \\ sd $s6, 176($t0)
752 \\ sd $s7, 184($t0)
753 \\ sd $t8, 192($t0)
754 \\ sd $t9, 200($t0)
755 \\ sd $k0, 208($t0)
756 \\ sd $k1, 216($t0)
757 \\ sd $gp, 224($t0)
758 \\ sd $sp, 232($t0)
759 \\ sd $fp, 240($t0)
760 \\ sd $ra, 248($t0)
761 \\ bal 1f
762 \\1:
763 \\ sd $ra, 256($t0)
764 \\ ld $ra, 248($t0)
765 \\ .set pop
766 else
767 \\ .set push
768 \\ .set noat
769 \\ .set noreorder
770 \\ .set nomacro
771 \\ sw $zero, 0($t4)
772 \\ sw $at, 4($t4)
773 \\ sw $v0, 8($t4)
774 \\ sw $v1, 12($t4)
775 \\ sw $a0, 16($t4)
776 \\ sw $a1, 20($t4)
777 \\ sw $a2, 24($t4)
778 \\ sw $a3, 28($t4)
779 \\ sw $t0, 32($t4)
780 \\ sw $t1, 36($t4)
781 \\ sw $t2, 40($t4)
782 \\ sw $t3, 44($t4)
783 \\ sw $t4, 48($t4)
784 \\ sw $t5, 52($t4)
785 \\ sw $t6, 56($t4)
786 \\ sw $t7, 60($t4)
787 \\ sw $s0, 64($t4)
788 \\ sw $s1, 68($t4)
789 \\ sw $s2, 72($t4)
790 \\ sw $s3, 76($t4)
791 \\ sw $s4, 80($t4)
792 \\ sw $s5, 84($t4)
793 \\ sw $s6, 88($t4)
794 \\ sw $s7, 92($t4)
795 \\ sw $t8, 96($t4)
796 \\ sw $t9, 100($t4)
797 \\ sw $k0, 104($t4)
798 \\ sw $k1, 108($t4)
799 \\ sw $gp, 112($t4)
800 \\ sw $sp, 116($t4)
801 \\ sw $fp, 120($t4)
802 \\ sw $ra, 124($t4)
803 \\ bal 1f
804 \\1:
805 \\ sw $ra, 128($t4)
806 \\ lw $ra, 124($t4)
807 \\ .set pop
808 :
809 : [gprs] "{$12}" (&ctx),
810 : .{ .memory = true });
811 return ctx;
812 }
813
814 pub fn dwarfRegisterBytes(ctx: *Mips, register_num: u16) DwarfRegisterError![]u8 {
815 switch (register_num) {
816 0...31 => return @ptrCast(&ctx.r[register_num]),
817 66 => return @ptrCast(&ctx.pc),
818
819 // Who the hell knows what numbers exist for this architecture? What's an ABI
820 // specification anyway? We don't need that nonsense.
821 32...63 => return error.UnsupportedRegister, // f0 - f31, w0 - w31
822 64 => return error.UnsupportedRegister, // hi0 (ac0)
823 65 => return error.UnsupportedRegister, // lo0 (ac0)
824 176 => return error.UnsupportedRegister, // hi1 (ac1)
825 177 => return error.UnsupportedRegister, // lo1 (ac1)
826 178 => return error.UnsupportedRegister, // hi2 (ac2)
827 179 => return error.UnsupportedRegister, // lo2 (ac2)
828 180 => return error.UnsupportedRegister, // hi3 (ac3)
829 181 => return error.UnsupportedRegister, // lo3 (ac3)
830
831 else => return error.InvalidRegister,
832 }
833 }
834};
835
836/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
837const Powerpc = extern struct {
838 /// The numbered general-purpose registers r0 - r31.
839 r: [32]Gpr,
840 pc: Gpr,
841 lr: Gpr,
842
843 pub const Gpr = if (builtin.target.cpu.arch.isPowerPC64()) u64 else u32;
844
845 pub inline fn current() Powerpc {
846 var ctx: Powerpc = undefined;
847 asm volatile (if (Gpr == u64)
848 \\ std 0, 0(10)
849 \\ std 1, 8(10)
850 \\ std 2, 16(10)
851 \\ std 3, 24(10)
852 \\ std 4, 32(10)
853 \\ std 5, 40(10)
854 \\ std 6, 48(10)
855 \\ std 7, 56(10)
856 \\ std 8, 64(10)
857 \\ std 9, 72(10)
858 \\ std 10, 80(10)
859 \\ std 11, 88(10)
860 \\ std 12, 96(10)
861 \\ std 13, 104(10)
862 \\ std 14, 112(10)
863 \\ std 15, 120(10)
864 \\ std 16, 128(10)
865 \\ std 17, 136(10)
866 \\ std 18, 144(10)
867 \\ std 19, 152(10)
868 \\ std 20, 160(10)
869 \\ std 21, 168(10)
870 \\ std 22, 176(10)
871 \\ std 23, 184(10)
872 \\ std 24, 192(10)
873 \\ std 25, 200(10)
874 \\ std 26, 208(10)
875 \\ std 27, 216(10)
876 \\ std 28, 224(10)
877 \\ std 29, 232(10)
878 \\ std 30, 240(10)
879 \\ std 31, 248(10)
880 \\ mflr 8
881 \\ std 8, 264(10)
882 \\ bl 1f
883 \\1:
884 \\ mflr 8
885 \\ std 8, 256(10)
886 \\ ld 8, 64(10)
887 else
888 \\ stw 0, 0(10)
889 \\ stw 1, 4(10)
890 \\ stw 2, 8(10)
891 \\ stw 3, 12(10)
892 \\ stw 4, 16(10)
893 \\ stw 5, 20(10)
894 \\ stw 6, 24(10)
895 \\ stw 7, 28(10)
896 \\ stw 8, 32(10)
897 \\ stw 9, 36(10)
898 \\ stw 10, 40(10)
899 \\ stw 11, 44(10)
900 \\ stw 12, 48(10)
901 \\ stw 13, 52(10)
902 \\ stw 14, 56(10)
903 \\ stw 15, 60(10)
904 \\ stw 16, 64(10)
905 \\ stw 17, 68(10)
906 \\ stw 18, 72(10)
907 \\ stw 19, 76(10)
908 \\ stw 20, 80(10)
909 \\ stw 21, 84(10)
910 \\ stw 22, 88(10)
911 \\ stw 23, 92(10)
912 \\ stw 24, 96(10)
913 \\ stw 25, 100(10)
914 \\ stw 26, 104(10)
915 \\ stw 27, 108(10)
916 \\ stw 28, 112(10)
917 \\ stw 29, 116(10)
918 \\ stw 30, 120(10)
919 \\ stw 31, 124(10)
920 \\ mflr 8
921 \\ stw 8, 132(10)
922 \\ bl 1f
923 \\1:
924 \\ mflr 8
925 \\ stw 8, 128(10)
926 \\ lwz 8, 32(10)
927 :
928 : [gprs] "{r10}" (&ctx),
929 : .{ .lr = true, .memory = true });
930 return ctx;
931 }
932
933 pub fn dwarfRegisterBytes(ctx: *Powerpc, register_num: u16) DwarfRegisterError![]u8 {
934 // References:
935 //
936 // * System V Application Binary Interface - PowerPC Processor Supplement §3-46
937 // * Power Architecture 32-bit Application Binary Interface Supplement 1.0 - Linux & Embedded §3.4
938 // * 64-bit ELF V2 ABI Specification - Power Architecture Revision 1.5 §2.4
939 // * ??? AIX?
940 //
941 // Are we having fun yet?
942
943 if (Gpr == u64) switch (register_num) {
944 65 => return @ptrCast(&ctx.lr), // lr
945
946 66 => return error.UnsupportedRegister, // ctr
947 68...75 => return error.UnsupportedRegister, // cr0 - cr7
948 76 => return error.UnsupportedRegister, // xer
949 77...108 => return error.UnsupportedRegister, // vr0 - vr31
950 109 => return error.UnsupportedRegister, // vrsave (LLVM)
951 110 => return error.UnsupportedRegister, // vscr
952 114 => return error.UnsupportedRegister, // tfhar
953 115 => return error.UnsupportedRegister, // tfiar
954 116 => return error.UnsupportedRegister, // texasr
955
956 else => {},
957 } else switch (register_num) {
958 65 => return @ptrCast(&ctx.lr), // fpscr (SVR4 / EABI), or lr if you ask LLVM
959 108 => return @ptrCast(&ctx.lr),
960
961 64 => return error.UnsupportedRegister, // cr
962 66 => return error.UnsupportedRegister, // msr (SVR4 / EABI), or ctr if you ask LLVM
963 68...75 => return error.UnsupportedRegister, // cr0 - cr7 if you ask LLVM
964 76 => return error.UnsupportedRegister, // xer if you ask LLVM
965 99 => return error.UnsupportedRegister, // acc
966 100 => return error.UnsupportedRegister, // mq
967 101 => return error.UnsupportedRegister, // xer
968 102...107 => return error.UnsupportedRegister, // SPRs
969 109 => return error.UnsupportedRegister, // ctr
970 110...111 => return error.UnsupportedRegister, // SPRs
971 112 => return error.UnsupportedRegister, // spefscr
972 113...1123 => return error.UnsupportedRegister, // SPRs
973 1124...1155 => return error.UnsupportedRegister, // SPE v0 - v31
974 1200...1231 => return error.UnsupportedRegister, // SPE upper r0 - r31
975 3072...4095 => return error.UnsupportedRegister, // DCRs
976 4096...5120 => return error.UnsupportedRegister, // PMRs
977
978 else => {},
979 }
980
981 switch (register_num) {
982 0...31 => return @ptrCast(&ctx.r[register_num]),
983 67 => return @ptrCast(&ctx.pc),
984
985 32...63 => return error.UnsupportedRegister, // f0 - f31
986
987 else => return error.InvalidRegister,
988 }
989 }
990};
991
992/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
993const Riscv = extern struct {
994 /// The numbered general-purpose registers r0 - r31. r0 must be zero.
995 r: [32]Gpr,
996 pc: Gpr,
997
998 pub const Gpr = if (builtin.target.cpu.arch.isRiscv64()) u64 else u32;
684999
685 pub inline fn current() Riscv {1000 pub inline fn current() Riscv {
686 var ctx: Riscv = undefined;1001 var ctx: Riscv = undefined;
687 asm volatile (if (@sizeOf(usize) == 8)1002 asm volatile (if (Gpr == u64)
688 \\ sd zero, 0(t0)1003 \\ sd zero, 0(t0)
689 \\ sd ra, 8(t0)1004 \\ sd ra, 8(t0)
690 \\ sd sp, 16(t0)1005 \\ sd sp, 16(t0)
...@@ -767,7 +1082,13 @@ pub const Riscv = extern struct {...@@ -767,7 +1082,13 @@ pub const Riscv = extern struct {
767 pub fn dwarfRegisterBytes(ctx: *Riscv, register_num: u16) DwarfRegisterError![]u8 {1082 pub fn dwarfRegisterBytes(ctx: *Riscv, register_num: u16) DwarfRegisterError![]u8 {
768 switch (register_num) {1083 switch (register_num) {
769 0...31 => return @ptrCast(&ctx.r[register_num]),1084 0...31 => return @ptrCast(&ctx.r[register_num]),
770 32 => return @ptrCast(&ctx.pc),1085 65 => return @ptrCast(&ctx.pc),
1086
1087 32...63 => return error.UnsupportedRegister, // f0 - f31
1088 64 => return error.UnsupportedRegister, // Alternate Frame Return Column
1089 96...127 => return error.UnsupportedRegister, // v0 - v31
1090 3072...4095 => return error.UnsupportedRegister, // Custom extensions
1091 4096...8191 => return error.UnsupportedRegister, // CSRs
7711092
772 else => return error.InvalidRegister,1093 else => return error.InvalidRegister,
773 }1094 }
...@@ -775,11 +1096,9 @@ pub const Riscv = extern struct {...@@ -775,11 +1096,9 @@ pub const Riscv = extern struct {
775};1096};
7761097
777/// This is an `extern struct` so that inline assembly in `current` can use field offsets.1098/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
778pub const S390x = extern struct {1099const S390x = extern struct {
779 /// The numbered general-purpose registers r0 - r15.1100 /// The numbered general-purpose registers r0 - r15.
780 r: [16]u64,1101 r: [16]u64,
781 /// The numbered floating-point registers f0 - f15. Yes, really - they can be used in DWARF CFI.
782 f: [16]f64,
783 /// The program counter.1102 /// The program counter.
784 psw: extern struct {1103 psw: extern struct {
785 mask: u64,1104 mask: u64,
...@@ -790,26 +1109,10 @@ pub const S390x = extern struct {...@@ -790,26 +1109,10 @@ pub const S390x = extern struct {
790 var ctx: S390x = undefined;1109 var ctx: S390x = undefined;
791 asm volatile (1110 asm volatile (
792 \\ stmg %%r0, %%r15, 0(%%r2)1111 \\ stmg %%r0, %%r15, 0(%%r2)
793 \\ std %%f0, 128(%%r2)
794 \\ std %%f1, 136(%%r2)
795 \\ std %%f2, 144(%%r2)
796 \\ std %%f3, 152(%%r2)
797 \\ std %%f4, 160(%%r2)
798 \\ std %%f5, 168(%%r2)
799 \\ std %%f6, 176(%%r2)
800 \\ std %%f7, 184(%%r2)
801 \\ std %%f8, 192(%%r2)
802 \\ std %%f9, 200(%%r2)
803 \\ std %%f10, 208(%%r2)
804 \\ std %%f11, 216(%%r2)
805 \\ std %%f12, 224(%%r2)
806 \\ std %%f13, 232(%%r2)
807 \\ std %%f14, 240(%%r2)
808 \\ std %%f15, 248(%%r2)
809 \\ epsw %%r0, %%r11112 \\ epsw %%r0, %%r1
810 \\ stm %%r0, %%r1, 256(%%r2)1113 \\ stm %%r0, %%r1, 128(%%r2)
811 \\ larl %%r0, .1114 \\ larl %%r0, .
812 \\ stg %%r0, 264(%%r2)1115 \\ stg %%r0, 136(%%r2)
813 \\ lg %%r0, 0(%%r2)1116 \\ lg %%r0, 0(%%r2)
814 \\ lg %%r1, 8(%%r2)1117 \\ lg %%r1, 8(%%r2)
815 :1118 :
...@@ -821,27 +1124,13 @@ pub const S390x = extern struct {...@@ -821,27 +1124,13 @@ pub const S390x = extern struct {
821 pub fn dwarfRegisterBytes(ctx: *S390x, register_num: u16) DwarfRegisterError![]u8 {1124 pub fn dwarfRegisterBytes(ctx: *S390x, register_num: u16) DwarfRegisterError![]u8 {
822 switch (register_num) {1125 switch (register_num) {
823 0...15 => return @ptrCast(&ctx.r[register_num]),1126 0...15 => return @ptrCast(&ctx.r[register_num]),
824 // Why???
825 16 => return @ptrCast(&ctx.f[0]),
826 17 => return @ptrCast(&ctx.f[2]),
827 18 => return @ptrCast(&ctx.f[4]),
828 19 => return @ptrCast(&ctx.f[6]),
829 20 => return @ptrCast(&ctx.f[1]),
830 21 => return @ptrCast(&ctx.f[3]),
831 22 => return @ptrCast(&ctx.f[5]),
832 23 => return @ptrCast(&ctx.f[7]),
833 24 => return @ptrCast(&ctx.f[8]),
834 25 => return @ptrCast(&ctx.f[10]),
835 26 => return @ptrCast(&ctx.f[12]),
836 27 => return @ptrCast(&ctx.f[14]),
837 28 => return @ptrCast(&ctx.f[9]),
838 29 => return @ptrCast(&ctx.f[11]),
839 30 => return @ptrCast(&ctx.f[13]),
840 31 => return @ptrCast(&ctx.f[15]),
841 64 => return @ptrCast(&ctx.psw.mask),1127 64 => return @ptrCast(&ctx.psw.mask),
842 65 => return @ptrCast(&ctx.psw.addr),1128 65 => return @ptrCast(&ctx.psw.addr),
8431129
1130 16...31 => return error.UnsupportedRegister, // f0 - f15
1131 32...47 => return error.UnsupportedRegister, // cr0 - cr15
844 48...63 => return error.UnsupportedRegister, // a0 - a151132 48...63 => return error.UnsupportedRegister, // a0 - a15
1133 66...67 => return error.UnsupportedRegister, // z/OS stuff???
845 68...83 => return error.UnsupportedRegister, // v16 - v311134 68...83 => return error.UnsupportedRegister, // v16 - v31
8461135
847 else => return error.InvalidRegister,1136 else => return error.InvalidRegister,
lib/std/os/linux/hexagon.zig+3-3
...@@ -254,13 +254,13 @@ pub const mcontext_t = extern struct {...@@ -254,13 +254,13 @@ pub const mcontext_t = extern struct {
254 badva: u32,254 badva: u32,
255 cs0: u32,255 cs0: u32,
256 cs1: u32,256 cs1: u32,
257 _pad2: u32,257 _pad1: u32,
258};258};
259259
260pub const ucontext_t = extern struct {260pub const ucontext_t = extern struct {
261 flags: usize,261 flags: u32,
262 link: ?*ucontext_t,262 link: ?*ucontext_t,
263 stack: stack_t,263 stack: stack_t,
264 mcontext: mcontext_t,264 mcontext: mcontext_t,
265 sigmask: [2]u32,265 sigmask: sigset_t,
266};266};
lib/std/os/linux/mips.zig+30-2
...@@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;...@@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;
9const uid_t = linux.uid_t;9const uid_t = linux.uid_t;
10const gid_t = linux.gid_t;10const gid_t = linux.gid_t;
11const pid_t = linux.pid_t;11const pid_t = linux.pid_t;
12const stack_t = linux.stack_t;
13const sigset_t = linux.sigset_t;
12const sockaddr = linux.sockaddr;14const sockaddr = linux.sockaddr;
13const timespec = linux.timespec;15const timespec = linux.timespec;
1416
...@@ -347,5 +349,31 @@ pub const timezone = extern struct {...@@ -347,5 +349,31 @@ pub const timezone = extern struct {
347349
348pub const Elf_Symndx = u32;350pub const Elf_Symndx = u32;
349351
350/// TODO352pub const mcontext_t = extern struct {
351pub const ucontext_t = void;353 _regmask: u32,
354 _status: u32,
355 pc: u64,
356 regs: [32]u64,
357 fpregs: [32]f64,
358 acx: u32,
359 fpc_csr: u32,
360 _fpc_eir: u32,
361 used_math: u32,
362 dsp: u32,
363 mdhi: u64,
364 mdlo: u64,
365 hi1: u32,
366 lo1: u32,
367 hi2: u32,
368 lo2: u32,
369 hi3: u32,
370 lo3: u32,
371};
372
373pub const ucontext_t = extern struct {
374 flags: u32,
375 link: ?*ucontext_t,
376 stack: stack_t,
377 mcontext: mcontext_t,
378 sigmask: sigset_t,
379};
lib/std/os/linux/mips64.zig+27-2
...@@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;...@@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;
9const uid_t = linux.uid_t;9const uid_t = linux.uid_t;
10const gid_t = linux.gid_t;10const gid_t = linux.gid_t;
11const pid_t = linux.pid_t;11const pid_t = linux.pid_t;
12const stack_t = linux.stack_t;
13const sigset_t = linux.sigset_t;
12const sockaddr = linux.sockaddr;14const sockaddr = linux.sockaddr;
13const timespec = linux.timespec;15const timespec = linux.timespec;
1416
...@@ -326,5 +328,28 @@ pub const timezone = extern struct {...@@ -326,5 +328,28 @@ pub const timezone = extern struct {
326328
327pub const Elf_Symndx = u32;329pub const Elf_Symndx = u32;
328330
329/// TODO331pub const mcontext_t = extern struct {
330pub const ucontext_t = void;332 regs: [32]u64,
333 fpregs: [32]f64,
334 mdhi: u64,
335 hi1: u64,
336 hi2: u64,
337 hi3: u64,
338 mdlo: u64,
339 lo1: u64,
340 lo2: u64,
341 lo3: u64,
342 pc: u64,
343 fpc_csr: u32,
344 used_math: u32,
345 dsp: u32,
346 _reserved: u32,
347};
348
349pub const ucontext_t = extern struct {
350 flags: u32,
351 link: ?*ucontext_t,
352 stack: stack_t,
353 mcontext: mcontext_t,
354 sigmask: sigset_t,
355};