From 17f2af10b56dd508ebd4a22834fd594cb5a49864 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 1 Oct 2019 15:57:38 +0200 Subject: [PATCH] Correct signal bits for MIPS Also enable the segfault handler for all the supported architectures beside MIPS. --- lib/std/debug.zig | 29 +++++-- lib/std/os/bits/linux.zig | 131 +++++++++++++++++++++++++---- lib/std/os/bits/linux/arm-eabi.zig | 38 ++++++++- lib/std/os/bits/linux/arm64.zig | 21 +++++ lib/std/os/bits/linux/x86_64.zig | 54 ------------ lib/std/os/linux.zig | 11 ++- lib/std/os/linux/arm-eabi.zig | 18 ++++ lib/std/os/linux/arm64.zig | 12 +++ lib/std/os/linux/mipsel.zig | 18 ++++ lib/std/os/linux/riscv64.zig | 12 +++ lib/std/os/linux/x86_64.zig | 4 +- 11 files changed, 264 insertions(+), 84 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 52f33660fb..25868d67a1 100644 --- a/lib/std/debug.zig +++ b/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 diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 301c5d1775..5ed5c0b622 100644 --- a/lib/std/os/bits/linux.zig +++ b/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, diff --git a/lib/std/os/bits/linux/arm-eabi.zig b/lib/std/os/bits/linux/arm-eabi.zig index 4b3e1094da..ae169684fe 100644 --- a/lib/std/os/bits/linux/arm-eabi.zig +++ b/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; diff --git a/lib/std/os/bits/linux/arm64.zig b/lib/std/os/bits/linux/arm64.zig index 692efc0eb3..84f621b07a 100644 --- a/lib/std/os/bits/linux/arm64.zig +++ b/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; diff --git a/lib/std/os/bits/linux/x86_64.zig b/lib/std/os/bits/linux/x86_64.zig index 626acd00d6..7b1ad4dd5c 100644 --- a/lib/std/os/bits/linux/x86_64.zig +++ b/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 { diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 9550518842..e813519c68 100644 --- a/lib/std/os/linux.zig +++ b/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; } diff --git a/lib/std/os/linux/arm-eabi.zig b/lib/std/os/linux/arm-eabi.zig index a15234d742..c7371fc28d 100644 --- a/lib/std/os/linux/arm-eabi.zig +++ b/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" + ); +} diff --git a/lib/std/os/linux/arm64.zig b/lib/std/os/linux/arm64.zig index 28da9af1c6..b8d8a1636b 100644 --- a/lib/std/os/linux/arm64.zig +++ b/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" + ); +} diff --git a/lib/std/os/linux/mipsel.zig b/lib/std/os/linux/mipsel.zig index 09826753b8..b9a3120096 100644 --- a/lib/std/os/linux/mipsel.zig +++ b/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" + ); +} diff --git a/lib/std/os/linux/riscv64.zig b/lib/std/os/linux/riscv64.zig index 7bfe0295d3..64facede89 100644 --- a/lib/std/os/linux/riscv64.zig +++ b/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" + ); +} diff --git a/lib/std/os/linux/x86_64.zig b/lib/std/os/linux/x86_64.zig index 0f3a36636a..e0e4687c9f 100644 --- a/lib/std/os/linux/x86_64.zig +++ b/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" ); }