merged tag ooo/DEV300_m102
[LibreOffice.git] / sal / osl / unx / signal.c
blob5563375d95672791ccc4473e6f767e0c2818794a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
29 /* system headers */
30 #include "system.h"
32 #define MAX_STACK_FRAMES 256
34 #if defined( MACOSX )
36 #if defined( INTEL )
37 #include "backtrace.h"
38 #define INCLUDE_BACKTRACE
39 #define STACKTYPE "MacOsX_X86"
40 #endif /* INTEL */
42 #endif /* MACOSX */
44 #ifdef LINUX
45 #include <execinfo.h>
46 #include <link.h>
47 #define INCLUDE_BACKTRACE
48 #define STACKTYPE "Linux"
49 #endif
51 #ifdef SOLARIS
53 #include "backtrace.h"
54 #define INCLUDE_BACKTRACE
56 #if defined( SPARC )
57 #define STACKTYPE "Solaris_Sparc"
58 #elif defined( INTEL )
59 #define STACKTYPE "Solaris_X86"
60 #else
61 #define STACKTYPE "Solaris_Unknown"
62 #endif
64 #endif /* defined SOLARIS */
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 <rtl/bootstrap.h>
72 #include <rtl/digest.h>
74 #include "file_path_helper.h"
76 #define ACT_IGNORE 1
77 #define ACT_EXIT 2
78 #define ACT_SYSTEM 3
79 #define ACT_HIDE 4
80 #ifdef SAL_ENABLE_CRASH_REPORT
81 # define ACT_ABORT 5
82 #else
83 # define ACT_ABORT ACT_SYSTEM
84 #endif
86 #define MAX_PATH_LEN 2048
88 typedef struct _oslSignalHandlerImpl
90 oslSignalHandlerFunction Handler;
91 void* pData;
92 struct _oslSignalHandlerImpl* pNext;
93 } oslSignalHandlerImpl;
95 static struct SignalAction
97 int Signal;
98 int Action;
99 void (*Handler)(int);
100 } Signals[] =
102 { SIGHUP, ACT_IGNORE, NULL }, /* hangup */
103 { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */
104 { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */
105 { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */
106 /* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/
107 { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */
108 #if ( SIGIOT != SIGABRT )
109 { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */
110 #endif
111 { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */
112 #ifdef SIGEMT
113 { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */
114 /* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/
115 /* SIGEMT may also be used by the profiler - so it is probably not a good
116 plan to have the new handler use this signal*/
117 #endif
118 { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */
119 { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */
120 { SIGBUS, ACT_ABORT, NULL }, /* bus error */
121 { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */
122 #ifdef SIGSYS
123 { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */
124 #endif
125 { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */
126 { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */
127 { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */
128 { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */
129 { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */
130 { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */
131 #ifdef SIGPWR
132 { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */
133 #endif
134 { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */
135 { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */
136 #ifdef SIGPOLL
137 { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occured */
138 #endif
139 { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */
140 { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */
141 { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */
142 { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */
143 { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */
144 { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */
145 { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */
146 /*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do
147 not get taken by the new handler - the new handler does not pass on context
148 information which causes 'collect' to crash. This is a way of avoiding
149 what looks like a bug in the new handler*/
150 { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */
151 { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */
153 const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction);
155 static sal_Bool bErrorReportingEnabled = sal_True;
156 static sal_Bool bInitSignal = sal_False;
157 static oslMutex SignalListMutex;
158 static oslSignalHandlerImpl* SignalList;
159 static sal_Bool bDoHardKill = sal_False;
160 static sal_Bool bSetSEGVHandler = sal_False;
161 static sal_Bool bSetWINCHHandler = sal_False;
162 static sal_Bool bSetILLHandler = sal_False;
164 static void SignalHandlerFunction(int);
166 static void getExecutableName_Impl (rtl_String ** ppstrProgName)
168 rtl_uString * ustrProgFile = 0;
169 osl_getExecutableFile (&ustrProgFile);
170 if (ustrProgFile)
172 rtl_uString * ustrProgName = 0;
173 osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName);
174 if (ustrProgName != 0)
176 rtl_uString2String (
177 ppstrProgName,
178 rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName),
179 osl_getThreadTextEncoding(),
180 OUSTRING_TO_OSTRING_CVTFLAGS);
181 rtl_uString_release (ustrProgName);
183 rtl_uString_release (ustrProgFile);
187 static sal_Bool is_soffice_Impl (void)
189 sal_Int32 idx = -1;
190 rtl_String * strProgName = 0;
192 getExecutableName_Impl (&strProgName);
193 if (strProgName)
195 idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice");
196 rtl_string_release (strProgName);
198 return (idx != -1);
201 static sal_Bool InitSignal()
203 int i;
204 struct sigaction act;
205 struct sigaction oact;
206 sigset_t unset;
208 if (is_soffice_Impl())
210 sal_uInt32 argi;
211 sal_uInt32 argc;
212 rtl_uString *ustrCommandArg = 0;
214 argc = osl_getCommandArgCount();
215 for ( argi = 0; argi < argc; argi++ )
217 if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg))
219 if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean"))
221 bDoHardKill = sal_True;
222 break;
226 if (ustrCommandArg)
228 rtl_uString_release (ustrCommandArg);
229 ustrCommandArg = 0;
232 // WORKAROUND FOR SEGV HANDLER CONFLICT
234 // the java jit needs SIGSEGV for proper work
235 // and we need SIGSEGV for the office crashguard
237 // TEMPORARY SOLUTION:
238 // the office sets the signal handler during startup
239 // java can than overwrite it, if needed
240 bSetSEGVHandler = sal_True;
242 // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
243 bSetWINCHHandler = sal_True;
245 // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
246 bSetILLHandler = sal_True;
249 SignalListMutex = osl_createMutex();
251 act.sa_handler = SignalHandlerFunction;
252 act.sa_flags = SA_RESTART;
254 sigfillset(&(act.sa_mask));
256 /* Initialize the rest of the signals */
257 for (i = 0; i < NoSignals; i++)
259 /* hack: stomcatd is attaching JavaVM wich dont work with an sigaction(SEGV) */
260 if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV)
261 && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH)
262 && (bSetILLHandler || Signals[i].Signal != SIGILL))
264 if (Signals[i].Action != ACT_SYSTEM)
266 if (Signals[i].Action == ACT_HIDE)
268 struct sigaction ign;
270 ign.sa_handler = SIG_IGN;
271 ign.sa_flags = 0;
272 sigemptyset(&ign.sa_mask);
274 if (sigaction(Signals[i].Signal, &ign, &oact) == 0)
275 Signals[i].Handler = oact.sa_handler;
276 else
277 Signals[i].Handler = SIG_DFL;
279 else
280 if (sigaction(Signals[i].Signal, &act, &oact) == 0)
281 Signals[i].Handler = oact.sa_handler;
282 else
283 Signals[i].Handler = SIG_DFL;
288 /* Clear signal mask inherited from parent process (on Mac OS X, upon a
289 crash soffice re-execs itself from within the signal handler, so the
290 second soffice would have the guilty signal blocked and would freeze upon
291 encountering a similar crash again): */
292 if (sigemptyset(&unset) < 0 ||
293 pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0)
295 OSL_TRACE("sigemptyset or pthread_sigmask failed");
298 return sal_True;
301 static sal_Bool DeInitSignal()
303 int i;
304 struct sigaction act;
306 act.sa_flags = 0;
307 sigemptyset(&(act.sa_mask));
309 /* Initialize the rest of the signals */
310 for (i = NoSignals - 1; i >= 0; i--)
311 if (Signals[i].Action != ACT_SYSTEM)
313 act.sa_handler = Signals[i].Handler;
315 sigaction(Signals[i].Signal, &act, NULL);
318 osl_destroyMutex(SignalListMutex);
320 return sal_False;
323 #if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE)
325 /*****************************************************************************/
326 /* Generate MD5 checksum */
327 /*****************************************************************************/
329 static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
331 sal_uInt32 nBytesProcessed = 0;
333 FILE *fp = fopen( filename, "r" );
335 if ( fp )
337 rtlDigest digest = rtl_digest_createMD5();
339 if ( digest )
341 size_t nBytesRead;
342 sal_uInt8 buffer[4096];
343 rtlDigestError error = rtl_Digest_E_None;
345 while ( rtl_Digest_E_None == error &&
346 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
348 error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
349 nBytesProcessed += nBytesRead;
352 if ( rtl_Digest_E_None == error )
354 error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
357 if ( rtl_Digest_E_None != error )
358 nBytesProcessed = 0;
360 rtl_digest_destroyMD5( digest );
363 fclose( fp );
366 return nBytesProcessed;
369 /*****************************************************************************/
370 /* Call crash reporter */
371 /*****************************************************************************/
373 /* Helper function to encode and write a string to a stream */
375 static int fputs_xml( const char *string, FILE *stream )
377 int result = 0;
379 while ( result >= 0 && *string )
381 switch( *string )
383 case '&':
384 result = fputs( "&amp;", stream );
385 break;
386 case '<':
387 result = fputs( "&lt;", stream );
388 break;
389 case '>':
390 result = fputs( "&gt;", stream );
391 break;
392 default:
393 result = fputc( *string, stream );
394 break;
397 string++;
400 return result;
402 #endif
404 /* Create intermediate files and run crash reporter */
406 #define REPORTENV_PARAM "-crashreportenv:"
408 #if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \
409 defined LINUX
411 typedef struct
413 const char *name;
414 ElfW(Off) offset;
415 } dynamic_entry;
417 static int
418 callback(struct dl_phdr_info *info, size_t size, void *data)
420 const ElfW(Phdr) *pDynamic = NULL;
422 if (size == sizeof(struct dl_phdr_info))
424 int i;
425 for (i = 0; i < info->dlpi_phnum; ++i)
427 if (info->dlpi_phdr[i].p_type == PT_DYNAMIC)
429 pDynamic = &(info->dlpi_phdr[i]);
430 break;
435 if (pDynamic)
437 char buffer[100];
438 int len;
439 char exe[PATH_MAX];
440 const char *dsoname = info->dlpi_name;
442 dynamic_entry* entry = (dynamic_entry*)data;
444 if (strcmp(dsoname, "") == 0)
446 snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid());
447 if ((len = readlink(buffer, exe, PATH_MAX)) != -1)
449 exe[len] = '\0';
450 dsoname = exe;
454 if (strcmp(dsoname, entry->name) == 0)
456 entry->offset = pDynamic->p_offset;
457 return 1;
460 return 0;
463 /* Get the location of the .dynamic section offset for the given elf file.
464 * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo
466 * We want to know this value so that if the binaries have been modifed
467 * by prelink then we can still process the call stack on server side
468 * by comparing this value to that of an "un-prelinked but known to be
469 * otherwise equivalent" version of those binaries and adjust the call
470 * stack addresses by the differences between .dynamic addresses so as
471 * to be able to map the prelinked addresses back to the unprelinked
472 * addresses
474 * cmc@openoffice.org
476 static ElfW(Off)
477 dynamic_section_offset(const char *name)
479 dynamic_entry entry;
481 entry.name = name;
482 entry.offset = 0;
484 dl_iterate_phdr(callback, &entry);
486 return entry.offset;
488 #endif
490 static int ReportCrash( int Signal )
492 #ifdef SAL_ENABLE_CRASH_REPORT
493 static sal_Bool bCrashReporterExecuted = sal_False;
494 sal_Bool bAutoCrashReport = sal_False;
496 sal_uInt32 argi;
497 sal_uInt32 argc;
498 rtl_uString *ustrCommandArg = NULL;
500 if ( !bErrorReportingEnabled )
501 return -1;
503 argc = osl_getCommandArgCount();
505 for ( argi = 0; argi < argc; argi++ )
507 if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) )
509 if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-nocrashreport" ) )
511 rtl_uString_release( ustrCommandArg );
512 return -1;
514 else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-autocrashreport" ) )
516 bAutoCrashReport = sal_True;
518 else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength(
519 rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ),
520 REPORTENV_PARAM, strlen(REPORTENV_PARAM) )
523 rtl_uString *ustrEnvironment = NULL;
524 rtl_String *strEnv = NULL;
526 rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) );
528 if ( ustrEnvironment )
530 rtl_uString2String(
531 &strEnv,
532 rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ),
533 osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS
536 if ( strEnv )
538 putenv( rtl_string_getStr( strEnv ) );
539 rtl_string_release( strEnv );
542 rtl_uString_release( ustrEnvironment );
550 if ( ustrCommandArg )
551 rtl_uString_release( ustrCommandArg );
553 if ( !bCrashReporterExecuted )
555 int i;
556 /* struct sigaction act; */
558 for (i = 0; i < NoSignals; i++)
560 if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT )
562 int ret;
563 char szShellCmd[512] = { '\0' };
564 char *pXMLTempName = NULL;
565 char *pStackTempName = NULL;
566 char *pChecksumTempName = NULL;
568 #ifdef INCLUDE_BACKTRACE
569 char szXMLTempNameBuffer[L_tmpnam];
570 char szChecksumTempNameBuffer[L_tmpnam];
571 char szStackTempNameBuffer[L_tmpnam];
573 void *stackframes[MAX_STACK_FRAMES];
574 int iFrame;
575 int nFrames = backtrace( stackframes, sizeof(stackframes)/sizeof(stackframes[0]));
577 FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL;
578 int fdxml, fdstk, fdchksum;
580 strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) );
581 strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) );
583 strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) );
584 strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) );
586 strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) );
587 strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) );
589 fdxml = mkstemp(szXMLTempNameBuffer);
590 fdstk = mkstemp(szStackTempNameBuffer);
591 fdchksum = mkstemp(szChecksumTempNameBuffer);
593 xmlout = fdopen( fdxml , "w" );
594 stackout = fdopen( fdstk , "w" );
595 checksumout = fdopen( fdchksum, "w" );
597 pXMLTempName = szXMLTempNameBuffer;
598 pStackTempName = szStackTempNameBuffer;
599 pChecksumTempName = szChecksumTempNameBuffer;
602 if ( xmlout && stackout && checksumout )
604 fprintf( xmlout, "<errormail:Stack type=\"%s\">\n", STACKTYPE );
606 fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\n" );
608 for ( iFrame = 0; iFrame < nFrames; iFrame++ )
610 Dl_info dl_info;
612 fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":",
613 SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) );
615 fprintf( xmlout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"",
616 iFrame,
617 SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame])
620 memset( &dl_info, 0, sizeof(dl_info) );
622 /* dladdr may fail */
623 if ( dladdr( stackframes[iFrame], &dl_info) )
625 const char *dli_fname = NULL;
626 char *dli_fdir = NULL;
627 char szDirectory[PATH_MAX];
628 char szCanonicDirectory[PATH_MAX];
630 /* Don't expect that dladdr filled all members of dl_info */
632 dli_fname = dl_info.dli_fname ? strrchr( dl_info.dli_fname, '/' ) : NULL;
633 if ( dli_fname )
635 ++dli_fname;
636 memcpy( szDirectory, dl_info.dli_fname, dli_fname - dl_info.dli_fname );
637 szDirectory[dli_fname - dl_info.dli_fname] = 0;
639 dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory;
641 if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' )
642 strcat( dli_fdir, "/" );
644 else
645 dli_fname = dl_info.dli_fname;
647 /* create checksum of library on stack */
648 if ( dli_fname )
650 sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
652 sal_uInt32 nBytesProcessed = calc_md5_checksum(
653 dl_info.dli_fname, checksum, sizeof(checksum) );
654 if ( nBytesProcessed )
656 int j;
658 fprintf( checksumout, "<errormail:Checksum sum=\"0x" );
659 for ( j = 0; j < 16; fprintf( checksumout, "%02X", checksum[j++] ) );
660 fprintf( checksumout,
661 "\" bytes=\"%lu\" file=\"%s\"/>\n",
662 SAL_INT_CAST(
663 unsigned long, nBytesProcessed),
664 dli_fname );
668 if ( dl_info.dli_fbase && dl_info.dli_fname )
670 #ifdef LINUX
671 ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname);
672 fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset);
673 #endif
675 fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x",
676 dl_info.dli_fname,
677 (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase
680 fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase );
681 if ( dli_fname )
682 fprintf( xmlout, " name=\"%s\"", dli_fname );
684 if ( dli_fdir )
685 fprintf( xmlout, " path=\"%s\"", dli_fdir );
687 #ifdef LINUX
688 fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset );
689 #endif
691 else
692 fprintf( stackout, " ????????" );
694 if ( dl_info.dli_sname && dl_info.dli_saddr )
696 fputs( " (", stackout );
697 fputs_xml( dl_info.dli_sname, stackout );
698 fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)",
699 (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr );
701 fputs( " ordinal=\"", xmlout );
702 fputs_xml( dl_info.dli_sname, xmlout );
703 fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"",
704 (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr );
708 else /* dladdr failed */
710 fprintf( stackout, " ????????" );
713 fprintf( stackout, "\n" );
714 fprintf( xmlout, "/>\n" );
718 fprintf( xmlout, "</errormail:Stack>\n" );
719 fprintf( checksumout, "</errormail:Checksums>\n" );
721 else
723 pXMLTempName = NULL;
724 pStackTempName = NULL;
725 pChecksumTempName = NULL;
728 if ( stackout )
729 fclose( stackout );
730 if ( xmlout )
731 fclose( xmlout );
732 if ( checksumout )
733 fclose( checksumout );
735 if ( pXMLTempName && pChecksumTempName && pStackTempName )
736 #endif /* INCLUDE_BACKTRACE */
738 rtl_uString * crashrep_url = NULL;
739 rtl_uString * crashrep_path = NULL;
740 rtl_String * crashrep_path_system = NULL;
741 rtl_string2UString(
742 &crashrep_url,
743 RTL_CONSTASCII_USTRINGPARAM(
744 "$BRAND_BASE_DIR/program/crashrep"),
745 OSTRING_TO_OUSTRING_CVTFLAGS);
746 rtl_bootstrap_expandMacros(&crashrep_url);
747 osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path);
748 rtl_uString2String(
749 &crashrep_path_system,
750 rtl_uString_getStr(crashrep_path),
751 rtl_uString_getLength(crashrep_path),
752 osl_getThreadTextEncoding(),
753 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
754 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR));
755 rtl_uString_release(crashrep_url);
756 rtl_uString_release(crashrep_path);
757 #if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX)
758 snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
759 "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s",
760 rtl_string_getStr(crashrep_path_system),
761 getpid(),
762 Signal,
763 pXMLTempName,
764 pChecksumTempName,
765 pStackTempName,
766 bAutoCrashReport ? " -send" : "" );
767 #elif defined INCLUDE_BACKTRACE && defined SOLARIS
768 snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
769 "%s -p %d -s %d -xml %s -chksum %s -noui%s",
770 rtl_string_getStr(crashrep_path_system),
771 getpid(),
772 Signal,
773 pXMLTempName,
774 pChecksumTempName,
775 bAutoCrashReport ? " -send" : "" );
776 #else
777 snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
778 "%s -p %d -s %d -noui%s",
779 rtl_string_getStr(crashrep_path_system),
780 getpid(), Signal, bAutoCrashReport ? " -send" : "" );
781 #endif
782 rtl_string_release(crashrep_path_system);
785 ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd );
787 if ( pXMLTempName )
788 unlink( pXMLTempName );
790 if ( pStackTempName )
791 unlink( pStackTempName );
793 if ( pChecksumTempName )
794 unlink( pChecksumTempName );
796 if ( -1 != ret )
798 bCrashReporterExecuted = sal_True;
799 return 1;
801 else
802 return -1;
807 return 0;
810 return 1;
811 #else /* defined SAL_ENABLE_CRASH_REPORT */
812 /* the utility crash_report is not build, so do the same as when
813 the option -nocrashreport is used */
814 (void) Signal; // avoid warnings
815 return -1;
816 #endif /* defined SAL_ENABLE_CRASH_REPORT */
819 static void PrintStack( int sig )
821 #if ! defined(MACOSX) || defined(INCLUDE_BACKTRACE)
822 void *buffer[MAX_STACK_FRAMES];
823 int size = backtrace( buffer, sizeof(buffer) / sizeof(buffer[0]) );
824 #endif
826 fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
828 #if defined(MACOSX) && ! defined(INCLUDE_BACKTRACE)
829 fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
830 #else
831 if ( size > 0 )
833 fputs( "Stack:\n", stderr );
834 backtrace_symbols_fd( buffer, size, fileno(stderr) );
836 #endif
839 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
841 oslSignalHandlerImpl* pHandler = SignalList;
842 oslSignalAction Action = osl_Signal_ActCallNextHdl;
844 while (pHandler != NULL)
846 if ((Action = pHandler->Handler(pHandler->pData, pInfo))
847 != osl_Signal_ActCallNextHdl)
848 break;
850 pHandler = pHandler->pNext;
853 return Action;
856 void CallSystemHandler(int Signal)
858 int i;
859 struct sigaction act;
861 for (i = 0; i < NoSignals; i++)
863 if (Signals[i].Signal == Signal)
864 break;
867 if (i < NoSignals)
869 if ((Signals[i].Handler == NULL) ||
870 (Signals[i].Handler == SIG_DFL) ||
871 (Signals[i].Handler == SIG_IGN) ||
872 (Signals[i].Handler == SIG_ERR))
874 switch (Signals[i].Action)
876 case ACT_EXIT: /* terminate */
877 /* prevent dumping core on exit() */
878 _exit(255);
879 break;
881 case ACT_ABORT: /* terminate witch core dump */
882 ReportCrash( Signal );
883 act.sa_handler = SIG_DFL;
884 act.sa_flags = 0;
885 sigemptyset(&(act.sa_mask));
886 sigaction(SIGABRT, &act, NULL);
887 PrintStack( Signal );
888 abort();
889 break;
891 case ACT_IGNORE: /* ignore */
892 break;
894 default: /* should never happen */
895 OSL_ASSERT(0);
898 else
899 (*Signals[i].Handler)(Signal);
904 /*****************************************************************************/
905 /* SignalHandlerFunction */
906 /*****************************************************************************/
907 void SignalHandlerFunction(int Signal)
909 oslSignalInfo Info;
910 struct sigaction act;
912 Info.UserSignal = Signal;
913 Info.UserData = NULL;
915 switch (Signal)
917 case SIGBUS:
918 case SIGILL:
919 case SIGSEGV:
920 case SIGIOT:
921 #if ( SIGIOT != SIGABRT )
922 case SIGABRT:
923 #endif
924 Info.Signal = osl_Signal_AccessViolation;
925 break;
927 case -1:
928 Info.Signal = osl_Signal_IntegerDivideByZero;
929 break;
931 case SIGFPE:
932 Info.Signal = osl_Signal_FloatDivideByZero;
933 break;
935 case SIGINT:
936 case SIGTERM:
937 case SIGQUIT:
938 case SIGHUP:
939 Info.Signal = osl_Signal_Terminate;
940 break;
942 default:
943 Info.Signal = osl_Signal_System;
944 break;
947 ReportCrash( Signal );
949 /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
950 if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation))
951 _exit(255);
952 /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
955 switch (CallSignalHandler(&Info))
957 case osl_Signal_ActCallNextHdl:
958 CallSystemHandler(Signal);
959 break;
961 case osl_Signal_ActAbortApp:
962 ReportCrash( Signal );
963 act.sa_handler = SIG_DFL;
964 act.sa_flags = 0;
965 sigemptyset(&(act.sa_mask));
966 sigaction(SIGABRT, &act, NULL);
967 PrintStack( Signal );
968 abort();
969 break;
971 case osl_Signal_ActKillApp:
972 /* prevent dumping core on exit() */
973 _exit(255);
974 break;
975 default:
976 break;
980 /*****************************************************************************/
981 /* osl_addSignalHandler */
982 /*****************************************************************************/
983 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
985 oslSignalHandlerImpl* pHandler;
987 OSL_ASSERT(Handler != NULL);
988 if ( Handler == 0 )
990 return 0;
993 if (! bInitSignal)
994 bInitSignal = InitSignal();
996 pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl));
998 if (pHandler != NULL)
1000 pHandler->Handler = Handler;
1001 pHandler->pData = pData;
1003 osl_acquireMutex(SignalListMutex);
1005 pHandler->pNext = SignalList;
1006 SignalList = pHandler;
1008 osl_releaseMutex(SignalListMutex);
1010 return (pHandler);
1013 return (NULL);
1016 /*****************************************************************************/
1017 /* osl_removeSignalHandler */
1018 /*****************************************************************************/
1019 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
1021 oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
1023 OSL_ASSERT(Handler != NULL);
1025 if (! bInitSignal)
1026 bInitSignal = InitSignal();
1028 osl_acquireMutex(SignalListMutex);
1030 pHandler = SignalList;
1032 while (pHandler != NULL)
1034 if (pHandler == Handler)
1036 if (pPrevious)
1037 pPrevious->pNext = pHandler->pNext;
1038 else
1039 SignalList = pHandler->pNext;
1041 osl_releaseMutex(SignalListMutex);
1043 if (SignalList == NULL)
1044 bInitSignal = DeInitSignal();
1046 free(pHandler);
1048 return (sal_True);
1051 pPrevious = pHandler;
1052 pHandler = pHandler->pNext;
1055 osl_releaseMutex(SignalListMutex);
1057 return (sal_False);
1060 /*****************************************************************************/
1061 /* osl_raiseSignal */
1062 /*****************************************************************************/
1063 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
1065 oslSignalInfo Info;
1066 oslSignalAction Action;
1068 if (! bInitSignal)
1069 bInitSignal = InitSignal();
1071 osl_acquireMutex(SignalListMutex);
1073 Info.Signal = osl_Signal_User;
1074 Info.UserSignal = UserSignal;
1075 Info.UserData = UserData;
1077 Action = CallSignalHandler(&Info);
1079 osl_releaseMutex(SignalListMutex);
1081 return (Action);
1084 /*****************************************************************************/
1085 /* osl_setErrorReporting */
1086 /*****************************************************************************/
1087 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
1089 sal_Bool bOld = bErrorReportingEnabled;
1090 bErrorReportingEnabled = bEnable;
1092 return bOld;