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
InitSignal(void)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
DeInitSignal(void)79 static sal_Bool DeInitSignal(void)
80 {
81 SetUnhandledExceptionFilter(NULL);
82
83 osl_destroyMutex(SignalListMutex);
84
85 return sal_False;
86 }
87
CallSignalHandler(oslSignalInfo * pInfo)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
ReportCrash(LPEXCEPTION_POINTERS lpEP)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
IsWin95A(void)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
SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP)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 /*****************************************************************************/
osl_addSignalHandler(oslSignalHandlerFunction Handler,void * pData)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 /*****************************************************************************/
osl_removeSignalHandler(oslSignalHandler Handler)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 /*****************************************************************************/
osl_raiseSignal(sal_Int32 UserSignal,void * UserData)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
win_seh_translator(unsigned nSEHCode,_EXCEPTION_POINTERS * pExcPtrs)429 void win_seh_translator( unsigned nSEHCode, _EXCEPTION_POINTERS* pExcPtrs)
430 {
431 (void*)pExcPtrs; // currently unused, but useful inside a debugger
432 const char* pSEHName = NULL;
433 switch( nSEHCode)
434 {
435 case EXCEPTION_ACCESS_VIOLATION: pSEHName = "SEH Exception: ACCESS VIOLATION"; break;
436 case EXCEPTION_DATATYPE_MISALIGNMENT: pSEHName = "SEH Exception: DATATYPE MISALIGNMENT"; break;
437 case EXCEPTION_BREAKPOINT: /*pSEHName = "SEH Exception: BREAKPOINT";*/ break;
438 case EXCEPTION_SINGLE_STEP: /*pSEHName = "SEH Exception: SINGLE STEP";*/ break;
439 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: pSEHName = "SEH Exception: ARRAY BOUNDS EXCEEDED"; break;
440 case EXCEPTION_FLT_DENORMAL_OPERAND: pSEHName = "SEH Exception: DENORMAL FLOAT OPERAND"; break;
441 case EXCEPTION_FLT_DIVIDE_BY_ZERO: pSEHName = "SEH Exception: FLOAT DIVIDE_BY_ZERO"; break;
442 case EXCEPTION_FLT_INEXACT_RESULT: pSEHName = "SEH Exception: FLOAT INEXACT RESULT"; break;
443 case EXCEPTION_FLT_INVALID_OPERATION: pSEHName = "SEH Exception: INVALID FLOAT OPERATION"; break;
444 case EXCEPTION_FLT_OVERFLOW: pSEHName = "SEH Exception: FLOAT OVERFLOW"; break;
445 case EXCEPTION_FLT_STACK_CHECK: pSEHName = "SEH Exception: FLOAT STACK_CHECK"; break;
446 case EXCEPTION_FLT_UNDERFLOW: pSEHName = "SEH Exception: FLOAT UNDERFLOW"; break;
447 case EXCEPTION_INT_DIVIDE_BY_ZERO: pSEHName = "SEH Exception: INTEGER DIVIDE_BY_ZERO"; break;
448 case EXCEPTION_INT_OVERFLOW: pSEHName = "SEH Exception: INTEGER OVERFLOW"; break;
449 case EXCEPTION_PRIV_INSTRUCTION: pSEHName = "SEH Exception: PRIVILEDGED INSTRUCTION"; break;
450 case EXCEPTION_IN_PAGE_ERROR: pSEHName = "SEH Exception: IN_PAGE_ERROR"; break;
451 case EXCEPTION_ILLEGAL_INSTRUCTION: pSEHName = "SEH Exception: ILLEGAL INSTRUCTION"; break;
452 case EXCEPTION_NONCONTINUABLE_EXCEPTION: pSEHName = "SEH Exception: NONCONTINUABLE EXCEPTION"; break;
453 case EXCEPTION_STACK_OVERFLOW: pSEHName = "SEH Exception: STACK OVERFLOW"; break;
454 case EXCEPTION_INVALID_DISPOSITION: pSEHName = "SEH Exception: INVALID DISPOSITION"; break;
455 case EXCEPTION_GUARD_PAGE: pSEHName = "SEH Exception: GUARD PAGE"; break;
456 case EXCEPTION_INVALID_HANDLE: pSEHName = "SEH Exception: INVALID HANDLE"; break;
457 // case EXCEPTION_POSSIBLE_DEADLOCK: pSEHName = "SEH Exception: POSSIBLE DEADLOCK"; break;
458 default: pSEHName = "Unknown SEH Exception"; break;
459 }
460
461 if( pSEHName)
462 throw std::runtime_error( pSEHName);
463 }
464
osl_setErrorReporting(sal_Bool bEnable)465 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
466 {
467 sal_Bool bOld = bErrorReportingEnabled;
468 bErrorReportingEnabled = bEnable;
469
470 if( !bEnable) // if the crash reporter is disabled
471 {
472 // fall back to handle Window's SEH events as C++ exceptions
473 _set_se_translator( win_seh_translator);
474 }
475
476 return bOld;
477 }
478