commit 2aea7a42b085f1775889f9d49141faa8098221f9 (tree)
parent e959a86bb92006eea4d0f15cc1c0f82ecccbc58b
Author: Alex Rønne Petersen <alex@alexrp.com>
Date: Wed, 8 Oct 2025 06:29:28 +0200
Merge pull request #25493 from alexrp/std-debug-mips-ppc
`std.debug`: MIPS and PowerPC unwind support + some other stuff
Diffstat:
9 files changed, 436 insertions(+), 81 deletions(-)
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
@@ -623,7 +623,7 @@ pub const StackUnwindOptions = struct {
/// the given buffer, so `addr_buf` must have a lifetime at least equal to the `StackTrace`.
///
/// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it.
-pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace {
+pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace {
const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} };
if (!std.options.allow_stack_tracing) return empty_trace;
var it = StackIterator.init(options.context) catch return empty_trace;
@@ -661,7 +661,7 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize)
/// Write the current stack trace to `writer`, annotated with source locations.
///
/// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing.
-pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void {
+pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void {
if (!std.options.allow_stack_tracing) {
tty_config.setColor(writer, .dim) catch {};
try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{});
diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig
@@ -1432,8 +1432,10 @@ pub fn ipRegNum(arch: std.Target.Cpu.Arch) ?u16 {
.aarch64, .aarch64_be => 32,
.arm, .armeb, .thumb, .thumbeb => 15,
.hexagon => 76,
- .loongarch32, .loongarch64 => 32,
- .riscv32, .riscv32be, .riscv64, .riscv64be => 32,
+ .loongarch32, .loongarch64 => 64,
+ .mips, .mipsel, .mips64, .mips64el => 66,
+ .powerpc, .powerpcle, .powerpc64, .powerpc64le => 67,
+ .riscv32, .riscv32be, .riscv64, .riscv64be => 65,
.s390x => 65,
.x86 => 8,
.x86_64 => 16,
@@ -1447,6 +1449,8 @@ pub fn fpRegNum(arch: std.Target.Cpu.Arch) u16 {
.arm, .armeb, .thumb, .thumbeb => 11,
.hexagon => 30,
.loongarch32, .loongarch64 => 22,
+ .mips, .mipsel, .mips64, .mips64el => 30,
+ .powerpc, .powerpcle, .powerpc64, .powerpc64le => 1,
.riscv32, .riscv32be, .riscv64, .riscv64be => 8,
.s390x => 11,
.x86 => 5,
@@ -1461,6 +1465,8 @@ pub fn spRegNum(arch: std.Target.Cpu.Arch) u16 {
.arm, .armeb, .thumb, .thumbeb => 13,
.hexagon => 29,
.loongarch32, .loongarch64 => 3,
+ .mips, .mipsel, .mips64, .mips64el => 29,
+ .powerpc, .powerpcle, .powerpc64, .powerpc64le => 1,
.riscv32, .riscv32be, .riscv64, .riscv64be => 2,
.s390x => 15,
.x86 => 4,
diff --git a/lib/std/debug/Dwarf/SelfUnwinder.zig b/lib/std/debug/Dwarf/SelfUnwinder.zig
@@ -229,8 +229,10 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
} = switch (rule) {
.default => val: {
// The default rule is typically equivalent to `.undefined`, but ABIs may override it.
- if (builtin.cpu.arch.isAARCH64() and register >= 19 and register <= 28) {
- break :val .same;
+ switch (builtin.target.cpu.arch) {
+ .aarch64, .aarch64_be => if (register >= 19 and register <= 28) break :val .same,
+ .s390x => if (register >= 6 and register <= 15) break :val .same,
+ else => {},
}
break :val .undefined;
},
diff --git a/lib/std/debug/Dwarf/expression.zig b/lib/std/debug/Dwarf/expression.zig
@@ -1160,22 +1160,19 @@ test "basics" {
mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);
(try regNative(&cpu_context, fp_reg_num)).* = 1;
- (try regNative(&cpu_context, sp_reg_num)).* = 2;
- (try regNative(&cpu_context, ip_reg_num)).* = 3;
+ (try regNative(&cpu_context, ip_reg_num)).* = 2;
try b.writeBreg(writer, fp_reg_num, @as(usize, 100));
- try b.writeBreg(writer, sp_reg_num, @as(usize, 200));
- try b.writeBregx(writer, ip_reg_num, @as(usize, 300));
- try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400));
+ try b.writeBregx(writer, ip_reg_num, @as(usize, 200));
+ try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 300));
_ = try stack_machine.run(program.written(), allocator, context, 0);
const regval_type = stack_machine.stack.pop().?.regval_type;
- try testing.expectEqual(@as(usize, 400), regval_type.type_offset);
+ try testing.expectEqual(@as(usize, 300), regval_type.type_offset);
try testing.expectEqual(@as(u8, @sizeOf(usize)), regval_type.type_size);
try testing.expectEqual(@as(usize, 0xee), regval_type.value);
- try testing.expectEqual(@as(usize, 303), stack_machine.stack.pop().?.generic);
try testing.expectEqual(@as(usize, 202), stack_machine.stack.pop().?.generic);
try testing.expectEqual(@as(usize, 101), stack_machine.stack.pop().?.generic);
}
diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig
@@ -99,6 +99,14 @@ pub const can_unwind: bool = s: {
.aarch64_be,
.hexagon,
.loongarch64,
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ .powerpc,
+ .powerpcle,
+ .powerpc64,
+ .powerpc64le,
.riscv32,
.riscv64,
.s390x,
diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig
@@ -8,6 +8,8 @@ else switch (native_arch) {
.arm, .armeb, .thumb, .thumbeb => Arm,
.hexagon => Hexagon,
.loongarch32, .loongarch64 => LoongArch,
+ .mips, .mipsel, .mips64, .mips64el => Mips,
+ .powerpc, .powerpcle, .powerpc64, .powerpc64le => Powerpc,
.riscv32, .riscv32be, .riscv64, .riscv64be => Riscv,
.s390x => S390x,
.x86 => X86,
@@ -196,6 +198,33 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
},
else => null,
},
+ .mips, .mipsel => switch (builtin.os.tag) {
+ // The O32 kABI uses 64-bit fields for some reason...
+ .linux => .{
+ .r = s: {
+ var regs: [32]Mips.Gpr = undefined;
+ for (uc.mcontext.regs, 0..) |r, i| regs[i] = @truncate(r); // includes r0 (hardwired zero)
+ break :s regs;
+ },
+ .pc = @truncate(uc.mcontext.pc),
+ },
+ else => null,
+ },
+ .mips64, .mips64el => switch (builtin.os.tag) {
+ .linux => .{
+ .r = uc.mcontext.regs, // includes r0 (hardwired zero)
+ .pc = uc.mcontext.pc,
+ },
+ else => null,
+ },
+ .powerpc, .powerpcle, .powerpc64, .powerpc64le => switch (builtin.os.tag) {
+ .linux => .{
+ .r = uc.mcontext.gp_regs[0..32].*,
+ .pc = uc.mcontext.gp_regs[32],
+ .lr = uc.mcontext.gp_regs[36],
+ },
+ else => null,
+ },
.riscv32, .riscv64 => switch (builtin.os.tag) {
.linux => .{
.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 {
.s390x => switch (builtin.os.tag) {
.linux => .{
.r = uc.mcontext.gregs,
- .f = uc.mcontext.fregs,
.psw = .{
.mask = uc.mcontext.psw.mask,
.addr = uc.mcontext.psw.addr,
@@ -269,7 +297,7 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native {
};
}
-pub const X86 = struct {
+const X86 = struct {
/// The first 8 registers here intentionally match the order of registers in the x86 instruction
/// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings,
/// among other things.
@@ -313,7 +341,7 @@ pub const X86 = struct {
// x86-macos is a deprecated target which is not supported by the Zig Standard Library.
0...8 => return @ptrCast(&ctx.gprs.values[register_num]),
- 9 => return error.UnsupportedRegister, // rflags
+ 9 => return error.UnsupportedRegister, // eflags
11...18 => return error.UnsupportedRegister, // st0 - st7
21...28 => return error.UnsupportedRegister, // xmm0 - xmm7
29...36 => return error.UnsupportedRegister, // mm0 - mm7
@@ -321,14 +349,14 @@ pub const X86 = struct {
40...45 => return error.UnsupportedRegister, // es, cs, ss, ds, fs, gs
48 => return error.UnsupportedRegister, // tr
49 => return error.UnsupportedRegister, // ldtr
- 93...94 => return error.UnsupportedRegister, // fs.base, gs.base
+ 93...100 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
else => return error.InvalidRegister,
}
}
};
-pub const X86_64 = struct {
+const X86_64 = struct {
/// The order here intentionally matches the order of the DWARF register mappings. It's unclear
/// where those mappings actually originated from---the ordering of the first 4 registers seems
/// quite unusual---but it is currently convenient for us to match DWARF.
@@ -389,13 +417,16 @@ pub const X86_64 = struct {
64 => return error.UnsupportedRegister, // mxcsr
65 => return error.UnsupportedRegister, // fcw
66 => return error.UnsupportedRegister, // fsw
+ 67...82 => return error.UnsupportedRegister, // xmm16 - xmm31 (AVX-512)
+ 118...125 => return error.UnsupportedRegister, // k0 - k7 (AVX-512)
+ 130...145 => return error.UnsupportedRegister, // r16 - r31 (APX)
else => return error.InvalidRegister,
}
}
};
-pub const Arm = struct {
+const Arm = struct {
/// The numbered general-purpose registers R0 - R15.
r: [16]u32,
@@ -449,7 +480,7 @@ pub const Arm = struct {
};
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
-pub const Aarch64 = extern struct {
+const Aarch64 = extern struct {
/// The numbered general-purpose registers X0 - X30.
x: [31]u64,
sp: u64,
@@ -492,13 +523,13 @@ pub const Aarch64 = extern struct {
31 => return @ptrCast(&ctx.sp),
32 => return @ptrCast(&ctx.pc),
- 33 => return error.UnsupportedRegister, // ELF_mode
+ 33 => return error.UnsupportedRegister, // ELR_mode
34 => return error.UnsupportedRegister, // RA_SIGN_STATE
35 => return error.UnsupportedRegister, // TPIDRRO_ELO
- 36 => return error.UnsupportedRegister, // RPIDR_ELO
- 37 => return error.UnsupportedRegister, // RPIDR_EL1
- 38 => return error.UnsupportedRegister, // RPIDR_EL2
- 39 => return error.UnsupportedRegister, // RPIDR_EL3
+ 36 => return error.UnsupportedRegister, // TPIDR_ELO
+ 37 => return error.UnsupportedRegister, // TPIDR_EL1
+ 38 => return error.UnsupportedRegister, // TPIDR_EL2
+ 39 => return error.UnsupportedRegister, // TPIDR_EL3
46 => return error.UnsupportedRegister, // VG
47 => return error.UnsupportedRegister, // FFR
48...63 => return error.UnsupportedRegister, // P0 - P15
@@ -511,7 +542,7 @@ pub const Aarch64 = extern struct {
};
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
-pub const Hexagon = extern struct {
+const Hexagon = extern struct {
/// The numbered general-purpose registers r0 - r31.
r: [32]u32,
pc: u32,
@@ -579,14 +610,16 @@ pub const Hexagon = extern struct {
};
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
-pub const LoongArch = extern struct {
+const LoongArch = extern struct {
/// The numbered general-purpose registers r0 - r31. r0 must be zero.
- r: [32]usize,
- pc: usize,
+ r: [32]Gpr,
+ pc: Gpr,
+
+ pub const Gpr = if (builtin.target.cpu.arch == .loongarch64) u64 else u32;
pub inline fn current() LoongArch {
var ctx: LoongArch = undefined;
- asm volatile (if (@sizeOf(usize) == 8)
+ asm volatile (if (Gpr == u64)
\\ st.d $zero, $t0, 0
\\ st.d $ra, $t0, 8
\\ st.d $tp, $t0, 16
@@ -669,7 +702,9 @@ pub const LoongArch = extern struct {
pub fn dwarfRegisterBytes(ctx: *LoongArch, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
- 32 => return @ptrCast(&ctx.pc),
+ 64 => return @ptrCast(&ctx.pc),
+
+ 32...63 => return error.UnsupportedRegister, // f0 - f31
else => return error.InvalidRegister,
}
@@ -677,14 +712,294 @@ pub const LoongArch = extern struct {
};
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
-pub const Riscv = extern struct {
+const Mips = extern struct {
/// The numbered general-purpose registers r0 - r31. r0 must be zero.
- r: [32]usize,
- pc: usize,
+ r: [32]Gpr,
+ pc: Gpr,
+
+ pub const Gpr = if (builtin.target.cpu.arch.isMIPS64()) u64 else u32;
+
+ pub inline fn current() Mips {
+ var ctx: Mips = undefined;
+ asm volatile (if (Gpr == u64)
+ \\ .set push
+ \\ .set noat
+ \\ .set noreorder
+ \\ .set nomacro
+ \\ sd $zero, 0($t0)
+ \\ sd $at, 8($t0)
+ \\ sd $v0, 16($t0)
+ \\ sd $v1, 24($t0)
+ \\ sd $a0, 32($t0)
+ \\ sd $a1, 40($t0)
+ \\ sd $a2, 48($t0)
+ \\ sd $a3, 56($t0)
+ \\ sd $a4, 64($t0)
+ \\ sd $a5, 72($t0)
+ \\ sd $a6, 80($t0)
+ \\ sd $a7, 88($t0)
+ \\ sd $t0, 96($t0)
+ \\ sd $t1, 104($t0)
+ \\ sd $t2, 112($t0)
+ \\ sd $t3, 120($t0)
+ \\ sd $s0, 128($t0)
+ \\ sd $s1, 136($t0)
+ \\ sd $s2, 144($t0)
+ \\ sd $s3, 152($t0)
+ \\ sd $s4, 160($t0)
+ \\ sd $s5, 168($t0)
+ \\ sd $s6, 176($t0)
+ \\ sd $s7, 184($t0)
+ \\ sd $t8, 192($t0)
+ \\ sd $t9, 200($t0)
+ \\ sd $k0, 208($t0)
+ \\ sd $k1, 216($t0)
+ \\ sd $gp, 224($t0)
+ \\ sd $sp, 232($t0)
+ \\ sd $fp, 240($t0)
+ \\ sd $ra, 248($t0)
+ \\ bal 1f
+ \\1:
+ \\ sd $ra, 256($t0)
+ \\ ld $ra, 248($t0)
+ \\ .set pop
+ else
+ \\ .set push
+ \\ .set noat
+ \\ .set noreorder
+ \\ .set nomacro
+ \\ sw $zero, 0($t4)
+ \\ sw $at, 4($t4)
+ \\ sw $v0, 8($t4)
+ \\ sw $v1, 12($t4)
+ \\ sw $a0, 16($t4)
+ \\ sw $a1, 20($t4)
+ \\ sw $a2, 24($t4)
+ \\ sw $a3, 28($t4)
+ \\ sw $t0, 32($t4)
+ \\ sw $t1, 36($t4)
+ \\ sw $t2, 40($t4)
+ \\ sw $t3, 44($t4)
+ \\ sw $t4, 48($t4)
+ \\ sw $t5, 52($t4)
+ \\ sw $t6, 56($t4)
+ \\ sw $t7, 60($t4)
+ \\ sw $s0, 64($t4)
+ \\ sw $s1, 68($t4)
+ \\ sw $s2, 72($t4)
+ \\ sw $s3, 76($t4)
+ \\ sw $s4, 80($t4)
+ \\ sw $s5, 84($t4)
+ \\ sw $s6, 88($t4)
+ \\ sw $s7, 92($t4)
+ \\ sw $t8, 96($t4)
+ \\ sw $t9, 100($t4)
+ \\ sw $k0, 104($t4)
+ \\ sw $k1, 108($t4)
+ \\ sw $gp, 112($t4)
+ \\ sw $sp, 116($t4)
+ \\ sw $fp, 120($t4)
+ \\ sw $ra, 124($t4)
+ \\ bal 1f
+ \\1:
+ \\ sw $ra, 128($t4)
+ \\ lw $ra, 124($t4)
+ \\ .set pop
+ :
+ : [gprs] "{$12}" (&ctx),
+ : .{ .memory = true });
+ return ctx;
+ }
+
+ pub fn dwarfRegisterBytes(ctx: *Mips, register_num: u16) DwarfRegisterError![]u8 {
+ switch (register_num) {
+ 0...31 => return @ptrCast(&ctx.r[register_num]),
+ 66 => return @ptrCast(&ctx.pc),
+
+ // Who the hell knows what numbers exist for this architecture? What's an ABI
+ // specification anyway? We don't need that nonsense.
+ 32...63 => return error.UnsupportedRegister, // f0 - f31, w0 - w31
+ 64 => return error.UnsupportedRegister, // hi0 (ac0)
+ 65 => return error.UnsupportedRegister, // lo0 (ac0)
+ 176 => return error.UnsupportedRegister, // hi1 (ac1)
+ 177 => return error.UnsupportedRegister, // lo1 (ac1)
+ 178 => return error.UnsupportedRegister, // hi2 (ac2)
+ 179 => return error.UnsupportedRegister, // lo2 (ac2)
+ 180 => return error.UnsupportedRegister, // hi3 (ac3)
+ 181 => return error.UnsupportedRegister, // lo3 (ac3)
+
+ else => return error.InvalidRegister,
+ }
+ }
+};
+
+/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
+const Powerpc = extern struct {
+ /// The numbered general-purpose registers r0 - r31.
+ r: [32]Gpr,
+ pc: Gpr,
+ lr: Gpr,
+
+ pub const Gpr = if (builtin.target.cpu.arch.isPowerPC64()) u64 else u32;
+
+ pub inline fn current() Powerpc {
+ var ctx: Powerpc = undefined;
+ asm volatile (if (Gpr == u64)
+ \\ std 0, 0(10)
+ \\ std 1, 8(10)
+ \\ std 2, 16(10)
+ \\ std 3, 24(10)
+ \\ std 4, 32(10)
+ \\ std 5, 40(10)
+ \\ std 6, 48(10)
+ \\ std 7, 56(10)
+ \\ std 8, 64(10)
+ \\ std 9, 72(10)
+ \\ std 10, 80(10)
+ \\ std 11, 88(10)
+ \\ std 12, 96(10)
+ \\ std 13, 104(10)
+ \\ std 14, 112(10)
+ \\ std 15, 120(10)
+ \\ std 16, 128(10)
+ \\ std 17, 136(10)
+ \\ std 18, 144(10)
+ \\ std 19, 152(10)
+ \\ std 20, 160(10)
+ \\ std 21, 168(10)
+ \\ std 22, 176(10)
+ \\ std 23, 184(10)
+ \\ std 24, 192(10)
+ \\ std 25, 200(10)
+ \\ std 26, 208(10)
+ \\ std 27, 216(10)
+ \\ std 28, 224(10)
+ \\ std 29, 232(10)
+ \\ std 30, 240(10)
+ \\ std 31, 248(10)
+ \\ mflr 8
+ \\ std 8, 264(10)
+ \\ bl 1f
+ \\1:
+ \\ mflr 8
+ \\ std 8, 256(10)
+ \\ ld 8, 64(10)
+ else
+ \\ stw 0, 0(10)
+ \\ stw 1, 4(10)
+ \\ stw 2, 8(10)
+ \\ stw 3, 12(10)
+ \\ stw 4, 16(10)
+ \\ stw 5, 20(10)
+ \\ stw 6, 24(10)
+ \\ stw 7, 28(10)
+ \\ stw 8, 32(10)
+ \\ stw 9, 36(10)
+ \\ stw 10, 40(10)
+ \\ stw 11, 44(10)
+ \\ stw 12, 48(10)
+ \\ stw 13, 52(10)
+ \\ stw 14, 56(10)
+ \\ stw 15, 60(10)
+ \\ stw 16, 64(10)
+ \\ stw 17, 68(10)
+ \\ stw 18, 72(10)
+ \\ stw 19, 76(10)
+ \\ stw 20, 80(10)
+ \\ stw 21, 84(10)
+ \\ stw 22, 88(10)
+ \\ stw 23, 92(10)
+ \\ stw 24, 96(10)
+ \\ stw 25, 100(10)
+ \\ stw 26, 104(10)
+ \\ stw 27, 108(10)
+ \\ stw 28, 112(10)
+ \\ stw 29, 116(10)
+ \\ stw 30, 120(10)
+ \\ stw 31, 124(10)
+ \\ mflr 8
+ \\ stw 8, 132(10)
+ \\ bl 1f
+ \\1:
+ \\ mflr 8
+ \\ stw 8, 128(10)
+ \\ lwz 8, 32(10)
+ :
+ : [gprs] "{r10}" (&ctx),
+ : .{ .lr = true, .memory = true });
+ return ctx;
+ }
+
+ pub fn dwarfRegisterBytes(ctx: *Powerpc, register_num: u16) DwarfRegisterError![]u8 {
+ // References:
+ //
+ // * System V Application Binary Interface - PowerPC Processor Supplement §3-46
+ // * Power Architecture 32-bit Application Binary Interface Supplement 1.0 - Linux & Embedded §3.4
+ // * 64-bit ELF V2 ABI Specification - Power Architecture Revision 1.5 §2.4
+ // * ??? AIX?
+ //
+ // Are we having fun yet?
+
+ if (Gpr == u64) switch (register_num) {
+ 65 => return @ptrCast(&ctx.lr), // lr
+
+ 66 => return error.UnsupportedRegister, // ctr
+ 68...75 => return error.UnsupportedRegister, // cr0 - cr7
+ 76 => return error.UnsupportedRegister, // xer
+ 77...108 => return error.UnsupportedRegister, // vr0 - vr31
+ 109 => return error.UnsupportedRegister, // vrsave (LLVM)
+ 110 => return error.UnsupportedRegister, // vscr
+ 114 => return error.UnsupportedRegister, // tfhar
+ 115 => return error.UnsupportedRegister, // tfiar
+ 116 => return error.UnsupportedRegister, // texasr
+
+ else => {},
+ } else switch (register_num) {
+ 65 => return @ptrCast(&ctx.lr), // fpscr (SVR4 / EABI), or lr if you ask LLVM
+ 108 => return @ptrCast(&ctx.lr),
+
+ 64 => return error.UnsupportedRegister, // cr
+ 66 => return error.UnsupportedRegister, // msr (SVR4 / EABI), or ctr if you ask LLVM
+ 68...75 => return error.UnsupportedRegister, // cr0 - cr7 if you ask LLVM
+ 76 => return error.UnsupportedRegister, // xer if you ask LLVM
+ 99 => return error.UnsupportedRegister, // acc
+ 100 => return error.UnsupportedRegister, // mq
+ 101 => return error.UnsupportedRegister, // xer
+ 102...107 => return error.UnsupportedRegister, // SPRs
+ 109 => return error.UnsupportedRegister, // ctr
+ 110...111 => return error.UnsupportedRegister, // SPRs
+ 112 => return error.UnsupportedRegister, // spefscr
+ 113...1123 => return error.UnsupportedRegister, // SPRs
+ 1124...1155 => return error.UnsupportedRegister, // SPE v0 - v31
+ 1200...1231 => return error.UnsupportedRegister, // SPE upper r0 - r31
+ 3072...4095 => return error.UnsupportedRegister, // DCRs
+ 4096...5120 => return error.UnsupportedRegister, // PMRs
+
+ else => {},
+ }
+
+ switch (register_num) {
+ 0...31 => return @ptrCast(&ctx.r[register_num]),
+ 67 => return @ptrCast(&ctx.pc),
+
+ 32...63 => return error.UnsupportedRegister, // f0 - f31
+
+ else => return error.InvalidRegister,
+ }
+ }
+};
+
+/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
+const Riscv = extern struct {
+ /// The numbered general-purpose registers r0 - r31. r0 must be zero.
+ r: [32]Gpr,
+ pc: Gpr,
+
+ pub const Gpr = if (builtin.target.cpu.arch.isRiscv64()) u64 else u32;
pub inline fn current() Riscv {
var ctx: Riscv = undefined;
- asm volatile (if (@sizeOf(usize) == 8)
+ asm volatile (if (Gpr == u64)
\\ sd zero, 0(t0)
\\ sd ra, 8(t0)
\\ sd sp, 16(t0)
@@ -767,7 +1082,13 @@ pub const Riscv = extern struct {
pub fn dwarfRegisterBytes(ctx: *Riscv, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...31 => return @ptrCast(&ctx.r[register_num]),
- 32 => return @ptrCast(&ctx.pc),
+ 65 => return @ptrCast(&ctx.pc),
+
+ 32...63 => return error.UnsupportedRegister, // f0 - f31
+ 64 => return error.UnsupportedRegister, // Alternate Frame Return Column
+ 96...127 => return error.UnsupportedRegister, // v0 - v31
+ 3072...4095 => return error.UnsupportedRegister, // Custom extensions
+ 4096...8191 => return error.UnsupportedRegister, // CSRs
else => return error.InvalidRegister,
}
@@ -775,11 +1096,9 @@ pub const Riscv = extern struct {
};
/// This is an `extern struct` so that inline assembly in `current` can use field offsets.
-pub const S390x = extern struct {
+const S390x = extern struct {
/// The numbered general-purpose registers r0 - r15.
r: [16]u64,
- /// The numbered floating-point registers f0 - f15. Yes, really - they can be used in DWARF CFI.
- f: [16]f64,
/// The program counter.
psw: extern struct {
mask: u64,
@@ -790,26 +1109,10 @@ pub const S390x = extern struct {
var ctx: S390x = undefined;
asm volatile (
\\ stmg %%r0, %%r15, 0(%%r2)
- \\ std %%f0, 128(%%r2)
- \\ std %%f1, 136(%%r2)
- \\ std %%f2, 144(%%r2)
- \\ std %%f3, 152(%%r2)
- \\ std %%f4, 160(%%r2)
- \\ std %%f5, 168(%%r2)
- \\ std %%f6, 176(%%r2)
- \\ std %%f7, 184(%%r2)
- \\ std %%f8, 192(%%r2)
- \\ std %%f9, 200(%%r2)
- \\ std %%f10, 208(%%r2)
- \\ std %%f11, 216(%%r2)
- \\ std %%f12, 224(%%r2)
- \\ std %%f13, 232(%%r2)
- \\ std %%f14, 240(%%r2)
- \\ std %%f15, 248(%%r2)
\\ epsw %%r0, %%r1
- \\ stm %%r0, %%r1, 256(%%r2)
+ \\ stm %%r0, %%r1, 128(%%r2)
\\ larl %%r0, .
- \\ stg %%r0, 264(%%r2)
+ \\ stg %%r0, 136(%%r2)
\\ lg %%r0, 0(%%r2)
\\ lg %%r1, 8(%%r2)
:
@@ -821,27 +1124,13 @@ pub const S390x = extern struct {
pub fn dwarfRegisterBytes(ctx: *S390x, register_num: u16) DwarfRegisterError![]u8 {
switch (register_num) {
0...15 => return @ptrCast(&ctx.r[register_num]),
- // Why???
- 16 => return @ptrCast(&ctx.f[0]),
- 17 => return @ptrCast(&ctx.f[2]),
- 18 => return @ptrCast(&ctx.f[4]),
- 19 => return @ptrCast(&ctx.f[6]),
- 20 => return @ptrCast(&ctx.f[1]),
- 21 => return @ptrCast(&ctx.f[3]),
- 22 => return @ptrCast(&ctx.f[5]),
- 23 => return @ptrCast(&ctx.f[7]),
- 24 => return @ptrCast(&ctx.f[8]),
- 25 => return @ptrCast(&ctx.f[10]),
- 26 => return @ptrCast(&ctx.f[12]),
- 27 => return @ptrCast(&ctx.f[14]),
- 28 => return @ptrCast(&ctx.f[9]),
- 29 => return @ptrCast(&ctx.f[11]),
- 30 => return @ptrCast(&ctx.f[13]),
- 31 => return @ptrCast(&ctx.f[15]),
64 => return @ptrCast(&ctx.psw.mask),
65 => return @ptrCast(&ctx.psw.addr),
+ 16...31 => return error.UnsupportedRegister, // f0 - f15
+ 32...47 => return error.UnsupportedRegister, // cr0 - cr15
48...63 => return error.UnsupportedRegister, // a0 - a15
+ 66...67 => return error.UnsupportedRegister, // z/OS stuff???
68...83 => return error.UnsupportedRegister, // v16 - v31
else => return error.InvalidRegister,
diff --git a/lib/std/os/linux/hexagon.zig b/lib/std/os/linux/hexagon.zig
@@ -254,13 +254,13 @@ pub const mcontext_t = extern struct {
badva: u32,
cs0: u32,
cs1: u32,
- _pad2: u32,
+ _pad1: u32,
};
pub const ucontext_t = extern struct {
- flags: usize,
+ flags: u32,
link: ?*ucontext_t,
stack: stack_t,
mcontext: mcontext_t,
- sigmask: [2]u32,
+ sigmask: sigset_t,
};
diff --git a/lib/std/os/linux/mips.zig b/lib/std/os/linux/mips.zig
@@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;
const uid_t = linux.uid_t;
const gid_t = linux.gid_t;
const pid_t = linux.pid_t;
+const stack_t = linux.stack_t;
+const sigset_t = linux.sigset_t;
const sockaddr = linux.sockaddr;
const timespec = linux.timespec;
@@ -347,5 +349,31 @@ pub const timezone = extern struct {
pub const Elf_Symndx = u32;
-/// TODO
-pub const ucontext_t = void;
+pub const mcontext_t = extern struct {
+ _regmask: u32,
+ _status: u32,
+ pc: u64,
+ regs: [32]u64,
+ fpregs: [32]f64,
+ acx: u32,
+ fpc_csr: u32,
+ _fpc_eir: u32,
+ used_math: u32,
+ dsp: u32,
+ mdhi: u64,
+ mdlo: u64,
+ hi1: u32,
+ lo1: u32,
+ hi2: u32,
+ lo2: u32,
+ hi3: u32,
+ lo3: u32,
+};
+
+pub const ucontext_t = extern struct {
+ flags: u32,
+ link: ?*ucontext_t,
+ stack: stack_t,
+ mcontext: mcontext_t,
+ sigmask: sigset_t,
+};
diff --git a/lib/std/os/linux/mips64.zig b/lib/std/os/linux/mips64.zig
@@ -9,6 +9,8 @@ const iovec_const = std.posix.iovec_const;
const uid_t = linux.uid_t;
const gid_t = linux.gid_t;
const pid_t = linux.pid_t;
+const stack_t = linux.stack_t;
+const sigset_t = linux.sigset_t;
const sockaddr = linux.sockaddr;
const timespec = linux.timespec;
@@ -326,5 +328,28 @@ pub const timezone = extern struct {
pub const Elf_Symndx = u32;
-/// TODO
-pub const ucontext_t = void;
+pub const mcontext_t = extern struct {
+ regs: [32]u64,
+ fpregs: [32]f64,
+ mdhi: u64,
+ hi1: u64,
+ hi2: u64,
+ hi3: u64,
+ mdlo: u64,
+ lo1: u64,
+ lo2: u64,
+ lo3: u64,
+ pc: u64,
+ fpc_csr: u32,
+ used_math: u32,
+ dsp: u32,
+ _reserved: u32,
+};
+
+pub const ucontext_t = extern struct {
+ flags: u32,
+ link: ?*ucontext_t,
+ stack: stack_t,
+ mcontext: mcontext_t,
+ sigmask: sigset_t,
+};