xref: /trunk/main/sal/osl/unx/signal.c (revision 910823ae)
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 
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 
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 
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 
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 
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 
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
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)
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 
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 
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 
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 
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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 /*****************************************************************************/
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