xref: /trunk/main/sal/osl/unx/signal.c (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
28 
29 /* system headers */
30 #include "system.h"
31 
32 #define MAX_STACK_FRAMES 256
33 
34 #if defined( MACOSX )
35 
36 #if defined( INTEL )
37 #include "backtrace.h"
38 #define INCLUDE_BACKTRACE
39 #define STACKTYPE "MacOsX_X86"
40 #endif /* INTEL */
41 
42 #endif /* MACOSX */
43 
44 #ifdef LINUX
45 #include <execinfo.h>
46 #include <link.h>
47 #define INCLUDE_BACKTRACE
48 #define STACKTYPE "Linux"
49 #endif
50 
51 #ifdef SOLARIS
52 
53 #include "backtrace.h"
54 #define INCLUDE_BACKTRACE
55 
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
63 
64 #endif /* defined SOLARIS */
65 
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>
73 
74 #include "file_path_helper.h"
75 
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
85 
86 #define MAX_PATH_LEN    2048
87 
88 typedef struct _oslSignalHandlerImpl
89 {
90     oslSignalHandlerFunction      Handler;
91     void*                         pData;
92     struct _oslSignalHandlerImpl* pNext;
93 } oslSignalHandlerImpl;
94 
95 static struct SignalAction
96 {
97     int Signal;
98     int Action;
99     void (*Handler)(int);
100 } Signals[] =
101 {
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 */
152 };
153 const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction);
154 
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;
163 
164 static void SignalHandlerFunction(int);
165 
166 static void getExecutableName_Impl (rtl_String ** ppstrProgName)
167 {
168     rtl_uString * ustrProgFile = 0;
169     osl_getExecutableFile (&ustrProgFile);
170     if (ustrProgFile)
171     {
172         rtl_uString * ustrProgName = 0;
173         osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName);
174         if (ustrProgName != 0)
175         {
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);
182         }
183         rtl_uString_release (ustrProgFile);
184     }
185 }
186 
187 static sal_Bool is_soffice_Impl (void)
188 {
189     sal_Int32    idx       = -1;
190     rtl_String * strProgName = 0;
191 
192     getExecutableName_Impl (&strProgName);
193     if (strProgName)
194     {
195         idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice");
196         rtl_string_release (strProgName);
197     }
198     return (idx != -1);
199 }
200 
201 static sal_Bool InitSignal()
202 {
203     int i;
204     struct sigaction act;
205     struct sigaction oact;
206     sigset_t unset;
207 
208     if (is_soffice_Impl())
209     {
210         sal_uInt32  argi;
211         sal_uInt32  argc;
212         rtl_uString *ustrCommandArg = 0;
213 
214         argc = osl_getCommandArgCount();
215         for ( argi = 0; argi < argc; argi++ )
216         {
217             if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg))
218             {
219                 if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean"))
220                 {
221                     bDoHardKill = sal_True;
222                     break;
223                 }
224             }
225         }
226         if (ustrCommandArg)
227         {
228             rtl_uString_release (ustrCommandArg);
229             ustrCommandArg = 0;
230         }
231 
232         // WORKAROUND FOR SEGV HANDLER CONFLICT
233         //
234         // the java jit needs SIGSEGV for proper work
235         // and we need SIGSEGV for the office crashguard
236         //
237         // TEMPORARY SOLUTION:
238         //   the office sets the signal handler during startup
239         //   java can than overwrite it, if needed
240         bSetSEGVHandler = sal_True;
241 
242         // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
243         bSetWINCHHandler = sal_True;
244 
245         // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
246         bSetILLHandler = sal_True;
247     }
248 
249     SignalListMutex = osl_createMutex();
250 
251     act.sa_handler = SignalHandlerFunction;
252     act.sa_flags   = SA_RESTART;
253 
254     sigfillset(&(act.sa_mask));
255 
256     /* Initialize the rest of the signals */
257     for (i = 0; i < NoSignals; i++)
258     {
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))
263         {
264             if (Signals[i].Action != ACT_SYSTEM)
265             {
266                 if (Signals[i].Action == ACT_HIDE)
267                 {
268                     struct sigaction ign;
269 
270                     ign.sa_handler = SIG_IGN;
271                     ign.sa_flags   = 0;
272                     sigemptyset(&ign.sa_mask);
273 
274                     if (sigaction(Signals[i].Signal, &ign, &oact) == 0)
275                         Signals[i].Handler = oact.sa_handler;
276                     else
277                         Signals[i].Handler = SIG_DFL;
278                 }
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;
284             }
285         }
286     }
287 
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)
294     {
295         OSL_TRACE("sigemptyset or pthread_sigmask failed");
296     }
297 
298     return sal_True;
299 }
300 
301 static sal_Bool DeInitSignal()
302 {
303     int i;
304     struct sigaction act;
305 
306     act.sa_flags   = 0;
307     sigemptyset(&(act.sa_mask));
308 
309     /* Initialize the rest of the signals */
310     for (i = NoSignals - 1; i >= 0; i--)
311         if (Signals[i].Action != ACT_SYSTEM)
312         {
313             act.sa_handler = Signals[i].Handler;
314 
315             sigaction(Signals[i].Signal, &act, NULL);
316         }
317 
318     osl_destroyMutex(SignalListMutex);
319 
320     return sal_False;
321 }
322 
323 #if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE)
324 
325 /*****************************************************************************/
326 /* Generate MD5 checksum    */
327 /*****************************************************************************/
328 
329 static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
330 {
331     sal_uInt32  nBytesProcessed = 0;
332 
333     FILE *fp = fopen( filename, "r" );
334 
335     if ( fp )
336     {
337         rtlDigest digest = rtl_digest_createMD5();
338 
339         if ( digest )
340         {
341             size_t          nBytesRead;
342             sal_uInt8       buffer[4096];
343             rtlDigestError  error = rtl_Digest_E_None;
344 
345             while ( rtl_Digest_E_None == error &&
346                 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
347             {
348                 error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
349                 nBytesProcessed += nBytesRead;
350             }
351 
352             if ( rtl_Digest_E_None == error )
353             {
354                 error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
355             }
356 
357             if ( rtl_Digest_E_None != error )
358                 nBytesProcessed = 0;
359 
360             rtl_digest_destroyMD5( digest );
361         }
362 
363         fclose( fp );
364     }
365 
366     return nBytesProcessed;
367 }
368 
369 /*****************************************************************************/
370 /* Call crash reporter  */
371 /*****************************************************************************/
372 
373 /* Helper function to encode and write a string to a stream */
374 
375 static int fputs_xml( const char *string, FILE *stream )
376 {
377     int result = 0;
378 
379     while ( result >= 0 && *string )
380     {
381         switch( *string )
382         {
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;
395         }
396 
397         string++;
398     }
399 
400     return result;
401 }
402 #endif
403 
404 /* Create intermediate files and run crash reporter */
405 
406 #define REPORTENV_PARAM     "-crashreportenv:"
407 
408 #if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \
409     defined LINUX
410 
411 typedef struct
412 {
413     const char *name;
414     ElfW(Off) offset;
415 } dynamic_entry;
416 
417 static int
418 callback(struct dl_phdr_info *info, size_t size, void *data)
419 {
420     const ElfW(Phdr) *pDynamic = NULL;
421 
422     if (size == sizeof(struct dl_phdr_info))
423     {
424         int i;
425         for (i = 0; i < info->dlpi_phnum; ++i)
426         {
427             if (info->dlpi_phdr[i].p_type == PT_DYNAMIC)
428             {
429                 pDynamic = &(info->dlpi_phdr[i]);
430                 break;
431             }
432         }
433     }
434 
435     if (pDynamic)
436     {
437         char buffer[100];
438         int len;
439         char exe[PATH_MAX];
440         const char *dsoname = info->dlpi_name;
441 
442         dynamic_entry* entry = (dynamic_entry*)data;
443 
444         if (strcmp(dsoname, "") == 0)
445         {
446             snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid());
447             if ((len = readlink(buffer, exe, PATH_MAX)) != -1)
448             {
449                 exe[len] = '\0';
450                 dsoname = exe;
451             }
452         }
453 
454         if (strcmp(dsoname, entry->name) == 0)
455         {
456             entry->offset = pDynamic->p_offset;
457             return 1;
458         }
459     }
460     return 0;
461 }
462 
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
465  *
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
473  *
474  * cmc@openoffice.org
475  */
476 static ElfW(Off)
477 dynamic_section_offset(const char *name)
478 {
479     dynamic_entry entry;
480 
481     entry.name = name;
482     entry.offset = 0;
483 
484     dl_iterate_phdr(callback, &entry);
485 
486     return entry.offset;
487 }
488 #endif
489 
490 static int ReportCrash( int Signal )
491 {
492 #ifdef SAL_ENABLE_CRASH_REPORT
493     static sal_Bool bCrashReporterExecuted = sal_False;
494     sal_Bool        bAutoCrashReport = sal_False;
495 
496     sal_uInt32  argi;
497     sal_uInt32  argc;
498     rtl_uString *ustrCommandArg = NULL;
499 
500     if ( !bErrorReportingEnabled )
501         return -1;
502 
503     argc = osl_getCommandArgCount();
504 
505     for ( argi = 0; argi < argc; argi++ )
506     {
507         if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) )
508         {
509             if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-nocrashreport" ) )
510             {
511                 rtl_uString_release( ustrCommandArg );
512                 return -1;
513             }
514             else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "-autocrashreport" ) )
515             {
516                 bAutoCrashReport = sal_True;
517             }
518             else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength(
519                 rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ),
520                 REPORTENV_PARAM, strlen(REPORTENV_PARAM) )
521                 )
522             {
523                 rtl_uString *ustrEnvironment = NULL;
524                 rtl_String *strEnv = NULL;
525 
526                 rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) );
527 
528                 if ( ustrEnvironment )
529                 {
530                     rtl_uString2String(
531                         &strEnv,
532                         rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ),
533                         osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS
534                         );
535 
536                     if ( strEnv )
537                     {
538                         putenv( rtl_string_getStr( strEnv ) );
539                         rtl_string_release( strEnv );
540                     }
541 
542                     rtl_uString_release( ustrEnvironment );
543                 }
544 
545             }
546 
547         }
548     }
549 
550     if ( ustrCommandArg )
551         rtl_uString_release( ustrCommandArg );
552 
553     if ( !bCrashReporterExecuted )
554     {
555         int i;
556         /* struct sigaction act; */
557 
558         for (i = 0; i < NoSignals; i++)
559         {
560             if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT )
561             {
562                 int  ret;
563                 char szShellCmd[512] = { '\0' };
564                 char *pXMLTempName = NULL;
565                 char *pStackTempName = NULL;
566                 char *pChecksumTempName = NULL;
567 
568 #ifdef INCLUDE_BACKTRACE
569                 char szXMLTempNameBuffer[L_tmpnam];
570                 char szChecksumTempNameBuffer[L_tmpnam];
571                 char szStackTempNameBuffer[L_tmpnam];
572 
573                 void *stackframes[MAX_STACK_FRAMES];
574                 int  iFrame;
575                 int  nFrames = backtrace( stackframes, sizeof(stackframes)/sizeof(stackframes[0]));
576 
577                 FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL;
578                 int fdxml, fdstk, fdchksum;
579 
580                 strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) );
581                 strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) );
582 
583                 strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) );
584                 strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) );
585 
586                 strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) );
587                 strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) );
588 
589                 fdxml = mkstemp(szXMLTempNameBuffer);
590                 fdstk = mkstemp(szStackTempNameBuffer);
591                 fdchksum = mkstemp(szChecksumTempNameBuffer);
592 
593                 xmlout = fdopen( fdxml , "w" );
594                 stackout = fdopen( fdstk , "w" );
595                 checksumout = fdopen( fdchksum, "w" );
596 
597                 pXMLTempName = szXMLTempNameBuffer;
598                 pStackTempName = szStackTempNameBuffer;
599                 pChecksumTempName = szChecksumTempNameBuffer;
600 
601 
602                 if ( xmlout && stackout && checksumout )
603                 {
604                     fprintf( xmlout, "<errormail:Stack type=\"%s\">\n", STACKTYPE );
605 
606                     fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\n" );
607 
608                     for ( iFrame = 0; iFrame < nFrames; iFrame++ )
609                     {
610                         Dl_info dl_info;
611 
612                         fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":",
613                             SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) );
614 
615                         fprintf( xmlout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"",
616                             iFrame,
617                             SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame])
618                             );
619 
620                         memset( &dl_info, 0, sizeof(dl_info) );
621 
622                         /* dladdr may fail */
623                         if ( dladdr( stackframes[iFrame], &dl_info) )
624                         {
625                             const char *dli_fname = NULL;
626                             char *dli_fdir = NULL;
627                             char szDirectory[PATH_MAX];
628                             char szCanonicDirectory[PATH_MAX];
629 
630                             /* Don't expect that dladdr filled all members of dl_info */
631 
632                             dli_fname = dl_info.dli_fname ? strrchr(  dl_info.dli_fname, '/' ) : NULL;
633                             if ( dli_fname )
634                             {
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;
638 
639                                 dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory;
640 
641                                 if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' )
642                                     strcat( dli_fdir, "/" );
643                             }
644                             else
645                                 dli_fname = dl_info.dli_fname;
646 
647                             /* create checksum of library on stack */
648                             if ( dli_fname )
649                             {
650                                 sal_uInt8   checksum[RTL_DIGEST_LENGTH_MD5];
651 
652                                 sal_uInt32 nBytesProcessed = calc_md5_checksum(
653                                     dl_info.dli_fname, checksum, sizeof(checksum) );
654                                 if ( nBytesProcessed )
655                                 {
656                                     int j;
657 
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 );
665                                 }
666                             }
667 
668                             if ( dl_info.dli_fbase && dl_info.dli_fname )
669                             {
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
674 
675                                 fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x",
676                                     dl_info.dli_fname,
677                                     (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase
678                                     );
679 
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 );
683 
684                                 if ( dli_fdir )
685                                     fprintf( xmlout, " path=\"%s\"", dli_fdir );
686 
687 #ifdef LINUX
688                                 fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset );
689 #endif
690                             }
691                             else
692                                 fprintf( stackout, " ????????" );
693 
694                             if ( dl_info.dli_sname && dl_info.dli_saddr )
695                             {
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 );
700 
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 );
705                             }
706 
707                         }
708                         else /* dladdr failed */
709                         {
710                             fprintf( stackout, " ????????" );
711                         }
712 
713                         fprintf( stackout, "\n" );
714                         fprintf( xmlout, "/>\n" );
715 
716                     }
717 
718                     fprintf( xmlout, "</errormail:Stack>\n" );
719                     fprintf( checksumout, "</errormail:Checksums>\n" );
720                 }
721                 else
722                 {
723                     pXMLTempName = NULL;
724                     pStackTempName = NULL;
725                     pChecksumTempName = NULL;
726                 }
727 
728                 if ( stackout )
729                     fclose( stackout );
730                 if ( xmlout )
731                     fclose( xmlout );
732                 if ( checksumout )
733                     fclose( checksumout );
734 
735                 if ( pXMLTempName && pChecksumTempName && pStackTempName )
736 #endif /* INCLUDE_BACKTRACE */
737                 {
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);
783                 }
784 
785                 ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd );
786 
787                 if ( pXMLTempName )
788                     unlink( pXMLTempName );
789 
790                 if ( pStackTempName )
791                     unlink( pStackTempName );
792 
793                 if ( pChecksumTempName )
794                     unlink( pChecksumTempName );
795 
796                 if ( -1 != ret )
797                 {
798                     bCrashReporterExecuted = sal_True;
799                     return 1;
800                 }
801                 else
802                     return -1;
803 
804             }
805         }
806 
807         return 0;
808     }
809 
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 */
817 }
818 
819 static void PrintStack( int sig )
820 {
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
825 
826     fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
827 
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 )
832     {
833         fputs( "Stack:\n", stderr );
834         backtrace_symbols_fd( buffer, size, fileno(stderr) );
835     }
836 #endif
837 }
838 
839 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
840 {
841     oslSignalHandlerImpl* pHandler = SignalList;
842     oslSignalAction Action = osl_Signal_ActCallNextHdl;
843 
844     while (pHandler != NULL)
845     {
846         if ((Action = pHandler->Handler(pHandler->pData, pInfo))
847             != osl_Signal_ActCallNextHdl)
848             break;
849 
850         pHandler = pHandler->pNext;
851     }
852 
853     return Action;
854 }
855 
856 void CallSystemHandler(int Signal)
857 {
858     int i;
859     struct sigaction act;
860 
861     for (i = 0; i < NoSignals; i++)
862     {
863         if (Signals[i].Signal == Signal)
864             break;
865     }
866 
867     if (i < NoSignals)
868     {
869         if ((Signals[i].Handler == NULL)    ||
870             (Signals[i].Handler == SIG_DFL) ||
871             (Signals[i].Handler == SIG_IGN) ||
872             (Signals[i].Handler == SIG_ERR))
873         {
874             switch (Signals[i].Action)
875             {
876                 case ACT_EXIT:      /* terminate */
877                     /* prevent dumping core on exit() */
878                     _exit(255);
879                     break;
880 
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;
890 
891                 case ACT_IGNORE:    /* ignore */
892                     break;
893 
894                 default:            /* should never happen */
895                     OSL_ASSERT(0);
896             }
897         }
898         else
899             (*Signals[i].Handler)(Signal);
900     }
901 }
902 
903 
904 /*****************************************************************************/
905 /* SignalHandlerFunction    */
906 /*****************************************************************************/
907 void SignalHandlerFunction(int Signal)
908 {
909     oslSignalInfo    Info;
910     struct sigaction act;
911 
912     Info.UserSignal = Signal;
913     Info.UserData   = NULL;
914 
915     switch (Signal)
916     {
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;
926 
927         case -1:
928             Info.Signal = osl_Signal_IntegerDivideByZero;
929             break;
930 
931         case SIGFPE:
932             Info.Signal = osl_Signal_FloatDivideByZero;
933             break;
934 
935         case SIGINT:
936         case SIGTERM:
937     case SIGQUIT:
938     case SIGHUP:
939             Info.Signal = osl_Signal_Terminate;
940             break;
941 
942         default:
943             Info.Signal = osl_Signal_System;
944             break;
945     }
946 
947     ReportCrash( Signal );
948 
949     /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
950     if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation))
951         _exit(255);
952     /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
953 
954 
955     switch (CallSignalHandler(&Info))
956     {
957     case osl_Signal_ActCallNextHdl:
958         CallSystemHandler(Signal);
959         break;
960 
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;
970 
971     case osl_Signal_ActKillApp:
972         /* prevent dumping core on exit() */
973         _exit(255);
974         break;
975     default:
976         break;
977     }
978 }
979 
980 /*****************************************************************************/
981 /* osl_addSignalHandler */
982 /*****************************************************************************/
983 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
984 {
985     oslSignalHandlerImpl* pHandler;
986 
987     OSL_ASSERT(Handler != NULL);
988     if ( Handler == 0 )
989     {
990         return 0;
991     }
992 
993     if (! bInitSignal)
994         bInitSignal = InitSignal();
995 
996     pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl));
997 
998     if (pHandler != NULL)
999     {
1000         pHandler->Handler = Handler;
1001         pHandler->pData   = pData;
1002 
1003         osl_acquireMutex(SignalListMutex);
1004 
1005         pHandler->pNext = SignalList;
1006         SignalList      = pHandler;
1007 
1008         osl_releaseMutex(SignalListMutex);
1009 
1010         return (pHandler);
1011     }
1012 
1013     return (NULL);
1014 }
1015 
1016 /*****************************************************************************/
1017 /* osl_removeSignalHandler */
1018 /*****************************************************************************/
1019 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
1020 {
1021     oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
1022 
1023     OSL_ASSERT(Handler != NULL);
1024 
1025     if (! bInitSignal)
1026         bInitSignal = InitSignal();
1027 
1028     osl_acquireMutex(SignalListMutex);
1029 
1030     pHandler = SignalList;
1031 
1032     while (pHandler != NULL)
1033     {
1034         if (pHandler == Handler)
1035         {
1036             if (pPrevious)
1037                 pPrevious->pNext = pHandler->pNext;
1038             else
1039                 SignalList = pHandler->pNext;
1040 
1041             osl_releaseMutex(SignalListMutex);
1042 
1043             if (SignalList == NULL)
1044                 bInitSignal = DeInitSignal();
1045 
1046             free(pHandler);
1047 
1048             return (sal_True);
1049         }
1050 
1051         pPrevious = pHandler;
1052         pHandler  = pHandler->pNext;
1053     }
1054 
1055     osl_releaseMutex(SignalListMutex);
1056 
1057     return (sal_False);
1058 }
1059 
1060 /*****************************************************************************/
1061 /* osl_raiseSignal */
1062 /*****************************************************************************/
1063 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
1064 {
1065     oslSignalInfo   Info;
1066     oslSignalAction Action;
1067 
1068     if (! bInitSignal)
1069         bInitSignal = InitSignal();
1070 
1071     osl_acquireMutex(SignalListMutex);
1072 
1073     Info.Signal     = osl_Signal_User;
1074     Info.UserSignal = UserSignal;
1075     Info.UserData   = UserData;
1076 
1077     Action = CallSignalHandler(&Info);
1078 
1079     osl_releaseMutex(SignalListMutex);
1080 
1081     return (Action);
1082 }
1083 
1084 /*****************************************************************************/
1085 /* osl_setErrorReporting */
1086 /*****************************************************************************/
1087 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
1088 {
1089     sal_Bool bOld = bErrorReportingEnabled;
1090     bErrorReportingEnabled = bEnable;
1091 
1092     return bOld;
1093 }
1094