1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 /* system headers */ 25 #include "system.h" 26 #include <tchar.h> 27 28 #include "file_url.h" 29 #include "path_helper.hxx" 30 31 #include <osl/diagnose.h> 32 #include <osl/mutex.h> 33 #include <osl/signal.h> 34 #ifndef __MINGW32__ 35 #include <DbgHelp.h> 36 #endif 37 #include <ErrorRep.h> 38 #include <systools/win32/uwinapi.h> 39 #include <eh.h> 40 #include <stdexcept> 41 42 typedef struct _oslSignalHandlerImpl 43 { 44 oslSignalHandlerFunction Handler; 45 void* pData; 46 struct _oslSignalHandlerImpl* pNext; 47 } oslSignalHandlerImpl; 48 49 static sal_Bool bErrorReportingEnabled = sal_True; 50 static sal_Bool bInitSignal = sal_False; 51 static oslMutex SignalListMutex; 52 static oslSignalHandlerImpl* SignalList; 53 54 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP); 55 56 static sal_Bool InitSignal(void) 57 { 58 HMODULE hFaultRep; 59 60 SignalListMutex = osl_createMutex(); 61 62 SetUnhandledExceptionFilter(SignalHandlerFunction); 63 64 hFaultRep = LoadLibrary( "faultrep.dll" ); 65 if ( hFaultRep ) 66 { 67 #ifdef __MINGW32__ 68 typedef BOOL (WINAPI *pfn_ADDEREXCLUDEDAPPLICATIONW)(LPCWSTR); 69 #endif 70 pfn_ADDEREXCLUDEDAPPLICATIONW pfn = (pfn_ADDEREXCLUDEDAPPLICATIONW)GetProcAddress( hFaultRep, "AddERExcludedApplicationW" ); 71 if ( pfn ) 72 pfn( L"SOFFICE.EXE" ); 73 FreeLibrary( hFaultRep ); 74 } 75 76 return sal_True; 77 } 78 79 static sal_Bool DeInitSignal(void) 80 { 81 SetUnhandledExceptionFilter(NULL); 82 83 osl_destroyMutex(SignalListMutex); 84 85 return sal_False; 86 } 87 88 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) 89 { 90 oslSignalHandlerImpl* pHandler = SignalList; 91 oslSignalAction Action = osl_Signal_ActCallNextHdl; 92 93 while (pHandler != NULL) 94 { 95 if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl) 96 break; 97 98 pHandler = pHandler->pNext; 99 } 100 101 return Action; 102 } 103 104 /*****************************************************************************/ 105 /* SignalHandlerFunction */ 106 /*****************************************************************************/ 107 108 #define REPORTENV_PARAM "-crashreportenv:" 109 #define REPORTENV_PARAM2 "/crashreportenv:" 110 111 static BOOL ReportCrash( LPEXCEPTION_POINTERS lpEP ) 112 { 113 BOOL fSuccess = FALSE; 114 BOOL fAutoReport = FALSE; 115 TCHAR szBuffer[1024]; 116 ::osl::LongPathBuffer< sal_Char > aPath( MAX_LONG_PATH ); 117 LPTSTR lpFilePart; 118 PROCESS_INFORMATION ProcessInfo; 119 STARTUPINFO StartupInfo; 120 int argi; 121 122 if ( !bErrorReportingEnabled ) 123 return FALSE; 124 125 /* Check if crash reporter was disabled by command line */ 126 127 for ( argi = 1; argi < __argc; argi++ ) 128 { 129 if ( 130 0 == stricmp( __argv[argi], "-nocrashreport" ) || 131 0 == stricmp( __argv[argi], "/nocrashreport" ) 132 ) 133 return FALSE; 134 else if ( 135 0 == stricmp( __argv[argi], "-autocrashreport" ) || 136 0 == stricmp( __argv[argi], "/autocrashreport" ) 137 ) 138 fAutoReport = TRUE; 139 else if ( 140 0 == strnicmp( __argv[argi], REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) || 141 0 == strnicmp( __argv[argi], REPORTENV_PARAM2, strlen(REPORTENV_PARAM2) ) 142 ) 143 { 144 const char *envparam = __argv[argi] + strlen(REPORTENV_PARAM); 145 const char *delim = strchr(envparam, '=' ); 146 147 if ( delim ) 148 { 149 CHAR *lpVariable; 150 CHAR *lpValue; 151 const char *variable = envparam; 152 size_t variable_len = delim - envparam; 153 const char *value = delim + 1; 154 size_t value_len = strlen(envparam) - variable_len - 1; 155 156 if ( '\"' == *value ) 157 { 158 const char *quote; 159 160 value++; 161 value_len--; 162 163 quote = strchr( value, '\"' ); 164 if ( quote ) 165 value_len = quote - value; 166 } 167 168 lpVariable = reinterpret_cast< CHAR* >( _alloca( variable_len + 1 ) ); 169 memcpy( lpVariable, variable, variable_len ); 170 lpVariable[variable_len] = 0; 171 172 lpValue = reinterpret_cast< CHAR* >( _alloca( value_len + 1) ); 173 memcpy( lpValue, value, value_len ); 174 lpValue[value_len] = 0; 175 176 SetEnvironmentVariable( lpVariable, lpValue ); 177 } 178 } 179 } 180 181 if ( SearchPath( NULL, TEXT( "crashrep.exe" ), NULL, aPath.getBufSizeInSymbols(), aPath, &lpFilePart ) ) 182 { 183 ZeroMemory( &StartupInfo, sizeof(StartupInfo) ); 184 StartupInfo.cb = sizeof(StartupInfo.cb); 185 186 187 sntprintf( szBuffer, elementsof(szBuffer), 188 _T("%s -p %u -excp 0x%p -t %u%s"), 189 static_cast<sal_Char*>( aPath ), 190 GetCurrentProcessId(), 191 lpEP, 192 GetCurrentThreadId(), 193 fAutoReport ? _T(" -noui -send") : _T(" -noui") ); 194 195 if ( 196 CreateProcess( 197 NULL, 198 szBuffer, 199 NULL, 200 NULL, 201 FALSE, 202 #ifdef UNICODE 203 CREATE_UNICODE_ENVIRONMENT, 204 #else 205 0, 206 #endif 207 NULL, NULL, &StartupInfo, &ProcessInfo ) 208 ) 209 { 210 DWORD dwExitCode; 211 212 WaitForSingleObject( ProcessInfo.hProcess, INFINITE ); 213 if ( GetExitCodeProcess( ProcessInfo.hProcess, &dwExitCode ) && 0 == dwExitCode ) 214 215 fSuccess = TRUE; 216 217 } 218 } 219 220 return fSuccess; 221 } 222 223 /*****************************************************************************/ 224 /* SignalHandlerFunction */ 225 /*****************************************************************************/ 226 227 static BOOL WINAPI IsWin95A(void) 228 { 229 OSVERSIONINFO ovi; 230 231 ZeroMemory( &ovi, sizeof(ovi) ); 232 ovi.dwOSVersionInfoSize = sizeof(ovi); 233 234 if ( GetVersionEx( &ovi ) ) 235 /* See MSDN January 2000 documentation of GetVersionEx */ 236 return (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && 237 (ovi.dwMajorVersion <= 4) && 238 (ovi.dwMinorVersion == 0) && 239 (ovi.dwBuildNumber == 0x040003B6); 240 241 /* Something wrent wrong. So assume we have an older operating prior Win95 */ 242 243 return TRUE; 244 } 245 246 /* magic Microsoft C++ compiler exception constant */ 247 #define EXCEPTION_MSC_CPP_EXCEPTION 0xe06d7363 248 249 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP) 250 { 251 static sal_Bool bNested = sal_False; 252 sal_Bool bRaiseCrashReporter = sal_False; 253 oslSignalInfo Info; 254 oslSignalAction Action; 255 256 Info.UserSignal = lpEP->ExceptionRecord->ExceptionCode; 257 Info.UserData = NULL; 258 259 switch (lpEP->ExceptionRecord->ExceptionCode) 260 { 261 /* Transform unhandled exceptions into access violations. 262 Microsoft C++ compiler (add more for other compilers if necessary). 263 */ 264 case EXCEPTION_MSC_CPP_EXCEPTION: 265 case EXCEPTION_ACCESS_VIOLATION: 266 Info.Signal = osl_Signal_AccessViolation; 267 bRaiseCrashReporter = sal_True; 268 break; 269 270 case EXCEPTION_INT_DIVIDE_BY_ZERO: 271 Info.Signal = osl_Signal_IntegerDivideByZero; 272 bRaiseCrashReporter = sal_True; 273 break; 274 275 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 276 Info.Signal = osl_Signal_FloatDivideByZero; 277 bRaiseCrashReporter = sal_True; 278 break; 279 280 case EXCEPTION_BREAKPOINT: 281 Info.Signal = osl_Signal_DebugBreak; 282 break; 283 284 default: 285 Info.Signal = osl_Signal_System; 286 bRaiseCrashReporter = sal_True; 287 break; 288 } 289 290 if ( !bNested ) 291 { 292 bNested = sal_True; 293 294 if ( bRaiseCrashReporter && ReportCrash( lpEP ) || IsWin95A() ) 295 { 296 CallSignalHandler(&Info); 297 Action = osl_Signal_ActKillApp; 298 } 299 else 300 Action = CallSignalHandler(&Info); 301 } 302 else 303 Action = osl_Signal_ActKillApp; 304 305 306 switch ( Action ) 307 { 308 case osl_Signal_ActCallNextHdl: 309 return (EXCEPTION_CONTINUE_SEARCH); 310 311 case osl_Signal_ActAbortApp: 312 return (EXCEPTION_EXECUTE_HANDLER); 313 314 case osl_Signal_ActKillApp: 315 SetErrorMode(SEM_NOGPFAULTERRORBOX); 316 exit(255); 317 break; 318 default: 319 break; 320 } 321 322 return (EXCEPTION_CONTINUE_EXECUTION); 323 } 324 325 /*****************************************************************************/ 326 /* osl_addSignalHandler */ 327 /*****************************************************************************/ 328 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) 329 { 330 oslSignalHandlerImpl* pHandler; 331 332 OSL_ASSERT(Handler != NULL); 333 334 if (! bInitSignal) 335 bInitSignal = InitSignal(); 336 337 pHandler = reinterpret_cast< oslSignalHandlerImpl* >( calloc( 1, sizeof(oslSignalHandlerImpl) ) ); 338 339 if (pHandler != NULL) 340 { 341 pHandler->Handler = Handler; 342 pHandler->pData = pData; 343 344 osl_acquireMutex(SignalListMutex); 345 346 pHandler->pNext = SignalList; 347 SignalList = pHandler; 348 349 osl_releaseMutex(SignalListMutex); 350 351 return (pHandler); 352 } 353 354 return (NULL); 355 } 356 357 /*****************************************************************************/ 358 /* osl_removeSignalHandler */ 359 /*****************************************************************************/ 360 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) 361 { 362 oslSignalHandlerImpl *pHandler, *pPrevious = NULL; 363 364 OSL_ASSERT(Handler != NULL); 365 366 if (! bInitSignal) 367 bInitSignal = InitSignal(); 368 369 osl_acquireMutex(SignalListMutex); 370 371 pHandler = SignalList; 372 373 while (pHandler != NULL) 374 { 375 if (pHandler == Handler) 376 { 377 if (pPrevious) 378 pPrevious->pNext = pHandler->pNext; 379 else 380 SignalList = pHandler->pNext; 381 382 osl_releaseMutex(SignalListMutex); 383 384 if (SignalList == NULL) 385 bInitSignal = DeInitSignal(); 386 387 free(pHandler); 388 389 return (sal_True); 390 } 391 392 pPrevious = pHandler; 393 pHandler = pHandler->pNext; 394 } 395 396 osl_releaseMutex(SignalListMutex); 397 398 return (sal_False); 399 } 400 401 /*****************************************************************************/ 402 /* osl_raiseSignal */ 403 /*****************************************************************************/ 404 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) 405 { 406 oslSignalInfo Info; 407 oslSignalAction Action; 408 409 if (! bInitSignal) 410 bInitSignal = InitSignal(); 411 412 osl_acquireMutex(SignalListMutex); 413 414 Info.Signal = osl_Signal_User; 415 Info.UserSignal = UserSignal; 416 Info.UserData = UserData; 417 418 Action = CallSignalHandler(&Info); 419 420 osl_releaseMutex(SignalListMutex); 421 422 return (Action); 423 } 424 425 /*****************************************************************************/ 426 /* osl_setErrorReporting */ 427 /*****************************************************************************/ 428 429 void win_seh_translator( unsigned nSEHCode, _EXCEPTION_POINTERS* pExcPtrs) 430 { 431 const char* pSEHName = NULL; 432 switch( nSEHCode) 433 { 434 case EXCEPTION_ACCESS_VIOLATION: pSEHName = "SEH Exception: ACCESS VIOLATION"; break; 435 case EXCEPTION_DATATYPE_MISALIGNMENT: pSEHName = "SEH Exception: DATATYPE MISALIGNMENT"; break; 436 case EXCEPTION_BREAKPOINT: /*pSEHName = "SEH Exception: BREAKPOINT";*/ break; 437 case EXCEPTION_SINGLE_STEP: /*pSEHName = "SEH Exception: SINGLE STEP";*/ break; 438 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: pSEHName = "SEH Exception: ARRAY BOUNDS EXCEEDED"; break; 439 case EXCEPTION_FLT_DENORMAL_OPERAND: pSEHName = "SEH Exception: DENORMAL FLOAT OPERAND"; break; 440 case EXCEPTION_FLT_DIVIDE_BY_ZERO: pSEHName = "SEH Exception: FLOAT DIVIDE_BY_ZERO"; break; 441 case EXCEPTION_FLT_INEXACT_RESULT: pSEHName = "SEH Exception: FLOAT INEXACT RESULT"; break; 442 case EXCEPTION_FLT_INVALID_OPERATION: pSEHName = "SEH Exception: INVALID FLOAT OPERATION"; break; 443 case EXCEPTION_FLT_OVERFLOW: pSEHName = "SEH Exception: FLOAT OVERFLOW"; break; 444 case EXCEPTION_FLT_STACK_CHECK: pSEHName = "SEH Exception: FLOAT STACK_CHECK"; break; 445 case EXCEPTION_FLT_UNDERFLOW: pSEHName = "SEH Exception: FLOAT UNDERFLOW"; break; 446 case EXCEPTION_INT_DIVIDE_BY_ZERO: pSEHName = "SEH Exception: INTEGER DIVIDE_BY_ZERO"; break; 447 case EXCEPTION_INT_OVERFLOW: pSEHName = "SEH Exception: INTEGER OVERFLOW"; break; 448 case EXCEPTION_PRIV_INSTRUCTION: pSEHName = "SEH Exception: PRIVILEDGED INSTRUCTION"; break; 449 case EXCEPTION_IN_PAGE_ERROR: pSEHName = "SEH Exception: IN_PAGE_ERROR"; break; 450 case EXCEPTION_ILLEGAL_INSTRUCTION: pSEHName = "SEH Exception: ILLEGAL INSTRUCTION"; break; 451 case EXCEPTION_NONCONTINUABLE_EXCEPTION: pSEHName = "SEH Exception: NONCONTINUABLE EXCEPTION"; break; 452 case EXCEPTION_STACK_OVERFLOW: pSEHName = "SEH Exception: STACK OVERFLOW"; break; 453 case EXCEPTION_INVALID_DISPOSITION: pSEHName = "SEH Exception: INVALID DISPOSITION"; break; 454 case EXCEPTION_GUARD_PAGE: pSEHName = "SEH Exception: GUARD PAGE"; break; 455 case EXCEPTION_INVALID_HANDLE: pSEHName = "SEH Exception: INVALID HANDLE"; break; 456 // case EXCEPTION_POSSIBLE_DEADLOCK: pSEHName = "SEH Exception: POSSIBLE DEADLOCK"; break; 457 default: pSEHName = "Unknown SEH Exception"; break; 458 } 459 460 if( pSEHName) 461 throw std::runtime_error( pSEHName); 462 } 463 464 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) 465 { 466 sal_Bool bOld = bErrorReportingEnabled; 467 bErrorReportingEnabled = bEnable; 468 469 if( !bEnable) // if the crash reporter is disabled 470 { 471 // fall back to handle Window's SEH events as C++ exceptions 472 _set_se_translator( win_seh_translator); 473 } 474 475 return bOld; 476 } 477