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