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