From: <cn...@us...> - 2008-12-30 22:10:33
|
Revision: 113 http://hgengine.svn.sourceforge.net/hgengine/?rev=113&view=rev Author: cnlohr Date: 2008-12-30 22:10:30 +0000 (Tue, 30 Dec 2008) Log Message: ----------- crash handler Modified Paths: -------------- Mercury2/adv_set.c Mercury2/src/Mercury2.cpp Added Paths: ----------- Mercury2/src/MercuryBacktrace.c Mercury2/src/MercuryBacktrace.h Mercury2/src/MercuryCrash.c Mercury2/src/MercuryCrash.h Modified: Mercury2/adv_set.c =================================================================== --- Mercury2/adv_set.c 2008-12-30 21:37:42 UTC (rev 112) +++ Mercury2/adv_set.c 2008-12-30 22:10:30 UTC (rev 113) @@ -3,17 +3,12 @@ FOLDERS="src" -SOURCES="src/Mercury2.cpp src/MercuryAsset.cpp \ - src/MercuryNode.cpp src/MercuryPoint.cpp \ - src/MercuryThreads.cpp src/MercuryMath.cpp \ - src/MercuryWindow.cpp src/RenderableNode.cpp \ - src/TransformNode.cpp src/MercuryMatrix.cpp \ - src/Viewport.cpp src/Quad.cpp src/MercuryUtil.cpp \ - src/Texture.cpp src/RawImageData.cpp src/BMPLoader.cpp \ - src/PNGLoader.cpp src/ImageLoader.cpp \ - src/MercuryVBO.cpp src/MSemaphore.cpp \ - src/UpdateThreader.cpp src/HGMDLMesh.cpp \ - src/HGMDLModel.cpp src/MercuryString.cpp" +SOURCES="src/Mercury2.cpp src/MercuryAsset.cpp src/MercuryNode.cpp src/MercuryPoint.cpp \ + src/MercuryThreads.cpp src/MercuryMath.cpp src/MercuryWindow.cpp src/RenderableNode.cpp \ + src/TransformNode.cpp src/MercuryMatrix.cpp src/Viewport.cpp src/Quad.cpp src/MercuryUtil.cpp \ + src/Texture.cpp src/RawImageData.cpp src/BMPLoader.cpp src/PNGLoader.cpp src/ImageLoader.cpp \ + src/MercuryVBO.cpp src/MSemaphore.cpp src/UpdateThreader.cpp src/HGMDLMesh.cpp \ + src/HGMDLModel.cpp src/MercuryString.cpp src/MercuryCrash.c src/MercuryBacktrace.c" #ifdef USE_LIBXML SOURCES="$SOURCES src/XMLParser.cpp" @@ -24,8 +19,8 @@ #endif PROJ="mercury" -CFLAGS="$CFLAGS -DHAVE_CONFIG -DHGENGINE -fno-exceptions -fPIC -Isrc" -LDFLAGS="$LDFLAGS -rdynamic -g -fPIC" +CFLAGS="$CFLAGS -DHAVE_CONFIG -DHGENGINE -fno-exceptions -fPIC -Isrc -g " +LDFLAGS="$LDFLAGS -rdynamic -g -fPIC " /* * (c) 2007-2008 Charles Lohr Modified: Mercury2/src/Mercury2.cpp =================================================================== --- Mercury2/src/Mercury2.cpp 2008-12-30 21:37:42 UTC (rev 112) +++ Mercury2/src/Mercury2.cpp 2008-12-30 22:10:30 UTC (rev 113) @@ -8,6 +8,9 @@ #include <RenderableNode.h> +#include <MercuryCrash.h> +#include <MercuryBacktrace.h> + MSemaphore UpdateLoopGo; void* UpdateThread(void* node) { @@ -19,11 +22,23 @@ return NULL; } +int SignalHandler( int signal ) +{ + char buffer[2048]; + printf( "Fatal error encountered in Mercury 2: %s\n", cn_get_crash_description( signal ) ); + cnget_backtrace( 1, buffer, 2047 ); + printf( "%s\n", buffer ); + + return 0; //Continue regular crash. +} + int main() { unsigned long m_count = 0; long m_time; - + + cnset_execute_on_crash( SignalHandler ); + MercuryWindow* w = MercuryWindow::MakeWindow(); MercuryNode* root = new MercuryNode(); Added: Mercury2/src/MercuryBacktrace.c =================================================================== --- Mercury2/src/MercuryBacktrace.c (rev 0) +++ Mercury2/src/MercuryBacktrace.c 2008-12-30 22:10:30 UTC (rev 113) @@ -0,0 +1,611 @@ +#include "MercuryBacktrace.h" + + +#ifdef WIN32 +#define _CWINDOWS +#else +#if defined( MACOSX ) || defined( __APPLE__ ) +#define _CMAC +#else +#define _CLINUX +#endif +#endif + + + +#if defined ( _CWINDOWS ) +#define CPU_X86 +#include <windows.h> +#include <dbghelp.h> +#pragma comment( lib, "dbghelp.lib" ) +/*Since we have inline code in windows, there are + warnings associated with disabling optimization, + ignore them. */ +#pragma warning( disable : 4748) +/*Ignore CRT_SECURE_NO_DEPRECIATE for snprintf */ +#pragma warning( disable : 4996) +#elif defined( _CMAC ) || defined( _CLINUX ) + +#ifdef _CLINUX +#include <malloc.h> +#include <execinfo.h> +#define HAVE_EXECINFO +#endif + + +#ifdef HAVE_LIBIBERTY + +/*Ok, even StepMania had this question!: + This is in libiberty. Where is it declared? */ +#ifdef __cplusplus +extern "C" { +#endif +char *cplus_demangle (const char *mangled, int options); +#ifdef __cplusplus +}; +#endif +#endif + +#if !defined( __USE_GNU ) && !defined( _CMAC ) + +typedef struct +{ + __const char *dli_fname; /* File name of defining object. */ + void *dli_fbase; /* Load address of that object. */ + __const char *dli_sname; /* Name of nearest symbol. */ + void *dli_saddr; /* Exact value of nearest symbol. */ +} Dl_info; + +extern int dladdr (__const void *__address, Dl_info *__info); +extern void *dlopen (__const char *__file, int __mode); +extern int dlclose (void *__handle); +extern void *dlsym (void *__restrict __handle, + __const char *__restrict __name); + +#endif + +#include <dlfcn.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +int bUseAddr2Line, DBGSetup = 0; + +#endif + + + + +struct BacktraceContext +{ + int dummy; +#if defined( _CWINDOWS) + CONTEXT context; + HANDLE hThread; + HANDLE hProcess; +#endif +}; + +#include <stdio.h> + +int GetBacktrace( void **buf, unsigned size, struct BacktraceContext *ctx ); +int GetBTName( const void * ptr, char * str, int maxlen, struct BacktraceContext * ctx ); +void SetupDBGHelp(); + + +int cnget_backtrace( int SkipFirst, char * buffer, int max_size ) +{ + char * tmpbuf = buffer; + + void * buf[256]; + int i = 0; + SetupDBGHelp(); + GetBacktrace( (void **)buf, 256, 0 ); + + for( ; i < SkipFirst; i++ ) + if( buf[i] == 0 ) + return 0; + + while( buf[i] != 0 ) + { + int space_left = max_size-(int)(tmpbuf-buffer)-2; + tmpbuf+=GetBTName( buf[i], tmpbuf, space_left, 0 ); + *tmpbuf='\n'; + tmpbuf++; + *tmpbuf='\0'; + i++; + } + + return i-1; +} + + + + + + + +#if defined( _CMAC ) || defined( _CLINUX ) +//Based off of http://stackoverflow.com/questions/289820/getting-the-current-stack-trace-on-mac-os-x + +int GetBacktrace( void **buffer, unsigned size, struct BacktraceContext *ctx ) +{ +#ifdef HAVE_EXECINFO + return backtrace( buffer, size ); +#else + //Todo: See if the return is beyond the end of a function. + + void **frame = (void **)__builtin_frame_address(0); + void **bp = ( void **)(*frame); + void *ip = frame[1]; + int i; + + for ( i = 0; bp && ip && i < size; i++ ) + { + *(buffer++) = ip; + ip = bp[1]; + bp = (void**)(bp[0]); + } + + return i; +#endif +} + +int Demangle( char * out, int maxlen, const char * in ) +{ + *out = 0; + if( !in ) + return 0; +#ifdef HAVE_LIBIBERTY + int pos = 0; + char * demangled = cplus_demangle( in, 0 ); + if( !demangled ) + return 0; + while( demangled[pos] != 0 && pos + 1 < maxlen ) + { + out[pos] = demangled[pos]; + pos++; + } + out[pos] = 0; + free( demangled ); + return pos; +#else + return 0; +#endif +} + + +int Addr2Line( char * out, char * demangled, int maxlen, const char * file, const void * offset ) +{ + int tmp; + char execline[1024]; + char buffer[1024]; + int fds[2]; + int readbytes; + int newlinepos; + int slashpos; + + *out = 0; + *demangled = 0; + + if( strlen( file ) < 1 ) + return 0; + + tmp = open( file, O_RDONLY ); + if( !tmp ) + return 0; + close( tmp ); + + if( pipe( fds ) != 0 ) + return 0; + +#ifdef _CMAC + sprintf( execline, "atos -o %s 0x%lx 1>&%d", file, (unsigned long)offset, fds[1] ); + printf( "Crash Progress: Executing command: %s\n", execline ); +#else + sprintf( execline, "addr2line -fC -e %s 0x%lx 1>&%d", file, (unsigned long)offset, fds[1] ); +#endif + system( execline ); + + readbytes = read( fds[0], buffer, 1024 ); + if( readbytes + 1 >= maxlen ) + readbytes = maxlen - 1; + close( fds[0] ); + close( fds[1] ); + + //Something went wrong. + if( readbytes < 3 ) + return 0; +#ifdef _CMAC + memcpy( out, buffer, readbytes - 1 ); + out[readbytes] = 0; + return 1; +#else + //??:0 is a bad return value. + if( buffer[0] == '?' ) + return 0; + + if( strstr( buffer, ": No such file" ) > 0 ) + return 0; + + newlinepos = 0; + for( tmp = 0; tmp < readbytes; tmp++ ) + if( buffer[tmp] == '\n' ) break; + newlinepos = tmp; + + if( tmp == readbytes ) + return 0; + + memcpy( demangled, buffer, newlinepos ); + demangled[newlinepos] = 0; + + slashpos = 0; + for( tmp = newlinepos; tmp < readbytes; tmp++ ) + { + if( buffer[tmp] == '/' ) slashpos = tmp; + } + + if( slashpos == 0 ) + slashpos = newlinepos; + slashpos++; + if( slashpos >= readbytes ) + slashpos = 0; + + readbytes -= slashpos; + memcpy( out, buffer + slashpos, readbytes ); + + if( readbytes > 1 ) + out[readbytes-1] = 0; + else + out[readbytes] = 0; + + return readbytes; +#endif + +} + + +int GetBTName( const void * ptr, char * str, int maxlen, struct BacktraceContext * ctx ) +{ + char demangled[1024], floc[1024]; + const char * symbol; + Dl_info dli; + int c = 0; + int useaddr=0; + + c = snprintf(str, maxlen, " [%0*lx]", (int)sizeof(void*)*2, (long unsigned int)ptr ); + + if (dladdr(ptr, &dli)) + { + unsigned offset; + symbol = dli.dli_sname; + + if( dli.dli_fbase && dli.dli_fname ) + { + if( bUseAddr2Line ) + { + unsigned long actualptr = (unsigned long)ptr; + int fnamelen = strlen( dli.dli_fname ); + + //If it's a .so, we need ot check relatively to the start of the .so + //since it was compiled with -fPIC + + if( dli.dli_fname[fnamelen-3] == '.' && + dli.dli_fname[fnamelen-2] == 's' && + dli.dli_fname[fnamelen-1] == 'o' ) + { + actualptr-=(unsigned long)dli.dli_fbase; + } + + if( Addr2Line( floc, demangled, 1024, dli.dli_fname, (void*)actualptr ) ) + { + symbol = demangled; + useaddr=1; + } + } + } + + //If addr2line doesn't work right, we can try using demangle from libiberty + if( !useaddr ) + if( Demangle( demangled, 1024, symbol ) ) + symbol = demangled; + + if( symbol ) + { + offset = ptr - dli.dli_saddr; + c += snprintf(str+c, maxlen-c, " (%s+0x%x (0x%lx))", symbol, offset,(unsigned long)dli.dli_saddr ); + } + if( dli.dli_fbase && dli.dli_fname ) + { + if( useaddr ) + c += snprintf(str+c, maxlen-c, " [%s]", floc ); + else + c += snprintf(str+c, maxlen-c, " [%s+0x%lx]", dli.dli_fname, (unsigned long)dli.dli_fbase ); + } + } + return c; +} + +void SetupDBGHelp() +{ + int fds[2]; + char execline[1024]; + if( DBGSetup ) + return; + DBGSetup = 1; + pipe( fds ); + +#ifdef _CMAC + sprintf( execline, "atos 2>&%d", fds[0] ); +#else + sprintf( execline, "addr2line -v 1>&%d", fds[0] ); +#endif + + if( system( execline ) == 0 ) + bUseAddr2Line = 1; + else + bUseAddr2Line = 0; + close( fds[0] ); + close( fds[1] ); +} + + +#elif defined( _CWINDOWS ) + +int wGetCurrentContext( struct BacktraceContext *CTX ) +{ + CTX->context.ContextFlags = CONTEXT_CONTROL; + CTX->hThread = GetCurrentThread(); + CTX->hProcess = GetCurrentProcess(); +#ifdef CPU_X86 + //no way to do it except in ASM, see below. +#else + if( !RtlCaptureContext( &CTX->context ) ) + { + printf( "Could not launch context helper.\n" ); + return -1; + } +#endif + return 0; +} + +int GetBacktrace( void **buf, size_t size, struct BacktraceContext *CTX ) +{ + const void **pLast = buf + size - 1; + int bFirst = 1; + DWORD MachineType; + CONTEXT * pContext; + HANDLE hThread; + HANDLE hProcess; + struct BacktraceContext MCTX; //in case we don't have a context. + int ActuallyThisThread = 0; + if( CTX == 0 ) + { + if( wGetCurrentContext( &MCTX ) != 0) + return -2; + pContext = &(MCTX.context); + hThread = MCTX.hThread; + hProcess = MCTX.hProcess; + ActuallyThisThread = 1; + } + else + { + pContext = &(CTX->context); + hThread = CTX->hThread; + hProcess = CTX->hProcess; + } + + { + size_t count = 0; + STACKFRAME64 sf64; + +#ifdef CPU_X86 + CONTEXT Context; + MachineType = IMAGE_FILE_MACHINE_I386; + + if( ActuallyThisThread ) + { + ZeroMemory( &Context, sizeof( CONTEXT ) ); + + //http://jpassing.wordpress.com/2008/03/12/walking-the-stack-of-the-current-thread/ + __asm + { + Label: + mov [Context.Ebp], ebp; + mov [Context.Esp], esp; + mov eax, [Label]; + mov [Context.Eip], eax; + } + Context.ContextFlags = CONTEXT_CONTROL; + pContext = &Context; + } + + memset( &sf64, '\0', sizeof sf64 ); + sf64.AddrPC.Offset = Context.Eip; + sf64.AddrPC.Mode = AddrModeFlat; + sf64.AddrFrame.Offset = Context.Ebp; + sf64.AddrFrame.Mode = AddrModeFlat; + sf64.AddrStack.Offset = Context.Esp; + sf64.AddrStack.Segment = AddrModeFlat; +#else + MachineType = IMAGE_FILE_MACHINE_AMD64; + memset( &sf64, '\0', sizeof sf64 ); + sf64.AddrPC.Offset = Context.Rip; + sf64.AddrPC.Mode = AddrModeFlat; + sf64.AddrFrame.Offset = Context.Rsp; + sf64.AddrFrame.Mode = AddrModeFlat; + sf64.AddrStack.Offset = Context.Rsp; + sf64.AddrStack.Segment = AddrModeFlat; +#endif + while( 1 ) + { + int ret; + SetLastError( 0 ); + ret = StackWalk64( MachineType, hProcess, hThread, &sf64, pContext, 0, + SymFunctionTableAccess64, SymGetModuleBase64, 0 ); + + if( !ret ) + { + break; + } + + if( sf64.AddrPC.Offset != 0) + *buf = (void*)sf64.AddrPC.Offset; + else + *buf = (void*)-1; + buf++; + count++; + if( count + 1 >= size ) break; + } + } + SetLastError( 0 ); + *buf = 0; + + return 0; +} + +int GetBTName( const void * ptr, char * str, int maxlen, struct BacktraceContext * ctx ) +{ + char lsymbol[1024], lfile[1024]; + IMAGEHLP_LINE64 Line; + PSYMBOL_INFO Symbol; + HANDLE hProcess; + int i, pwd = 0; + + Symbol = malloc( sizeof( SYMBOL_INFO ) + 501 ); + Line.SizeOfStruct = sizeof( IMAGEHLP_LINE64 ); + + Symbol->MaxNameLen = 500; + + if( ctx ) + hProcess = ctx->hProcess; + else + hProcess = GetCurrentProcess(); + + i = SymFromAddr( hProcess, (DWORD64)ptr, 0, Symbol ); + if( !i ) + { + return _snprintf( str, maxlen, "%p (unknown)", ptr ); + } + i = SymGetLineFromAddr64( hProcess, (DWORD64)ptr, &pwd, &Line ); + + if( i == 0) + { + Line.FileName = 0; + Line.LineNumber = 0; + } + + for( i = 0; i < 1023; i++ ) + { + TCHAR c = Symbol->Name[i]; + lsymbol[i] = (char)c; + if( c < 28 ) break; + } + lsymbol[i] = 0; + + if( Line.FileName ) + { + for( i = 0; i < 1023; i++ ) + { + TCHAR c = Line.FileName[i]; + lfile[i] = (char)c; + if( c < 28 ) break; + } + lfile[i] = 0; + } + + if( Line.FileName ) + return _snprintf( str, maxlen, "%p %s (%s:%d)", ptr, lsymbol, lfile, Line.LineNumber ); + else + return _snprintf( str, maxlen, "%p %s", ptr, lsymbol ); +} + +//Base off of example from http://www.debuginfo.com/example + +void SetupDBGHelp() +{ + int bRet = 0; + static int already_set_up = 0; + DWORD Options; + + if (already_set_up) return; + already_set_up = 1; + + Options = SymGetOptions(); + Options |= SYMOPT_DEBUG; + Options |= SYMOPT_LOAD_LINES; + SymSetOptions( Options ); + + bRet = SymInitialize ( + GetCurrentProcess(), // Process handle of the current process + NULL, // No user-defined search path -> use default + TRUE // Load symbols for all modules in the current process + ); + + if( !bRet ) + { + printf("Error: SymInitialize() failed. Error code: %u \n", GetLastError()); + return; + } + + { + TCHAR pFileName[2048]; + + DWORD64 ModBase; + DWORD64 BaseAddr = 0x10000000; + DWORD FileSize = 0; + + GetModuleFileName( 0, pFileName, 2048 ); + + if( !GetFileSize( pFileName, &FileSize ) ) + return; + + ModBase = SymLoadModule64 ( + GetCurrentProcess(), + NULL, + (PSTR)pFileName, + NULL, + BaseAddr, + FileSize + ); + + if( ModBase == 0 ) + { + printf( "Error: SymLoadModule64() failed. Error code: %u \n" , GetLastError()); + return; + } + } + + + return; +} + +#else +#error Neither _CWINDOWS, _CMAC OR _CLINUX are defined! +#endif + + +/* + * (c) 2003-2008 Glenn Maynard, Steve Checkoway, Avery Lee, Charles Lohr + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ Added: Mercury2/src/MercuryBacktrace.h =================================================================== --- Mercury2/src/MercuryBacktrace.h (rev 0) +++ Mercury2/src/MercuryBacktrace.h 2008-12-30 22:10:30 UTC (rev 113) @@ -0,0 +1,39 @@ +#ifndef _HGBACKTRACE_H +#define _HGBACKTRACE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int cnget_backtrace( int SkipFirst, char * buffer, int max_size ); + +#ifdef __cplusplus +}; +#endif + +#endif + +/* + * (c) 2003-2008 Glenn Maynard, Steve Checkoway, Avery Lee, Charles Lohr + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ Added: Mercury2/src/MercuryCrash.c =================================================================== --- Mercury2/src/MercuryCrash.c (rev 0) +++ Mercury2/src/MercuryCrash.c 2008-12-30 22:10:30 UTC (rev 113) @@ -0,0 +1,214 @@ +#include "MercuryCrash.h" +#include <stdlib.h> +#include <stdio.h> + +#ifdef WIN32 +#define _CWINDOWS +#else +#if defined( MACOSX ) || defined( __APPLE__ ) +#define _CMAC +#else +#define _CLINUX +#endif +#endif + + + +#if defined( _CLINUX ) || defined( _CMAC ) + +#ifdef _CLINUX + +#ifndef __USE_POSIX +#define __USE_POSIX +#include <signal.h> +#undef__USE_POSIX +#else +#include <signal.h> +#endif + +#include <bits/siginfo.h> + +#else + +#include <signal.h> + +#endif + +int inCrashHandler = 0; + +static int msignals[] = +{ + SIGALRM, SIGBUS, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGABRT, + SIGQUIT, SIGSEGV, SIGTRAP, SIGTERM, SIGVTALRM, SIGXCPU, SIGXFSZ, +#if defined(HAVE_DECL_SIGPWR) && HAVE_DECL_SIGPWR + SIGPWR, +#endif +#if defined(HAVE_DECL_SIGUSR1) && HAVE_DECL_SIGUSR1 + SIGUSR1, +#endif + -1 +}; + +static const struct ExceptionLookup { + int code; + const char *name; +} exceptions[]={ + { SIGALRM, "SIGALRM" }, + { SIGBUS, "SIGBUS" }, + { SIGFPE, "SIGFPE" }, + { SIGINT, "SIGINT" }, + { SIGABRT, "SIGABRT" }, + { SIGQUIT, "SIGQUIT" }, + { SIGSEGV, "Segmentation Fault", }, + { SIGTRAP, "SIGTRAP", }, + { SIGTERM, "SIGTERM", }, + { SIGXCPU, "SIGXCPU", }, + { SIGXFSZ, "SIGXFSZ", }, + { 0, "Unknown Exception", }, + { 0 }, +}; + +FNType chHandler; + +static void SigHandler( int signal, siginfo_t *si, void *ucp ) +{ + if( inCrashHandler ) + exit( -1 ); + + inCrashHandler = 1; + + if( chHandler( signal ) == 0x12121212 ) + return; + + inCrashHandler = 0; + if( signal == SIGINT || signal == SIGQUIT ) + { + printf( "Ctrl+Break Hit, Exit.\n" ); + exit( 1 ); + return; + } + + if( signal == SIGTERM || signal == SIGHUP ) + return; + + struct sigaction sa; + sa.sa_flags = 0; + sigemptyset( &sa.sa_mask ); + sa.sa_handler = SIG_DFL; + + struct sigaction old; + sigaction( signal, &sa, &old ); + raise( signal ); + sigaction( signal, &old, NULL ); +} + + +int cnset_execute_on_crash( FNType fn ) +{ + int i; + struct sigaction sa; + chHandler = fn; + + sa.sa_flags = 0; + sa.sa_flags |= SA_NODEFER; + sa.sa_flags |= SA_SIGINFO; + sigemptyset(&sa.sa_mask); + + // Set up our signal handlers. + sa.sa_sigaction = SigHandler; + for( i = 0; msignals[i] != -1; ++i ) + sigaction( msignals[i], &sa, NULL ); + + // Block SIGPIPE, so we get EPIPE. + sa.sa_handler = SIG_IGN; + sigaction( SIGPIPE, &sa, NULL ); + return 0; +} + +#elif defined( _CWINDOWS ) +#include <windows.h> + +FNType top; + +long __stdcall cnException( + struct _EXCEPTION_POINTERS * filter) +{ + int ret = 0; + ret = top( filter->ExceptionRecord->ExceptionCode ); + if( ret == 0x12121212 ) + return EXCEPTION_CONTINUE_EXECUTION; + else + return EXCEPTION_EXECUTE_HANDLER; +} + +int cnset_execute_on_crash( FNType fn ) +{ + top = fn; + SetUnhandledExceptionFilter(cnException); + return 0; +} + +static const struct ExceptionLookup { + DWORD code; + const char *name; +} exceptions[]={ + { EXCEPTION_ACCESS_VIOLATION, "Access Violation" }, + { EXCEPTION_BREAKPOINT, "Breakpoint" }, + { EXCEPTION_FLT_DENORMAL_OPERAND, "FP Denormal Operand" }, + { EXCEPTION_FLT_DIVIDE_BY_ZERO, "FP Divide-by-Zero" }, + { EXCEPTION_FLT_INEXACT_RESULT, "FP Inexact Result" }, + { EXCEPTION_FLT_INVALID_OPERATION, "FP Invalid Operation" }, + { EXCEPTION_FLT_OVERFLOW, "FP Overflow", }, + { EXCEPTION_FLT_STACK_CHECK, "FP Stack Check", }, + { EXCEPTION_FLT_UNDERFLOW, "FP Underflow", }, + { EXCEPTION_INT_DIVIDE_BY_ZERO, "Integer Divide-by-Zero", }, + { EXCEPTION_INT_OVERFLOW, "Integer Overflow", }, + { EXCEPTION_PRIV_INSTRUCTION, "Privileged Instruction", }, + { EXCEPTION_ILLEGAL_INSTRUCTION, "Illegal instruction" }, + { EXCEPTION_INVALID_HANDLE, "Invalid handle" }, + { EXCEPTION_STACK_OVERFLOW, "Stack overflow" }, + { 0xe06d7363, "Unhandled Microsoft C++ Exception", }, + { 0, "UNKNOWN EXCEPTION", }, + { 0 }, +}; + + +#endif + + +const char * cn_get_crash_description( int code ) +{ + int i; + + for( i = 0; exceptions[i].code; ++i ) + if( exceptions[i].code == code ) + return exceptions[i].name; + + return exceptions[i].name; +} + + +/* + * (c) 2003-2008 Glenn Maynard, Steve Checkoway, Avery Lee, Charles Lohr + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ Added: Mercury2/src/MercuryCrash.h =================================================================== --- Mercury2/src/MercuryCrash.h (rev 0) +++ Mercury2/src/MercuryCrash.h 2008-12-30 22:10:30 UTC (rev 113) @@ -0,0 +1,44 @@ +#ifndef _HGCRASH_H +#define _HGCRASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +//If you return 0x12121212, it will attempt not to crash. Otherwise, it will just do whatever it feels it should. +typedef int (*FNType)( int signal ); + +int cnset_execute_on_crash( FNType fn ); +const char * cn_get_crash_description( int code ); + +#ifdef __cplusplus +}; +#endif + +#endif + + +/* + * (c) 2003-2008 Glenn Maynard, Steve Checkoway, Avery Lee, Charles Lohr + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |