xref: /trunk/main/sal/osl/unx/signal.c (revision 033ed79537b07af43f0f091b11f5dc308cb4c9ad)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 
25 /* system headers */
26 #include "system.h"
27 
28 #define MAX_STACK_FRAMES 256
29 
30 #if defined( MACOSX )
31 
32 #if defined( INTEL )
33 #include "backtrace.h"
34 #define INCLUDE_BACKTRACE
35 #define STACKTYPE "MacOsX_X86"
36 #endif /* INTEL */
37 
38 #endif /* MACOSX */
39 
40 #ifdef LINUX
41 #include <execinfo.h>
42 #include <link.h>
43 #define INCLUDE_BACKTRACE
44 #define STACKTYPE "Linux"
45 #endif
46 
47 #ifdef FREEBSD
48 #include <execinfo.h>
49 #include <link.h>
50 #define INCLUDE_BACKTRACE
51 #define STACKTYPE "FreeBSD"
52 #endif
53 
54 #ifdef SOLARIS
55 
56 #include "backtrace.h"
57 #define INCLUDE_BACKTRACE
58 
59 #if defined( SPARC )
60 #define STACKTYPE "Solaris_Sparc"
61 #elif defined( INTEL )
62 #define STACKTYPE "Solaris_X86"
63 #else
64 #define STACKTYPE "Solaris_Unknown"
65 #endif
66 
67 #endif /* defined SOLARIS */
68 
69 #include <osl/diagnose.h>
70 #include <osl/mutex.h>
71 #include <osl/signal.h>
72 #include <osl/process.h>
73 #include <osl/thread.h>
74 #include <rtl/bootstrap.h>
75 #include <rtl/digest.h>
76 
77 #include "file_path_helper.h"
78 
79 #define ACT_IGNORE  1
80 #define ACT_EXIT    2
81 #define ACT_SYSTEM  3
82 #define ACT_HIDE    4
83 #ifdef SAL_ENABLE_CRASH_REPORT
84 #    define ACT_ABORT   5
85 #else
86 #    define ACT_ABORT   ACT_SYSTEM
87 #endif
88 
89 #define MAX_PATH_LEN    2048
90 
91 typedef struct _oslSignalHandlerImpl
92 {
93     oslSignalHandlerFunction      Handler;
94     void*                         pData;
95     struct _oslSignalHandlerImpl* pNext;
96 } oslSignalHandlerImpl;
97 
98 static struct SignalAction
99 {
100     int Signal;
101     int Action;
102     void (*Handler)(int);
103 } Signals[] =
104 {
105     { SIGHUP,    ACT_IGNORE, 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 */
155 };
156 const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction);
157 
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;
166 
167 static void SignalHandlerFunction(int);
168 
169 static void getExecutableName_Impl (rtl_String ** ppstrProgName)
170 {
171     rtl_uString * ustrProgFile = NULL;
172     osl_getExecutableFile (&ustrProgFile);
173     if (ustrProgFile)
174     {
175         rtl_uString * ustrProgName = NULL;
176         osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName);
177         if (ustrProgName != NULL)
178         {
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);
185         }
186         rtl_uString_release (ustrProgFile);
187     }
188 }
189 
190 static sal_Bool is_soffice_Impl (void)
191 {
192     sal_Int32    idx       = -1;
193     rtl_String * strProgName = NULL;
194 
195     getExecutableName_Impl (&strProgName);
196     if (strProgName)
197     {
198         idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice");
199         rtl_string_release (strProgName);
200     }
201     return (idx != -1);
202 }
203 
204 static sal_Bool InitSignal()
205 {
206     int i;
207     struct sigaction act;
208     struct sigaction oact;
209     sigset_t unset;
210 
211     if (is_soffice_Impl())
212     {
213         sal_uInt32  argi;
214         sal_uInt32  argc;
215         rtl_uString *ustrCommandArg = NULL;
216 
217         argc = osl_getCommandArgCount();
218         for ( argi = 0; argi < argc; argi++ )
219         {
220             if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg))
221             {
222                 if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean"))
223                 {
224                     bDoHardKill = sal_True;
225                     break;
226                 }
227             }
228         }
229         if (ustrCommandArg)
230         {
231             rtl_uString_release (ustrCommandArg);
232             ustrCommandArg = NULL;
233         }
234 
235         // WORKAROUND FOR SEGV HANDLER CONFLICT
236         //
237         // the java jit needs SIGSEGV for proper work
238         // and we need SIGSEGV for the office crashguard
239         //
240         // TEMPORARY SOLUTION:
241         //   the office sets the signal handler during startup
242         //   java can than overwrite it, if needed
243         bSetSEGVHandler = sal_True;
244 
245         // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
246         bSetWINCHHandler = sal_True;
247 
248         // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
249         bSetILLHandler = sal_True;
250     }
251 
252     SignalListMutex = osl_createMutex();
253 
254     act.sa_handler = SignalHandlerFunction;
255     act.sa_flags   = SA_RESTART;
256 
257     sigfillset(&(act.sa_mask));
258 
259     /* Initialize the rest of the signals */
260     for (i = 0; i < NoSignals; i++)
261     {
262         /* hack: stomcatd is attaching JavaVM which dont work with an sigaction(SEGV) */
263         if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV)
264         && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH)
265         && (bSetILLHandler   || Signals[i].Signal != SIGILL))
266         {
267             if (Signals[i].Action != ACT_SYSTEM)
268             {
269                 if (Signals[i].Action == ACT_HIDE)
270                 {
271                     struct sigaction ign;
272 
273                     ign.sa_handler = SIG_IGN;
274                     ign.sa_flags   = 0;
275                     sigemptyset(&ign.sa_mask);
276 
277                     if (sigaction(Signals[i].Signal, &ign, &oact) == 0)
278                         Signals[i].Handler = oact.sa_handler;
279                     else
280                         Signals[i].Handler = SIG_DFL;
281                 }
282                 else
283                     if (sigaction(Signals[i].Signal, &act, &oact) == 0)
284                         Signals[i].Handler = oact.sa_handler;
285                     else
286                         Signals[i].Handler = SIG_DFL;
287             }
288         }
289     }
290 
291     /* Clear signal mask inherited from parent process (on Mac OS X, upon a
292        crash soffice re-execs itself from within the signal handler, so the
293        second soffice would have the guilty signal blocked and would freeze upon
294        encountering a similar crash again): */
295     if (sigemptyset(&unset) < 0 ||
296         pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0)
297     {
298         OSL_TRACE("sigemptyset or pthread_sigmask failed");
299     }
300 
301     return sal_True;
302 }
303 
304 static sal_Bool DeInitSignal()
305 {
306     int i;
307     struct sigaction act;
308 
309     act.sa_flags   = 0;
310     sigemptyset(&(act.sa_mask));
311 
312     /* Initialize the rest of the signals */
313     for (i = NoSignals - 1; i >= 0; i--)
314         if (Signals[i].Action != ACT_SYSTEM)
315         {
316             act.sa_handler = Signals[i].Handler;
317 
318             sigaction(Signals[i].Signal, &act, NULL);
319         }
320 
321     osl_destroyMutex(SignalListMutex);
322 
323     return sal_False;
324 }
325 
326 #if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE)
327 
328 /*****************************************************************************/
329 /* Generate MD5 checksum    */
330 /*****************************************************************************/
331 
332 static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
333 {
334     sal_uInt32  nBytesProcessed = 0;
335 
336     FILE *fp = fopen( filename, "r" );
337 
338     if ( fp )
339     {
340         rtlDigest digest = rtl_digest_createMD5();
341 
342         if ( digest )
343         {
344             size_t          nBytesRead;
345             sal_uInt8       buffer[4096];
346             rtlDigestError  error = rtl_Digest_E_None;
347 
348             while ( rtl_Digest_E_None == error &&
349                 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
350             {
351                 error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
352                 nBytesProcessed += nBytesRead;
353             }
354 
355             if ( rtl_Digest_E_None == error )
356             {
357                 error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
358             }
359 
360             if ( rtl_Digest_E_None != error )
361                 nBytesProcessed = 0;
362 
363             rtl_digest_destroyMD5( digest );
364         }
365 
366         fclose( fp );
367     }
368 
369     return nBytesProcessed;
370 }
371 
372 /*****************************************************************************/
373 /* Call crash reporter  */
374 /*****************************************************************************/
375 
376 /* Helper function to encode and write a string to a stream */
377 
378 static int fputs_xml( const char *string, FILE *stream )
379 {
380     int result = 0;
381 
382     while ( result >= 0 && *string )
383     {
384         switch( *string )
385         {
386         case '&':
387             result = fputs( "&amp;", stream );
388             break;
389         case '<':
390             result = fputs( "&lt;", stream );
391             break;
392         case '>':
393             result = fputs( "&gt;", stream );
394             break;
395         default:
396             result = fputc( *string, stream );
397             break;
398         }
399 
400         string++;
401     }
402 
403     return result;
404 }
405 #endif
406 
407 /* Create intermediate files and run crash reporter */
408 
409 #define REPORTENV_PARAM     "-crashreportenv:"
410 
411 #if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \
412     defined LINUX
413 
414 typedef struct
415 {
416     const char *name;
417     ElfW(Off) offset;
418 } dynamic_entry;
419 
420 static int
421 callback(struct dl_phdr_info *info, size_t size, void *data)
422 {
423     const ElfW(Phdr) *pDynamic = NULL;
424 
425     if (size == sizeof(struct dl_phdr_info))
426     {
427         int i;
428         for (i = 0; i < info->dlpi_phnum; ++i)
429         {
430             if (info->dlpi_phdr[i].p_type == PT_DYNAMIC)
431             {
432                 pDynamic = &(info->dlpi_phdr[i]);
433                 break;
434             }
435         }
436     }
437 
438     if (pDynamic)
439     {
440         char buffer[100];
441         int len;
442         char exe[PATH_MAX];
443         const char *dsoname = info->dlpi_name;
444 
445         dynamic_entry* entry = (dynamic_entry*)data;
446 
447         if (strcmp(dsoname, "") == 0)
448         {
449             snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid());
450             if ((len = readlink(buffer, exe, PATH_MAX)) != -1)
451             {
452                 exe[len] = '\0';
453                 dsoname = exe;
454             }
455         }
456 
457         if (strcmp(dsoname, entry->name) == 0)
458         {
459             entry->offset = pDynamic->p_offset;
460             return 1;
461         }
462     }
463     return 0;
464 }
465 
466 /* Get the location of the .dynamic section offset for the given elf file.
467  * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo
468  *
469  * We want to know this value so that if the binaries have been modifed
470  * by prelink then we can still process the call stack on server side
471  * by comparing this value to that of an "un-prelinked but known to be
472  * otherwise equivalent" version of those binaries and adjust the call
473  * stack addresses by the differences between .dynamic addresses so as
474  * to be able to map the prelinked addresses back to the unprelinked
475  * addresses
476  *
477  * cmc@openoffice.org
478  */
479 static ElfW(Off)
480 dynamic_section_offset(const char *name)
481 {
482     dynamic_entry entry;
483 
484     entry.name = name;
485     entry.offset = 0;
486 
487     dl_iterate_phdr(callback, &entry);
488 
489     return entry.offset;
490 }
491 #endif
492 
493 static int ReportCrash( int Signal )
494 {
495 #ifdef SAL_ENABLE_CRASH_REPORT
496     static sal_Bool bCrashReporterExecuted = sal_False;
497     sal_Bool        bAutoCrashReport = sal_False;
498 
499     sal_uInt32  argi;
500     sal_uInt32  argc;
501     rtl_uString *ustrCommandArg = NULL;
502 
503     if ( !bErrorReportingEnabled )
504         return -1;
505 
506     argc = osl_getCommandArgCount();
507 
508     for ( argi = 0; argi < argc; argi++ )
509     {
510         if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) )
511         {
512             if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-nocrashreport" ) )
513             {
514                 rtl_uString_release( ustrCommandArg );
515                 return -1;
516             }
517             else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-autocrashreport" ) )
518             {
519                 bAutoCrashReport = sal_True;
520             }
521             else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength(
522                 rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ),
523                 REPORTENV_PARAM, strlen(REPORTENV_PARAM) )
524                 )
525             {
526                 rtl_uString *ustrEnvironment = NULL;
527                 rtl_String *strEnv = NULL;
528 
529                 rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) );
530 
531                 if ( ustrEnvironment )
532                 {
533                     rtl_uString2String(
534                         &strEnv,
535                         rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ),
536                         osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS
537                         );
538 
539                     if ( strEnv )
540                     {
541                         putenv( rtl_string_getStr( strEnv ) );
542                         rtl_string_release( strEnv );
543                     }
544 
545                     rtl_uString_release( ustrEnvironment );
546                 }
547 
548             }
549 
550         }
551     }
552 
553     if ( ustrCommandArg )
554         rtl_uString_release( ustrCommandArg );
555 
556     if ( !bCrashReporterExecuted )
557     {
558         int i;
559         /* struct sigaction act; */
560 
561         for (i = 0; i < NoSignals; i++)
562         {
563             if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT )
564             {
565                 int  ret;
566                 char szShellCmd[512] = { '\0' };
567                 char *pXMLTempName = NULL;
568                 char *pStackTempName = NULL;
569                 char *pChecksumTempName = NULL;
570 
571 #ifdef INCLUDE_BACKTRACE
572                 char szXMLTempNameBuffer[L_tmpnam];
573                 char szChecksumTempNameBuffer[L_tmpnam];
574                 char szStackTempNameBuffer[L_tmpnam];
575 
576                 void *stackframes[MAX_STACK_FRAMES];
577                 int  iFrame;
578                 int  nFrames = backtrace( stackframes, sizeof(stackframes)/sizeof(stackframes[0]));
579 
580                 FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL;
581                 int fdxml, fdstk, fdchksum;
582 
583                 strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) );
584                 strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) );
585 
586                 strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) );
587                 strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) );
588 
589                 strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) );
590                 strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) );
591 
592                 fdxml = mkstemp(szXMLTempNameBuffer);
593                 fdstk = mkstemp(szStackTempNameBuffer);
594                 fdchksum = mkstemp(szChecksumTempNameBuffer);
595 
596                 xmlout = fdopen( fdxml , "w" );
597                 stackout = fdopen( fdstk , "w" );
598                 checksumout = fdopen( fdchksum, "w" );
599 
600                 pXMLTempName = szXMLTempNameBuffer;
601                 pStackTempName = szStackTempNameBuffer;
602                 pChecksumTempName = szChecksumTempNameBuffer;
603 
604 
605                 if ( xmlout && stackout && checksumout )
606                 {
607                     fprintf( xmlout, "<errormail:Stack type=\"%s\">\n", STACKTYPE );
608 
609                     fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\n" );
610 
611                     for ( iFrame = 0; iFrame < nFrames; iFrame++ )
612                     {
613                         Dl_info dl_info;
614 
615                         fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":",
616                             SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) );
617 
618                         fprintf( xmlout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"",
619                             iFrame,
620                             SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame])
621                             );
622 
623                         memset( &dl_info, 0, sizeof(dl_info) );
624 
625                         /* dladdr may fail */
626                         if ( dladdr( stackframes[iFrame], &dl_info) )
627                         {
628                             const char *dli_fname = NULL;
629                             char *dli_fdir = NULL;
630                             char szDirectory[PATH_MAX];
631                             char szCanonicDirectory[PATH_MAX];
632 
633                             /* Don't expect that dladdr filled all members of dl_info */
634 
635                             dli_fname = dl_info.dli_fname ? strrchr(  dl_info.dli_fname, '/' ) : NULL;
636                             if ( dli_fname )
637                             {
638                                 ++dli_fname;
639                                 memcpy( szDirectory, dl_info.dli_fname, dli_fname - dl_info.dli_fname );
640                                 szDirectory[dli_fname - dl_info.dli_fname] = 0;
641 
642                                 dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory;
643 
644                                 if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' )
645                                     strcat( dli_fdir, "/" );
646                             }
647                             else
648                                 dli_fname = dl_info.dli_fname;
649 
650                             /* create checksum of library on stack */
651                             if ( dli_fname )
652                             {
653                                 sal_uInt8   checksum[RTL_DIGEST_LENGTH_MD5];
654 
655                                 sal_uInt32 nBytesProcessed = calc_md5_checksum(
656                                     dl_info.dli_fname, checksum, sizeof(checksum) );
657                                 if ( nBytesProcessed )
658                                 {
659                                     int j;
660 
661                                     fprintf( checksumout, "<errormail:Checksum sum=\"0x" );
662                                     for ( j = 0; j < 16; fprintf( checksumout, "%02X", checksum[j++] ) );
663                                     fprintf( checksumout,
664                                         "\" bytes=\"%lu\" file=\"%s\"/>\n",
665                                         SAL_INT_CAST(
666                                             unsigned long, nBytesProcessed),
667                                         dli_fname );
668                                 }
669                             }
670 
671                             if ( dl_info.dli_fbase && dl_info.dli_fname )
672                             {
673 #ifdef LINUX
674                                 ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname);
675                                 fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset);
676 #endif
677 
678                                 fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x",
679                                     dl_info.dli_fname,
680                                     (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase
681                                     );
682 
683                                 fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase );
684                                 if ( dli_fname )
685                                     fprintf( xmlout, " name=\"%s\"", dli_fname );
686 
687                                 if ( dli_fdir )
688                                     fprintf( xmlout, " path=\"%s\"", dli_fdir );
689 
690 #ifdef LINUX
691                                 fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset );
692 #endif
693                             }
694                             else
695                                 fprintf( stackout, " ????????" );
696 
697                             if ( dl_info.dli_sname && dl_info.dli_saddr )
698                             {
699                                 fputs( " (", stackout );
700                                 fputs_xml( dl_info.dli_sname, stackout );
701                                 fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)",
702                                     (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr );
703 
704                                 fputs( " ordinal=\"", xmlout );
705                                 fputs_xml( dl_info.dli_sname, xmlout );
706                                 fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"",
707                                     (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr );
708                             }
709 
710                         }
711                         else /* dladdr failed */
712                         {
713                             fprintf( stackout, " ????????" );
714                         }
715 
716                         fprintf( stackout, "\n" );
717                         fprintf( xmlout, "/>\n" );
718 
719                     }
720 
721                     fprintf( xmlout, "</errormail:Stack>\n" );
722                     fprintf( checksumout, "</errormail:Checksums>\n" );
723                 }
724                 else
725                 {
726                     pXMLTempName = NULL;
727                     pStackTempName = NULL;
728                     pChecksumTempName = NULL;
729                 }
730 
731                 if ( stackout )
732                     fclose( stackout );
733                 if ( xmlout )
734                     fclose( xmlout );
735                 if ( checksumout )
736                     fclose( checksumout );
737 
738                 if ( pXMLTempName && pChecksumTempName && pStackTempName )
739 #endif /* INCLUDE_BACKTRACE */
740                 {
741                     rtl_uString * crashrep_url = NULL;
742                     rtl_uString * crashrep_path = NULL;
743                     rtl_String  * crashrep_path_system = NULL;
744                     rtl_string2UString(
745                         &crashrep_url,
746                         RTL_CONSTASCII_USTRINGPARAM(
747                             "$OOO_BASE_DIR/program/crashrep"),
748                         OSTRING_TO_OUSTRING_CVTFLAGS);
749                     rtl_bootstrap_expandMacros(&crashrep_url);
750                     osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path);
751                     rtl_uString2String(
752                         &crashrep_path_system,
753                         rtl_uString_getStr(crashrep_path),
754                         rtl_uString_getLength(crashrep_path),
755                         osl_getThreadTextEncoding(),
756                         (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
757                          | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR));
758                     rtl_uString_release(crashrep_url);
759                     rtl_uString_release(crashrep_path);
760 #if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX)
761                     snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
762                         "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s",
763                         rtl_string_getStr(crashrep_path_system),
764                         getpid(),
765                         Signal,
766                         pXMLTempName,
767                         pChecksumTempName,
768                         pStackTempName,
769                         bAutoCrashReport ? " -send" : "" );
770 #elif defined INCLUDE_BACKTRACE && defined SOLARIS
771                     snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
772                         "%s -p %d -s %d -xml %s -chksum %s -noui%s",
773                         rtl_string_getStr(crashrep_path_system),
774                         getpid(),
775                         Signal,
776                         pXMLTempName,
777                         pChecksumTempName,
778                         bAutoCrashReport ? " -send" : "" );
779 #else
780                     snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
781                         "%s -p %d -s %d -noui%s",
782                         rtl_string_getStr(crashrep_path_system),
783                         getpid(), Signal, bAutoCrashReport ? " -send" : "" );
784 #endif
785                     rtl_string_release(crashrep_path_system);
786                 }
787 
788                 ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd );
789 
790                 if ( pXMLTempName )
791                     unlink( pXMLTempName );
792 
793                 if ( pStackTempName )
794                     unlink( pStackTempName );
795 
796                 if ( pChecksumTempName )
797                     unlink( pChecksumTempName );
798 
799                 if ( -1 != ret )
800                 {
801                     bCrashReporterExecuted = sal_True;
802                     return 1;
803                 }
804                 else
805                     return -1;
806 
807             }
808         }
809 
810         return 0;
811     }
812 
813     return 1;
814 #else /* defined SAL_ENABLE_CRASH_REPORT */
815     /* the utility crash_report is not build, so do the same as when
816        the option -nocrashreport is used */
817     (void) Signal; // avoid warnings
818     return -1;
819 #endif /* defined SAL_ENABLE_CRASH_REPORT */
820 }
821 
822 static void PrintStack( int sig )
823 {
824 #if ! defined(MACOSX) || defined(INCLUDE_BACKTRACE)
825     void *buffer[MAX_STACK_FRAMES];
826     int size = backtrace( buffer, sizeof(buffer) / sizeof(buffer[0]) );
827 #endif
828 
829     fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
830 
831 #if defined(MACOSX) && ! defined(INCLUDE_BACKTRACE)
832     fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
833 #else
834     if ( size > 0 )
835     {
836         fputs( "Stack:\n", stderr );
837         backtrace_symbols_fd( buffer, size, fileno(stderr) );
838     }
839 #endif
840 }
841 
842 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
843 {
844     oslSignalHandlerImpl* pHandler = SignalList;
845     oslSignalAction Action = osl_Signal_ActCallNextHdl;
846 
847     while (pHandler != NULL)
848     {
849         if ((Action = pHandler->Handler(pHandler->pData, pInfo))
850             != osl_Signal_ActCallNextHdl)
851             break;
852 
853         pHandler = pHandler->pNext;
854     }
855 
856     return Action;
857 }
858 
859 void CallSystemHandler(int Signal)
860 {
861     int i;
862     struct sigaction act;
863 
864     for (i = 0; i < NoSignals; i++)
865     {
866         if (Signals[i].Signal == Signal)
867             break;
868     }
869 
870     if (i < NoSignals)
871     {
872         if ((Signals[i].Handler == NULL)    ||
873             (Signals[i].Handler == SIG_DFL) ||
874             (Signals[i].Handler == SIG_IGN) ||
875             (Signals[i].Handler == SIG_ERR))
876         {
877             switch (Signals[i].Action)
878             {
879                 case ACT_EXIT:      /* terminate */
880                     /* prevent dumping core on exit() */
881                     _exit(255);
882                     break;
883 
884                 case ACT_ABORT:     /* terminate witch core dump */
885                     ReportCrash( Signal );
886                     act.sa_handler = SIG_DFL;
887                     act.sa_flags   = 0;
888                     sigemptyset(&(act.sa_mask));
889                     sigaction(SIGABRT, &act, NULL);
890                     PrintStack( Signal );
891                     abort();
892                     break;
893 
894                 case ACT_IGNORE:    /* ignore */
895                     break;
896 
897                 default:            /* should never happen */
898                     OSL_ASSERT(0);
899             }
900         }
901         else
902             (*Signals[i].Handler)(Signal);
903     }
904 }
905 
906 
907 /*****************************************************************************/
908 /* SignalHandlerFunction    */
909 /*****************************************************************************/
910 void SignalHandlerFunction(int Signal)
911 {
912     oslSignalInfo    Info;
913     struct sigaction act;
914 
915     Info.UserSignal = Signal;
916     Info.UserData   = NULL;
917 
918     switch (Signal)
919     {
920         case SIGBUS:
921         case SIGILL:
922         case SIGSEGV:
923         case SIGIOT:
924 #if ( SIGIOT != SIGABRT )
925         case SIGABRT:
926 #endif
927             Info.Signal = osl_Signal_AccessViolation;
928             break;
929 
930         case -1:
931             Info.Signal = osl_Signal_IntegerDivideByZero;
932             break;
933 
934         case SIGFPE:
935             Info.Signal = osl_Signal_FloatDivideByZero;
936             break;
937 
938         case SIGINT:
939         case SIGTERM:
940     case SIGQUIT:
941     case SIGHUP:
942             Info.Signal = osl_Signal_Terminate;
943             break;
944 
945         default:
946             Info.Signal = osl_Signal_System;
947             break;
948     }
949 
950     ReportCrash( Signal );
951 
952     /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
953     if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation))
954         _exit(255);
955     /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
956 
957 
958     switch (CallSignalHandler(&Info))
959     {
960     case osl_Signal_ActCallNextHdl:
961         CallSystemHandler(Signal);
962         break;
963 
964     case osl_Signal_ActAbortApp:
965         ReportCrash( Signal );
966         act.sa_handler = SIG_DFL;
967         act.sa_flags   = 0;
968         sigemptyset(&(act.sa_mask));
969         sigaction(SIGABRT, &act, NULL);
970         PrintStack( Signal );
971         abort();
972         break;
973 
974     case osl_Signal_ActKillApp:
975         /* prevent dumping core on exit() */
976         _exit(255);
977         break;
978     default:
979         break;
980     }
981 }
982 
983 /*****************************************************************************/
984 /* osl_addSignalHandler */
985 /*****************************************************************************/
986 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
987 {
988     oslSignalHandlerImpl* pHandler;
989 
990     OSL_ASSERT(Handler != NULL);
991     if ( Handler == 0 )
992     {
993         return 0;
994     }
995 
996     if (! bInitSignal)
997         bInitSignal = InitSignal();
998 
999     pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl));
1000 
1001     if (pHandler != NULL)
1002     {
1003         pHandler->Handler = Handler;
1004         pHandler->pData   = pData;
1005 
1006         osl_acquireMutex(SignalListMutex);
1007 
1008         pHandler->pNext = SignalList;
1009         SignalList      = pHandler;
1010 
1011         osl_releaseMutex(SignalListMutex);
1012 
1013         return (pHandler);
1014     }
1015 
1016     return (NULL);
1017 }
1018 
1019 /*****************************************************************************/
1020 /* osl_removeSignalHandler */
1021 /*****************************************************************************/
1022 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
1023 {
1024     oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
1025 
1026     OSL_ASSERT(Handler != NULL);
1027 
1028     if (! bInitSignal)
1029         bInitSignal = InitSignal();
1030 
1031     osl_acquireMutex(SignalListMutex);
1032 
1033     pHandler = SignalList;
1034 
1035     while (pHandler != NULL)
1036     {
1037         if (pHandler == Handler)
1038         {
1039             if (pPrevious)
1040                 pPrevious->pNext = pHandler->pNext;
1041             else
1042                 SignalList = pHandler->pNext;
1043 
1044             osl_releaseMutex(SignalListMutex);
1045 
1046             if (SignalList == NULL)
1047                 bInitSignal = DeInitSignal();
1048 
1049             free(pHandler);
1050 
1051             return (sal_True);
1052         }
1053 
1054         pPrevious = pHandler;
1055         pHandler  = pHandler->pNext;
1056     }
1057 
1058     osl_releaseMutex(SignalListMutex);
1059 
1060     return (sal_False);
1061 }
1062 
1063 /*****************************************************************************/
1064 /* osl_raiseSignal */
1065 /*****************************************************************************/
1066 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
1067 {
1068     oslSignalInfo   Info;
1069     oslSignalAction Action;
1070 
1071     if (! bInitSignal)
1072         bInitSignal = InitSignal();
1073 
1074     osl_acquireMutex(SignalListMutex);
1075 
1076     Info.Signal     = osl_Signal_User;
1077     Info.UserSignal = UserSignal;
1078     Info.UserData   = UserData;
1079 
1080     Action = CallSignalHandler(&Info);
1081 
1082     osl_releaseMutex(SignalListMutex);
1083 
1084     return (Action);
1085 }
1086 
1087 /*****************************************************************************/
1088 /* osl_setErrorReporting */
1089 /*****************************************************************************/
1090 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
1091 {
1092     sal_Bool bOld = bErrorReportingEnabled;
1093     bErrorReportingEnabled = bEnable;
1094 
1095     return bOld;
1096 }
1097