blob: ebbeaa0e86056a758db684127283b9da687d370c [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include "components/nacl/loader/nonsfi/irt_interfaces.h"
#include "native_client/src/include/nacl_macros.h"
#include "native_client/src/shared/platform/nacl_log.h"
#include "native_client/src/trusted/service_runtime/nacl_exception.h"
#include "native_client/src/trusted/service_runtime/nacl_signal.h"
namespace nacl {
namespace nonsfi {
namespace {
// This is NonSFI version of exception handling codebase, NaCl side of
// things resides in:
// native_client/src/trusted/service_runtime/linux/nacl_signal.c
// native_client/src/trusted/service_runtime/sys_exception.c
// Crash signals to handle. The differences from SFI NaCl are that
// NonSFI NaCl does not use NACL_THREAD_SUSPEND_SIGNAL (==SIGUSR1),
// and SIGSYS is reserved for seccomp-bpf.
const int kSignals[] = {
#if !defined(__mips__)
// This signal does not exist on MIPS.
SIGSTKFLT,
#endif
SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV,
// Handle SIGABRT in case someone sends it asynchronously using kill().
SIGABRT
};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
NaClExceptionHandler signal_handler_function_pointer = NULL;
// Signal handler, responsible for calling the registered handler.
void SignalCatch(int sig, siginfo_t* info, void* uc) {
if (signal_handler_function_pointer) {
NaClSignalContext signal_context;
NaClSignalContextFromHandler(&signal_context, uc);
NaClExceptionFrame exception_frame;
NaClSignalSetUpExceptionFrame(&exception_frame,
&signal_context,
0 /* context_user_addr,
not useful for NonSFI NaCl. */);
signal_handler_function_pointer(&exception_frame.context);
}
_exit(-sig);
}
int IrtExceptionHandler(NaClExceptionHandler handler,
NaClExceptionHandler* old_handler) {
pthread_mutex_lock(&mutex);
if (old_handler)
*old_handler = signal_handler_function_pointer;
signal_handler_function_pointer = handler;
pthread_mutex_unlock(&mutex);
return 0;
}
int IrtExceptionStack(void* stack, size_t size) {
// TODO(uekawa): Implement this function so that the exception stack
// actually gets used for running an exception handler. Currently
// we don't switch stack, which means we can't handle stack overflow
// exceptions.
return 0;
}
int IrtExceptionClearFlag(void) {
// TODO(uekawa): Implement clear_flag() to behave like SFI NaCl's
// implementation, so that a thread can handle a second exception
// after handling a first exception
return ENOSYS;
}
} // namespace
const struct nacl_irt_exception_handling kIrtExceptionHandling = {
IrtExceptionHandler,
IrtExceptionStack,
IrtExceptionClearFlag,
};
void InitializeSignalHandler() {
struct sigaction sa;
unsigned int a;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = SignalCatch;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
// Mask all signals we catch to prevent re-entry.
for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) {
sigaddset(&sa.sa_mask, kSignals[a]);
}
// Install all handlers.
for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) {
if (sigaction(kSignals[a], &sa, NULL) != 0)
NaClLog(LOG_FATAL, "sigaction to register signals failed.\n");
}
}
} // namespace nonsfi
} // namespace nacl