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