diff options
Diffstat (limited to 'xorg-server/os/osinit.c')
-rw-r--r-- | xorg-server/os/osinit.c | 121 |
1 files changed, 118 insertions, 3 deletions
diff --git a/xorg-server/os/osinit.c b/xorg-server/os/osinit.c index 74e2457f2..e8fcd4540 100644 --- a/xorg-server/os/osinit.c +++ b/xorg-server/os/osinit.c @@ -54,6 +54,15 @@ SOFTWARE. #include "os.h" #include "osdep.h" #include <X11/Xos.h> +#include <signal.h> +#include <errno.h> +#ifdef HAVE_DLFCN_H +# include <dlfcn.h> +#endif +#ifdef HAVE_BACKTRACE +#include <execinfo.h> +#endif + #include "dixstruct.h" @@ -88,6 +97,66 @@ int limitStackSpace = -1; int limitNoFile = -1; #endif +static OsSigWrapperPtr OsSigWrapper = NULL; + +OsSigWrapperPtr +OsRegisterSigWrapper(OsSigWrapperPtr newSigWrapper) +{ + OsSigWrapperPtr oldSigWrapper = OsSigWrapper; + + OsSigWrapper = newSigWrapper; + + return oldSigWrapper; +} + +/* + * OsSigHandler -- + * Catch unexpected signals and exit or continue cleanly. + */ +static void +#ifdef SA_SIGINFO +OsSigHandler(int signo, siginfo_t *sip, void *unused) +#else +OsSigHandler(int signo) +#endif +{ +#ifdef RTLD_DI_SETSIGNAL + const char *dlerr = dlerror(); + + if (dlerr) { + LogMessage(X_ERROR, "Dynamic loader error: %s\n", dlerr); + } +#endif /* RTLD_DI_SETSIGNAL */ + + if (OsSigWrapper != NULL) { + if (OsSigWrapper(signo) == 0) { + /* ddx handled signal and wants us to continue */ + return; + } + } + + /* log, cleanup, and abort */ + xorg_backtrace(); + +#ifdef SA_SIGINFO + if (sip->si_code == SI_USER) { + ErrorF("Recieved signal %d sent by process %ld, uid %ld\n", + signo, (long) sip->si_pid, (long) sip->si_uid); + } else { + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGILL: + case SIGFPE: + ErrorF("%s at address %p\n", strsignal(signo), sip->si_addr); + } + } +#endif + + FatalError("Caught signal %d (%s). Server aborting\n", + signo, strsignal(signo)); +} + void OsInit(void) { @@ -96,11 +165,57 @@ OsInit(void) static char* devnull = "/dev/null"; char fname[PATH_MAX]; -#ifdef macII - set42sig(); + if (!been_here) { + struct sigaction act, oact; + int i; + int siglist[] = { SIGSEGV, SIGQUIT, SIGILL, SIGFPE, SIGBUS, +#ifdef SIGSYS + SIGSYS, +#endif +#ifdef SIGXCPU + SIGXCPU, +#endif +#ifdef SIGXFSZ + SIGXFSZ, +#endif +#ifdef SIGEMT + SIGEMT, +#endif + 0 /* must be last */ }; + sigemptyset(&act.sa_mask); +#ifdef SA_SIGINFO + act.sa_sigaction = OsSigHandler; + act.sa_flags = SA_SIGINFO; +#else + act.sa_handler = OsSigHandler; + act.sa_flags = 0; +#endif + for (i = 0; siglist[i] != 0; i++) { + if (sigaction(siglist[i], &act, &oact)) { + ErrorF("failed to install signal handler for signal %d: %s\n", + siglist[i], strerror(errno)); + } + } +#ifdef HAVE_BACKTRACE + /* + * initialize the backtracer, since the ctor calls dlopen(), which + * calls malloc(), which isn't signal-safe. + */ + do { + void *array; + backtrace(&array, 1); + } while (0); +#endif + +#ifdef RTLD_DI_SETSIGNAL + /* Tell runtime linker to send a signal we can catch instead of SIGKILL + * for failures to load libraries/modules at runtime so we can clean up + * after ourselves. + */ + int failure_signal = SIGQUIT; + dlinfo(RTLD_SELF, RTLD_DI_SETSIGNAL, &failure_signal); #endif - if (!been_here) { #if !defined(__SCO__) && !defined(__CYGWIN__) && !defined(__UNIXWARE__) fclose(stdin); fclose(stdout); |