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 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 sal_Bool InitSignal(void) 55 { 56 HMODULE hFaultRep; 57 58 SignalListMutex = osl_createMutex(); 59 60 SetUnhandledExceptionFilter(SignalHandlerFunction); 61 62 hFaultRep = LoadLibrary( "faultrep.dll" ); 63 if ( hFaultRep ) 64 { 65 #ifdef __MINGW32__ 66 typedef BOOL (WINAPI *pfn_ADDEREXCLUDEDAPPLICATIONW)(LPCWSTR); 67 #endif 68 pfn_ADDEREXCLUDEDAPPLICATIONW pfn = (pfn_ADDEREXCLUDEDAPPLICATIONW)GetProcAddress( hFaultRep, "AddERExcludedApplicationW" ); 69 if ( pfn ) 70 pfn( L"SOFFICE.EXE" ); 71 FreeLibrary( hFaultRep ); 72 } 73 74 return sal_True; 75 } 76 77 static sal_Bool DeInitSignal(void) 78 { 79 SetUnhandledExceptionFilter(NULL); 80 81 osl_destroyMutex(SignalListMutex); 82 83 return sal_False; 84 } 85 86 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) 87 { 88 oslSignalHandlerImpl* pHandler = SignalList; 89 oslSignalAction Action = osl_Signal_ActCallNextHdl; 90 91 while (pHandler != NULL) 92 { 93 if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl) 94 break; 95 96 pHandler = pHandler->pNext; 97 } 98 99 return Action; 100 } 101 102 /*****************************************************************************/ 103 /* SignalHandlerFunction */ 104 /*****************************************************************************/ 105 106 #define REPORTENV_PARAM "-crashreportenv:" 107 #define REPORTENV_PARAM2 "/crashreportenv:" 108 109 static BOOL ReportCrash( LPEXCEPTION_POINTERS lpEP ) 110 { 111 BOOL fSuccess = FALSE; 112 BOOL fAutoReport = FALSE; 113 TCHAR szBuffer[1024]; 114 ::osl::LongPathBuffer< sal_Char > aPath( MAX_LONG_PATH ); 115 LPTSTR lpFilePart; 116 PROCESS_INFORMATION ProcessInfo; 117 STARTUPINFO StartupInfo; 118 int argi; 119 120 if ( !bErrorReportingEnabled ) 121 return FALSE; 122 123 /* Check if crash reporter was disabled by command line */ 124 125 for ( argi = 1; argi < __argc; argi++ ) 126 { 127 if ( 128 0 == stricmp( __argv[argi], "-nocrashreport" ) || 129 0 == stricmp( __argv[argi], "/nocrashreport" ) 130 ) 131 return FALSE; 132 else if ( 133 0 == stricmp( __argv[argi], "-autocrashreport" ) || 134 0 == stricmp( __argv[argi], "/autocrashreport" ) 135 ) 136 fAutoReport = TRUE; 137 else if ( 138 0 == strnicmp( __argv[argi], REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) || 139 0 == strnicmp( __argv[argi], REPORTENV_PARAM2, strlen(REPORTENV_PARAM2) ) 140 ) 141 { 142 const char *envparam = __argv[argi] + strlen(REPORTENV_PARAM); 143 const char *delim = strchr(envparam, '=' ); 144 145 if ( delim ) 146 { 147 CHAR *lpVariable; 148 CHAR *lpValue; 149 const char *variable = envparam; 150 size_t variable_len = delim - envparam; 151 const char *value = delim + 1; 152 size_t value_len = strlen(envparam) - variable_len - 1; 153 154 if ( '\"' == *value ) 155 { 156 const char *quote; 157 158 value++; 159 value_len--; 160 161 quote = strchr( value, '\"' ); 162 if ( quote ) 163 value_len = quote - value; 164 } 165 166 lpVariable = reinterpret_cast< CHAR* >( _alloca( variable_len + 1 ) ); 167 memcpy( lpVariable, variable, variable_len ); 168 lpVariable[variable_len] = 0; 169 170 lpValue = reinterpret_cast< CHAR* >( _alloca( value_len + 1) ); 171 memcpy( lpValue, value, value_len ); 172 lpValue[value_len] = 0; 173 174 SetEnvironmentVariable( lpVariable, lpValue ); 175 } 176 } 177 } 178 179 if ( SearchPath( NULL, TEXT( "crashrep.exe" ), NULL, aPath.getBufSizeInSymbols(), aPath, &lpFilePart ) ) 180 { 181 ZeroMemory( &StartupInfo, sizeof(StartupInfo) ); 182 StartupInfo.cb = sizeof(StartupInfo.cb); 183 184 185 sntprintf( szBuffer, elementsof(szBuffer), 186 _T("%s -p %u -excp 0x%p -t %u%s"), 187 static_cast<sal_Char*>( aPath ), 188 GetCurrentProcessId(), 189 lpEP, 190 GetCurrentThreadId(), 191 fAutoReport ? _T(" -noui -send") : _T(" -noui") ); 192 193 if ( 194 CreateProcess( 195 NULL, 196 szBuffer, 197 NULL, 198 NULL, 199 FALSE, 200 #ifdef UNICODE 201 CREATE_UNICODE_ENVIRONMENT, 202 #else 203 0, 204 #endif 205 NULL, NULL, &StartupInfo, &ProcessInfo ) 206 ) 207 { 208 DWORD dwExitCode; 209 210 WaitForSingleObject( ProcessInfo.hProcess, INFINITE ); 211 if ( GetExitCodeProcess( ProcessInfo.hProcess, &dwExitCode ) && 0 == dwExitCode ) 212 213 fSuccess = TRUE; 214 215 } 216 } 217 218 return fSuccess; 219 } 220 221 /*****************************************************************************/ 222 /* SignalHandlerFunction */ 223 /*****************************************************************************/ 224 225 static BOOL WINAPI IsWin95A(void) 226 { 227 OSVERSIONINFO ovi; 228 229 ZeroMemory( &ovi, sizeof(ovi) ); 230 ovi.dwOSVersionInfoSize = sizeof(ovi); 231 232 if ( GetVersionEx( &ovi ) ) 233 /* See MSDN January 2000 documentation of GetVersionEx */ 234 return (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && 235 (ovi.dwMajorVersion <= 4) && 236 (ovi.dwMinorVersion == 0) && 237 (ovi.dwBuildNumber == 0x040003B6); 238 239 /* Something wrent wrong. So assume we have an older operating prior Win95 */ 240 241 return TRUE; 242 } 243 244 /* magic Microsoft C++ compiler exception constant */ 245 #define EXCEPTION_MSC_CPP_EXCEPTION 0xe06d7363 246 247 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP) 248 { 249 static sal_Bool bNested = sal_False; 250 sal_Bool bRaiseCrashReporter = sal_False; 251 oslSignalInfo Info; 252 oslSignalAction Action; 253 254 Info.UserSignal = lpEP->ExceptionRecord->ExceptionCode; 255 Info.UserData = NULL; 256 257 switch (lpEP->ExceptionRecord->ExceptionCode) 258 { 259 /* Transform unhandled exceptions into access violations. 260 Microsoft C++ compiler (add more for other compilers if necessary). 261 */ 262 case EXCEPTION_MSC_CPP_EXCEPTION: 263 case EXCEPTION_ACCESS_VIOLATION: 264 Info.Signal = osl_Signal_AccessViolation; 265 bRaiseCrashReporter = sal_True; 266 break; 267 268 case EXCEPTION_INT_DIVIDE_BY_ZERO: 269 Info.Signal = osl_Signal_IntegerDivideByZero; 270 bRaiseCrashReporter = sal_True; 271 break; 272 273 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 274 Info.Signal = osl_Signal_FloatDivideByZero; 275 bRaiseCrashReporter = sal_True; 276 break; 277 278 case EXCEPTION_BREAKPOINT: 279 Info.Signal = osl_Signal_DebugBreak; 280 break; 281 282 default: 283 Info.Signal = osl_Signal_System; 284 bRaiseCrashReporter = sal_True; 285 break; 286 } 287 288 if ( !bNested ) 289 { 290 bNested = sal_True; 291 292 if ( bRaiseCrashReporter && ReportCrash( lpEP ) || IsWin95A() ) 293 { 294 CallSignalHandler(&Info); 295 Action = osl_Signal_ActKillApp; 296 } 297 else 298 Action = CallSignalHandler(&Info); 299 } 300 else 301 Action = osl_Signal_ActKillApp; 302 303 304 switch ( Action ) 305 { 306 case osl_Signal_ActCallNextHdl: 307 return (EXCEPTION_CONTINUE_SEARCH); 308 309 case osl_Signal_ActAbortApp: 310 return (EXCEPTION_EXECUTE_HANDLER); 311 312 case osl_Signal_ActKillApp: 313 SetErrorMode(SEM_NOGPFAULTERRORBOX); 314 exit(255); 315 break; 316 default: 317 break; 318 } 319 320 return (EXCEPTION_CONTINUE_EXECUTION); 321 } 322 323 /*****************************************************************************/ 324 /* osl_addSignalHandler */ 325 /*****************************************************************************/ 326 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) 327 { 328 oslSignalHandlerImpl* pHandler; 329 330 OSL_ASSERT(Handler != NULL); 331 332 if (! bInitSignal) 333 bInitSignal = InitSignal(); 334 335 pHandler = reinterpret_cast< oslSignalHandlerImpl* >( calloc( 1, sizeof(oslSignalHandlerImpl) ) ); 336 337 if (pHandler != NULL) 338 { 339 pHandler->Handler = Handler; 340 pHandler->pData = pData; 341 342 osl_acquireMutex(SignalListMutex); 343 344 pHandler->pNext = SignalList; 345 SignalList = pHandler; 346 347 osl_releaseMutex(SignalListMutex); 348 349 return (pHandler); 350 } 351 352 return (NULL); 353 } 354 355 /*****************************************************************************/ 356 /* osl_removeSignalHandler */ 357 /*****************************************************************************/ 358 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) 359 { 360 oslSignalHandlerImpl *pHandler, *pPrevious = NULL; 361 362 OSL_ASSERT(Handler != NULL); 363 364 if (! bInitSignal) 365 bInitSignal = InitSignal(); 366 367 osl_acquireMutex(SignalListMutex); 368 369 pHandler = SignalList; 370 371 while (pHandler != NULL) 372 { 373 if (pHandler == Handler) 374 { 375 if (pPrevious) 376 pPrevious->pNext = pHandler->pNext; 377 else 378 SignalList = pHandler->pNext; 379 380 osl_releaseMutex(SignalListMutex); 381 382 if (SignalList == NULL) 383 bInitSignal = DeInitSignal(); 384 385 free(pHandler); 386 387 return (sal_True); 388 } 389 390 pPrevious = pHandler; 391 pHandler = pHandler->pNext; 392 } 393 394 osl_releaseMutex(SignalListMutex); 395 396 return (sal_False); 397 } 398 399 /*****************************************************************************/ 400 /* osl_raiseSignal */ 401 /*****************************************************************************/ 402 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) 403 { 404 oslSignalInfo Info; 405 oslSignalAction Action; 406 407 if (! bInitSignal) 408 bInitSignal = InitSignal(); 409 410 osl_acquireMutex(SignalListMutex); 411 412 Info.Signal = osl_Signal_User; 413 Info.UserSignal = UserSignal; 414 Info.UserData = UserData; 415 416 Action = CallSignalHandler(&Info); 417 418 osl_releaseMutex(SignalListMutex); 419 420 return (Action); 421 } 422 423 /*****************************************************************************/ 424 /* osl_setErrorReporting */ 425 /*****************************************************************************/ 426 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) 427 { 428 sal_Bool bOld = bErrorReportingEnabled; 429 bErrorReportingEnabled = bEnable; 430 431 return bOld; 432 } 433