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