1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 /* system headers */ 29 #include "system.h" 30 #include <tchar.h> 31 32 #include "file_url.h" 33 #include "path_helper.hxx" 34 35 #include <osl/diagnose.h> 36 #include <osl/mutex.h> 37 #include <osl/signal.h> 38 #ifndef __MINGW32__ 39 #include <DbgHelp.h> 40 #endif 41 #include <ErrorRep.h> 42 #include <systools/win32/uwinapi.h> 43 44 typedef struct _oslSignalHandlerImpl 45 { 46 oslSignalHandlerFunction Handler; 47 void* pData; 48 struct _oslSignalHandlerImpl* pNext; 49 } oslSignalHandlerImpl; 50 51 static sal_Bool bErrorReportingEnabled = sal_True; 52 static sal_Bool bInitSignal = sal_False; 53 static oslMutex SignalListMutex; 54 static oslSignalHandlerImpl* SignalList; 55 56 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP); 57 58 static sal_Bool InitSignal(void) 59 { 60 HMODULE hFaultRep; 61 62 SignalListMutex = osl_createMutex(); 63 64 SetUnhandledExceptionFilter(SignalHandlerFunction); 65 66 hFaultRep = LoadLibrary( "faultrep.dll" ); 67 if ( hFaultRep ) 68 { 69 #ifdef __MINGW32__ 70 typedef BOOL (WINAPI *pfn_ADDEREXCLUDEDAPPLICATIONW)(LPCWSTR); 71 #endif 72 pfn_ADDEREXCLUDEDAPPLICATIONW pfn = (pfn_ADDEREXCLUDEDAPPLICATIONW)GetProcAddress( hFaultRep, "AddERExcludedApplicationW" ); 73 if ( pfn ) 74 pfn( L"SOFFICE.EXE" ); 75 FreeLibrary( hFaultRep ); 76 } 77 78 return sal_True; 79 } 80 81 static sal_Bool DeInitSignal(void) 82 { 83 SetUnhandledExceptionFilter(NULL); 84 85 osl_destroyMutex(SignalListMutex); 86 87 return sal_False; 88 } 89 90 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) 91 { 92 oslSignalHandlerImpl* pHandler = SignalList; 93 oslSignalAction Action = osl_Signal_ActCallNextHdl; 94 95 while (pHandler != NULL) 96 { 97 if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl) 98 break; 99 100 pHandler = pHandler->pNext; 101 } 102 103 return Action; 104 } 105 106 /*****************************************************************************/ 107 /* SignalHandlerFunction */ 108 /*****************************************************************************/ 109 110 #define REPORTENV_PARAM "-crashreportenv:" 111 #define REPORTENV_PARAM2 "/crashreportenv:" 112 113 static BOOL ReportCrash( LPEXCEPTION_POINTERS lpEP ) 114 { 115 BOOL fSuccess = FALSE; 116 BOOL fAutoReport = FALSE; 117 TCHAR szBuffer[1024]; 118 ::osl::LongPathBuffer< sal_Char > aPath( MAX_LONG_PATH ); 119 LPTSTR lpFilePart; 120 PROCESS_INFORMATION ProcessInfo; 121 STARTUPINFO StartupInfo; 122 int argi; 123 124 if ( !bErrorReportingEnabled ) 125 return FALSE; 126 127 /* Check if crash reporter was disabled by command line */ 128 129 for ( argi = 1; argi < __argc; argi++ ) 130 { 131 if ( 132 0 == stricmp( __argv[argi], "-nocrashreport" ) || 133 0 == stricmp( __argv[argi], "/nocrashreport" ) 134 ) 135 return FALSE; 136 else if ( 137 0 == stricmp( __argv[argi], "-autocrashreport" ) || 138 0 == stricmp( __argv[argi], "/autocrashreport" ) 139 ) 140 fAutoReport = TRUE; 141 else if ( 142 0 == strnicmp( __argv[argi], REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) || 143 0 == strnicmp( __argv[argi], REPORTENV_PARAM2, strlen(REPORTENV_PARAM2) ) 144 ) 145 { 146 const char *envparam = __argv[argi] + strlen(REPORTENV_PARAM); 147 const char *delim = strchr(envparam, '=' ); 148 149 if ( delim ) 150 { 151 CHAR *lpVariable; 152 CHAR *lpValue; 153 const char *variable = envparam; 154 size_t variable_len = delim - envparam; 155 const char *value = delim + 1; 156 size_t value_len = strlen(envparam) - variable_len - 1; 157 158 if ( '\"' == *value ) 159 { 160 const char *quote; 161 162 value++; 163 value_len--; 164 165 quote = strchr( value, '\"' ); 166 if ( quote ) 167 value_len = quote - value; 168 } 169 170 lpVariable = reinterpret_cast< CHAR* >( _alloca( variable_len + 1 ) ); 171 memcpy( lpVariable, variable, variable_len ); 172 lpVariable[variable_len] = 0; 173 174 lpValue = reinterpret_cast< CHAR* >( _alloca( value_len + 1) ); 175 memcpy( lpValue, value, value_len ); 176 lpValue[value_len] = 0; 177 178 SetEnvironmentVariable( lpVariable, lpValue ); 179 } 180 } 181 } 182 183 if ( SearchPath( NULL, TEXT( "crashrep.exe" ), NULL, aPath.getBufSizeInSymbols(), aPath, &lpFilePart ) ) 184 { 185 ZeroMemory( &StartupInfo, sizeof(StartupInfo) ); 186 StartupInfo.cb = sizeof(StartupInfo.cb); 187 188 189 sntprintf( szBuffer, elementsof(szBuffer), 190 _T("%s -p %u -excp 0x%p -t %u%s"), 191 static_cast<sal_Char*>( aPath ), 192 GetCurrentProcessId(), 193 lpEP, 194 GetCurrentThreadId(), 195 fAutoReport ? _T(" -noui -send") : _T(" -noui") ); 196 197 if ( 198 CreateProcess( 199 NULL, 200 szBuffer, 201 NULL, 202 NULL, 203 FALSE, 204 #ifdef UNICODE 205 CREATE_UNICODE_ENVIRONMENT, 206 #else 207 0, 208 #endif 209 NULL, NULL, &StartupInfo, &ProcessInfo ) 210 ) 211 { 212 DWORD dwExitCode; 213 214 WaitForSingleObject( ProcessInfo.hProcess, INFINITE ); 215 if ( GetExitCodeProcess( ProcessInfo.hProcess, &dwExitCode ) && 0 == dwExitCode ) 216 217 fSuccess = TRUE; 218 219 } 220 } 221 222 return fSuccess; 223 } 224 225 /*****************************************************************************/ 226 /* SignalHandlerFunction */ 227 /*****************************************************************************/ 228 229 static BOOL WINAPI IsWin95A(void) 230 { 231 OSVERSIONINFO ovi; 232 233 ZeroMemory( &ovi, sizeof(ovi) ); 234 ovi.dwOSVersionInfoSize = sizeof(ovi); 235 236 if ( GetVersionEx( &ovi ) ) 237 /* See MSDN January 2000 documentation of GetVersionEx */ 238 return (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && 239 (ovi.dwMajorVersion <= 4) && 240 (ovi.dwMinorVersion == 0) && 241 (ovi.dwBuildNumber == 0x040003B6); 242 243 /* Something wrent wrong. So assume we have an older operating prior Win95 */ 244 245 return TRUE; 246 } 247 248 /* magic Microsoft C++ compiler exception constant */ 249 #define EXCEPTION_MSC_CPP_EXCEPTION 0xe06d7363 250 251 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP) 252 { 253 static sal_Bool bNested = sal_False; 254 sal_Bool bRaiseCrashReporter = sal_False; 255 oslSignalInfo Info; 256 oslSignalAction Action; 257 258 Info.UserSignal = lpEP->ExceptionRecord->ExceptionCode; 259 Info.UserData = NULL; 260 261 switch (lpEP->ExceptionRecord->ExceptionCode) 262 { 263 /* Transform unhandled exceptions into access violations. 264 Microsoft C++ compiler (add more for other compilers if necessary). 265 */ 266 case EXCEPTION_MSC_CPP_EXCEPTION: 267 case EXCEPTION_ACCESS_VIOLATION: 268 Info.Signal = osl_Signal_AccessViolation; 269 bRaiseCrashReporter = sal_True; 270 break; 271 272 case EXCEPTION_INT_DIVIDE_BY_ZERO: 273 Info.Signal = osl_Signal_IntegerDivideByZero; 274 bRaiseCrashReporter = sal_True; 275 break; 276 277 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 278 Info.Signal = osl_Signal_FloatDivideByZero; 279 bRaiseCrashReporter = sal_True; 280 break; 281 282 case EXCEPTION_BREAKPOINT: 283 Info.Signal = osl_Signal_DebugBreak; 284 break; 285 286 default: 287 Info.Signal = osl_Signal_System; 288 bRaiseCrashReporter = sal_True; 289 break; 290 } 291 292 if ( !bNested ) 293 { 294 bNested = sal_True; 295 296 if ( bRaiseCrashReporter && ReportCrash( lpEP ) || IsWin95A() ) 297 { 298 CallSignalHandler(&Info); 299 Action = osl_Signal_ActKillApp; 300 } 301 else 302 Action = CallSignalHandler(&Info); 303 } 304 else 305 Action = osl_Signal_ActKillApp; 306 307 308 switch ( Action ) 309 { 310 case osl_Signal_ActCallNextHdl: 311 return (EXCEPTION_CONTINUE_SEARCH); 312 313 case osl_Signal_ActAbortApp: 314 return (EXCEPTION_EXECUTE_HANDLER); 315 316 case osl_Signal_ActKillApp: 317 SetErrorMode(SEM_NOGPFAULTERRORBOX); 318 exit(255); 319 break; 320 default: 321 break; 322 } 323 324 return (EXCEPTION_CONTINUE_EXECUTION); 325 } 326 327 /*****************************************************************************/ 328 /* osl_addSignalHandler */ 329 /*****************************************************************************/ 330 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) 331 { 332 oslSignalHandlerImpl* pHandler; 333 334 OSL_ASSERT(Handler != NULL); 335 336 if (! bInitSignal) 337 bInitSignal = InitSignal(); 338 339 pHandler = reinterpret_cast< oslSignalHandlerImpl* >( calloc( 1, sizeof(oslSignalHandlerImpl) ) ); 340 341 if (pHandler != NULL) 342 { 343 pHandler->Handler = Handler; 344 pHandler->pData = pData; 345 346 osl_acquireMutex(SignalListMutex); 347 348 pHandler->pNext = SignalList; 349 SignalList = pHandler; 350 351 osl_releaseMutex(SignalListMutex); 352 353 return (pHandler); 354 } 355 356 return (NULL); 357 } 358 359 /*****************************************************************************/ 360 /* osl_removeSignalHandler */ 361 /*****************************************************************************/ 362 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) 363 { 364 oslSignalHandlerImpl *pHandler, *pPrevious = NULL; 365 366 OSL_ASSERT(Handler != NULL); 367 368 if (! bInitSignal) 369 bInitSignal = InitSignal(); 370 371 osl_acquireMutex(SignalListMutex); 372 373 pHandler = SignalList; 374 375 while (pHandler != NULL) 376 { 377 if (pHandler == Handler) 378 { 379 if (pPrevious) 380 pPrevious->pNext = pHandler->pNext; 381 else 382 SignalList = pHandler->pNext; 383 384 osl_releaseMutex(SignalListMutex); 385 386 if (SignalList == NULL) 387 bInitSignal = DeInitSignal(); 388 389 free(pHandler); 390 391 return (sal_True); 392 } 393 394 pPrevious = pHandler; 395 pHandler = pHandler->pNext; 396 } 397 398 osl_releaseMutex(SignalListMutex); 399 400 return (sal_False); 401 } 402 403 /*****************************************************************************/ 404 /* osl_raiseSignal */ 405 /*****************************************************************************/ 406 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) 407 { 408 oslSignalInfo Info; 409 oslSignalAction Action; 410 411 if (! bInitSignal) 412 bInitSignal = InitSignal(); 413 414 osl_acquireMutex(SignalListMutex); 415 416 Info.Signal = osl_Signal_User; 417 Info.UserSignal = UserSignal; 418 Info.UserData = UserData; 419 420 Action = CallSignalHandler(&Info); 421 422 osl_releaseMutex(SignalListMutex); 423 424 return (Action); 425 } 426 427 /*****************************************************************************/ 428 /* osl_setErrorReporting */ 429 /*****************************************************************************/ 430 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) 431 { 432 sal_Bool bOld = bErrorReportingEnabled; 433 bErrorReportingEnabled = bEnable; 434 435 return bOld; 436 } 437