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 {
623623/// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`.
624624///
625625/// 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 {
627627 const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} };
628628 if (!std.options.allow_stack_tracing) return empty_trace;
629629 var it = StackIterator.init(options.context) catch return empty_trace;
......@@ -661,7 +661,7 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize)
661661/// Write the current stack trace to `writer`, annotated with source locations.
662662///
663663/// 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 {
665665 if (!std.options.allow_stack_tracing) {
666666 tty_config.setColor(writer, .dim) catch {};
667667 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 {
14321432 .aarch64, .aarch64_be => 32,
14331433 .arm, .armeb, .thumb, .thumbeb => 15,
14341434 .hexagon => 76,
1435 .loongarch32, .loongarch64 => 32,
1436 .riscv32, .riscv32be, .riscv64, .riscv64be => 32,
1435 .loongarch32, .loongarch64 => 64,
1436 .mips, .mipsel, .mips64, .mips64el => 66,
1437 .powerpc, .powerpcle, .powerpc64, .powerpc64le => 67,
1438 .riscv32, .riscv32be, .riscv64, .riscv64be => 65,
14371439 .s390x => 65,
14381440 .x86 => 8,
14391441 .x86_64 => 16,
......@@ -1447,6 +1449,8 @@ pub fn fpRegNum(arch: std.Target.Cpu.Arch) u16 {
14471449 .arm, .armeb, .thumb, .thumbeb => 11,
14481450 .hexagon => 30,
14491451 .loongarch32, .loongarch64 => 22,
1452 .mips, .mipsel, .mips64, .mips64el => 30,
1453 .powerpc, .powerpcle, .powerpc64, .powerpc64le => 1,
14501454 .riscv32, .riscv32be, .riscv64, .riscv64be => 8,
14511455 .s390x => 11,
14521456 .x86 => 5,
......@@ -1461,6 +1465,8 @@ pub fn spRegNum(arch: std.Target.Cpu.Arch) u16 {
14611465 .arm, .armeb, .thumb, .thumbeb => 13,
14621466 .hexagon => 29,
14631467 .loongarch32, .loongarch64 => 3,
1468 .mips, .mipsel, .mips64, .mips64el => 29,
1469 .powerpc, .powerpcle, .powerpc64, .powerpc64le => 1,
14641470 .riscv32, .riscv32be, .riscv64, .riscv64be => 2,
14651471 .s390x => 15,
14661472 .x86 => 4,
lib/std/debug/Dwarf/SelfUnwinder.zig+4-2
......@@ -229,8 +229,10 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
229229 } = switch (rule) {
230230 .default => val: {
231231 // 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) {
233 break :val .same;
232 switch (builtin.target.cpu.arch) {
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 => {},
234236 }
235237 break :val .undefined;
236238 },
lib/std/debug/Dwarf/expression.zig+4-7
......@@ -1160,22 +1160,19 @@ test "basics" {
11601160
11611161 mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);
11621162 (try regNative(&cpu_context, fp_reg_num)).* = 1;
1163 (try regNative(&cpu_context, sp_reg_num)).* = 2;
1164 (try regNative(&cpu_context, ip_reg_num)).* = 3;
1163 (try regNative(&cpu_context, ip_reg_num)).* = 2;
11651164
11661165 try b.writeBreg(writer, fp_reg_num, @as(usize, 100));
1167 try b.writeBreg(writer, sp_reg_num, @as(usize, 200));
1168 try b.writeBregx(writer, ip_reg_num, @as(usize, 300));
1169 try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400));
1166 try b.writeBregx(writer, ip_reg_num, @as(usize, 200));
1167 try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 300));
11701168
11711169 _ = try stack_machine.run(program.written(), allocator, context, 0);
11721170
11731171 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);
11751173 try testing.expectEqual(@as(u8, @sizeOf(usize)), regval_type.type_size);
11761174 try testing.expectEqual(@as(usize, 0xee), regval_type.value);
11771175
1178 try testing.expectEqual(@as(usize, 303), stack_machine.stack.pop().?.generic);
11791176 try testing.expectEqual(@as(usize, 202), stack_machine.stack.pop().?.generic);
11801177 try testing.expectEqual(@as(usize, 101), stack_machine.stack.pop().?.generic);
11811178 }
lib/std/debug/SelfInfo/Elf.zig+8
......@@ -99,6 +99,14 @@ pub const can_unwind: bool = s: {
9999 .aarch64_be,
100100 .hexagon,
101101 .loongarch64,
102 .mips,
103 .mipsel,
104 .mips64,
105 .mips64el,
106 .powerpc,
107 .powerpcle,
108 .powerpc64,
109 .powerpc64le,
102110 .riscv32,
103111 .riscv64,
104112 .s390x,
lib/std/debug/cpu_context.zig+350-61
......@@ -8,6 +8,8 @@ else switch (native_arch) {
88 .arm, .armeb, .thumb, .thumbeb => Arm,
99 .hexagon => Hexagon,
1010 .loongarch32, .loongarch64 => LoongArch,
11 .mips, .mipsel, .mips64, .mips64el => Mips,
12 .powerpc, .powerpcle, .powerpc64, .powerpc64le => Powerpc,
1113 .riscv32, .riscv32be, .riscv64, .riscv64be => Riscv,
1214 .s390x => S390x,
1315 .x86 => X86,
......@@ -196,6 +198,33 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
196198 },
197199 else => null,
198200 },
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 },
199228 .riscv32, .riscv64 => switch (builtin.os.tag) {
200229 .linux => .{
201230 .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 {
210239 .s390x => switch (builtin.os.tag) {
211240 .linux => .{
212241 .r = uc.mcontext.gregs,
213 .f = uc.mcontext.fregs,
214242 .psw = .{
215243 .mask = uc.mcontext.psw.mask,
216244 .addr = uc.mcontext.psw.addr,
......@@ -269,7 +297,7 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native {
269297 };
270298}
271299
272pub const X86 = struct {
300const X86 = struct {
273301 /// The first 8 registers here intentionally match the order of registers in the x86 instruction
274302 /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings,
275303 /// among other things.
......@@ -313,7 +341,7 @@ pub const X86 = struct {
313341 // x86-macos is a deprecated target which is not supported by the Zig Standard Library.
314342 0...8 => return @ptrCast(&ctx.gprs.values[register_num]),
315343
316 9 => return error.UnsupportedRegister, // rflags
344 9 => return error.UnsupportedRegister, // eflags
317345 11...18 => return error.UnsupportedRegister, // st0 - st7
318346 21...28 => return error.UnsupportedRegister, // xmm0 - xmm7
319347 29...36 => return error.UnsupportedRegister, // mm0 - mm7
......@@ -321,14 +349,14 @@ pub const X86 = struct {
321349 40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
322350 48 => return error.UnsupportedRegister, // tr
323351 49 => return error.UnsupportedRegister, // ldtr
324 93...94 => return error.UnsupportedRegister, // fs.base, gs.base
352 93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
325353
326354 else => return error.InvalidRegister,
327355 }
328356 }
329357};
330358
331pub const X86_64 = struct {
359const X86_64 = struct {
332360 /// The order here intentionally matches the order of the DWARF register mappings. It's unclear
333361 /// where those mappings actually originated from---the ordering of the first 4 registers seems
334362 /// quite unusual---but it is currently convenient for us to match DWARF.
......@@ -389,13 +417,16 @@ pub const X86_64 = struct {
389417 64 => return error.UnsupportedRegister, // mxcsr
390418 65 => return error.UnsupportedRegister, // fcw
391419 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
393424 else => return error.InvalidRegister,
394425 }
395426 }
396427};
397428
398pub const Arm = struct {
429const Arm = struct {
399430 /// The numbered general-purpose registers R0 - R15.
400431 r: [16]u32,
401432
......@@ -449,7 +480,7 @@ pub const Arm = struct {
449480};
450481
451482/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
452pub const Aarch64 = extern struct {
483const Aarch64 = extern struct {
453484 /// The numbered general-purpose registers X0 - X30.
454485 x: [31]u64,
455486 sp: u64,
......@@ -492,13 +523,13 @@ pub const Aarch64 = extern struct {
492523 31 => return @ptrCast(&ctx.sp),
493524 32 => return @ptrCast(&ctx.pc),
494525
495 33 => return error.UnsupportedRegister, // ELF_mode
526 33 => return error.UnsupportedRegister, // ELR_mode
496527 34 => return error.UnsupportedRegister, // RA_SIGN_STATE
497528 35 => return error.UnsupportedRegister, // TPIDRRO_ELO
498 36 => return error.UnsupportedRegister, // RPIDR_ELO
499 37 => return error.UnsupportedRegister, // RPIDR_EL1
500 38 => return error.UnsupportedRegister, // RPIDR_EL2
501 39 => return error.UnsupportedRegister, // RPIDR_EL3
529 36 => return error.UnsupportedRegister, // TPIDR_ELO
530 37 => return error.UnsupportedRegister, // TPIDR_EL1
531 38 => return error.UnsupportedRegister, // TPIDR_EL2
532 39 => return error.UnsupportedRegister, // TPIDR_EL3
502533 46 => return error.UnsupportedRegister, // VG
503534 47 => return error.UnsupportedRegister, // FFR
504535 48...63 => return error.UnsupportedRegister, // P0 - P15
......@@ -511,7 +542,7 @@ pub const Aarch64 = extern struct {
511542};
512543
513544/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
514pub const Hexagon = extern struct {
545const Hexagon = extern struct {
515546 /// The numbered general-purpose registers r0 - r31.
516547 r: [32]u32,
517548 pc: u32,
......@@ -579,14 +610,16 @@ pub const Hexagon = extern struct {
579610};
580611
581612/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
582pub const LoongArch = extern struct {
613const LoongArch = extern struct {
583614 /// The numbered general-purpose registers r0 - r31. r0 must be zero.
584 r: [32]usize,
585 pc: usize,
615 r: [32]Gpr,
616 pc: Gpr,
617
618 pub const Gpr = if (builtin.target.cpu.arch == .loongarch64) u64 else u32;
586619
587620 pub inline fn current() LoongArch {
588621 var ctx: LoongArch = undefined;
589 asm volatile (if (@sizeOf(usize) == 8)
622 asm volatile (if (Gpr == u64)
590623 \\ st.d $zero, $t0, 0
591624 \\ st.d $ra, $t0, 8
592625 \\ st.d $tp, $t0, 16
......@@ -669,7 +702,9 @@ pub const LoongArch = extern struct {
669702 pub fn dwarfRegisterBytes(ctx: *LoongArch, register_num: u16) DwarfRegisterError![]u8 {
670703 switch (register_num) {
671704 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
674709 else => return error.InvalidRegister,
675710 }
......@@ -677,14 +712,294 @@ pub const LoongArch = extern struct {
677712};
678713
679714/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
680pub const Riscv = extern struct {
715const Mips = extern struct {
681716 /// The numbered general-purpose registers r0 - r31. r0 must be zero.
682 r: [32]usize,
683 pc: usize,
717 r: [32]Gpr,
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
6851000 pub inline fn current() Riscv {
6861001 var ctx: Riscv = undefined;
687 asm volatile (if (@sizeOf(usize) == 8)
1002 asm volatile (if (Gpr == u64)
6881003 \\ sd zero, 0(t0)
6891004 \\ sd ra, 8(t0)
6901005 \\ sd sp, 16(t0)
......@@ -767,7 +1082,13 @@ pub const Riscv = extern struct {
7671082 pub fn dwarfRegisterBytes(ctx: *Riscv, register_num: u16) DwarfRegisterError![]u8 {
7681083 switch (register_num) {
7691084 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
7721093 else => return error.InvalidRegister,
7731094 }
......@@ -775,11 +1096,9 @@ pub const Riscv = extern struct {
7751096};
7761097
7771098/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
778pub const S390x = extern struct {
1099const S390x = extern struct {
7791100 /// The numbered general-purpose registers r0 - r15.
7801101 r: [16]u64,
781 /// The numbered floating-point registers f0 - f15. Yes, really - they can be used in DWARF CFI.
782 f: [16]f64,
7831102 /// The program counter.
7841103 psw: extern struct {
7851104 mask: u64,
......@@ -790,26 +1109,10 @@ pub const S390x = extern struct {
7901109 var ctx: S390x = undefined;
7911110 asm volatile (
7921111 \\ 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)
8091112 \\ epsw %%r0, %%r1
810 \\ stm %%r0, %%r1, 256(%%r2)
1113 \\ stm %%r0, %%r1, 128(%%r2)
8111114 \\ larl %%r0, .
812 \\ stg %%r0, 264(%%r2)
1115 \\ stg %%r0, 136(%%r2)
8131116 \\ lg %%r0, 0(%%r2)
8141117 \\ lg %%r1, 8(%%r2)
8151118 :
......@@ -821,27 +1124,13 @@ pub const S390x = extern struct {
8211124 pub fn dwarfRegisterBytes(ctx: *S390x, register_num: u16) DwarfRegisterError![]u8 {
8221125 switch (register_num) {
8231126 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]),
8411127 64 => return @ptrCast(&ctx.psw.mask),
8421128 65 => return @ptrCast(&ctx.psw.addr),
8431129
1130 16...31 => return error.UnsupportedRegister, // f0 - f15
1131 32...47 => return error.UnsupportedRegister, // cr0 - cr15
8441132 48...63 => return error.UnsupportedRegister, // a0 - a15
1133 66...67 => return error.UnsupportedRegister, // z/OS stuff???
8451134 68...83 => return error.UnsupportedRegister, // v16 - v31
8461135
8471136 else => return error.InvalidRegister,
lib/std/os/linux/hexagon.zig+3-3
......@@ -254,13 +254,13 @@ pub const mcontext_t = extern struct {
254254 badva: u32,
255255 cs0: u32,
256256 cs1: u32,
257 _pad2: u32,
257 _pad1: u32,
258258};
259259
260260pub const ucontext_t = extern struct {
261 flags: usize,
261 flags: u32,
262262 link: ?*ucontext_t,
263263 stack: stack_t,
264264 mcontext: mcontext_t,
265 sigmask: [2]u32,
265 sigmask: sigset_t,
266266};
lib/std/os/linux/mips.zig+30-2
......@@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;
99const uid_t = linux.uid_t;
1010const gid_t = linux.gid_t;
1111const pid_t = linux.pid_t;
12const stack_t = linux.stack_t;
13const sigset_t = linux.sigset_t;
1214const sockaddr = linux.sockaddr;
1315const timespec = linux.timespec;
1416
......@@ -347,5 +349,31 @@ pub const timezone = extern struct {
347349
348350pub const Elf_Symndx = u32;
349351
350/// TODO
351pub const ucontext_t = void;
352pub const mcontext_t = extern struct {
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;
99const uid_t = linux.uid_t;
1010const gid_t = linux.gid_t;
1111const pid_t = linux.pid_t;
12const stack_t = linux.stack_t;
13const sigset_t = linux.sigset_t;
1214const sockaddr = linux.sockaddr;
1315const timespec = linux.timespec;
1416
......@@ -326,5 +328,28 @@ pub const timezone = extern struct {
326328
327329pub const Elf_Symndx = u32;
328330
329/// TODO
330pub const ucontext_t = void;
331pub const mcontext_t = extern struct {
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};