Bump for 3.6-28
[LibreOffice.git] / sal / osl / unx / signal.c
blob57263c7ba9a22698db244e7931227b6faf4a8466
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 /* system headers */
31 #include "system.h"
33 #define MAX_STACK_FRAMES 256
35 #if defined( MACOSX )
37 #if defined( INTEL )
38 #include "backtrace.h"
39 #define INCLUDE_BACKTRACE
40 #define STACKTYPE "MacOsX_X86"
41 #endif /* INTEL */
43 #endif /* MACOSX */
45 #ifdef LINUX
46 #include <execinfo.h>
47 #include <link.h>
48 #define INCLUDE_BACKTRACE
49 #define STACKTYPE "Linux"
50 #endif
52 #ifdef SOLARIS
54 #include "backtrace.h"
55 #define INCLUDE_BACKTRACE
57 #if defined( SPARC )
58 #define STACKTYPE "Solaris_Sparc"
59 #elif defined( INTEL )
60 #define STACKTYPE "Solaris_X86"
61 #else
62 #define STACKTYPE "Solaris_Unknown"
63 #endif
65 #endif /* defined SOLARIS */
67 #include <osl/diagnose.h>
68 #include <osl/mutex.h>
69 #include <osl/signal.h>
70 #include <osl/process.h>
71 #include <osl/thread.h>
72 #include <sal/macros.h>
73 #include <rtl/bootstrap.h>
74 #include <rtl/digest.h>
76 #include "file_path_helper.h"
78 #define ACT_IGNORE 1
79 #define ACT_EXIT 2
80 #define ACT_SYSTEM 3
81 #define ACT_HIDE 4
82 #ifdef SAL_ENABLE_CRASH_REPORT
83 # define ACT_ABORT 5
84 #else
85 # define ACT_ABORT ACT_SYSTEM
86 #endif
88 #define MAX_PATH_LEN 2048
90 #if defined(HAVE_MEMCHECK_H)
91 #include <memcheck.h>
92 #endif
94 typedef struct _oslSignalHandlerImpl
96 oslSignalHandlerFunction Handler;
97 void* pData;
98 struct _oslSignalHandlerImpl* pNext;
99 } oslSignalHandlerImpl;
101 static struct SignalAction
103 int Signal;
104 int Action;
105 void (*Handler)(int);
106 } Signals[] =
108 { SIGHUP, ACT_IGNORE, NULL }, /* hangup */
109 { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */
110 { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */
111 { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */
112 /* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/
113 { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */
114 #if ( SIGIOT != SIGABRT )
115 { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */
116 #endif
117 { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */
118 #ifdef SIGEMT
119 { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */
120 /* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/
121 /* SIGEMT may also be used by the profiler - so it is probably not a good
122 plan to have the new handler use this signal*/
123 #endif
124 { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */
125 { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */
126 { SIGBUS, ACT_ABORT, NULL }, /* bus error */
127 { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */
128 #ifdef SIGSYS
129 { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */
130 #endif
131 { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */
132 { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */
133 { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */
134 { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */
135 { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */
136 { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */
137 #ifdef SIGPWR
138 { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */
139 #endif
140 { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */
141 { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */
142 #ifdef SIGPOLL
143 { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occurred */
144 #endif
145 { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */
146 { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */
147 { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */
148 { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */
149 { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */
150 { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */
151 { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */
152 /*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do
153 not get taken by the new handler - the new handler does not pass on context
154 information which causes 'collect' to crash. This is a way of avoiding
155 what looks like a bug in the new handler*/
156 { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */
157 { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */
159 const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction);
161 static sal_Bool bErrorReportingEnabled = sal_True;
162 static sal_Bool bInitSignal = sal_False;
163 static oslMutex SignalListMutex;
164 static oslSignalHandlerImpl* SignalList;
165 static sal_Bool bDoHardKill = sal_False;
166 static sal_Bool bSetSEGVHandler = sal_False;
167 static sal_Bool bSetWINCHHandler = sal_False;
168 static sal_Bool bSetILLHandler = sal_False;
170 static void SignalHandlerFunction(int);
172 static void getExecutableName_Impl (rtl_String ** ppstrProgName)
174 rtl_uString * ustrProgFile = 0;
175 osl_getExecutableFile (&ustrProgFile);
176 if (ustrProgFile)
178 rtl_uString * ustrProgName = 0;
179 osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName);
180 if (ustrProgName != 0)
182 rtl_uString2String (
183 ppstrProgName,
184 rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName),
185 osl_getThreadTextEncoding(),
186 OUSTRING_TO_OSTRING_CVTFLAGS);
187 rtl_uString_release (ustrProgName);
189 rtl_uString_release (ustrProgFile);
193 static sal_Bool is_soffice_Impl (void)
195 sal_Int32 idx = -1;
196 rtl_String * strProgName = 0;
198 getExecutableName_Impl (&strProgName);
199 if (strProgName)
201 idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice");
202 rtl_string_release (strProgName);
204 return (idx != -1);
207 static sal_Bool InitSignal()
209 int i;
210 struct sigaction act;
211 struct sigaction oact;
212 sigset_t unset;
214 if (is_soffice_Impl())
216 sal_uInt32 argi;
217 sal_uInt32 argc;
218 rtl_uString *ustrCommandArg = 0;
220 argc = osl_getCommandArgCount();
221 for ( argi = 0; argi < argc; argi++ )
223 if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg))
225 if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean"))
227 bDoHardKill = sal_True;
228 break;
232 if (ustrCommandArg)
234 rtl_uString_release (ustrCommandArg);
235 ustrCommandArg = 0;
238 // WORKAROUND FOR SEGV HANDLER CONFLICT
240 // the java jit needs SIGSEGV for proper work
241 // and we need SIGSEGV for the office crashguard
243 // TEMPORARY SOLUTION:
244 // the office sets the signal handler during startup
245 // java can than overwrite it, if needed
246 bSetSEGVHandler = sal_True;
248 // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
249 bSetWINCHHandler = sal_True;
251 // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
252 bSetILLHandler = sal_True;
255 #ifdef DBG_UTIL
256 bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = bDoHardKill = sal_False;
257 #endif
259 SignalListMutex = osl_createMutex();
261 act.sa_handler = SignalHandlerFunction;
262 act.sa_flags = SA_RESTART;
264 sigfillset(&(act.sa_mask));
266 /* Initialize the rest of the signals */
267 for (i = 0; i < NoSignals; ++i)
269 #if defined(HAVE_MEMCHECK_H)
270 if (Signals[i].Signal == SIGUSR2 && RUNNING_ON_VALGRIND)
271 Signals[i].Action = ACT_IGNORE;
272 #endif
274 /* hack: stomcatd is attaching JavaVM wich dont work with an sigaction(SEGV) */
275 if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV)
276 && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH)
277 && (bSetILLHandler || Signals[i].Signal != SIGILL))
279 if (Signals[i].Action != ACT_SYSTEM)
281 if (Signals[i].Action == ACT_HIDE)
283 struct sigaction ign;
285 ign.sa_handler = SIG_IGN;
286 ign.sa_flags = 0;
287 sigemptyset(&ign.sa_mask);
289 if (sigaction(Signals[i].Signal, &ign, &oact) == 0)
290 Signals[i].Handler = oact.sa_handler;
291 else
292 Signals[i].Handler = SIG_DFL;
294 else
296 if (sigaction(Signals[i].Signal, &act, &oact) == 0)
297 Signals[i].Handler = oact.sa_handler;
298 else
299 Signals[i].Handler = SIG_DFL;
305 /* Clear signal mask inherited from parent process (on Mac OS X, upon a
306 crash soffice re-execs itself from within the signal handler, so the
307 second soffice would have the guilty signal blocked and would freeze upon
308 encountering a similar crash again): */
309 if (sigemptyset(&unset) < 0 ||
310 pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0)
312 OSL_TRACE("sigemptyset or pthread_sigmask failed");
315 return sal_True;
318 static sal_Bool DeInitSignal()
320 int i;
321 struct sigaction act;
323 act.sa_flags = 0;
324 sigemptyset(&(act.sa_mask));
326 /* Initialize the rest of the signals */
327 for (i = NoSignals - 1; i >= 0; i--)
328 if (Signals[i].Action != ACT_SYSTEM)
330 act.sa_handler = Signals[i].Handler;
332 sigaction(Signals[i].Signal, &act, NULL);
335 osl_destroyMutex(SignalListMutex);
337 return sal_False;
340 #if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE)
342 /*****************************************************************************/
343 /* Generate MD5 checksum */
344 /*****************************************************************************/
346 static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
348 sal_uInt32 nBytesProcessed = 0;
350 FILE *fp = fopen( filename, "r" );
352 if ( fp )
354 rtlDigest digest = rtl_digest_createMD5();
356 if ( digest )
358 size_t nBytesRead;
359 sal_uInt8 buffer[4096];
360 rtlDigestError error = rtl_Digest_E_None;
362 while ( rtl_Digest_E_None == error &&
363 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
365 error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
366 nBytesProcessed += nBytesRead;
369 if ( rtl_Digest_E_None == error )
371 error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
374 if ( rtl_Digest_E_None != error )
375 nBytesProcessed = 0;
377 rtl_digest_destroyMD5( digest );
380 fclose( fp );
383 return nBytesProcessed;
386 /*****************************************************************************/
387 /* Call crash reporter */
388 /*****************************************************************************/
390 /* Helper function to encode and write a string to a stream */
392 static int fputs_xml( const char *string, FILE *stream )
394 int result = 0;
396 while ( result >= 0 && *string )
398 switch( *string )
400 case '&':
401 result = fputs( "&amp;", stream );
402 break;
403 case '<':
404 result = fputs( "&lt;", stream );
405 break;
406 case '>':
407 result = fputs( "&gt;", stream );
408 break;
409 default:
410 result = fputc( *string, stream );
411 break;
414 string++;
417 return result;
419 #endif
421 /* Create intermediate files and run crash reporter */
423 #define REPORTENV_PARAM "-crashreportenv:"
425 #if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \
426 defined LINUX
428 typedef struct
430 const char *name;
431 ElfW(Off) offset;
432 } dynamic_entry;
434 static int
435 callback(struct dl_phdr_info *info, size_t size, void *data)
437 const ElfW(Phdr) *pDynamic = NULL;
439 if (size == sizeof(struct dl_phdr_info))
441 int i;
442 for (i = 0; i < info->dlpi_phnum; ++i)
444 if (info->dlpi_phdr[i].p_type == PT_DYNAMIC)
446 pDynamic = &(info->dlpi_phdr[i]);
447 break;
452 if (pDynamic)
454 char buffer[100];
455 int len;
456 char exe[PATH_MAX];
457 const char *dsoname = info->dlpi_name;
459 dynamic_entry* entry = (dynamic_entry*)data;
461 if (strcmp(dsoname, "") == 0)
463 snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid());
464 if ((len = readlink(buffer, exe, PATH_MAX)) != -1)
466 exe[len] = '\0';
467 dsoname = exe;
471 if (strcmp(dsoname, entry->name) == 0)
473 entry->offset = pDynamic->p_offset;
474 return 1;
477 return 0;
480 /* Get the location of the .dynamic section offset for the given elf file.
481 * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo
483 * We want to know this value so that if the binaries have been modifed
484 * by prelink then we can still process the call stack on server side
485 * by comparing this value to that of an "un-prelinked but known to be
486 * otherwise equivalent" version of those binaries and adjust the call
487 * stack addresses by the differences between .dynamic addresses so as
488 * to be able to map the prelinked addresses back to the unprelinked
489 * addresses
491 * cmc@openoffice.org
493 static ElfW(Off)
494 dynamic_section_offset(const char *name)
496 dynamic_entry entry;
498 entry.name = name;
499 entry.offset = 0;
501 dl_iterate_phdr(callback, &entry);
503 return entry.offset;
505 #endif
507 static int ReportCrash( int Signal )
509 #ifdef SAL_ENABLE_CRASH_REPORT
510 static sal_Bool bCrashReporterExecuted = sal_False;
511 sal_Bool bAutoCrashReport = sal_False;
513 sal_uInt32 argi;
514 sal_uInt32 argc;
515 rtl_uString *ustrCommandArg = NULL;
517 if ( !bErrorReportingEnabled )
518 return -1;
520 argc = osl_getCommandArgCount();
522 for ( argi = 0; argi < argc; argi++ )
524 if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) )
526 if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--nocrashreport" ) )
528 rtl_uString_release( ustrCommandArg );
529 return -1;
531 else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--autocrashreport" ) )
533 bAutoCrashReport = sal_True;
535 else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength(
536 rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ),
537 REPORTENV_PARAM, strlen(REPORTENV_PARAM) )
540 rtl_uString *ustrEnvironment = NULL;
541 rtl_String *strEnv = NULL;
543 rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) );
545 if ( ustrEnvironment )
547 rtl_uString2String(
548 &strEnv,
549 rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ),
550 osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS
553 if ( strEnv )
555 putenv( rtl_string_getStr( strEnv ) );
556 rtl_string_release( strEnv );
559 rtl_uString_release( ustrEnvironment );
567 if ( ustrCommandArg )
568 rtl_uString_release( ustrCommandArg );
570 if ( !bCrashReporterExecuted )
572 int i;
573 /* struct sigaction act; */
575 for (i = 0; i < NoSignals; i++)
577 if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT )
579 int ret;
580 char szShellCmd[512] = { '\0' };
581 char *pXMLTempName = NULL;
582 char *pStackTempName = NULL;
583 char *pChecksumTempName = NULL;
585 #ifdef INCLUDE_BACKTRACE
586 char szXMLTempNameBuffer[L_tmpnam];
587 char szChecksumTempNameBuffer[L_tmpnam];
588 char szStackTempNameBuffer[L_tmpnam];
590 void *stackframes[MAX_STACK_FRAMES];
591 int iFrame;
592 int nFrames = backtrace( stackframes, SAL_N_ELEMENTS(stackframes) );
594 FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL;
595 int fdxml, fdstk, fdchksum;
597 strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) );
598 strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) );
600 strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) );
601 strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) );
603 strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) );
604 strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) );
606 fdxml = mkstemp(szXMLTempNameBuffer);
607 fdstk = mkstemp(szStackTempNameBuffer);
608 fdchksum = mkstemp(szChecksumTempNameBuffer);
610 xmlout = fdopen( fdxml , "w" );
611 stackout = fdopen( fdstk , "w" );
612 checksumout = fdopen( fdchksum, "w" );
614 pXMLTempName = szXMLTempNameBuffer;
615 pStackTempName = szStackTempNameBuffer;
616 pChecksumTempName = szChecksumTempNameBuffer;
619 if ( xmlout && stackout && checksumout )
621 fprintf( xmlout, "<errormail:Stack type=\"%s\">\n", STACKTYPE );
623 fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\n" );
625 for ( iFrame = 0; iFrame < nFrames; iFrame++ )
627 Dl_info dl_info;
629 fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":",
630 SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) );
632 fprintf( xmlout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"",
633 iFrame,
634 SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame])
637 memset( &dl_info, 0, sizeof(dl_info) );
639 /* dladdr may fail */
640 if ( dladdr( stackframes[iFrame], &dl_info) )
642 const char *dli_fname = NULL;
643 char *dli_fdir = NULL;
644 char szDirectory[PATH_MAX];
645 char szCanonicDirectory[PATH_MAX];
647 /* Don't expect that dladdr filled all members of dl_info */
649 dli_fname = dl_info.dli_fname ? strrchr( dl_info.dli_fname, '/' ) : NULL;
650 if ( dli_fname )
652 ++dli_fname;
653 memcpy( szDirectory, dl_info.dli_fname, dli_fname - dl_info.dli_fname );
654 szDirectory[dli_fname - dl_info.dli_fname] = 0;
656 dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory;
658 if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' )
659 strcat( dli_fdir, "/" );
661 else
662 dli_fname = dl_info.dli_fname;
664 /* create checksum of library on stack */
665 if ( dli_fname )
667 sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
669 sal_uInt32 nBytesProcessed = calc_md5_checksum(
670 dl_info.dli_fname, checksum, sizeof(checksum) );
671 if ( nBytesProcessed )
673 int j;
675 fprintf( checksumout, "<errormail:Checksum sum=\"0x" );
676 for ( j = 0; j < 16; fprintf( checksumout, "%02X", checksum[j++] ) );
677 fprintf( checksumout,
678 "\" bytes=\"%lu\" file=\"%s\"/>\n",
679 SAL_INT_CAST(
680 unsigned long, nBytesProcessed),
681 dli_fname );
685 if ( dl_info.dli_fbase && dl_info.dli_fname )
687 #ifdef LINUX
688 ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname);
689 fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset);
690 #endif
692 fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x",
693 dl_info.dli_fname,
694 (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase
697 fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase );
698 if ( dli_fname )
699 fprintf( xmlout, " name=\"%s\"", dli_fname );
701 if ( dli_fdir )
702 fprintf( xmlout, " path=\"%s\"", dli_fdir );
704 #ifdef LINUX
705 fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset );
706 #endif
708 else
709 fprintf( stackout, " ????????" );
711 if ( dl_info.dli_sname && dl_info.dli_saddr )
713 fputs( " (", stackout );
714 fputs_xml( dl_info.dli_sname, stackout );
715 fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)",
716 (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr );
718 fputs( " ordinal=\"", xmlout );
719 fputs_xml( dl_info.dli_sname, xmlout );
720 fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"",
721 (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr );
725 else /* dladdr failed */
727 fprintf( stackout, " ????????" );
730 fprintf( stackout, "\n" );
731 fprintf( xmlout, "/>\n" );
735 fprintf( xmlout, "</errormail:Stack>\n" );
736 fprintf( checksumout, "</errormail:Checksums>\n" );
738 else
740 pXMLTempName = NULL;
741 pStackTempName = NULL;
742 pChecksumTempName = NULL;
745 if ( stackout )
746 fclose( stackout );
747 if ( xmlout )
748 fclose( xmlout );
749 if ( checksumout )
750 fclose( checksumout );
752 if ( pXMLTempName && pChecksumTempName && pStackTempName )
753 #endif /* INCLUDE_BACKTRACE */
755 rtl_uString * crashrep_url = NULL;
756 rtl_uString * crashrep_path = NULL;
757 rtl_String * crashrep_path_system = NULL;
758 rtl_string2UString(
759 &crashrep_url,
760 RTL_CONSTASCII_USTRINGPARAM(
761 "$BRAND_BASE_DIR/program/crashrep"),
762 OSTRING_TO_OUSTRING_CVTFLAGS);
763 rtl_bootstrap_expandMacros(&crashrep_url);
764 osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path);
765 rtl_uString2String(
766 &crashrep_path_system,
767 rtl_uString_getStr(crashrep_path),
768 rtl_uString_getLength(crashrep_path),
769 osl_getThreadTextEncoding(),
770 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
771 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR));
772 rtl_uString_release(crashrep_url);
773 rtl_uString_release(crashrep_path);
774 #if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX)
775 snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
776 "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s",
777 rtl_string_getStr(crashrep_path_system),
778 getpid(),
779 Signal,
780 pXMLTempName,
781 pChecksumTempName,
782 pStackTempName,
783 bAutoCrashReport ? " -send" : "" );
784 #elif defined INCLUDE_BACKTRACE && defined SOLARIS
785 snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
786 "%s -p %d -s %d -xml %s -chksum %s -noui%s",
787 rtl_string_getStr(crashrep_path_system),
788 getpid(),
789 Signal,
790 pXMLTempName,
791 pChecksumTempName,
792 bAutoCrashReport ? " -send" : "" );
793 #else
794 snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
795 "%s -p %d -s %d -noui%s",
796 rtl_string_getStr(crashrep_path_system),
797 getpid(), Signal, bAutoCrashReport ? " -send" : "" );
798 #endif
799 rtl_string_release(crashrep_path_system);
802 ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd );
804 if ( pXMLTempName )
805 unlink( pXMLTempName );
807 if ( pStackTempName )
808 unlink( pStackTempName );
810 if ( pChecksumTempName )
811 unlink( pChecksumTempName );
813 if ( -1 != ret )
815 bCrashReporterExecuted = sal_True;
816 return 1;
818 else
819 return -1;
824 return 0;
827 return 1;
828 #else /* defined SAL_ENABLE_CRASH_REPORT */
829 /* the utility crash_report is not build, so do the same as when
830 the option -nocrashreport is used */
831 (void) Signal; // avoid warnings
832 return -1;
833 #endif /* defined SAL_ENABLE_CRASH_REPORT */
836 static void PrintStack( int sig )
838 #ifdef INCLUDE_BACKTRACE
839 void *buffer[MAX_STACK_FRAMES];
840 int size = backtrace( buffer, SAL_N_ELEMENTS(buffer) );
841 #endif
843 fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
845 #if defined( MACOSX ) && !defined( INCLUDE_BACKTRACE )
846 fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
847 #else
848 #ifdef INCLUDE_BACKTRACE
849 if ( size > 0 )
851 fputs( "Stack:\n", stderr );
852 backtrace_symbols_fd( buffer, size, fileno(stderr) );
854 #endif
855 #endif
858 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
860 oslSignalHandlerImpl* pHandler = SignalList;
861 oslSignalAction Action = osl_Signal_ActCallNextHdl;
863 while (pHandler != NULL)
865 if ((Action = pHandler->Handler(pHandler->pData, pInfo))
866 != osl_Signal_ActCallNextHdl)
867 break;
869 pHandler = pHandler->pNext;
872 return Action;
875 void CallSystemHandler(int Signal)
877 int i;
878 struct sigaction act;
880 for (i = 0; i < NoSignals; i++)
882 if (Signals[i].Signal == Signal)
883 break;
886 if (i < NoSignals)
888 if ((Signals[i].Handler == NULL) ||
889 (Signals[i].Handler == SIG_DFL) ||
890 (Signals[i].Handler == SIG_IGN) ||
891 (Signals[i].Handler == SIG_ERR))
893 switch (Signals[i].Action)
895 case ACT_EXIT: /* terminate */
896 /* prevent dumping core on exit() */
897 _exit(255);
898 break;
900 case ACT_ABORT: /* terminate witch core dump */
901 ReportCrash( Signal );
902 act.sa_handler = SIG_DFL;
903 act.sa_flags = 0;
904 sigemptyset(&(act.sa_mask));
905 sigaction(SIGABRT, &act, NULL);
906 PrintStack( Signal );
907 abort();
908 break;
910 case ACT_IGNORE: /* ignore */
911 break;
913 default: /* should never happen */
914 OSL_ASSERT(0);
917 else
918 (*Signals[i].Handler)(Signal);
922 #if defined(HAVE_MEMCHECK_H)
923 static void DUMPCURRENTALLOCS()
925 VALGRIND_PRINTF( "=== start memcheck dump of active allocations ===\n" );
927 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
928 # pragma GCC diagnostic push
929 # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
930 #endif
932 VALGRIND_DO_LEAK_CHECK;
934 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
935 # pragma GCC diagnostic pop
936 #endif
938 VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" );
940 #endif
942 /*****************************************************************************/
943 /* SignalHandlerFunction */
944 /*****************************************************************************/
945 void SignalHandlerFunction(int Signal)
947 oslSignalInfo Info;
948 struct sigaction act;
950 Info.UserSignal = Signal;
951 Info.UserData = NULL;
953 switch (Signal)
955 case SIGBUS:
956 case SIGILL:
957 case SIGSEGV:
958 case SIGIOT:
959 #if ( SIGIOT != SIGABRT )
960 case SIGABRT:
961 #endif
962 Info.Signal = osl_Signal_AccessViolation;
963 break;
965 case -1:
966 Info.Signal = osl_Signal_IntegerDivideByZero;
967 break;
969 case SIGFPE:
970 Info.Signal = osl_Signal_FloatDivideByZero;
971 break;
973 case SIGINT:
974 case SIGTERM:
975 case SIGQUIT:
976 case SIGHUP:
977 Info.Signal = osl_Signal_Terminate;
978 break;
980 #if defined(HAVE_MEMCHECK_H)
981 case SIGUSR2:
982 if (RUNNING_ON_VALGRIND)
983 DUMPCURRENTALLOCS();
984 Info.Signal = osl_Signal_System;
985 break;
986 #endif
988 default:
989 Info.Signal = osl_Signal_System;
990 break;
993 ReportCrash( Signal );
995 /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
996 if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation))
997 _exit(255);
998 /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1001 switch (CallSignalHandler(&Info))
1003 case osl_Signal_ActCallNextHdl:
1004 CallSystemHandler(Signal);
1005 break;
1007 case osl_Signal_ActAbortApp:
1008 ReportCrash( Signal );
1009 act.sa_handler = SIG_DFL;
1010 act.sa_flags = 0;
1011 sigemptyset(&(act.sa_mask));
1012 sigaction(SIGABRT, &act, NULL);
1013 PrintStack( Signal );
1014 abort();
1015 break;
1017 case osl_Signal_ActKillApp:
1018 /* prevent dumping core on exit() */
1019 _exit(255);
1020 break;
1021 default:
1022 break;
1026 /*****************************************************************************/
1027 /* osl_addSignalHandler */
1028 /*****************************************************************************/
1029 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
1031 oslSignalHandlerImpl* pHandler;
1033 OSL_ASSERT(Handler != NULL);
1034 if ( Handler == 0 )
1036 return 0;
1039 if (! bInitSignal)
1040 bInitSignal = InitSignal();
1042 pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl));
1044 if (pHandler != NULL)
1046 pHandler->Handler = Handler;
1047 pHandler->pData = pData;
1049 osl_acquireMutex(SignalListMutex);
1051 pHandler->pNext = SignalList;
1052 SignalList = pHandler;
1054 osl_releaseMutex(SignalListMutex);
1056 return (pHandler);
1059 return (NULL);
1062 /*****************************************************************************/
1063 /* osl_removeSignalHandler */
1064 /*****************************************************************************/
1065 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
1067 oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
1069 OSL_ASSERT(Handler != NULL);
1071 if (! bInitSignal)
1072 bInitSignal = InitSignal();
1074 osl_acquireMutex(SignalListMutex);
1076 pHandler = SignalList;
1078 while (pHandler != NULL)
1080 if (pHandler == Handler)
1082 if (pPrevious)
1083 pPrevious->pNext = pHandler->pNext;
1084 else
1085 SignalList = pHandler->pNext;
1087 osl_releaseMutex(SignalListMutex);
1089 if (SignalList == NULL)
1090 bInitSignal = DeInitSignal();
1092 free(pHandler);
1094 return (sal_True);
1097 pPrevious = pHandler;
1098 pHandler = pHandler->pNext;
1101 osl_releaseMutex(SignalListMutex);
1103 return (sal_False);
1106 /*****************************************************************************/
1107 /* osl_raiseSignal */
1108 /*****************************************************************************/
1109 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
1111 oslSignalInfo Info;
1112 oslSignalAction Action;
1114 if (! bInitSignal)
1115 bInitSignal = InitSignal();
1117 osl_acquireMutex(SignalListMutex);
1119 Info.Signal = osl_Signal_User;
1120 Info.UserSignal = UserSignal;
1121 Info.UserData = UserData;
1123 Action = CallSignalHandler(&Info);
1125 osl_releaseMutex(SignalListMutex);
1127 return (Action);
1130 /*****************************************************************************/
1131 /* osl_setErrorReporting */
1132 /*****************************************************************************/
1133 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
1135 sal_Bool bOld = bErrorReportingEnabled;
1136 bErrorReportingEnabled = bEnable;
1138 return bOld;
1141 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */