blob: 8b3af0970c1a55c39362a55ea6428fec3f4ffbb8 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
/* system headers */
#include "system.h"
#include <tchar.h>
#include "file_url.h"
#include "path_helper.hxx"
#include <osl/diagnose.h>
#include <osl/mutex.h>
#include <osl/signal.h>
#ifndef __MINGW32__
#include <DbgHelp.h>
#endif
#include <ErrorRep.h>
#include <systools/win32/uwinapi.h>
#include <eh.h>
#include <stdexcept>
typedef struct _oslSignalHandlerImpl
{
oslSignalHandlerFunction Handler;
void* pData;
struct _oslSignalHandlerImpl* pNext;
} oslSignalHandlerImpl;
static sal_Bool bErrorReportingEnabled = sal_True;
static sal_Bool bInitSignal = sal_False;
static oslMutex SignalListMutex;
static oslSignalHandlerImpl* SignalList;
static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP);
static sal_Bool InitSignal(void)
{
HMODULE hFaultRep;
SignalListMutex = osl_createMutex();
SetUnhandledExceptionFilter(SignalHandlerFunction);
hFaultRep = LoadLibrary( "faultrep.dll" );
if ( hFaultRep )
{
#ifdef __MINGW32__
typedef BOOL (WINAPI *pfn_ADDEREXCLUDEDAPPLICATIONW)(LPCWSTR);
#endif
pfn_ADDEREXCLUDEDAPPLICATIONW pfn = (pfn_ADDEREXCLUDEDAPPLICATIONW)GetProcAddress( hFaultRep, "AddERExcludedApplicationW" );
if ( pfn )
pfn( L"SOFFICE.EXE" );
FreeLibrary( hFaultRep );
}
return sal_True;
}
static sal_Bool DeInitSignal(void)
{
SetUnhandledExceptionFilter(NULL);
osl_destroyMutex(SignalListMutex);
return sal_False;
}
static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
{
oslSignalHandlerImpl* pHandler = SignalList;
oslSignalAction Action = osl_Signal_ActCallNextHdl;
while (pHandler != NULL)
{
if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl)
break;
pHandler = pHandler->pNext;
}
return Action;
}
/*****************************************************************************/
/* SignalHandlerFunction */
/*****************************************************************************/
#define REPORTENV_PARAM "-crashreportenv:"
#define REPORTENV_PARAM2 "/crashreportenv:"
static BOOL ReportCrash( LPEXCEPTION_POINTERS lpEP )
{
BOOL fSuccess = FALSE;
BOOL fAutoReport = FALSE;
TCHAR szBuffer[1024];
::osl::LongPathBuffer< sal_Char > aPath( MAX_LONG_PATH );
LPTSTR lpFilePart;
PROCESS_INFORMATION ProcessInfo;
STARTUPINFO StartupInfo;
int argi;
if ( !bErrorReportingEnabled )
return FALSE;
/* Check if crash reporter was disabled by command line */
for ( argi = 1; argi < __argc; argi++ )
{
if (
0 == stricmp( __argv[argi], "-nocrashreport" ) ||
0 == stricmp( __argv[argi], "/nocrashreport" )
)
return FALSE;
else if (
0 == stricmp( __argv[argi], "-autocrashreport" ) ||
0 == stricmp( __argv[argi], "/autocrashreport" )
)
fAutoReport = TRUE;
else if (
0 == strnicmp( __argv[argi], REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) ||
0 == strnicmp( __argv[argi], REPORTENV_PARAM2, strlen(REPORTENV_PARAM2) )
)
{
const char *envparam = __argv[argi] + strlen(REPORTENV_PARAM);
const char *delim = strchr(envparam, '=' );
if ( delim )
{
CHAR *lpVariable;
CHAR *lpValue;
const char *variable = envparam;
size_t variable_len = delim - envparam;
const char *value = delim + 1;
size_t value_len = strlen(envparam) - variable_len - 1;
if ( '\"' == *value )
{
const char *quote;
value++;
value_len--;
quote = strchr( value, '\"' );
if ( quote )
value_len = quote - value;
}
lpVariable = reinterpret_cast< CHAR* >( _alloca( variable_len + 1 ) );
memcpy( lpVariable, variable, variable_len );
lpVariable[variable_len] = 0;
lpValue = reinterpret_cast< CHAR* >( _alloca( value_len + 1) );
memcpy( lpValue, value, value_len );
lpValue[value_len] = 0;
SetEnvironmentVariable( lpVariable, lpValue );
}
}
}
if ( SearchPath( NULL, TEXT( "crashrep.exe" ), NULL, aPath.getBufSizeInSymbols(), aPath, &lpFilePart ) )
{
ZeroMemory( &StartupInfo, sizeof(StartupInfo) );
StartupInfo.cb = sizeof(StartupInfo.cb);
sntprintf( szBuffer, elementsof(szBuffer),
_T("%s -p %u -excp 0x%p -t %u%s"),
static_cast<sal_Char*>( aPath ),
GetCurrentProcessId(),
lpEP,
GetCurrentThreadId(),
fAutoReport ? _T(" -noui -send") : _T(" -noui") );
if (
CreateProcess(
NULL,
szBuffer,
NULL,
NULL,
FALSE,
#ifdef UNICODE
CREATE_UNICODE_ENVIRONMENT,
#else
0,
#endif
NULL, NULL, &StartupInfo, &ProcessInfo )
)
{
DWORD dwExitCode;
WaitForSingleObject( ProcessInfo.hProcess, INFINITE );
if ( GetExitCodeProcess( ProcessInfo.hProcess, &dwExitCode ) && 0 == dwExitCode )
fSuccess = TRUE;
}
}
return fSuccess;
}
/*****************************************************************************/
/* SignalHandlerFunction */
/*****************************************************************************/
static BOOL WINAPI IsWin95A(void)
{
OSVERSIONINFO ovi;
ZeroMemory( &ovi, sizeof(ovi) );
ovi.dwOSVersionInfoSize = sizeof(ovi);
if ( GetVersionEx( &ovi ) )
/* See MSDN January 2000 documentation of GetVersionEx */
return (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
(ovi.dwMajorVersion <= 4) &&
(ovi.dwMinorVersion == 0) &&
(ovi.dwBuildNumber == 0x040003B6);
/* Something wrent wrong. So assume we have an older operating prior Win95 */
return TRUE;
}
/* magic Microsoft C++ compiler exception constant */
#define EXCEPTION_MSC_CPP_EXCEPTION 0xe06d7363
static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP)
{
static sal_Bool bNested = sal_False;
sal_Bool bRaiseCrashReporter = sal_False;
oslSignalInfo Info;
oslSignalAction Action;
Info.UserSignal = lpEP->ExceptionRecord->ExceptionCode;
Info.UserData = NULL;
switch (lpEP->ExceptionRecord->ExceptionCode)
{
/* Transform unhandled exceptions into access violations.
Microsoft C++ compiler (add more for other compilers if necessary).
*/
case EXCEPTION_MSC_CPP_EXCEPTION:
case EXCEPTION_ACCESS_VIOLATION:
Info.Signal = osl_Signal_AccessViolation;
bRaiseCrashReporter = sal_True;
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
Info.Signal = osl_Signal_IntegerDivideByZero;
bRaiseCrashReporter = sal_True;
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
Info.Signal = osl_Signal_FloatDivideByZero;
bRaiseCrashReporter = sal_True;
break;
case EXCEPTION_BREAKPOINT:
Info.Signal = osl_Signal_DebugBreak;
break;
default:
Info.Signal = osl_Signal_System;
bRaiseCrashReporter = sal_True;
break;
}
if ( !bNested )
{
bNested = sal_True;
if ( bRaiseCrashReporter && ReportCrash( lpEP ) || IsWin95A() )
{
CallSignalHandler(&Info);
Action = osl_Signal_ActKillApp;
}
else
Action = CallSignalHandler(&Info);
}
else
Action = osl_Signal_ActKillApp;
switch ( Action )
{
case osl_Signal_ActCallNextHdl:
return (EXCEPTION_CONTINUE_SEARCH);
case osl_Signal_ActAbortApp:
return (EXCEPTION_EXECUTE_HANDLER);
case osl_Signal_ActKillApp:
SetErrorMode(SEM_NOGPFAULTERRORBOX);
exit(255);
break;
default:
break;
}
return (EXCEPTION_CONTINUE_EXECUTION);
}
/*****************************************************************************/
/* osl_addSignalHandler */
/*****************************************************************************/
oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
{
oslSignalHandlerImpl* pHandler;
OSL_ASSERT(Handler != NULL);
if (! bInitSignal)
bInitSignal = InitSignal();
pHandler = reinterpret_cast< oslSignalHandlerImpl* >( calloc( 1, sizeof(oslSignalHandlerImpl) ) );
if (pHandler != NULL)
{
pHandler->Handler = Handler;
pHandler->pData = pData;
osl_acquireMutex(SignalListMutex);
pHandler->pNext = SignalList;
SignalList = pHandler;
osl_releaseMutex(SignalListMutex);
return (pHandler);
}
return (NULL);
}
/*****************************************************************************/
/* osl_removeSignalHandler */
/*****************************************************************************/
sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
{
oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
OSL_ASSERT(Handler != NULL);
if (! bInitSignal)
bInitSignal = InitSignal();
osl_acquireMutex(SignalListMutex);
pHandler = SignalList;
while (pHandler != NULL)
{
if (pHandler == Handler)
{
if (pPrevious)
pPrevious->pNext = pHandler->pNext;
else
SignalList = pHandler->pNext;
osl_releaseMutex(SignalListMutex);
if (SignalList == NULL)
bInitSignal = DeInitSignal();
free(pHandler);
return (sal_True);
}
pPrevious = pHandler;
pHandler = pHandler->pNext;
}
osl_releaseMutex(SignalListMutex);
return (sal_False);
}
/*****************************************************************************/
/* osl_raiseSignal */
/*****************************************************************************/
oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
{
oslSignalInfo Info;
oslSignalAction Action;
if (! bInitSignal)
bInitSignal = InitSignal();
osl_acquireMutex(SignalListMutex);
Info.Signal = osl_Signal_User;
Info.UserSignal = UserSignal;
Info.UserData = UserData;
Action = CallSignalHandler(&Info);
osl_releaseMutex(SignalListMutex);
return (Action);
}
/*****************************************************************************/
/* osl_setErrorReporting */
/*****************************************************************************/
void win_seh_translator( unsigned nSEHCode, _EXCEPTION_POINTERS* pExcPtrs)
{
(void*)pExcPtrs; // currently unused, but useful inside a debugger
const char* pSEHName = NULL;
switch( nSEHCode)
{
case EXCEPTION_ACCESS_VIOLATION: pSEHName = "SEH Exception: ACCESS VIOLATION"; break;
case EXCEPTION_DATATYPE_MISALIGNMENT: pSEHName = "SEH Exception: DATATYPE MISALIGNMENT"; break;
case EXCEPTION_BREAKPOINT: /*pSEHName = "SEH Exception: BREAKPOINT";*/ break;
case EXCEPTION_SINGLE_STEP: /*pSEHName = "SEH Exception: SINGLE STEP";*/ break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: pSEHName = "SEH Exception: ARRAY BOUNDS EXCEEDED"; break;
case EXCEPTION_FLT_DENORMAL_OPERAND: pSEHName = "SEH Exception: DENORMAL FLOAT OPERAND"; break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO: pSEHName = "SEH Exception: FLOAT DIVIDE_BY_ZERO"; break;
case EXCEPTION_FLT_INEXACT_RESULT: pSEHName = "SEH Exception: FLOAT INEXACT RESULT"; break;
case EXCEPTION_FLT_INVALID_OPERATION: pSEHName = "SEH Exception: INVALID FLOAT OPERATION"; break;
case EXCEPTION_FLT_OVERFLOW: pSEHName = "SEH Exception: FLOAT OVERFLOW"; break;
case EXCEPTION_FLT_STACK_CHECK: pSEHName = "SEH Exception: FLOAT STACK_CHECK"; break;
case EXCEPTION_FLT_UNDERFLOW: pSEHName = "SEH Exception: FLOAT UNDERFLOW"; break;
case EXCEPTION_INT_DIVIDE_BY_ZERO: pSEHName = "SEH Exception: INTEGER DIVIDE_BY_ZERO"; break;
case EXCEPTION_INT_OVERFLOW: pSEHName = "SEH Exception: INTEGER OVERFLOW"; break;
case EXCEPTION_PRIV_INSTRUCTION: pSEHName = "SEH Exception: PRIVILEDGED INSTRUCTION"; break;
case EXCEPTION_IN_PAGE_ERROR: pSEHName = "SEH Exception: IN_PAGE_ERROR"; break;
case EXCEPTION_ILLEGAL_INSTRUCTION: pSEHName = "SEH Exception: ILLEGAL INSTRUCTION"; break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION: pSEHName = "SEH Exception: NONCONTINUABLE EXCEPTION"; break;
case EXCEPTION_STACK_OVERFLOW: pSEHName = "SEH Exception: STACK OVERFLOW"; break;
case EXCEPTION_INVALID_DISPOSITION: pSEHName = "SEH Exception: INVALID DISPOSITION"; break;
case EXCEPTION_GUARD_PAGE: pSEHName = "SEH Exception: GUARD PAGE"; break;
case EXCEPTION_INVALID_HANDLE: pSEHName = "SEH Exception: INVALID HANDLE"; break;
// case EXCEPTION_POSSIBLE_DEADLOCK: pSEHName = "SEH Exception: POSSIBLE DEADLOCK"; break;
default: pSEHName = "Unknown SEH Exception"; break;
}
if( pSEHName)
throw std::runtime_error( pSEHName);
}
sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
{
sal_Bool bOld = bErrorReportingEnabled;
bErrorReportingEnabled = bEnable;
if( !bEnable) // if the crash reporter is disabled
{
// fall back to handle Window's SEH events as C++ exceptions
_set_se_translator( win_seh_translator);
}
return bOld;
}