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( "&", stream );
381 break;
382 case '<':
383 result = fputs( "<", stream );
384 break;
385 case '>':
386 result = fputs( ">", 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