xref: /AOO41X/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