Commit 17f2af10b5

LemonBoy <thatlemon@gmail.com>
2019-10-01 15:57:38
Correct signal bits for MIPS
Also enable the segfault handler for all the supported architectures beside MIPS.
1 parent bed4bfa
lib/std/os/bits/linux/arm-eabi.zig
@@ -1,10 +1,11 @@
 // arm-eabi-specific declarations that are intended to be imported into the POSIX namespace.
-
-const std = @import("../../std.zig");
+const std = @import("../../../std.zig");
 const linux = std.os.linux;
 const socklen_t = linux.socklen_t;
 const iovec = linux.iovec;
 const iovec_const = linux.iovec_const;
+const stack_t = linux.stack_t;
+const sigset_t = linux.sigset_t;
 
 pub const SYS_restart_syscall = 0;
 pub const SYS_exit = 1;
@@ -565,4 +566,37 @@ pub const timezone = extern struct {
     tz_dsttime: i32,
 };
 
+pub const mcontext_t = extern struct {
+    trap_no: usize,
+    error_code: usize,
+    oldmask: usize,
+    arm_r0: usize,
+    arm_r1: usize,
+    arm_r2: usize,
+    arm_r3: usize,
+    arm_r4: usize,
+    arm_r5: usize,
+    arm_r6: usize,
+    arm_r7: usize,
+    arm_r8: usize,
+    arm_r9: usize,
+    arm_r10: usize,
+    arm_fp: usize,
+    arm_ip: usize,
+    arm_sp: usize,
+    arm_lr: usize,
+    arm_pc: usize,
+    arm_cpsr: usize,
+    fault_address: usize,
+};
+
+pub const ucontext_t = extern struct {
+    flags: usize,
+    link: *ucontext_t,
+    stack: stack_t,
+    mcontext: mcontext_t,
+    sigmask: sigset_t,
+    regspace: [64]u64,
+};
+
 pub const Elf_Symndx = u32;
lib/std/os/bits/linux/arm64.zig
@@ -8,6 +8,8 @@ const iovec = linux.iovec;
 const iovec_const = linux.iovec_const;
 const uid_t = linux.uid_t;
 const gid_t = linux.gid_t;
+const stack_t = linux.stack_t;
+const sigset_t = linux.sigset_t;
 
 pub const SYS_io_setup = 0;
 pub const SYS_io_destroy = 1;
@@ -445,4 +447,23 @@ pub const timezone = extern struct {
     tz_dsttime: i32,
 };
 
+pub const mcontext_t = extern struct {
+    fault_address: usize,
+    regs: [31]usize,
+    sp: usize,
+    pc: usize,
+    pstate: usize,
+    // Make sure the field is correctly aligned since this area
+    // holds various FP/vector registers
+    reserved1: [256 * 16]u8 align(16),
+};
+
+pub const ucontext_t = extern struct {
+    flags: usize,
+    link: *ucontext_t,
+    stack: stack_t,
+    sigmask: sigset_t,
+    mcontext: mcontext_t,
+};
+
 pub const Elf_Symndx = u32;
lib/std/os/bits/linux/x86_64.zig
@@ -536,60 +536,6 @@ pub const timezone = extern struct {
 
 pub const Elf_Symndx = u32;
 
-pub const sigval = extern union {
-    int: i32,
-    ptr: *c_void,
-};
-
-pub const siginfo_t = extern struct {
-    signo: i32,
-    errno: i32,
-    code: i32,
-    fields: extern union {
-        pad: [128 - 2 * @sizeOf(c_int) - @sizeOf(c_long)]u8,
-        common: extern struct {
-            first: extern union {
-                piduid: extern struct {
-                    pid: pid_t,
-                    uid: uid_t,
-                },
-                timer: extern struct {
-                    timerid: i32,
-                    overrun: i32,
-                },
-            },
-            second: extern union {
-                value: sigval,
-                sigchld: extern struct {
-                    status: i32,
-                    utime: clock_t,
-                    stime: clock_t,
-                },
-            },
-        },
-        sigfault: extern struct {
-            addr: *c_void,
-            addr_lsb: i16,
-            first: extern union {
-                addr_bnd: extern struct {
-                    lower: *c_void,
-                    upper: *c_void,
-                },
-                pkey: u32,
-            },
-        },
-        sigpoll: extern struct {
-            band: isize,
-            fd: i32,
-        },
-        sigsys: extern struct {
-            call_addr: *c_void,
-            syscall: i32,
-            arch: u32,
-        },
-    },
-};
-
 pub const greg_t = usize;
 pub const gregset_t = [23]greg_t;
 pub const fpstate = extern struct {
lib/std/os/bits/linux.zig
@@ -140,9 +140,27 @@ pub const WEXITED = 4;
 pub const WCONTINUED = 8;
 pub const WNOWAIT = 0x1000000;
 
-pub const SA_NOCLDSTOP = 1;
-pub const SA_NOCLDWAIT = 2;
-pub const SA_SIGINFO = 4;
+pub usingnamespace if (is_mips)
+    struct {
+        pub const SA_NOCLDSTOP = 1;
+        pub const SA_NOCLDWAIT = 0x10000;
+        pub const SA_SIGINFO = 8;
+
+        pub const SIG_BLOCK = 1;
+        pub const SIG_UNBLOCK = 2;
+        pub const SIG_SETMASK = 3;
+    }
+else
+    struct {
+        pub const SA_NOCLDSTOP = 1;
+        pub const SA_NOCLDWAIT = 2;
+        pub const SA_SIGINFO = 4;
+
+        pub const SIG_BLOCK = 0;
+        pub const SIG_UNBLOCK = 1;
+        pub const SIG_SETMASK = 2;
+    };
+
 pub const SA_ONSTACK = 0x08000000;
 pub const SA_RESTART = 0x10000000;
 pub const SA_NODEFER = 0x40000000;
@@ -209,10 +227,6 @@ pub const SEEK_SET = 0;
 pub const SEEK_CUR = 1;
 pub const SEEK_END = 2;
 
-pub const SIG_BLOCK = 0;
-pub const SIG_UNBLOCK = 1;
-pub const SIG_SETMASK = 2;
-
 pub const PROTO_ip = 0o000;
 pub const PROTO_icmp = 0o001;
 pub const PROTO_igmp = 0o002;
@@ -786,17 +800,34 @@ pub const winsize = extern struct {
     ws_ypixel: u16,
 };
 
-pub const NSIG = 65;
+pub const NSIG = if (is_mips) 128 else 65;
 pub const sigset_t = [128 / @sizeOf(usize)]usize;
-pub const all_mask = [_]u32{ 0xffffffff, 0xffffffff };
-pub const app_mask = [_]u32{ 0xfffffffc, 0x7fffffff };
 
-pub const k_sigaction = extern struct {
-    sigaction: ?extern fn (i32, *siginfo_t, *c_void) void,
-    flags: usize,
-    restorer: extern fn () void,
-    mask: [2]u32,
-};
+pub usingnamespace if (NSIG == 65)
+    struct {
+        pub const all_mask = [2]u32{ 0xffffffff, 0xffffffff };
+        pub const app_mask = [2]u32{ 0xfffffffc, 0x7fffffff };
+    }
+else
+    struct {
+        pub const all_mask = [4]u32{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
+        pub const app_mask = [4]u32{ 0xfffffffc, 0x7fffffff, 0xffffffff, 0xffffffff };
+    };
+
+pub const k_sigaction = if (is_mips)
+    extern struct {
+        flags: usize,
+        sigaction: ?extern fn (i32, *siginfo_t, *c_void) void,
+        mask: [4]u32,
+        restorer: extern fn () void,
+    }
+else
+    extern struct {
+        sigaction: ?extern fn (i32, *siginfo_t, *c_void) void,
+        flags: usize,
+        restorer: extern fn () void,
+        mask: [2]u32,
+    };
 
 /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
 pub const Sigaction = extern struct {
@@ -1030,12 +1061,12 @@ pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t {
 //#define CPU_EQUAL(s1,s2) CPU_EQUAL_S(sizeof(cpu_set_t),s1,s2)
 
 pub const MINSIGSTKSZ = switch (builtin.arch) {
-    .i386, .x86_64, .arm => 2048,
+    .i386, .x86_64, .arm, .mipsel => 2048,
     .aarch64 => 5120,
     else => @compileError("MINSIGSTKSZ not defined for this architecture"),
 };
 pub const SIGSTKSZ = switch (builtin.arch) {
-    .i386, .x86_64, .arm => 8192,
+    .i386, .x86_64, .arm, .mipsel => 8192,
     .aarch64 => 16384,
     else => @compileError("SIGSTKSZ not defined for this architecture"),
 };
@@ -1050,6 +1081,70 @@ pub const stack_t = extern struct {
     ss_size: isize,
 };
 
+pub const sigval = extern union {
+    int: i32,
+    ptr: *c_void,
+};
+
+const siginfo_fields_union = extern union {
+    pad: [128 - 2 * @sizeOf(c_int) - @sizeOf(c_long)]u8,
+    common: extern struct {
+        first: extern union {
+            piduid: extern struct {
+                pid: pid_t,
+                uid: uid_t,
+            },
+            timer: extern struct {
+                timerid: i32,
+                overrun: i32,
+            },
+        },
+        second: extern union {
+            value: sigval,
+            sigchld: extern struct {
+                status: i32,
+                utime: clock_t,
+                stime: clock_t,
+            },
+        },
+    },
+    sigfault: extern struct {
+        addr: *c_void,
+        addr_lsb: i16,
+        first: extern union {
+            addr_bnd: extern struct {
+                lower: *c_void,
+                upper: *c_void,
+            },
+            pkey: u32,
+        },
+    },
+    sigpoll: extern struct {
+        band: isize,
+        fd: i32,
+    },
+    sigsys: extern struct {
+        call_addr: *c_void,
+        syscall: i32,
+        arch: u32,
+    },
+};
+
+pub const siginfo_t = if (is_mips)
+    extern struct {
+        signo: i32,
+        code: i32,
+        errno: i32,
+        fields: siginfo_fields_union,
+    }
+else
+    extern struct {
+        signo: i32,
+        errno: i32,
+        code: i32,
+        fields: siginfo_fields_union,
+    };
+
 pub const io_uring_params = extern struct {
     sq_entries: u32,
     cq_entries: u32,
lib/std/os/linux/arm-eabi.zig
@@ -1,3 +1,5 @@
+usingnamespace @import("../bits.zig");
+
 pub fn syscall0(number: usize) usize {
     return asm volatile ("svc #0"
         : [ret] "={r0}" (-> usize)
@@ -94,3 +96,19 @@ pub extern fn getThreadPointer() usize {
         : [ret] "=r" (-> usize)
     );
 }
+
+pub nakedcc fn restore() void {
+    return asm volatile ("svc #0"
+        :
+        : [number] "{r7}" (usize(SYS_sigreturn))
+        : "memory"
+    );
+}
+
+pub nakedcc fn restore_rt() void {
+    return asm volatile ("svc #0"
+        :
+        : [number] "{r7}" (usize(SYS_rt_sigreturn))
+        : "memory"
+    );
+}
lib/std/os/linux/arm64.zig
@@ -1,3 +1,5 @@
+usingnamespace @import("../bits.zig");
+
 pub fn syscall0(number: usize) usize {
     return asm volatile ("svc #0"
         : [ret] "={x0}" (-> usize)
@@ -85,3 +87,13 @@ pub fn syscall6(
 
 /// This matches the libc clone function.
 pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
+
+pub const restore = restore_rt;
+
+pub nakedcc fn restore_rt() void {
+    return asm volatile ("svc #0"
+        :
+        : [number] "{x8}" (usize(SYS_rt_sigreturn))
+        : "memory", "cc"
+    );
+}
lib/std/os/linux/mipsel.zig
@@ -1,3 +1,5 @@
+usingnamespace @import("../bits.zig");
+
 pub fn syscall0(number: usize) usize {
     return asm volatile (
         \\ syscall
@@ -122,3 +124,19 @@ pub fn syscall6(
 
 /// This matches the libc clone function.
 pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
+
+pub nakedcc fn restore() void {
+    return asm volatile ("syscall"
+        :
+        : [number] "{$2}" (usize(SYS_sigreturn))
+        : "memory", "cc", "$7"
+    );
+}
+
+pub nakedcc fn restore_rt() void {
+    return asm volatile ("syscall"
+        :
+        : [number] "{$2}" (usize(SYS_rt_sigreturn))
+        : "memory", "cc", "$7"
+    );
+}
lib/std/os/linux/riscv64.zig
@@ -1,3 +1,5 @@
+usingnamespace @import("../bits.zig");
+
 pub fn syscall0(number: usize) usize {
     return asm volatile ("ecall"
         : [ret] "={x10}" (-> usize)
@@ -84,3 +86,13 @@ pub fn syscall6(
 }
 
 pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
+
+pub const restore = restore_rt;
+
+pub nakedcc fn restore_rt() void {
+    return asm volatile ("ecall"
+        :
+        : [number] "{x17}" (usize(SYS_rt_sigreturn))
+        : "memory"
+    );
+}
lib/std/os/linux/x86_64.zig
@@ -88,10 +88,12 @@ pub fn syscall6(
 /// This matches the libc clone function.
 pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
 
+pub const restore = restore_rt;
+
 pub nakedcc fn restore_rt() void {
     return asm volatile ("syscall"
         :
         : [number] "{rax}" (usize(SYS_rt_sigreturn))
-        : "rcx", "r11"
+        : "rcx", "r11", "memory"
     );
 }
lib/std/os/linux.zig
@@ -673,15 +673,18 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti
     assert(sig >= 1);
     assert(sig != SIGKILL);
     assert(sig != SIGSTOP);
+
+    const restorer_fn = if ((act.flags & SA_SIGINFO) != 0) restore_rt else restore;
     var ksa = k_sigaction{
         .sigaction = act.sigaction,
         .flags = act.flags | SA_RESTORER,
         .mask = undefined,
-        .restorer = @ptrCast(extern fn () void, restore_rt),
+        .restorer = @ptrCast(extern fn () void, restorer_fn),
     };
     var ksa_old: k_sigaction = undefined;
-    @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8);
-    const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask)));
+    const ksa_mask_size = @sizeOf(@typeOf(ksa_old.mask));
+    @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), ksa_mask_size);
+    const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), ksa_mask_size);
     const err = getErrno(result);
     if (err != 0) {
         return result;
@@ -689,7 +692,7 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti
     if (oact) |old| {
         old.sigaction = ksa_old.sigaction;
         old.flags = @truncate(u32, ksa_old.flags);
-        @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask)));
+        @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), ksa_mask_size);
     }
     return 0;
 }
lib/std/debug.zig
@@ -2336,7 +2336,7 @@ fn getDebugInfoAllocator() *mem.Allocator {
 }
 
 /// Whether or not the current target can print useful debug information when a segfault occurs.
-pub const have_segfault_handling_support = (builtin.arch == builtin.Arch.x86_64 and builtin.os == .linux) or builtin.os == .windows;
+pub const have_segfault_handling_support = builtin.os == .linux or builtin.os == .windows;
 pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
     root.enable_segfault_handler
 else
@@ -2390,12 +2390,31 @@ extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *con
     // and the resulting segfault will crash the process rather than continually dump stack traces.
     resetSegfaultHandler();
 
-    const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
-    const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]);
-    const bp = @intCast(usize, ctx.mcontext.gregs[os.REG_RBP]);
     const addr = @ptrToInt(info.fields.sigfault.addr);
     std.debug.warn("Segmentation fault at address 0x{x}\n", addr);
-    dumpStackTraceFromBase(bp, ip);
+
+    switch (builtin.arch) {
+        .x86_64 => {
+            const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
+            const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]);
+            const bp = @intCast(usize, ctx.mcontext.gregs[os.REG_RBP]);
+            dumpStackTraceFromBase(bp, ip);
+        },
+        .arm => {
+            const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
+            const ip = @intCast(usize, ctx.mcontext.arm_pc);
+            const bp = @intCast(usize, ctx.mcontext.arm_fp);
+            dumpStackTraceFromBase(bp, ip);
+        },
+        .aarch64 => {
+            const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
+            const ip = @intCast(usize, ctx.mcontext.pc);
+            // x29 is the ABI-designated frame pointer
+            const bp = @intCast(usize, ctx.mcontext.regs[29]);
+            dumpStackTraceFromBase(bp, ip);
+        },
+        else => {},
+    }
 
     // We cannot allow the signal handler to return because when it runs the original instruction
     // again, the memory may be mapped and undefined behavior would occur rather than repeating