#ifndef WINELIB #include #include #include #include #include #include #include #include #include #include #include #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__svr4__) || defined(_SCO_DS) || defined(__EMX__) #if !defined(_SCO_DS) && !defined(__EMX__) #include #endif #include #else #include #endif #include "debugger.h" #include "options.h" #include "sigcontext.h" #include "win.h" #include "winsock.h" #if !defined(BSD4_4) || defined(linux) || defined(__FreeBSD__) char * cstack[4096]; #endif #ifdef linux extern void ___sig_restore(); extern void ___masksig_restore(); /* This is the sigaction structure from the Linux 2.1.20 kernel. */ struct kernel_sigaction { __sighandler_t sa_handler; unsigned long sa_mask; unsigned long sa_flags; void (*sa_restorer) __P ((void)); }; /* Similar to the sigaction function in libc, except it leaves alone the restorer field */ static int wine_sigaction(int sig,struct kernel_sigaction * new, struct kernel_sigaction * old) { __asm__("int $0x80":"=a" (sig) :"0" (SYS_sigaction),"b" (sig),"c" (new),"d" (old)); if (sig>=0) return 0; errno = -sig; return -1; } #endif /* linux */ #ifdef linux #define HANDLER_DEF(name) void name (int signal, SIGCONTEXT context_struct) #define HANDLER_PROLOG SIGCONTEXT *context = &context_struct; (void)context; { #define HANDLER_EPILOG } #elif defined(__svr4__) || defined(_SCO_DS) #define HANDLER_DEF(name) void name (int signal, void *siginfo, SIGCONTEXT *context) #define HANDLER_PROLOG /* nothing */ #define HANDLER_EPILOG /* nothing */ #else #define HANDLER_DEF(name) void name (int signal, int code, SIGCONTEXT *context) #define HANDLER_PROLOG /* nothing */ #define HANDLER_EPILOG /* nothing */ #endif extern BOOL32 INSTR_EmulateInstruction( SIGCONTEXT *context ); /********************************************************************** * wine_timer * * SIGALRM handler. */ static HANDLER_DEF(wine_timer) { HANDLER_PROLOG; /* Should do real-time timers here */ DOSMEM_Tick(); HANDLER_EPILOG; } /********************************************************************** * SIGNAL_break * * Handle Ctrl-C and such */ static HANDLER_DEF(SIGNAL_break) { HANDLER_PROLOG; if (Options.debug) wine_debug( signal, context ); /* Enter our debugger */ exit(0); HANDLER_EPILOG; } /********************************************************************** * SIGNAL_child * * wait4 terminated child processes */ static HANDLER_DEF(SIGNAL_child) { HANDLER_PROLOG; #ifdef HAVE_WAIT4 wait4( 0, NULL, WNOHANG, NULL); #elif defined (HAVE_WAITPID) /* I am sort-of guessing that this is the same as the wait4 call. */ waitpid (0, NULL, WNOHANG); #else wait(NULL); #endif HANDLER_EPILOG; } /********************************************************************** * SIGNAL_trap * * SIGTRAP handler. */ static HANDLER_DEF(SIGNAL_trap) { HANDLER_PROLOG; wine_debug( signal, context ); /* Enter our debugger */ HANDLER_EPILOG; } /********************************************************************** * SIGNAL_fault * * Segfault handler. */ static HANDLER_DEF(SIGNAL_fault) { HANDLER_PROLOG; if (CS_sig(context) == WINE_CODE_SELECTOR) { fprintf( stderr, "Segmentation fault in Wine program (%04x:%08lx)." " Please debug.\n", (unsigned short) CS_sig(context), EIP_sig(context)); } else { if (INSTR_EmulateInstruction( context )) return; fprintf( stderr, "Segmentation fault in Windows program %04x:%08lx.\n", (unsigned short) CS_sig(context), EIP_sig(context) ); } wine_debug( signal, context ); HANDLER_EPILOG; } /********************************************************************** * SIGNAL_SetHandler */ static void SIGNAL_SetHandler( int sig, void (*func)(), int flags ) { int ret; #ifdef linux struct kernel_sigaction sig_act; sig_act.sa_handler = func; sig_act.sa_flags = SA_RESTART | (flags) ? SA_NOMASK : 0; /* Point to the top of the stack, minus 4 just in case, and make it aligned */ sig_act.sa_restorer = (void (*)()) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3); ret = wine_sigaction( sig, &sig_act, NULL ); #endif /* linux */ #if defined(__NetBSD__) || defined(__FreeBSD__) struct sigaction sig_act; sigset_t sig_mask; sigemptyset(&sig_mask); sig_act.sa_handler = func; sig_act.sa_flags = SA_ONSTACK; sig_act.sa_mask = sig_mask; ret = sigaction( sig, &sig_act, NULL ); #endif /* __FreeBSD__ || __NetBSD__ */ #if defined (__svr4__) || defined(_SCO_DS) struct sigaction sig_act; sigset_t sig_mask; sigemptyset(&sig_mask); sig_act.sa_handler = func; sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART; sig_act.sa_mask = sig_mask; ret = sigaction( sig, &sig_act, NULL ); #endif /* __svr4__ || _SCO_DS */ #if defined(__EMX__) struct sigaction sig_act; sigset_t sig_mask; sigemptyset(&sig_mask); sig_act.sa_handler = func; sig_act.sa_flags = 0; /* FIXME: EMX has only SA_ACK and SA_SYSV */ sig_act.sa_mask = sig_mask; ret = sigaction( sig, &sig_act, NULL ); #endif /* __EMX__ */ if (ret < 0) { perror( "sigaction" ); exit(1); } } extern void stop_wait(int a); extern void WINSOCK_sigio(int a); /********************************************************************** * SIGNAL_Init */ BOOL32 SIGNAL_Init(void) { #if defined(__NetBSD__) || defined(__FreeBSD__) struct sigaltstack ss; if ((ss.ss_sp = malloc(MINSIGSTKSZ)) == NULL) { fprintf(stderr, "Unable to allocate signal stack (%d bytes)\n", MINSIGSTKSZ); return FALSE; } ss.ss_size = MINSIGSTKSZ; ss.ss_flags = 0; if (sigaltstack(&ss, NULL) < 0) { perror("sigstack"); return FALSE; } #endif /* __FreeBSD__ || __NetBSD__ */ #if defined (__svr4__) || defined(_SCO_DS) struct sigaltstack ss; if ((ss.ss_sp = malloc(SIGSTKSZ) ) == NULL) { fprintf(stderr, "Unable to allocate signal stack (%d bytes)\n", SIGSTKSZ); return FALSE; } ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; if (sigaltstack(&ss, NULL) < 0) { perror("sigstack"); return FALSE; } #endif /* __svr4__ || _SCO_DS */ SIGNAL_SetHandler( SIGALRM, (void (*)())wine_timer, 1); SIGNAL_SetHandler( SIGINT, (void (*)())SIGNAL_break, 1); SIGNAL_SetHandler( SIGCHLD, (void (*)())SIGNAL_child, 1); SIGNAL_SetHandler( SIGSEGV, (void (*)())SIGNAL_fault, 1); SIGNAL_SetHandler( SIGILL, (void (*)())SIGNAL_fault, 1); SIGNAL_SetHandler( SIGFPE, (void (*)())SIGNAL_fault, 1); SIGNAL_SetHandler( SIGTRAP, (void (*)())SIGNAL_trap, 1); /* debugger */ SIGNAL_SetHandler( SIGHUP, (void (*)())SIGNAL_trap, 1); /* forced break */ #ifdef SIGBUS SIGNAL_SetHandler( SIGBUS, (void (*)())SIGNAL_fault, 1); #endif #ifdef CONFIG_IPC SIGNAL_SetHandler( SIGUSR2, (void (*)())stop_wait, 1); /* For IPC */ #endif #ifndef __EMX__ /* FIXME */ SIGNAL_SetHandler( SIGIO, (void (*)())WINSOCK_sigio, 0); #endif return TRUE; } /********************************************************************** * SIGNAL_StartBIOSTimer * * Start the BIOS tick timer. */ void SIGNAL_StartBIOSTimer(void) { #ifndef __EMX__ /* FIXME: Time don't work... Use BIOS directly instead */ struct itimerval vt_timer; static int timer_started = 0; if (timer_started) return; timer_started = 1; vt_timer.it_interval.tv_sec = 0; vt_timer.it_interval.tv_usec = 54929; vt_timer.it_value = vt_timer.it_interval; setitimer(ITIMER_REAL, &vt_timer, NULL); #endif } /********************************************************************** * SIGNAL_MaskAsyncEvents */ void SIGNAL_MaskAsyncEvents( BOOL32 flag ) { sigset_t set; sigemptyset(&set); #ifndef __EMX__ /* FIXME */ sigaddset(&set, SIGIO); #endif sigaddset(&set, SIGUSR1); #ifdef CONFIG_IPC sigaddset(&set, SIGUSR2); #endif sigprocmask( (flag) ? SIG_BLOCK : SIG_UNBLOCK , &set, NULL); } #endif /* ifndef WINELIB */