update credits
[LibreOffice.git] / sal / osl / unx / signal.c
blob2c3f2b2f7453ca0b1223ebd816dd99a863b8d123
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 .
21 /* system headers */
22 #include "system.h"
24 #if defined( MACOSX )
26 #if defined( INTEL )
27 #include "backtrace.h"
28 #define INCLUDE_BACKTRACE
29 #ifdef SAL_ENABLE_CRASH_REPORT
30 #define STACKTYPE "MacOsX_X86"
31 #endif
32 #endif /* INTEL */
34 #endif /* MACOSX */
36 #ifdef LINUX
37 #include <execinfo.h>
38 #include <link.h>
39 #define INCLUDE_BACKTRACE
40 #if defined SAL_ENABLE_CRASH_REPORT
41 #define STACKTYPE "Linux"
42 #endif
43 #endif
45 #ifdef SOLARIS
47 #include "backtrace.h"
48 #define INCLUDE_BACKTRACE
50 #if defined SAL_ENABLE_CRASH_REPORT
51 #if defined( SPARC )
52 #define STACKTYPE "Solaris_Sparc"
53 #elif defined( INTEL )
54 #define STACKTYPE "Solaris_X86"
55 #else
56 #define STACKTYPE "Solaris_Unknown"
57 #endif
58 #endif
60 #endif /* defined SOLARIS */
62 #if defined INCLUDE_BACKTRACE
63 #define MAX_STACK_FRAMES 256
64 #endif
66 #include <osl/diagnose.h>
67 #include <osl/mutex.h>
68 #include <osl/signal.h>
69 #include <osl/process.h>
70 #include <osl/thread.h>
71 #include <sal/macros.h>
72 #include <rtl/bootstrap.h>
73 #include <rtl/digest.h>
75 #include "file_path_helper.h"
77 #define ACT_IGNORE 1
78 #define ACT_EXIT 2
79 #define ACT_SYSTEM 3
80 #define ACT_HIDE 4
81 #ifdef SAL_ENABLE_CRASH_REPORT
82 # define ACT_ABORT 5
83 #else
84 # define ACT_ABORT ACT_SYSTEM
85 #endif
87 #if defined HAVE_VALGRIND_HEADERS
88 #include <valgrind/memcheck.h>
89 #endif
91 typedef struct _oslSignalHandlerImpl
93 oslSignalHandlerFunction Handler;
94 void* pData;
95 struct _oslSignalHandlerImpl* pNext;
96 } oslSignalHandlerImpl;
98 static struct SignalAction
100 int Signal;
101 int Action;
102 void (*Handler)(int);
103 } Signals[] =
105 { SIGHUP, ACT_HIDE, NULL }, /* hangup */
106 { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */
107 { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */
108 { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */
109 /* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/
110 { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */
111 #if ( SIGIOT != SIGABRT )
112 { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */
113 #endif
114 { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */
115 #ifdef SIGEMT
116 { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */
117 /* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/
118 /* SIGEMT may also be used by the profiler - so it is probably not a good
119 plan to have the new handler use this signal*/
120 #endif
121 { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */
122 { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */
123 { SIGBUS, ACT_ABORT, NULL }, /* bus error */
124 { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */
125 #ifdef SIGSYS
126 { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */
127 #endif
128 { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */
129 { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */
130 { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */
131 { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */
132 { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */
133 { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */
134 #ifdef SIGPWR
135 { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */
136 #endif
137 { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */
138 { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */
139 #ifdef SIGPOLL
140 { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occurred */
141 #endif
142 { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */
143 { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */
144 { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */
145 { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */
146 { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */
147 { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */
148 { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */
149 /*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do
150 not get taken by the new handler - the new handler does not pass on context
151 information which causes 'collect' to crash. This is a way of avoiding
152 what looks like a bug in the new handler*/
153 { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */
154 { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */
156 const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction);
158 static sal_Bool bErrorReportingEnabled = sal_True;
159 static sal_Bool bInitSignal = sal_False;
160 static oslMutex SignalListMutex;
161 static oslSignalHandlerImpl* SignalList;
162 static sal_Bool bDoHardKill = sal_False;
163 static sal_Bool bSetSEGVHandler = sal_False;
164 static sal_Bool bSetWINCHHandler = sal_False;
165 static sal_Bool bSetILLHandler = sal_False;
167 static void SignalHandlerFunction(int);
169 static void getExecutableName_Impl (rtl_String ** ppstrProgName)
171 rtl_uString * ustrProgFile = 0;
172 osl_getExecutableFile (&ustrProgFile);
173 if (ustrProgFile)
175 rtl_uString * ustrProgName = 0;
176 osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName);
177 if (ustrProgName != 0)
179 rtl_uString2String (
180 ppstrProgName,
181 rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName),
182 osl_getThreadTextEncoding(),
183 OUSTRING_TO_OSTRING_CVTFLAGS);
184 rtl_uString_release (ustrProgName);
186 rtl_uString_release (ustrProgFile);
190 static sal_Bool is_soffice_Impl (void)
192 sal_Int32 idx = -1;
193 rtl_String * strProgName = 0;
195 getExecutableName_Impl (&strProgName);
196 if (strProgName)
198 idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice");
199 rtl_string_release (strProgName);
201 return (idx != -1);
204 static sal_Bool InitSignal()
206 int i;
207 struct sigaction act;
208 struct sigaction oact;
209 sigset_t unset;
211 if (is_soffice_Impl())
213 sal_uInt32 argi;
214 sal_uInt32 argc;
215 rtl_uString *ustrCommandArg = 0;
217 argc = osl_getCommandArgCount();
218 for ( argi = 0; argi < argc; argi++ )
220 if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg))
222 if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean"))
224 bDoHardKill = sal_True;
225 break;
229 if (ustrCommandArg)
231 rtl_uString_release (ustrCommandArg);
232 ustrCommandArg = 0;
235 // WORKAROUND FOR SEGV HANDLER CONFLICT
237 // the java jit needs SIGSEGV for proper work
238 // and we need SIGSEGV for the office crashguard
240 // TEMPORARY SOLUTION:
241 // the office sets the signal handler during startup
242 // java can than overwrite it, if needed
243 bSetSEGVHandler = sal_True;
245 // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
246 bSetWINCHHandler = sal_True;
248 // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
249 bSetILLHandler = sal_True;
252 #ifdef DBG_UTIL
253 bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = bDoHardKill = sal_False;
254 #endif
256 SignalListMutex = osl_createMutex();
258 act.sa_handler = SignalHandlerFunction;
259 act.sa_flags = SA_RESTART;
261 sigfillset(&(act.sa_mask));
263 /* Initialize the rest of the signals */
264 for (i = 0; i < NoSignals; ++i)
266 #if defined HAVE_VALGRIND_HEADERS
267 if (Signals[i].Signal == SIGUSR2 && RUNNING_ON_VALGRIND)
268 Signals[i].Action = ACT_IGNORE;
269 #endif
271 /* hack: stomcatd is attaching JavaVM which does not work with an sigaction(SEGV) */
272 if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV)
273 && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH)
274 && (bSetILLHandler || Signals[i].Signal != SIGILL))
276 if (Signals[i].Action != ACT_SYSTEM)
278 if (Signals[i].Action == ACT_HIDE)
280 struct sigaction ign;
282 ign.sa_handler = SIG_IGN;
283 ign.sa_flags = 0;
284 sigemptyset(&ign.sa_mask);
286 if (sigaction(Signals[i].Signal, &ign, &oact) == 0)
287 Signals[i].Handler = oact.sa_handler;
288 else
289 Signals[i].Handler = SIG_DFL;
291 else
293 if (sigaction(Signals[i].Signal, &act, &oact) == 0)
294 Signals[i].Handler = oact.sa_handler;
295 else
296 Signals[i].Handler = SIG_DFL;
302 /* Clear signal mask inherited from parent process (on Mac OS X, upon a
303 crash soffice re-execs itself from within the signal handler, so the
304 second soffice would have the guilty signal blocked and would freeze upon
305 encountering a similar crash again): */
306 if (sigemptyset(&unset) < 0 ||
307 pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0)
309 OSL_TRACE("sigemptyset or pthread_sigmask failed");
312 return sal_True;
315 static sal_Bool DeInitSignal()
317 int i;
318 struct sigaction act;
320 act.sa_flags = 0;
321 sigemptyset(&(act.sa_mask));
323 /* Initialize the rest of the signals */
324 for (i = NoSignals - 1; i >= 0; i--)
325 if (Signals[i].Action != ACT_SYSTEM)
327 act.sa_handler = Signals[i].Handler;
329 sigaction(Signals[i].Signal, &act, NULL);
332 osl_destroyMutex(SignalListMutex);
334 return sal_False;
337 #if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE)
339 /*****************************************************************************/
340 /* Generate MD5 checksum */
341 /*****************************************************************************/
343 static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
345 sal_uInt32 nBytesProcessed = 0;
347 FILE *fp = fopen( filename, "r" );
349 if ( fp )
351 rtlDigest digest = rtl_digest_createMD5();
353 if ( digest )
355 size_t nBytesRead;
356 sal_uInt8 buffer[4096];
357 rtlDigestError error = rtl_Digest_E_None;
359 while ( rtl_Digest_E_None == error &&
360 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
362 error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
363 nBytesProcessed += nBytesRead;
366 if ( rtl_Digest_E_None == error )
368 error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
371 if ( rtl_Digest_E_None != error )
372 nBytesProcessed = 0;
374 rtl_digest_destroyMD5( digest );
377 fclose( fp );
380 return nBytesProcessed;
383 /*****************************************************************************/
384 /* Call crash reporter */
385 /*****************************************************************************/
387 /* Helper function to encode and write a string to a stream */
389 static int fputs_xml( const char *string, FILE *stream )
391 int result = 0;
393 while ( result >= 0 && *string )
395 switch( *string )
397 case '&':
398 result = fputs( "&amp;", stream );
399 break;
400 case '<':
401 result = fputs( "&lt;", stream );
402 break;
403 case '>':
404 result = fputs( "&gt;", stream );
405 break;
406 default:
407 result = fputc( *string, stream );
408 break;
411 string++;
414 return result;
416 #endif
418 /* Create intermediate files and run crash reporter */
420 #if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \
421 defined LINUX
423 typedef struct
425 const char *name;
426 ElfW(Off) offset;
427 } dynamic_entry;
429 static int
430 callback(struct dl_phdr_info *info, size_t size, void *data)
432 const ElfW(Phdr) *pDynamic = NULL;
434 if (size == sizeof(struct dl_phdr_info))
436 int i;
437 for (i = 0; i < info->dlpi_phnum; ++i)
439 if (info->dlpi_phdr[i].p_type == PT_DYNAMIC)
441 pDynamic = &(info->dlpi_phdr[i]);
442 break;
447 if (pDynamic)
449 char buffer[100];
450 int len;
451 char exe[PATH_MAX];
452 const char *dsoname = info->dlpi_name;
454 dynamic_entry* entry = (dynamic_entry*)data;
456 if (strcmp(dsoname, "") == 0)
458 snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid());
459 if ((len = readlink(buffer, exe, PATH_MAX)) != -1)
461 exe[len] = '\0';
462 dsoname = exe;
466 if (strcmp(dsoname, entry->name) == 0)
468 entry->offset = pDynamic->p_offset;
469 return 1;
472 return 0;
475 /* Get the location of the .dynamic section offset for the given elf file.
476 * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo
478 * We want to know this value so that if the binaries have been modifed
479 * by prelink then we can still process the call stack on server side
480 * by comparing this value to that of an "un-prelinked but known to be
481 * otherwise equivalent" version of those binaries and adjust the call
482 * stack addresses by the differences between .dynamic addresses so as
483 * to be able to map the prelinked addresses back to the unprelinked
484 * addresses
486 * cmc@openoffice.org
488 static ElfW(Off)
489 dynamic_section_offset(const char *name)
491 dynamic_entry entry;
493 entry.name = name;
494 entry.offset = 0;
496 dl_iterate_phdr(callback, &entry);
498 return entry.offset;
500 #endif
502 static int ReportCrash( int Signal )
504 #ifdef SAL_ENABLE_CRASH_REPORT
506 #define REPORTENV_PARAM "-crashreportenv:"
508 static sal_Bool bCrashReporterExecuted = sal_False;
509 sal_Bool bAutoCrashReport = sal_False;
511 sal_uInt32 argi;
512 sal_uInt32 argc;
513 rtl_uString *ustrCommandArg = NULL;
515 if ( !bErrorReportingEnabled )
516 return -1;
518 argc = osl_getCommandArgCount();
520 for ( argi = 0; argi < argc; argi++ )
522 if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) )
524 if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--nocrashreport" ) )
526 rtl_uString_release( ustrCommandArg );
527 return -1;
529 else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--autocrashreport" ) )
531 bAutoCrashReport = sal_True;
533 else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength(
534 rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ),
535 REPORTENV_PARAM, strlen(REPORTENV_PARAM) )
538 rtl_uString *ustrEnvironment = NULL;
539 rtl_String *strEnv = NULL;
541 rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) );
543 if ( ustrEnvironment )
545 rtl_uString2String(
546 &strEnv,
547 rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ),
548 osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS
551 if ( strEnv )
553 putenv( rtl_string_getStr( strEnv ) );
554 rtl_string_release( strEnv );
557 rtl_uString_release( ustrEnvironment );
565 if ( ustrCommandArg )
566 rtl_uString_release( ustrCommandArg );
568 if ( !bCrashReporterExecuted )
570 int i;
571 /* struct sigaction act; */
573 for (i = 0; i < NoSignals; i++)
575 if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT )
577 int ret;
578 char szShellCmd[512] = { '\0' };
579 char *pXMLTempName = NULL;
580 char *pStackTempName = NULL;
581 char *pChecksumTempName = NULL;
583 #ifdef INCLUDE_BACKTRACE
584 char szXMLTempNameBuffer[L_tmpnam];
585 char szChecksumTempNameBuffer[L_tmpnam];
586 char szStackTempNameBuffer[L_tmpnam];
588 void *stackframes[MAX_STACK_FRAMES];
589 int iFrame;
590 int nFrames = backtrace( stackframes, SAL_N_ELEMENTS(stackframes) );
592 FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL;
593 int fdxml, fdstk, fdchksum;
595 strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) );
596 strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) - strlen(szXMLTempNameBuffer) - 1 );
598 strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) );
599 strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) - strlen(szStackTempNameBuffer) - 1 );
601 strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) );
602 strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) - strlen(szChecksumTempNameBuffer) - 1 );
604 fdxml = mkstemp(szXMLTempNameBuffer);
605 fdstk = mkstemp(szStackTempNameBuffer);
606 fdchksum = mkstemp(szChecksumTempNameBuffer);
608 xmlout = fdopen( fdxml , "w" );
609 stackout = fdopen( fdstk , "w" );
610 checksumout = fdopen( fdchksum, "w" );
612 pXMLTempName = szXMLTempNameBuffer;
613 pStackTempName = szStackTempNameBuffer;
614 pChecksumTempName = szChecksumTempNameBuffer;
617 if ( xmlout && stackout && checksumout )
619 fprintf( xmlout, "<errormail:Stack type=\"%s\">\n", STACKTYPE );
621 fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\n" );
623 for ( iFrame = 0; iFrame < nFrames; iFrame++ )
625 Dl_info dl_info;
627 fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":",
628 SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) );
630 fprintf( xmlout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"",
631 iFrame,
632 SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame])
635 memset( &dl_info, 0, sizeof(dl_info) );
637 /* dladdr may fail */
638 if ( dladdr( stackframes[iFrame], &dl_info) )
640 const char *dli_fname = NULL;
641 char *dli_fdir = NULL;
642 char szDirectory[PATH_MAX];
643 char szCanonicDirectory[PATH_MAX];
645 /* Don't expect that dladdr filled all members of dl_info */
647 dli_fname = dl_info.dli_fname ? strrchr( dl_info.dli_fname, '/' ) : NULL;
648 if ( dli_fname )
650 ++dli_fname;
651 memcpy( szDirectory, dl_info.dli_fname, dli_fname - dl_info.dli_fname );
652 szDirectory[dli_fname - dl_info.dli_fname] = 0;
654 dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory;
656 if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' )
657 strcat( dli_fdir, "/" );
659 else
660 dli_fname = dl_info.dli_fname;
662 /* create checksum of library on stack */
663 if ( dli_fname )
665 sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
667 sal_uInt32 nBytesProcessed = calc_md5_checksum(
668 dl_info.dli_fname, checksum, sizeof(checksum) );
669 if ( nBytesProcessed )
671 int j;
673 fprintf( checksumout, "<errormail:Checksum sum=\"0x" );
674 for ( j = 0; j < 16; fprintf( checksumout, "%02X", checksum[j++] ) );
675 fprintf( checksumout,
676 "\" bytes=\"%lu\" file=\"%s\"/>\n",
677 SAL_INT_CAST(
678 unsigned long, nBytesProcessed),
679 dli_fname );
683 if ( dl_info.dli_fbase && dl_info.dli_fname )
685 #ifdef LINUX
686 ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname);
687 fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset);
688 #endif
690 fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x",
691 dl_info.dli_fname,
692 (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase
695 fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase );
696 if ( dli_fname )
697 fprintf( xmlout, " name=\"%s\"", dli_fname );
699 if ( dli_fdir )
700 fprintf( xmlout, " path=\"%s\"", dli_fdir );
702 #ifdef LINUX
703 fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset );
704 #endif
706 else
707 fprintf( stackout, " ????????" );
709 if ( dl_info.dli_sname && dl_info.dli_saddr )
711 fputs( " (", stackout );
712 fputs_xml( dl_info.dli_sname, stackout );
713 fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)",
714 (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr );
716 fputs( " ordinal=\"", xmlout );
717 fputs_xml( dl_info.dli_sname, xmlout );
718 fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"",
719 (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr );
723 else /* dladdr failed */
725 fprintf( stackout, " ????????" );
728 fprintf( stackout, "\n" );
729 fprintf( xmlout, "/>\n" );
733 fprintf( xmlout, "</errormail:Stack>\n" );
734 fprintf( checksumout, "</errormail:Checksums>\n" );
736 else
738 pXMLTempName = NULL;
739 pStackTempName = NULL;
740 pChecksumTempName = NULL;
743 if ( stackout )
744 fclose( stackout );
745 if ( xmlout )
746 fclose( xmlout );
747 if ( checksumout )
748 fclose( checksumout );
750 if ( pXMLTempName && pChecksumTempName && pStackTempName )
751 #endif /* INCLUDE_BACKTRACE */
753 rtl_uString * crashrep_url = NULL;
754 rtl_uString * crashrep_path = NULL;
755 rtl_String * crashrep_path_system = NULL;
756 rtl_string2UString(
757 &crashrep_url,
758 RTL_CONSTASCII_USTRINGPARAM(
759 "$BRAND_BASE_DIR/program/crashrep"),
760 OSTRING_TO_OUSTRING_CVTFLAGS);
761 rtl_bootstrap_expandMacros(&crashrep_url);
762 osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path);
763 rtl_uString2String(
764 &crashrep_path_system,
765 rtl_uString_getStr(crashrep_path),
766 rtl_uString_getLength(crashrep_path),
767 osl_getThreadTextEncoding(),
768 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
769 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR));
770 rtl_uString_release(crashrep_url);
771 rtl_uString_release(crashrep_path);
772 #if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX)
773 snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
774 "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s",
775 rtl_string_getStr(crashrep_path_system),
776 getpid(),
777 Signal,
778 pXMLTempName,
779 pChecksumTempName,
780 pStackTempName,
781 bAutoCrashReport ? " -send" : "" );
782 #elif defined INCLUDE_BACKTRACE && defined SOLARIS
783 snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
784 "%s -p %d -s %d -xml %s -chksum %s -noui%s",
785 rtl_string_getStr(crashrep_path_system),
786 getpid(),
787 Signal,
788 pXMLTempName,
789 pChecksumTempName,
790 bAutoCrashReport ? " -send" : "" );
791 #else
792 snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
793 "%s -p %d -s %d -noui%s",
794 rtl_string_getStr(crashrep_path_system),
795 getpid(), Signal, bAutoCrashReport ? " -send" : "" );
796 #endif
797 rtl_string_release(crashrep_path_system);
800 ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd );
802 if ( pXMLTempName )
803 unlink( pXMLTempName );
805 if ( pStackTempName )
806 unlink( pStackTempName );
808 if ( pChecksumTempName )
809 unlink( pChecksumTempName );
811 if ( -1 != ret )
813 bCrashReporterExecuted = sal_True;
814 return 1;
816 else
817 return -1;
822 return 0;
825 return 1;
826 #else /* defined SAL_ENABLE_CRASH_REPORT */
827 /* the utility crash_report is not build, so do the same as when
828 the option -nocrashreport is used */
829 (void) Signal; // avoid warnings
830 return -1;
831 #endif /* defined SAL_ENABLE_CRASH_REPORT */
834 static void PrintStack( int sig )
836 #ifdef INCLUDE_BACKTRACE
837 void *buffer[MAX_STACK_FRAMES];
838 int size = backtrace( buffer, SAL_N_ELEMENTS(buffer) );
839 #endif
841 fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
843 #if defined( MACOSX ) && !defined( INCLUDE_BACKTRACE )
844 fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
845 #else
846 #ifdef INCLUDE_BACKTRACE
847 if ( size > 0 )
849 fputs( "Stack:\n", stderr );
850 backtrace_symbols_fd( buffer, size, fileno(stderr) );
852 #endif
853 #endif
856 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
858 oslSignalHandlerImpl* pHandler = SignalList;
859 oslSignalAction Action = osl_Signal_ActCallNextHdl;
861 while (pHandler != NULL)
863 if ((Action = pHandler->Handler(pHandler->pData, pInfo))
864 != osl_Signal_ActCallNextHdl)
865 break;
867 pHandler = pHandler->pNext;
870 return Action;
873 void CallSystemHandler(int Signal)
875 int i;
876 struct sigaction act;
878 for (i = 0; i < NoSignals; i++)
880 if (Signals[i].Signal == Signal)
881 break;
884 if (i < NoSignals)
886 if ((Signals[i].Handler == NULL) ||
887 (Signals[i].Handler == SIG_DFL) ||
888 (Signals[i].Handler == SIG_IGN) ||
889 (Signals[i].Handler == SIG_ERR))
891 switch (Signals[i].Action)
893 case ACT_EXIT: /* terminate */
894 /* prevent dumping core on exit() */
895 _exit(255);
896 break;
898 case ACT_ABORT: /* terminate witch core dump */
899 ReportCrash( Signal );
900 act.sa_handler = SIG_DFL;
901 act.sa_flags = 0;
902 sigemptyset(&(act.sa_mask));
903 sigaction(SIGABRT, &act, NULL);
904 PrintStack( Signal );
905 abort();
906 break;
908 case ACT_IGNORE: /* ignore */
909 break;
911 default: /* should never happen */
912 OSL_ASSERT(0);
915 else
916 (*Signals[i].Handler)(Signal);
920 #if defined HAVE_VALGRIND_HEADERS
921 static void DUMPCURRENTALLOCS()
923 VALGRIND_PRINTF( "=== start memcheck dump of active allocations ===\n" );
925 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
926 # pragma GCC diagnostic push
927 # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
928 #endif
930 VALGRIND_DO_LEAK_CHECK;
932 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
933 # pragma GCC diagnostic pop
934 #endif
936 VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" );
938 #endif
940 /*****************************************************************************/
941 /* SignalHandlerFunction */
942 /*****************************************************************************/
943 void SignalHandlerFunction(int Signal)
945 oslSignalInfo Info;
946 struct sigaction act;
948 Info.UserSignal = Signal;
949 Info.UserData = NULL;
951 switch (Signal)
953 case SIGBUS:
954 case SIGILL:
955 case SIGSEGV:
956 case SIGIOT:
957 #if ( SIGIOT != SIGABRT )
958 case SIGABRT:
959 #endif
960 Info.Signal = osl_Signal_AccessViolation;
961 break;
963 case -1:
964 Info.Signal = osl_Signal_IntegerDivideByZero;
965 break;
967 case SIGFPE:
968 Info.Signal = osl_Signal_FloatDivideByZero;
969 break;
971 case SIGINT:
972 case SIGTERM:
973 case SIGQUIT:
974 Info.Signal = osl_Signal_Terminate;
975 break;
977 #if defined HAVE_VALGRIND_HEADERS
978 case SIGUSR2:
979 if (RUNNING_ON_VALGRIND)
980 DUMPCURRENTALLOCS();
981 Info.Signal = osl_Signal_System;
982 break;
983 #endif
985 default:
986 Info.Signal = osl_Signal_System;
987 break;
990 ReportCrash( Signal );
992 /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
993 if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation))
994 _exit(255);
995 /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
998 switch (CallSignalHandler(&Info))
1000 case osl_Signal_ActCallNextHdl:
1001 CallSystemHandler(Signal);
1002 break;
1004 case osl_Signal_ActAbortApp:
1005 ReportCrash( Signal );
1006 act.sa_handler = SIG_DFL;
1007 act.sa_flags = 0;
1008 sigemptyset(&(act.sa_mask));
1009 sigaction(SIGABRT, &act, NULL);
1010 PrintStack( Signal );
1011 abort();
1012 break;
1014 case osl_Signal_ActKillApp:
1015 /* prevent dumping core on exit() */
1016 _exit(255);
1017 break;
1018 default:
1019 break;
1023 /*****************************************************************************/
1024 /* osl_addSignalHandler */
1025 /*****************************************************************************/
1026 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
1028 oslSignalHandlerImpl* pHandler;
1030 OSL_ASSERT(Handler != NULL);
1031 if ( Handler == 0 )
1033 return 0;
1036 if (! bInitSignal)
1037 bInitSignal = InitSignal();
1039 pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl));
1041 if (pHandler != NULL)
1043 pHandler->Handler = Handler;
1044 pHandler->pData = pData;
1046 osl_acquireMutex(SignalListMutex);
1048 pHandler->pNext = SignalList;
1049 SignalList = pHandler;
1051 osl_releaseMutex(SignalListMutex);
1053 return (pHandler);
1056 return (NULL);
1059 /*****************************************************************************/
1060 /* osl_removeSignalHandler */
1061 /*****************************************************************************/
1062 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
1064 oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
1066 OSL_ASSERT(Handler != NULL);
1068 if (! bInitSignal)
1069 bInitSignal = InitSignal();
1071 osl_acquireMutex(SignalListMutex);
1073 pHandler = SignalList;
1075 while (pHandler != NULL)
1077 if (pHandler == Handler)
1079 if (pPrevious)
1080 pPrevious->pNext = pHandler->pNext;
1081 else
1082 SignalList = pHandler->pNext;
1084 osl_releaseMutex(SignalListMutex);
1086 if (SignalList == NULL)
1087 bInitSignal = DeInitSignal();
1089 free(pHandler);
1091 return (sal_True);
1094 pPrevious = pHandler;
1095 pHandler = pHandler->pNext;
1098 osl_releaseMutex(SignalListMutex);
1100 return (sal_False);
1103 /*****************************************************************************/
1104 /* osl_raiseSignal */
1105 /*****************************************************************************/
1106 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
1108 oslSignalInfo Info;
1109 oslSignalAction Action;
1111 if (! bInitSignal)
1112 bInitSignal = InitSignal();
1114 osl_acquireMutex(SignalListMutex);
1116 Info.Signal = osl_Signal_User;
1117 Info.UserSignal = UserSignal;
1118 Info.UserData = UserData;
1120 Action = CallSignalHandler(&Info);
1122 osl_releaseMutex(SignalListMutex);
1124 return (Action);
1127 /*****************************************************************************/
1128 /* osl_setErrorReporting */
1129 /*****************************************************************************/
1130 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
1132 sal_Bool bOld = bErrorReportingEnabled;
1133 bErrorReportingEnabled = bEnable;
1135 return bOld;
1138 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */