Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(721)

Unified Diff: src/nonsfi/linux/irt_signal_handling.c

Issue 1212613002: Non-SFI mode: Add Linux asynchronous signal support (Closed) Base URL: https://chromium.googlesource.com/native_client/src/native_client.git@master
Patch Set: Added a TODO to remove code after roll Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/nonsfi/linux/irt_signal_handling.h ('k') | src/nonsfi/linux/linux_pthread_private.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/nonsfi/linux/irt_signal_handling.c
diff --git a/src/nonsfi/linux/irt_exception_handling.c b/src/nonsfi/linux/irt_signal_handling.c
similarity index 51%
rename from src/nonsfi/linux/irt_exception_handling.c
rename to src/nonsfi/linux/irt_signal_handling.c
index 752e674a1d58f0a1c496fe30c27b5e1a3c251a55..9edd3754c84b3953d30b29561a23632b44eff2d5 100644
--- a/src/nonsfi/linux/irt_exception_handling.c
+++ b/src/nonsfi/linux/irt_signal_handling.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 The Native Client Authors. All rights reserved.
+ * Copyright (c) 2015 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -14,10 +14,12 @@
#include "native_client/src/include/elf_constants.h"
#include "native_client/src/include/nacl/nacl_exception.h"
#include "native_client/src/include/nacl_macros.h"
+#include "native_client/src/nonsfi/linux/irt_signal_handling.h"
#include "native_client/src/nonsfi/linux/linux_sys_private.h"
#include "native_client/src/nonsfi/linux/linux_syscall_defines.h"
#include "native_client/src/nonsfi/linux/linux_syscall_structs.h"
-#include "native_client/src/public/nonsfi/irt_exception_handling.h"
+#include "native_client/src/public/linux_syscalls/sys/syscall.h"
+#include "native_client/src/public/nonsfi/irt_signal_handling.h"
#include "native_client/src/untrusted/irt/irt.h"
typedef struct compat_sigaltstack {
@@ -30,28 +32,28 @@ typedef struct compat_sigaltstack {
/* From linux/arch/x86/include/uapi/asm/sigcontext32.h */
struct sigcontext_ia32 {
- unsigned short gs, __gsh;
- unsigned short fs, __fsh;
- unsigned short es, __esh;
- unsigned short ds, __dsh;
- unsigned int di;
- unsigned int si;
- unsigned int bp;
- unsigned int sp;
- unsigned int bx;
- unsigned int dx;
- unsigned int cx;
- unsigned int ax;
- unsigned int trapno;
- unsigned int err;
- unsigned int ip;
- unsigned short cs, __csh;
- unsigned int flags;
- unsigned int sp_at_signal;
- unsigned short ss, __ssh;
- unsigned int fpstate;
- unsigned int oldmask;
- unsigned int cr2;
+ uint16_t gs, __gsh;
+ uint16_t fs, __fsh;
+ uint16_t es, __esh;
+ uint16_t ds, __dsh;
+ uint32_t di;
+ uint32_t si;
+ uint32_t bp;
+ uint32_t sp;
+ uint32_t bx;
+ uint32_t dx;
+ uint32_t cx;
+ uint32_t ax;
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t ip;
+ uint16_t cs, __csh;
+ uint32_t flags;
+ uint32_t sp_at_signal;
+ uint16_t ss, __ssh;
+ uint32_t fpstate;
+ uint32_t oldmask;
+ uint32_t cr2;
};
typedef struct sigcontext_ia32 linux_mcontext_t;
@@ -113,7 +115,10 @@ static const int kSignals[] = {
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
static NaClExceptionHandler g_signal_handler_function_pointer = NULL;
+static NaClExceptionHandler g_exception_handler_function_pointer = NULL;
static int g_signal_handler_initialized = 0;
+static int g_tgid = 0;
+static int g_main_tid;
struct NonSfiExceptionFrame {
struct NaClExceptionContext context;
@@ -160,7 +165,7 @@ static void machine_context_to_register(const linux_mcontext_t *mctx,
#endif
}
-static void exception_frame_from_signal_context(
+static void nonsfi_exception_frame_from_signal_context(
struct NonSfiExceptionFrame *frame,
const void *raw_ctx) {
const struct linux_ucontext_t *uctx = (struct linux_ucontext_t *) raw_ctx;
@@ -189,22 +194,180 @@ static void exception_frame_from_signal_context(
#endif
}
-/* Signal handler, responsible for calling the registered handler. */
+/* A replacement of sigreturn. It does not restore the signal mask. */
+static void __attribute__((noreturn))
+nonsfi_restore_context(const linux_mcontext_t *mctx) {
+
+#if defined(__i386__)
+
+#define OFFSET(name) \
+ [name] "i" (offsetof(linux_mcontext_t, name))
+#define RESTORE_SEGMENT(name) \
+ "mov %c[" #name "](%%eax), %%" #name "\n"
+#define RESTORE(name) \
+ "movl %c[" #name "](%%eax), %%e" #name "\n"
+
+ __asm__ __volatile__(
+ /* Restore floating-point environment */
+ "mov %c[fpstate](%%eax), %%ecx\n"
+ "fldenv (%%ecx)\n"
+
+ /* Restore all segment registers */
+ RESTORE_SEGMENT(gs)
+ RESTORE_SEGMENT(fs)
+ RESTORE_SEGMENT(es)
+ RESTORE_SEGMENT(ds)
+
+ /*
+ * Restore most of the other registers.
+ */
+ RESTORE(di)
+ RESTORE(si)
+ RESTORE(bp)
+ RESTORE(bx)
+
+ /*
+ * Prepare the last registers. eip *must* be one slot above the original
+ * stack, since that is the only way eip and esp can be simultaneously
+ * restored. Here, we are using ecx as the pseudo stack pointer, and edx
+ * as a scratch register. Once the stack is laid out the way we want it to
+ * be, restore edx and eax last.
+ */
+ "mov %c[sp](%%eax), %%ecx\n"
+ "mov %c[ip](%%eax), %%edx\n"
+ "mov %%edx, -4(%%ecx)\n"
+ "mov %c[flags](%%eax), %%edx\n"
+ "mov %%edx, -8(%%ecx)\n"
+ "mov %c[cx](%%eax), %%edx\n"
+ "mov %%edx, -12(%%ecx)\n"
+ RESTORE(dx)
+ RESTORE(ax)
+ "lea -12(%%ecx), %%esp\n"
+
+ /*
+ * Finally pop ecx off the stack, restore the processor flags, and return
+ * to simultaneously restore esp and eip.
+ */
+ "pop %%ecx\n"
+ "popf\n"
+ "ret\n"
+ :
+ : "a" (mctx),
+ OFFSET(gs),
+ OFFSET(fs),
+ OFFSET(es),
+ OFFSET(ds),
+ OFFSET(di),
+ OFFSET(si),
+ OFFSET(bp),
+ OFFSET(sp),
+ OFFSET(bx),
+ OFFSET(dx),
+ OFFSET(cx),
+ OFFSET(ax),
+ OFFSET(ip),
+ OFFSET(flags),
+ OFFSET(fpstate)
+ );
+
+#undef OFFSET
+#undef RESTORE
+#undef RESTORE_SEGMENT
+
+#elif defined(__arm__)
+
+#define OFFSET(name) \
+ [name] "I" (offsetof(linux_mcontext_t, arm_ ## name) - \
+ offsetof(linux_mcontext_t, arm_r0))
+
+ register uint32_t a14 __asm__("r14") = (uint32_t) &mctx->arm_r0;
+
+ __asm__ __volatile__(
+ /* Restore flags */
+ "ldr r0, [r14, %[cpsr]]\n"
+ "msr APSR_nzcvqg, r0\n"
+
+ /*
+ * Restore general-purpose registers.
+ * This code does not use the simpler 'ldmia r14, {r0-pc}' since using
+ * ldmia with either sp or with both lr and pc is deprecated.
+ */
+ "ldmia r14, {r0-r10}\n"
+
+ /*
+ * Copy r11, r12, lr, and pc just before the original sp.
+ * r12 will work as a temporary sp. r11 will be the scratch register, and
+ * will be restored just before moving sp.
+ */
+ "ldr r12, [r14, %[sp]]\n"
+
+ "ldr r11, [r14, %[pc]]\n"
+ "stmdb r12!, {r11}\n"
+ "ldr r11, [r14, %[lr]]\n"
+ "stmdb r12!, {r11}\n"
+ "ldr r11, [r14, %[r12]]\n"
+ "stmdb r12!, {r11}\n"
+ "ldr r11, [r14, %[r11]]\n"
+ "mov sp, r12\n"
+
+ /*
+ * Restore r12, lr, and pc. sp will point to the correct location once
+ * we're done.
+ */
+ "pop {r12, lr}\n"
+ "pop {pc}\n"
+ :
+ : "r" (a14),
+ OFFSET(cpsr),
+ OFFSET(r11),
+ OFFSET(r12),
+ OFFSET(sp),
+ OFFSET(lr),
+ OFFSET(pc)
+ );
+
+#undef OFFSET
+
+#else
+# error Unsupported architecture
+#endif
+
+ /* Should never reach this. */
+ __builtin_trap();
+}
+
+static __attribute__((noreturn))
+void restore_context(void *raw_ctx) {
+ const struct linux_ucontext_t *uctx = (struct linux_ucontext_t *) raw_ctx;
+ const linux_mcontext_t *mctx = &uctx->uc_mcontext;
+ nonsfi_restore_context(mctx);
+}
+
+/* Signal handlers, responsible for calling the registered handlers. */
+static void exception_catch(int sig, linux_siginfo_t *info, void *uc) {
+ if (g_exception_handler_function_pointer) {
+ struct NonSfiExceptionFrame exception_frame;
+ nonsfi_exception_frame_from_signal_context(&exception_frame, uc);
+ g_exception_handler_function_pointer(&exception_frame.context);
+ }
+ _exit(-sig);
+}
+
static void signal_catch(int sig, linux_siginfo_t *info, void *uc) {
if (g_signal_handler_function_pointer) {
struct NonSfiExceptionFrame exception_frame;
- exception_frame_from_signal_context(&exception_frame, uc);
+ nonsfi_exception_frame_from_signal_context(&exception_frame, uc);
g_signal_handler_function_pointer(&exception_frame.context);
}
- _exit(-sig);
+ restore_context(uc);
}
-static void nonsfi_initialize_signal_handler_locked() {
+static void nonsfi_install_exception_handler_locked() {
struct linux_sigaction sa;
unsigned int a;
memset(&sa, 0, sizeof(sa));
- sa.sa_sigaction = signal_catch;
+ sa.sa_sigaction = exception_catch;
sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_ONSTACK;
/*
@@ -226,28 +389,63 @@ static void nonsfi_initialize_signal_handler_locked() {
}
}
+static void nonsfi_install_signal_handler_locked() {
+ struct linux_sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = signal_catch;
+
+ /*
+ * User signal handler can be recursively interrupted to avoid having
+ * to allow sigreturn/sigprocmask.
+ */
+ sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_NODEFER | LINUX_SA_RESTART;
+ sigset_t *mask = (sigset_t*)&sa.sa_mask;
+ sigemptyset(mask);
+
+ /*
+ * Install a single handler. Multiple signals can be multiplexed in
+ * userspace.
+ */
+ if (linux_sigaction(LINUX_SIGUSR1, &sa, NULL) != 0)
+ abort();
+}
+
+static void nonsfi_initialize_signal_handler_locked() {
+ if (g_signal_handler_initialized)
+ return;
+ pid_t tgid = getpid();
+ if (tgid == -1)
+ abort();
+ pid_t main_tid = syscall(__NR_gettid);
+ if (main_tid == -1)
+ abort();
+ nonsfi_install_exception_handler_locked();
+ nonsfi_install_signal_handler_locked();
+ g_tgid = tgid;
+ g_main_tid = main_tid;
+ g_signal_handler_initialized = 1;
+}
+
/*
* Initialize signal handlers before entering sandbox.
*/
void nonsfi_initialize_signal_handler() {
if (pthread_mutex_lock(&g_mutex) != 0)
abort();
- if (!g_signal_handler_initialized) {
- nonsfi_initialize_signal_handler_locked();
- g_signal_handler_initialized = 1;
- }
+ nonsfi_initialize_signal_handler_locked();
if (pthread_mutex_unlock(&g_mutex) != 0)
abort();
}
int nacl_exception_get_and_set_handler(NaClExceptionHandler handler,
NaClExceptionHandler *old_handler) {
- nonsfi_initialize_signal_handler();
if (pthread_mutex_lock(&g_mutex) != 0)
abort();
+ nonsfi_initialize_signal_handler_locked();
if (old_handler)
- *old_handler = g_signal_handler_function_pointer;
- g_signal_handler_function_pointer = handler;
+ *old_handler = g_exception_handler_function_pointer;
+ g_exception_handler_function_pointer = handler;
if (pthread_mutex_unlock(&g_mutex) != 0)
abort();
return 0;
@@ -293,3 +491,23 @@ int nacl_exception_set_stack(void *p, size_t s) {
/* Not implemented yet. */
return ENOSYS;
}
+
+int nacl_async_signal_set_handler(NaClIrtAsyncSignalHandler handler) {
+ if (pthread_mutex_lock(&g_mutex) != 0)
+ abort();
+ nonsfi_initialize_signal_handler_locked();
+ g_signal_handler_function_pointer = handler;
+ if (pthread_mutex_unlock(&g_mutex) != 0)
+ abort();
+ return 0;
+}
+
+int nacl_async_signal_send_async_signal(nacl_irt_tid_t tid) {
+ if (!g_signal_handler_initialized)
+ return ESRCH;
+ if (tid == 0)
+ tid = g_main_tid;
+ if (linux_tgkill(g_tgid, tid, LINUX_SIGUSR1) == -1)
+ return errno;
+ return 0;
+}
« no previous file with comments | « src/nonsfi/linux/irt_signal_handling.h ('k') | src/nonsfi/linux/linux_pthread_private.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698