📄 exceptions.cc
字号:
tells Windows to keep looking for an exception handler. */ if (exit_already) return 1; /* Coerce win32 value to posix value. */ switch (e->ExceptionCode) { case STATUS_FLOAT_DENORMAL_OPERAND: case STATUS_FLOAT_DIVIDE_BY_ZERO: case STATUS_FLOAT_INEXACT_RESULT: case STATUS_FLOAT_INVALID_OPERATION: case STATUS_FLOAT_OVERFLOW: case STATUS_FLOAT_STACK_CHECK: case STATUS_FLOAT_UNDERFLOW: case STATUS_INTEGER_DIVIDE_BY_ZERO: case STATUS_INTEGER_OVERFLOW: sig = SIGFPE; break; case STATUS_ILLEGAL_INSTRUCTION: case STATUS_PRIVILEGED_INSTRUCTION: case STATUS_NONCONTINUABLE_EXCEPTION: sig = SIGILL; break; case STATUS_TIMEOUT: sig = SIGALRM; break; case STATUS_ACCESS_VIOLATION: case STATUS_DATATYPE_MISALIGNMENT: case STATUS_ARRAY_BOUNDS_EXCEEDED: case STATUS_GUARD_PAGE_VIOLATION: case STATUS_IN_PAGE_ERROR: case STATUS_NO_MEMORY: case STATUS_INVALID_DISPOSITION: case STATUS_STACK_OVERFLOW: sig = SIGSEGV; break; case STATUS_CONTROL_C_EXIT: sig = SIGINT; break; case STATUS_INVALID_HANDLE: /* CloseHandle will throw this exception if it is given an invalid handle. We don't care about the exception; we just want CloseHandle to return an error. This can be revisited if gcc ever supports Windows style structured exception handling. */ return 0; default: /* If we don't recognize the exception, we have to assume that we are doing structured exception handling, and we let something else handle it. */ return 1; } debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp); debug_printf ("In cygwin_except_handler sig = %d at %p", sig, in->Eip); if (myself->getsig (sig).sa_mask & SIGTOMASK (sig)) syscall_printf ("signal %d, masked %p", sig, myself->getsig (sig).sa_mask); debug_printf ("In cygwin_except_handler calling %p", myself->getsig (sig).sa_handler); DWORD *ebp = (DWORD *)in->Esp; for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--) if (*ebp == in->SegCs && ebp[-1] == in->Eip) { ebp -= 2; break; } if (!myself->progname[0] || GetCurrentThreadId () == sigtid || (void *) myself->getsig (sig).sa_handler == (void *) SIG_DFL || (void *) myself->getsig (sig).sa_handler == (void *) SIG_IGN || (void *) myself->getsig (sig).sa_handler == (void *) SIG_ERR) { /* Print the exception to the console */ if (e) { for (int i = 0; status_info[i].name; i++) { if (status_info[i].code == e->ExceptionCode) { if (!myself->ppid_handle) system_printf ("Exception: %s", status_info[i].name); break; } } } /* Another exception could happen while tracing or while exiting. Only do this once. */ if (recursed++) system_printf ("Error while dumping state (probably corrupted stack)"); else { if (try_to_debug (0)) { debugging = 1; return 0; } open_stackdumpfile (); exception (e, in); stackdump ((DWORD) ebp, 0, 1); } signal_exit (0x80 | sig); // Flag signal + core dump } sig_send (NULL, sig, (DWORD) ebp, 1); // Signal myself return 0;}#endif /* __i386__ */#ifndef HAVE_STACK_TRACEvoidstack (void){ system_printf ("Stack trace not yet supported on this machine.");}#endif/* Utilities to call a user supplied exception handler. */#define SIG_NONMASKABLE (SIGTOMASK (SIGKILL) | SIGTOMASK (SIGSTOP))#ifdef __i386__#define HAVE_CALL_HANDLER/* Non-raceable sigsuspend * Note: This implementation is based on the Single UNIX Specification * man page. This indicates that sigsuspend always returns -1 and that * attempts to block unblockable signals will be silently ignored. * This is counter to what appears to be documented in some UNIX * man pages, e.g. Linux. */int __stdcallhandle_sigsuspend (sigset_t tempmask){ sig_dispatch_pending (0); sigframe thisframe (mainthread); sigset_t oldmask = myself->getsigmask (); // Remember for restoration set_process_mask (tempmask & ~SIG_NONMASKABLE);// Let signals we're // interested in through. sigproc_printf ("old mask %x, new mask %x", oldmask, tempmask); WaitForSingleObject (signal_arrived, INFINITE); set_sig_errno (EINTR); // Per POSIX /* A signal dispatch function will have been added to our stack and will be hit eventually. Set the old mask to be restored when the signal handler returns. */ sigsave.oldmask = oldmask; // Will be restored by signal handler return -1;}extern DWORD exec_exit; // Possible exit value for execextern int pending_signals;extern "C" {static voidsig_handle_tty_stop (int sig){ /* Silently ignore attempts to suspend if there is no accomodating cygwin parent to deal with this behavior. */ if (!myself->ppid_handle) { myself->process_state &= ~PID_STOPPED; return; } myself->stopsig = sig; /* See if we have a living parent. If so, send it a special signal. * It will figure out exactly which pid has stopped by scanning * its list of subprocesses. */ if (my_parent_is_alive ()) { pinfo parent (myself->ppid); if (!(parent->getsig (SIGCHLD).sa_flags & SA_NOCLDSTOP)) sig_send (parent, SIGCHLD); } sigproc_printf ("process %d stopped by signal %d, myself->ppid_handle %p", myself->pid, sig, myself->ppid_handle); if (WaitForSingleObject (sigCONT, INFINITE) != WAIT_OBJECT_0) api_fatal ("WaitSingleObject failed, %E"); (void) ResetEvent (sigCONT); return;}}intinterruptible (DWORD pc, int testvalid = 0){ int res; MEMORY_BASIC_INFORMATION m; memset (&m, 0, sizeof m); if (!VirtualQuery ((LPCVOID) pc, &m, sizeof m)) sigproc_printf ("couldn't get memory info, pc %p, %E", pc); char *checkdir = (char *) alloca (windows_system_directory_length + 4); memset (checkdir, 0, sizeof (checkdir));# define h ((HMODULE) m.AllocationBase) /* Apparently Windows 95 can sometimes return bogus addresses from GetThreadContext. These resolve to a strange allocation base. These should *never* be treated as interruptible. */ if (!h || m.State != MEM_COMMIT) res = 0; else if (testvalid) res = 1; /* All we wanted to know was if this was a valid module. */ else if (h == user_data->hmodule) res = 1; else if (h == cygwin_hmodule) res = 0; else if (!GetModuleFileName (h, checkdir, windows_system_directory_length + 2)) res = 0; else res = !strncasematch (windows_system_directory, checkdir, windows_system_directory_length); sigproc_printf ("pc %p, h %p, interruptible %d, testvalid %d", pc, h, res, testvalid);# undef h return res;}boolsigthread::get_winapi_lock (int test){ if (test) return !InterlockedExchange (&winapi_lock, 1); /* Need to do a busy loop because we can't block or a potential SuspendThread will hang. */ while (InterlockedExchange (&winapi_lock, 1)) low_priority_sleep (0); return 1;}voidsigthread::release_winapi_lock (){ /* Assumes that we have the lock. */ InterlockedExchange (&winapi_lock, 0);}static void __stdcall interrupt_setup (int sig, void *handler, DWORD retaddr, DWORD *retaddr_on_stack, struct sigaction& siga) __attribute__((regparm(3)));static void __stdcallinterrupt_setup (int sig, void *handler, DWORD retaddr, DWORD *retaddr_on_stack, struct sigaction& siga){ sigsave.retaddr = retaddr; sigsave.retaddr_on_stack = retaddr_on_stack; /* FIXME: Not multi-thread aware */ sigsave.oldmask = myself->getsigmask (); sigsave.newmask = sigsave.oldmask | siga.sa_mask | SIGTOMASK (sig); sigsave.sa_flags = siga.sa_flags; sigsave.func = (void (*)(int)) handler; sigsave.sig = sig; sigsave.saved_errno = -1; // Flag: no errno to save if (handler == sig_handle_tty_stop) { myself->stopsig = 0; myself->process_state |= PID_STOPPED; } /* Clear any waiting threads prior to dispatching to handler function */ proc_subproc (PROC_CLEARWAIT, 1); int res = SetEvent (signal_arrived); // For an EINTR case sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res);}static bool interrupt_now (CONTEXT *, int, void *, struct sigaction&) __attribute__((regparm(3)));static boolinterrupt_now (CONTEXT *ctx, int sig, void *handler, struct sigaction& siga){ interrupt_setup (sig, handler, ctx->Eip, 0, siga); ctx->Eip = (DWORD) sigdelayed; SetThreadContext (myself->getthread2signal (), ctx); /* Restart the thread in a new location */ return 1;}void __stdcallsignal_fixup_after_fork (){ if (sigsave.sig) { sigsave.sig = 0; if (sigsave.retaddr_on_stack) { *sigsave.retaddr_on_stack = sigsave.retaddr; set_process_mask (sigsave.oldmask); } } sigproc_init ();}void __stdcallsignal_fixup_after_exec (bool isspawn){ /* Set up child's signal handlers */ for (int i = 0; i < NSIG; i++) { myself->getsig (i).sa_mask = 0; if (myself->getsig (i).sa_handler != SIG_IGN || isspawn) myself->getsig (i).sa_handler = SIG_DFL; }}static int interrupt_on_return (sigthread *, int, void *, struct sigaction&) __attribute__((regparm(3)));static intinterrupt_on_return (sigthread *th, int sig, void *handler, struct sigaction& siga){ int i; DWORD ebp = th->frame; if (!ebp) return 0; thestack.init (ebp, 0, 1); /* Initialize from the input CONTEXT */ for (i = 0; i < 32 && thestack++ ; i++) if (th->exception || interruptible (thestack.sf.AddrReturn.Offset)) { DWORD *addr_retaddr = ((DWORD *)thestack.sf.AddrFrame.Offset) + 1; if (*addr_retaddr == thestack.sf.AddrReturn.Offset) { interrupt_setup (sig, handler, *addr_retaddr, addr_retaddr, siga); *addr_retaddr = (DWORD) sigdelayed; } return 1; } sigproc_printf ("couldn't find a stack frame, i %d", i); return 0;}extern "C" void __stdcallset_sig_errno (int e){ set_errno (e); sigsave.saved_errno = e; // sigproc_printf ("errno %d", e);}static int setup_handler (int, void *, struct sigaction&) __attribute__((regparm(3)));static intsetup_handler (int sig, void *handler, struct sigaction& siga){ CONTEXT cx; bool interrupted = false; sigthread *th = NULL; // Initialization needed to shut up gcc int prio = INFINITE; if (sigsave.sig) goto set_pending; for (int i = 0; i < CALL_HANDLER_RETRY; i++) { DWORD res; HANDLE hth; EnterCriticalSection (&mainthread.lock); if (mainthread.frame) { hth = NULL; th = &mainthread; } else { LeaveCriticalSection (&mainthread.lock); if (!mainthread.get_winapi_lock (1)) continue; hth = myself->getthread2signal (); th = NULL; /* Suspend the thread which will receive the signal. But first ensure that this thread doesn't have any mutos. (FIXME: Someday we should just grab all of the mutos rather than checking for them) For Windows 95, we also have to ensure that the addresses returned by GetThreadContext are valid. If one of these conditions is not true we loop for a fixed number of times since we don't want to stall the signal handler. FIXME: Will this result in noticeable delays? If the thread is already suspended (which can occur when a program has called SuspendThread on itself then just queue the signal. */ EnterCriticalSection (&mainthread.lock); sigproc_printf ("suspending mainthread"); res = SuspendThread (hth); /* Just release the lock now since we hav suspended the main thread and it definitely can't be grabbing it now. This will have to change, of course, if/when we can send signals to other than the main thread. */ LeaveCriticalSection (&mainthread.lock); /* Just set pending if thread is already suspended */ if (res) { (void) ResumeThread (hth); break; } mainthread.release_winapi_lock (); if (mainthread.frame) goto resume_thread; /* We just got the frame. What are the odds? Just loop and we'll hopefully pick it up on the next pass through. */ muto *m; /* FIXME: Make multi-thread aware */ for (m = muto_start.next; m != NULL; m = m->next)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -