Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / sal / osl / w32 / signal.cxx
blobf13a78ad27a31deba50f3de6714f7ea71623b24e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 /* system headers */
21 #include "system.h"
22 #include <tchar.h>
24 #include "file_url.h"
25 #include "path_helper.hxx"
27 #include <osl/diagnose.h>
28 #include <osl/mutex.h>
29 #include <osl/signal.h>
30 #ifndef __MINGW32__
31 #include <DbgHelp.h>
32 #endif
33 #include <errorrep.h>
34 #include <systools/win32/uwinapi.h>
35 #include <sal/macros.h>
37 typedef struct _oslSignalHandlerImpl
39 oslSignalHandlerFunction Handler;
40 void* pData;
41 struct _oslSignalHandlerImpl* pNext;
42 } oslSignalHandlerImpl;
44 static sal_Bool bErrorReportingEnabled = sal_True;
45 static sal_Bool bInitSignal = sal_False;
46 static oslMutex SignalListMutex;
47 static oslSignalHandlerImpl* SignalList;
49 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP);
51 static sal_Bool InitSignal(void)
53 HMODULE hFaultRep;
55 SignalListMutex = osl_createMutex();
57 SetUnhandledExceptionFilter(SignalHandlerFunction);
59 hFaultRep = LoadLibrary( "faultrep.dll" );
60 if ( hFaultRep )
62 pfn_ADDEREXCLUDEDAPPLICATIONW pfn = (pfn_ADDEREXCLUDEDAPPLICATIONW)GetProcAddress( hFaultRep, "AddERExcludedApplicationW" );
63 if ( pfn )
64 pfn( L"SOFFICE.EXE" );
65 FreeLibrary( hFaultRep );
68 return sal_True;
71 static sal_Bool DeInitSignal(void)
73 SetUnhandledExceptionFilter(NULL);
75 osl_destroyMutex(SignalListMutex);
77 return sal_False;
80 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
82 oslSignalHandlerImpl* pHandler = SignalList;
83 oslSignalAction Action = osl_Signal_ActCallNextHdl;
85 while (pHandler != NULL)
87 if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl)
88 break;
90 pHandler = pHandler->pNext;
93 return Action;
96 /*****************************************************************************/
97 /* SignalHandlerFunction */
98 /*****************************************************************************/
100 #define REPORTENV_PARAM "-crashreportenv:"
101 #define REPORTENV_PARAM2 "/crashreportenv:"
103 static BOOL ReportCrash( LPEXCEPTION_POINTERS lpEP )
105 BOOL fSuccess = FALSE;
106 BOOL fAutoReport = FALSE;
107 TCHAR szBuffer[1024];
108 ::osl::LongPathBuffer< sal_Char > aPath( MAX_LONG_PATH );
109 LPTSTR lpFilePart;
110 PROCESS_INFORMATION ProcessInfo;
111 STARTUPINFO StartupInfo;
112 int argi;
114 if ( !bErrorReportingEnabled )
115 return FALSE;
117 /* Check if crash reporter was disabled by command line */
119 for ( argi = 1; argi < __argc; argi++ )
121 if (
122 0 == stricmp( __argv[argi], "--nocrashreport" ) ||
123 0 == stricmp( __argv[argi], "/nocrashreport" )
125 return FALSE;
126 else if (
127 0 == stricmp( __argv[argi], "--autocrashreport" ) ||
128 0 == stricmp( __argv[argi], "/autocrashreport" )
130 fAutoReport = TRUE;
131 else if (
132 0 == strnicmp( __argv[argi], REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) ||
133 0 == strnicmp( __argv[argi], REPORTENV_PARAM2, strlen(REPORTENV_PARAM2) )
136 const char *envparam = __argv[argi] + strlen(REPORTENV_PARAM);
137 const char *delim = strchr(envparam, '=' );
139 if ( delim )
141 CHAR *lpVariable;
142 CHAR *lpValue;
143 const char *variable = envparam;
144 size_t variable_len = delim - envparam;
145 const char *value = delim + 1;
146 size_t value_len = strlen(envparam) - variable_len - 1;
148 if ( '\"' == *value )
150 const char *quote;
152 value++;
153 value_len--;
155 quote = strchr( value, '\"' );
156 if ( quote )
157 value_len = quote - value;
160 lpVariable = reinterpret_cast< CHAR* >( _alloca( variable_len + 1 ) );
161 memcpy( lpVariable, variable, variable_len );
162 lpVariable[variable_len] = 0;
164 lpValue = reinterpret_cast< CHAR* >( _alloca( value_len + 1) );
165 memcpy( lpValue, value, value_len );
166 lpValue[value_len] = 0;
168 SetEnvironmentVariable( lpVariable, lpValue );
173 if ( SearchPath( NULL, TEXT( "crashrep.exe" ), NULL, aPath.getBufSizeInSymbols(), aPath, &lpFilePart ) )
175 ZeroMemory( &StartupInfo, sizeof(StartupInfo) );
176 StartupInfo.cb = sizeof(StartupInfo.cb);
179 sntprintf( szBuffer, SAL_N_ELEMENTS(szBuffer),
180 _T("%s -p %lu -excp 0x%p -t %lu%s"),
181 static_cast<sal_Char*>( aPath ),
182 GetCurrentProcessId(),
183 lpEP,
184 GetCurrentThreadId(),
185 fAutoReport ? _T(" -noui -send") : _T(" -noui") );
187 if (
188 CreateProcess(
189 NULL,
190 szBuffer,
191 NULL,
192 NULL,
193 FALSE,
194 #ifdef UNICODE
195 CREATE_UNICODE_ENVIRONMENT,
196 #else
198 #endif
199 NULL, NULL, &StartupInfo, &ProcessInfo )
202 DWORD dwExitCode;
204 WaitForSingleObject( ProcessInfo.hProcess, INFINITE );
205 if ( GetExitCodeProcess( ProcessInfo.hProcess, &dwExitCode ) && 0 == dwExitCode )
207 fSuccess = TRUE;
212 return fSuccess;
215 /*****************************************************************************/
216 /* SignalHandlerFunction */
217 /*****************************************************************************/
219 /* magic Microsoft C++ compiler exception constant */
220 #define EXCEPTION_MSC_CPP_EXCEPTION 0xe06d7363
222 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP)
224 static sal_Bool bNested = sal_False;
225 sal_Bool bRaiseCrashReporter = sal_False;
226 oslSignalInfo Info;
227 oslSignalAction Action;
229 Info.UserSignal = lpEP->ExceptionRecord->ExceptionCode;
230 Info.UserData = NULL;
232 switch (lpEP->ExceptionRecord->ExceptionCode)
234 /* Transform unhandled exceptions into access violations.
235 Microsoft C++ compiler (add more for other compilers if necessary).
237 case EXCEPTION_MSC_CPP_EXCEPTION:
238 case EXCEPTION_ACCESS_VIOLATION:
239 Info.Signal = osl_Signal_AccessViolation;
240 bRaiseCrashReporter = sal_True;
241 break;
243 case EXCEPTION_INT_DIVIDE_BY_ZERO:
244 Info.Signal = osl_Signal_IntegerDivideByZero;
245 bRaiseCrashReporter = sal_True;
246 break;
248 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
249 Info.Signal = osl_Signal_FloatDivideByZero;
250 bRaiseCrashReporter = sal_True;
251 break;
253 case EXCEPTION_BREAKPOINT:
254 Info.Signal = osl_Signal_DebugBreak;
255 break;
257 default:
258 Info.Signal = osl_Signal_System;
259 bRaiseCrashReporter = sal_True;
260 break;
263 if ( !bNested )
265 bNested = sal_True;
267 if ( bRaiseCrashReporter && ReportCrash( lpEP ) )
269 CallSignalHandler(&Info);
270 Action = osl_Signal_ActKillApp;
272 else
273 Action = CallSignalHandler(&Info);
275 else
276 Action = osl_Signal_ActKillApp;
279 switch ( Action )
281 case osl_Signal_ActCallNextHdl:
282 return (EXCEPTION_CONTINUE_SEARCH);
284 case osl_Signal_ActAbortApp:
285 return (EXCEPTION_EXECUTE_HANDLER);
287 case osl_Signal_ActKillApp:
288 SetErrorMode(SEM_NOGPFAULTERRORBOX);
289 exit(255);
290 break;
291 default:
292 break;
295 return (EXCEPTION_CONTINUE_EXECUTION);
298 /*****************************************************************************/
299 /* osl_addSignalHandler */
300 /*****************************************************************************/
301 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
303 oslSignalHandlerImpl* pHandler;
305 OSL_ASSERT(Handler != NULL);
307 if (! bInitSignal)
308 bInitSignal = InitSignal();
310 pHandler = reinterpret_cast< oslSignalHandlerImpl* >( calloc( 1, sizeof(oslSignalHandlerImpl) ) );
312 if (pHandler != NULL)
314 pHandler->Handler = Handler;
315 pHandler->pData = pData;
317 osl_acquireMutex(SignalListMutex);
319 pHandler->pNext = SignalList;
320 SignalList = pHandler;
322 osl_releaseMutex(SignalListMutex);
324 return (pHandler);
327 return (NULL);
330 /*****************************************************************************/
331 /* osl_removeSignalHandler */
332 /*****************************************************************************/
333 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
335 oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
337 OSL_ASSERT(Handler != NULL);
339 if (! bInitSignal)
340 bInitSignal = InitSignal();
342 osl_acquireMutex(SignalListMutex);
344 pHandler = SignalList;
346 while (pHandler != NULL)
348 if (pHandler == Handler)
350 if (pPrevious)
351 pPrevious->pNext = pHandler->pNext;
352 else
353 SignalList = pHandler->pNext;
355 osl_releaseMutex(SignalListMutex);
357 if (SignalList == NULL)
358 bInitSignal = DeInitSignal();
360 free(pHandler);
362 return (sal_True);
365 pPrevious = pHandler;
366 pHandler = pHandler->pNext;
369 osl_releaseMutex(SignalListMutex);
371 return (sal_False);
374 /*****************************************************************************/
375 /* osl_raiseSignal */
376 /*****************************************************************************/
377 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
379 oslSignalInfo Info;
380 oslSignalAction Action;
382 if (! bInitSignal)
383 bInitSignal = InitSignal();
385 osl_acquireMutex(SignalListMutex);
387 Info.Signal = osl_Signal_User;
388 Info.UserSignal = UserSignal;
389 Info.UserData = UserData;
391 Action = CallSignalHandler(&Info);
393 osl_releaseMutex(SignalListMutex);
395 return (Action);
398 /*****************************************************************************/
399 /* osl_setErrorReporting */
400 /*****************************************************************************/
401 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
403 sal_Bool bOld = bErrorReportingEnabled;
404 bErrorReportingEnabled = bEnable;
406 return bOld;
409 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */