xref: /aoo41x/main/sal/osl/w32/signal.cxx (revision cdf0e10c)
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