From ea971de80969bf8d68005403e8b591de264e1402 Mon Sep 17 00:00:00 2001 From: Lubos Dolezel Date: Tue, 27 Oct 2015 15:20:22 +0100 Subject: [PATCH] sys_sigaction() and sys_sigreturn() implemented --- src/kernel/emulation/linux/CMakeLists.txt | 4 +- .../emulation/linux/signal/duct_signals.c | 3 +- .../emulation/linux/signal/duct_signals.h | 5 +- src/kernel/emulation/linux/signal/sigaction.c | 107 ++++++++++++++++++ src/kernel/emulation/linux/signal/sigaction.h | 81 +++++++++++++ src/kernel/emulation/linux/signal/sigreturn.c | 12 ++ src/kernel/emulation/linux/signal/sigreturn.h | 7 ++ src/kernel/emulation/linux/syscalls.c | 4 + 8 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 src/kernel/emulation/linux/signal/sigaction.c create mode 100644 src/kernel/emulation/linux/signal/sigaction.h create mode 100644 src/kernel/emulation/linux/signal/sigreturn.c create mode 100644 src/kernel/emulation/linux/signal/sigreturn.h diff --git a/src/kernel/emulation/linux/CMakeLists.txt b/src/kernel/emulation/linux/CMakeLists.txt index 1b0ec236d..4a8334f1c 100644 --- a/src/kernel/emulation/linux/CMakeLists.txt +++ b/src/kernel/emulation/linux/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.4.0) enable_language(C ASM) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fvisibility=hidden -fPIC -ggdb") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fvisibility=hidden -fPIC -ggdb -Wno-int-conversion") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostdlib") set(emulation_sources @@ -44,6 +44,8 @@ set(emulation_sources signal/duct_signals.c signal/kill.c signal/sigaltstack.c + signal/sigaction.c + signal/sigreturn.c misc/ioctl.c misc/thread_selfid.c misc/sysctl.c diff --git a/src/kernel/emulation/linux/signal/duct_signals.c b/src/kernel/emulation/linux/signal/duct_signals.c index 8aa3ae583..5150efc24 100644 --- a/src/kernel/emulation/linux/signal/duct_signals.c +++ b/src/kernel/emulation/linux/signal/duct_signals.c @@ -1,5 +1,6 @@ -#include "duct_signals.h" +#define __sigset_t_defined #include "../../../../../platform-include/sys/signal.h" +#include "duct_signals.h" int signum_linux_to_bsd(int signum) { diff --git a/src/kernel/emulation/linux/signal/duct_signals.h b/src/kernel/emulation/linux/signal/duct_signals.h index 81e7689e9..a8efcecfd 100644 --- a/src/kernel/emulation/linux/signal/duct_signals.h +++ b/src/kernel/emulation/linux/signal/duct_signals.h @@ -1,6 +1,5 @@ #ifndef LINUX_DUCT_SIGNALS_H #define LINUX_DUCT_SIGNALS_H -#include #define LINUX_NSIG 32 #define LINUX_SIGHUP 1 @@ -51,6 +50,10 @@ typedef unsigned long long linux_sigset_t; +#ifndef __sigset_t_defined +typedef unsigned int sigset_t; +#endif + int signum_linux_to_bsd(int signum); int signum_bsd_to_linux(int signum); void sigset_linux_to_bsd(const linux_sigset_t* linux, sigset_t* bsd); diff --git a/src/kernel/emulation/linux/signal/sigaction.c b/src/kernel/emulation/linux/signal/sigaction.c new file mode 100644 index 000000000..348bf2c49 --- /dev/null +++ b/src/kernel/emulation/linux/signal/sigaction.c @@ -0,0 +1,107 @@ +#include "sigaction.h" +#include "../base.h" +#include "../errno.h" +#include +#include +#include "../../../../../platform-include/sys/errno.h" + +static void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt); +static int sigflags_bsd_to_linux(int flags); +static int sigflags_linux_to_bsd(int flags); + +extern void* memcpy(void* dest, const void* src, unsigned long len); + +// Libc uses only one trampoline +void (*sa_tramp)(void*, int, int, struct bsd_siginfo*, void*) = 0; +static bsd_sig_handler* sig_handlers[32]; + +long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sigaction* osa) +{ + int ret, linux_signum; + struct linux_sigaction sa, olsa; + + linux_signum = signum_bsd_to_linux(signum); + if (linux_signum == 0) + return -EINVAL; + + if (nsa != NULL) + { + sa_tramp = nsa->sa_tramp; + sa.sa_sigaction = &handler_linux_to_bsd; + sigset_bsd_to_linux(&nsa->sa_mask, &sa.sa_mask); + sa.sa_flags = sigflags_bsd_to_linux(nsa->sa_flags); + sa.sa_restorer = NULL; + } + + ret = LINUX_SYSCALL(__NR_rt_sigaction, linux_signum, + (nsa != NULL) ? &sa : NULL, &olsa, + sizeof(sa.sa_mask)); + if (ret < 0) + return errno_linux_to_bsd(ret); + + if (nsa != NULL) + sig_handlers[linux_signum] = nsa->sa_sigaction; + + if (osa != NULL) + { + osa->sa_sigaction = sig_handlers[linux_signum]; + sigset_linux_to_bsd(&olsa.sa_mask, &osa->sa_mask); + osa->sa_flags = sigflags_linux_to_bsd(olsa.sa_flags); + } + + return 0; +} + +static void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt) +{ + int bsd_signum; + struct bsd_siginfo binfo; + + bsd_signum = signum_linux_to_bsd(linux_signum); + + memcpy(&binfo, info, sizeof(binfo)); + binfo.si_signo = signum_linux_to_bsd(binfo.si_signo); + + sig_handlers[linux_signum](bsd_signum, &binfo, ctxt); +} + +static int sigflags_bsd_to_linux(int flags) +{ + int linux_flags = LINUX_SA_SIGINFO; + + if (flags & BSD_SA_NOCLDSTOP) + linux_flags |= LINUX_SA_NOCLDSTOP; + if (flags & BSD_SA_NOCLDWAIT) + linux_flags |= LINUX_SA_NOCLDWAIT; + if (flags & BSD_SA_ONSTACK) + linux_flags |= LINUX_SA_ONSTACK; + if (flags & BSD_SA_NODEFER) + linux_flags |= LINUX_SA_NODEFER; + if (flags & BSD_SA_RESETHAND) + linux_flags |= LINUX_SA_RESETHAND; + if (flags & BSD_SA_RESTART) + linux_flags |= LINUX_SA_RESTART; + + return linux_flags; +} + +static int sigflags_linux_to_bsd(int flags) +{ + int bsd_flags = 0; + + if (flags & LINUX_SA_NOCLDSTOP) + bsd_flags |= BSD_SA_NOCLDSTOP; + if (flags & LINUX_SA_NOCLDWAIT) + bsd_flags |= BSD_SA_NOCLDWAIT; + if (flags & LINUX_SA_ONSTACK) + bsd_flags |= BSD_SA_ONSTACK; + if (flags & LINUX_SA_NODEFER) + bsd_flags |= BSD_SA_NODEFER; + if (flags & LINUX_SA_RESETHAND) + bsd_flags |= BSD_SA_RESETHAND; + if (flags & LINUX_SA_RESTART) + bsd_flags |= BSD_SA_RESTART; + + return bsd_flags; +} + diff --git a/src/kernel/emulation/linux/signal/sigaction.h b/src/kernel/emulation/linux/signal/sigaction.h new file mode 100644 index 000000000..5d197dfe0 --- /dev/null +++ b/src/kernel/emulation/linux/signal/sigaction.h @@ -0,0 +1,81 @@ +#ifndef LINUX_SIGACTION_H +#define LINUX_SIGACTION_H +#include "duct_signals.h" + +#define BSD_SA_ONSTACK 0x0001 +#define BSD_SA_RESTART 0x0002 +#define BSD_SA_RESETHAND 0x0004 +#define BSD_SA_NOCLDSTOP 0x0008 +#define BSD_SA_NODEFER 0x0010 +#define BSD_SA_NOCLDWAIT 0x0020 +#define BSD_SA_SIGINFO 0x0040 + +#define LINUX_SA_NOCLDSTOP 0x00000001u +#define LINUX_SA_NOCLDWAIT 0x00000002u +#define LINUX_SA_SIGINFO 0x00000004u +#define LINUX_SA_ONSTACK 0x08000000u +#define LINUX_SA_RESTART 0x10000000u +#define LINUX_SA_NODEFER 0x40000000u +#define LINUX_SA_RESETHAND 0x80000000u + +struct bsd_siginfo +{ + int si_signo; + int si_errno; + int si_code; + unsigned int si_pid; + unsigned int si_uid; + int si_status; + void* si_addr; + void* si_val_ptr; + long si_band; + unsigned long __pad[7]; +}; + +# define __SI_MAX_SIZE 128 +# if defined (__x86_64__) +# define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof (int)) - 4) +# else +# define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof (int)) - 3) +# endif + +struct linux_siginfo +{ + int si_signo; + int si_errno; + int si_code; + + union + { + int _pad[__SI_PAD_SIZE]; + }; +}; + +typedef void (bsd_sig_handler)(int, struct bsd_siginfo*, void*); +struct bsd_sigaction +{ + bsd_sig_handler* sa_sigaction; + unsigned int sa_mask; + int sa_flags; +}; + +struct bsd___sigaction +{ + bsd_sig_handler* sa_sigaction; + void (*sa_tramp)(void*, int, int, struct bsd_siginfo*, void*); + unsigned int sa_mask; + int sa_flags; +}; + +struct linux_sigaction +{ + void (*sa_sigaction)(int, struct linux_siginfo*, void*); + int sa_flags; + void (*sa_restorer)(void); + linux_sigset_t sa_mask; +}; + +long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sigaction* osa); + +#endif + diff --git a/src/kernel/emulation/linux/signal/sigreturn.c b/src/kernel/emulation/linux/signal/sigreturn.c new file mode 100644 index 000000000..36c3c46ab --- /dev/null +++ b/src/kernel/emulation/linux/signal/sigreturn.c @@ -0,0 +1,12 @@ +#include "sigreturn.h" +#include "../base.h" +#include "../errno.h" + +long sys_sigreturn() +{ + // Apple's libc invokes sigreturn directly, + // but Linux injects a rt_sigreturn() syscall on its own. + // Hance we must ignore this call. + return 0; +} + diff --git a/src/kernel/emulation/linux/signal/sigreturn.h b/src/kernel/emulation/linux/signal/sigreturn.h new file mode 100644 index 000000000..e6da59bb7 --- /dev/null +++ b/src/kernel/emulation/linux/signal/sigreturn.h @@ -0,0 +1,7 @@ +#ifndef LINUX_SIGRETURN_H +#define LINUX_SIGRETURN_H + +long sys_sigreturn(); + +#endif + diff --git a/src/kernel/emulation/linux/syscalls.c b/src/kernel/emulation/linux/syscalls.c index e5af432aa..63e07f159 100644 --- a/src/kernel/emulation/linux/syscalls.c +++ b/src/kernel/emulation/linux/syscalls.c @@ -30,6 +30,8 @@ #include "unistd/readlink.h" #include "signal/kill.h" #include "signal/sigaltstack.h" +#include "signal/sigaction.h" +#include "signal/sigreturn.h" #include "misc/ioctl.h" #include "misc/getrlimit.h" #include "misc/thread_selfid.h" @@ -59,6 +61,7 @@ void* __bsd_syscall_table[512] = { [36] = sys_sync, [37] = sys_kill, [41] = sys_dup, + [46] = sys_sigaction, [53] = sys_sigaltstack, [54] = sys_ioctl, [58] = sys_readlink, @@ -79,6 +82,7 @@ void* __bsd_syscall_table[512] = { [181] = sys_setgid, [182] = sys_setegid, [183] = sys_seteuid, + [184] = sys_sigreturn, [187] = sys_fdatasync, [188] = sys_stat, [189] = sys_fstat, -- 2.51.2