Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

fromPosixSignalContext

cpu_context.fromPosixSignalContext
pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native

File

lib/std/debug/cpu_context.zig:36

Code

pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
    if (signal_ucontext_t == void) return null;

    // In general, we include the hardwired zero register in the context if applicable.
    const uc: *const signal_ucontext_t = @ptrCast(@alignCast(ctx_ptr));

    // Deal with some special cases first.
    if (native_arch.isArc() and native_os == .linux) {
        var native: Native = .{
            .r = [_]u32{ uc.mcontext.r31, uc.mcontext.r30, 0, uc.mcontext.r28 } ++
                uc.mcontext.r27_26 ++
                uc.mcontext.r25_13 ++
                uc.mcontext.r12_0,
            .pcl = uc.mcontext.pcl,
        };

        // I have no idea why the kernel is storing these registers in such a bizarre order...
        std.mem.reverse(u32, native.r[0..]);

        return native;
    } else if (native_arch == .loongarch32 and native_os == .linux) {
        // The 32-bit kABI (added later) kept the 64-bit layout.
        return .{
            .r = s: {
                var regs: [32]LoongArch.Gpr = undefined;
                for (uc.mcontext.r, 0..) |r, i| regs[i] = @truncate(r);
                break :s regs;
            },
            .pc = @truncate(uc.mcontext.pc),
        };
    } else if (native_arch == .m88k and native_os == .openbsd) {
        // OpenBSD makes no effort to clear the V and E bits of the SXIP register when presenting it
        // to user space, so we need to do that here.
        return .{
            .r = uc.mcontext.r,
            .xip = uc.mcontext.xip & ~@as(u32, 0b11),
        };
    } else if (native_arch.isMIPS32() and native_os == .linux) {
        // The O32 kABI uses 64-bit fields for some reason.
        return .{
            .r = s: {
                var regs: [32]Mips.Gpr = undefined;
                for (uc.mcontext.r, 0..) |r, i| regs[i] = @truncate(r);
                break :s regs;
            },
            .pc = @truncate(uc.mcontext.pc),
        };
    } else if (native_arch.isSPARC() and native_os == .linux) {
        const SparcStackFrame = extern struct {
            l: [8]usize,
            i: [8]usize,
            _x: [8]usize,
        };

        // When invoking a signal handler, the kernel builds an `rt_signal_frame` structure on the
        // stack and passes a pointer to its `info` field to the signal handler. This implies that
        // prior to said `info` field, we will find the `ss` field which, among other things,
        // contains the incoming and local registers of the interrupted code.
        const frame = @as(*const SparcStackFrame, @ptrFromInt(@as(usize, @intFromPtr(ctx_ptr)) - @sizeOf(SparcStackFrame)));

        return .{
            .g = uc.mcontext.g,
            .o = uc.mcontext.o,
            .l = frame.l,
            .i = frame.i,
            .pc = uc.mcontext.pc,
        };
    }

    // Only unified conversions from here.
    return switch (native_arch) {
        .arm, .armeb, .thumb, .thumbeb => .{
            .r = uc.mcontext.r ++ [_]u32{uc.mcontext.pc},
        },
        .aarch64, .aarch64_be => .{
            .x = uc.mcontext.x ++ [_]u64{uc.mcontext.lr},
            .sp = uc.mcontext.sp,
            .pc = uc.mcontext.pc,
        },
        .alpha => .{
            .r = uc.mcontext.r,
            .pc = uc.mcontext.pc,
        },
        .csky => .{
            .r = uc.mcontext.r0_13 ++
                [_]u32{ uc.mcontext.r14, uc.mcontext.r15 } ++
                uc.mcontext.r16_30 ++
                [_]u32{uc.mcontext.r31},
            .pc = uc.mcontext.pc,
        },
        .hexagon, .loongarch32, .loongarch64, .mips, .mipsel, .mips64, .mips64el, .or1k => .{
            .r = uc.mcontext.r,
            .pc = uc.mcontext.pc,
        },
        .m68k => .{
            .d = uc.mcontext.d,
            .a = uc.mcontext.a,
            .pc = uc.mcontext.pc,
        },
        .powerpc, .powerpcle, .powerpc64, .powerpc64le => .{
            .r = uc.mcontext.r,
            .pc = uc.mcontext.pc,
            .lr = uc.mcontext.lr,
        },
        .riscv32, .riscv32be, .riscv64, .riscv64be => .{
            // You can thank FreeBSD and OpenBSD for this silliness; they decided to be cute and
            // group the registers by ABI mnemonic rather than register number.
            .x = [_]Riscv.Gpr{0} ++
                uc.mcontext.ra_sp_gp_tp ++
                uc.mcontext.t0_2 ++
                uc.mcontext.s0_1 ++
                uc.mcontext.a ++
                uc.mcontext.s2_11 ++
                uc.mcontext.t3_6,
            .pc = uc.mcontext.pc,
        },
        .s390x => .{
            .r = uc.mcontext.r,
            .psw = .{
                .mask = uc.mcontext.psw.mask,
                .addr = uc.mcontext.psw.addr,
            },
        },
        .x86 => .{ .gprs = .init(.{
            .eax = uc.mcontext.eax,
            .ecx = uc.mcontext.ecx,
            .edx = uc.mcontext.edx,
            .ebx = uc.mcontext.ebx,
            .esp = uc.mcontext.esp,
            .ebp = uc.mcontext.ebp,
            .esi = uc.mcontext.esi,
            .edi = uc.mcontext.edi,
            .eip = uc.mcontext.eip,
        }) },
        .x86_64 => .{ .gprs = .init(.{
            .rax = uc.mcontext.rax,
            .rdx = uc.mcontext.rdx,
            .rcx = uc.mcontext.rcx,
            .rbx = uc.mcontext.rbx,
            .rsi = uc.mcontext.rsi,
            .rdi = uc.mcontext.rdi,
            .rbp = uc.mcontext.rbp,
            .rsp = uc.mcontext.rsp,
            .r8 = uc.mcontext.r8,
            .r9 = uc.mcontext.r9,
            .r10 = uc.mcontext.r10,
            .r11 = uc.mcontext.r11,
            .r12 = uc.mcontext.r12,
            .r13 = uc.mcontext.r13,
            .r14 = uc.mcontext.r14,
            .r15 = uc.mcontext.r15,
            .rip = uc.mcontext.rip,
        }) },
        else => comptime unreachable,
    };
}