📄 exceptions.cc
字号:
/* exceptions.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <imagehlp.h>#include <errno.h>#include <stdlib.h>#include "exceptions.h"#include "sync.h"#include "sigproc.h"#include "pinfo.h"#include "cygerrno.h"#include "perthread.h"#include "shared_info.h"#include "perprocess.h"#include "security.h"#define CALL_HANDLER_RETRY 20char debugger_command[2 * MAX_PATH + 20];extern "C" {static int handle_exceptions (EXCEPTION_RECORD *, void *, CONTEXT *, void *);extern void sigreturn ();extern void sigdelayed ();extern void sigdelayed0 ();extern void siglast ();extern DWORD __no_sig_start, __no_sig_end;};extern DWORD sigtid;extern HANDLE hExeced;extern DWORD dwExeced;static BOOL WINAPI ctrl_c_handler (DWORD);static void signal_exit (int) __attribute__ ((noreturn));static char windows_system_directory[1024];static size_t windows_system_directory_length;/* This is set to indicate that we have already exited. */static NO_COPY int exit_already = 0;static NO_COPY muto *mask_sync = NULL;HMODULE NO_COPY cygwin_hmodule;NO_COPY static struct{ unsigned int code; const char *name;} status_info[] ={#define X(s) s, #s { X (STATUS_ABANDONED_WAIT_0) }, { X (STATUS_ACCESS_VIOLATION) }, { X (STATUS_ARRAY_BOUNDS_EXCEEDED) }, { X (STATUS_BREAKPOINT) }, { X (STATUS_CONTROL_C_EXIT) }, { X (STATUS_DATATYPE_MISALIGNMENT) }, { X (STATUS_FLOAT_DENORMAL_OPERAND) }, { X (STATUS_FLOAT_DIVIDE_BY_ZERO) }, { X (STATUS_FLOAT_INEXACT_RESULT) }, { X (STATUS_FLOAT_INVALID_OPERATION) }, { X (STATUS_FLOAT_OVERFLOW) }, { X (STATUS_FLOAT_STACK_CHECK) }, { X (STATUS_FLOAT_UNDERFLOW) }, { X (STATUS_GUARD_PAGE_VIOLATION) }, { X (STATUS_ILLEGAL_INSTRUCTION) }, { X (STATUS_INTEGER_DIVIDE_BY_ZERO) }, { X (STATUS_INTEGER_OVERFLOW) }, { X (STATUS_INVALID_DISPOSITION) }, { X (STATUS_IN_PAGE_ERROR) }, { X (STATUS_NONCONTINUABLE_EXCEPTION) }, { X (STATUS_NO_MEMORY) }, { X (STATUS_PENDING) }, { X (STATUS_PRIVILEGED_INSTRUCTION) }, { X (STATUS_SINGLE_STEP) }, { X (STATUS_STACK_OVERFLOW) }, { X (STATUS_TIMEOUT) }, { X (STATUS_USER_APC) }, { X (STATUS_WAIT_0) }, { 0, 0 }#undef X};/* Initialization code. */#ifdef __i386__// Set up the exception handler for the current thread. The PowerPC & Mips// use compiler generated tables to set up the exception handlers for each// region of code, and the kernel walks the call list until it finds a region// of code that handles exceptions. The x86 on the other hand uses segment// register fs, offset 0 to point to the current exception handler.asm (".equ __except_list,0");extern exception_list *_except_list asm ("%fs:__except_list");static voidinit_exception_handler (exception_list *el){ el->handler = handle_exceptions; el->prev = _except_list; _except_list = el;}#endifvoidearly_stuff_init (){ (void) SetConsoleCtrlHandler (ctrl_c_handler, FALSE); if (!SetConsoleCtrlHandler (ctrl_c_handler, TRUE)) system_printf ("SetConsoleCtrlHandler failed, %E"); /* Initialize global security attribute stuff */ sec_none.nLength = sec_none_nih.nLength = sec_all.nLength = sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES); sec_none.bInheritHandle = sec_all.bInheritHandle = TRUE; sec_none_nih.bInheritHandle = sec_all_nih.bInheritHandle = FALSE; sec_none.lpSecurityDescriptor = sec_none_nih.lpSecurityDescriptor = NULL; sec_all.lpSecurityDescriptor = sec_all_nih.lpSecurityDescriptor = get_null_sd ();}extern "C" voidinit_exceptions (exception_list *el){ init_exception_handler (el);}extern "C" voiderror_start_init (const char *buf){ if (!buf || !*buf) { debugger_command[0] = '\0'; return; } char pgm[MAX_PATH + 1]; if (!GetModuleFileName (NULL, pgm, MAX_PATH)) strcpy (pgm, "cygwin1.dll"); for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\')) *p = '/'; __small_sprintf (debugger_command, "%s %s", buf, pgm);}static voidopen_stackdumpfile (){ if (myself->progname[0]) { const char *p; /* write to progname.stackdump if possible */ if (!myself->progname[0]) p = "unknown"; else if ((p = strrchr (myself->progname, '\\'))) p++; else p = myself->progname; char corefile[strlen (p) + sizeof (".stackdump")]; __small_sprintf (corefile, "%s.stackdump", p); HANDLE h = CreateFile (corefile, GENERIC_WRITE, 0, &sec_none_nih, CREATE_ALWAYS, 0, 0); if (h != INVALID_HANDLE_VALUE) { if (!myself->ppid_handle) system_printf ("Dumping stack trace to %s", corefile); else debug_printf ("Dumping stack trace to %s", corefile); SetStdHandle (STD_ERROR_HANDLE, h); } }}/* Utilities for dumping the stack, etc. */static voidexception (EXCEPTION_RECORD *e, CONTEXT *in){ const char *exception_name = NULL; if (e) { for (int i = 0; status_info[i].name; i++) { if (status_info[i].code == e->ExceptionCode) { exception_name = status_info[i].name; break; } } }#ifdef __i386__#define HAVE_STATUS if (exception_name) small_printf ("Exception: %s at eip=%08x\r\n", exception_name, in->Eip); else small_printf ("Exception %d at eip=%08x\r\n", e->ExceptionCode, in->Eip); small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n", in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi); small_printf ("ebp=%08x esp=%08x program=%s\r\n", in->Ebp, in->Esp, myself->progname); small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n", in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs);#endif#ifndef HAVE_STATUS system_printf ("Had an exception");#endif}#ifdef __i386__/* Print a stack backtrace. */#define HAVE_STACK_TRACE/* A class for manipulating the stack. */class stack_info{ int walk (); /* Uses the "old" method */ char *next_offset () {return *((char **) sf.AddrFrame.Offset);} bool needargs; DWORD dummy_frame;public: STACKFRAME sf; /* For storing the stack information */ void init (DWORD, bool, bool); /* Called the first time that stack info is needed */ /* Postfix ++ iterates over the stack, returning zero when nothing is left. */ int operator ++(int) { return this->walk (); }};/* The number of parameters used in STACKFRAME */#define NPARAMS (sizeof (thestack.sf.Params) / sizeof (thestack.sf.Params[0]))/* This is the main stack frame info for this process. */static NO_COPY stack_info thestack;static signal_dispatch sigsave;/* Initialize everything needed to start iterating. */voidstack_info::init (DWORD ebp, bool wantargs, bool goodframe){# define debp ((DWORD *) ebp) memset (&sf, 0, sizeof (sf)); if (!goodframe) sf.AddrFrame.Offset = ebp; else { dummy_frame = ebp; sf.AddrFrame.Offset = (DWORD) &dummy_frame; } sf.AddrReturn.Offset = debp[1]; sf.AddrFrame.Mode = AddrModeFlat; needargs = wantargs;# undef debp}/* Walk the stack by looking at successive stored 'bp' frames. This is not foolproof. */intstack_info::walk (){ char **ebp; if ((ebp = (char **) next_offset ()) == NULL) return 0; sf.AddrFrame.Offset = (DWORD) ebp; sf.AddrPC.Offset = sf.AddrReturn.Offset; if (!sf.AddrPC.Offset) return 0; /* stack frames are exhausted */ /* The return address always follows the stack pointer */ sf.AddrReturn.Offset = (DWORD) *++ebp; if (needargs) /* The arguments follow the return address */ for (unsigned i = 0; i < NPARAMS; i++) sf.Params[i] = (DWORD) *++ebp; return 1;}static voidstackdump (DWORD ebp, int open_file, bool isexception){ extern unsigned long rlim_core; if (rlim_core == 0UL) return; if (open_file) open_stackdumpfile (); int i; thestack.init (ebp, 1, !isexception); /* Initialize from the input CONTEXT */ small_printf ("Stack trace:\r\nFrame Function Args\r\n"); for (i = 0; i < 16 && thestack++; i++) { small_printf ("%08x %08x ", thestack.sf.AddrFrame.Offset, thestack.sf.AddrPC.Offset); for (unsigned j = 0; j < NPARAMS; j++) small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack.sf.Params[j]); small_printf (")\r\n"); } small_printf ("End of stack trace%s", i == 16 ? " (more stack frames may be present)" : "");}/* Temporary (?) function for external callers to get a stack dump */extern "C" voidcygwin_stackdump (){ CONTEXT c; c.ContextFlags = CONTEXT_FULL; GetThreadContext (GetCurrentThread (), &c); stackdump (c.Ebp, 0, 0);}#define TIME_TO_WAIT_FOR_DEBUGGER 10000extern "C" inttry_to_debug (bool waitloop){ debug_printf ("debugger_command '%s'", debugger_command); if (*debugger_command == '\0' || being_debugged ()) return 0; __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ()); SetThreadPriority (hMainThread, THREAD_PRIORITY_HIGHEST); PROCESS_INFORMATION pi = {NULL, 0, 0, 0}; STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}; si.lpReserved = NULL; si.lpDesktop = NULL; si.dwFlags = 0; si.cb = sizeof (si); /* FIXME: need to know handles of all running threads to suspend_all_threads_except (current_thread_id); */ /* if any of these mutexes is owned, we will fail to start any cygwin app until trapped app exits */ ReleaseMutex (title_mutex); /* prevent recursive exception handling */ char* rawenv = GetEnvironmentStrings () ; for (char* p = rawenv; *p != '\0'; p = strchr (p, '\0') + 1) { if (strncmp (p, "CYGWIN=", sizeof ("CYGWIN=") - 1) == 0) { char* q = strstr (p, "error_start") ; /* replace 'error_start=...' with '_rror_start=...' */ if (q) *q = '_' ; SetEnvironmentVariable ("CYGWIN", p + sizeof ("CYGWIN=")) ; break ; } } BOOL dbg; dbg = CreateProcess (NULL, debugger_command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi); if (!dbg) system_printf ("Failed to start debugger: %E"); else { SetThreadPriority (hMainThread, THREAD_PRIORITY_IDLE); if (!waitloop) return 1; while (!being_debugged ()) /* spin */; Sleep (4000); small_printf ("*** continuing from debugger call\n"); } /* FIXME: need to know handles of all running threads to resume_all_threads_except (current_thread_id); */ return 0;}/* Main exception handler. */static inthandle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *){ int sig; static int NO_COPY debugging = 0; static int NO_COPY recursed = 0; if (debugging && ++debugging < 500000) { SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL); return 0; } /* If we've already exited, don't do anything here. Returning 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -