Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : /* system headers */
22 : #include "system.h"
23 :
24 : #if defined( MACOSX )
25 :
26 : #if defined( INTEL )
27 : #include "backtrace.h"
28 : #define INCLUDE_BACKTRACE
29 : #ifdef SAL_ENABLE_CRASH_REPORT
30 : #define STACKTYPE "MacOsX_X86"
31 : #endif
32 : #endif /* INTEL */
33 :
34 : #endif /* MACOSX */
35 :
36 : #ifdef LINUX
37 : #include <execinfo.h>
38 : #include <link.h>
39 : #define INCLUDE_BACKTRACE
40 : #if defined SAL_ENABLE_CRASH_REPORT
41 : #define STACKTYPE "Linux"
42 : #endif
43 : #endif
44 :
45 : #ifdef SOLARIS
46 :
47 : #include "backtrace.h"
48 : #define INCLUDE_BACKTRACE
49 :
50 : #if defined SAL_ENABLE_CRASH_REPORT
51 : #if defined( SPARC )
52 : #define STACKTYPE "Solaris_Sparc"
53 : #elif defined( INTEL )
54 : #define STACKTYPE "Solaris_X86"
55 : #else
56 : #define STACKTYPE "Solaris_Unknown"
57 : #endif
58 : #endif
59 :
60 : #endif /* defined SOLARIS */
61 :
62 : #if defined INCLUDE_BACKTRACE
63 : #define MAX_STACK_FRAMES 256
64 : #endif
65 :
66 : #include <osl/diagnose.h>
67 : #include <osl/mutex.h>
68 : #include <osl/signal.h>
69 : #include <osl/process.h>
70 : #include <osl/thread.h>
71 : #include <sal/macros.h>
72 : #include <rtl/bootstrap.h>
73 : #include <rtl/digest.h>
74 :
75 : #include "file_path_helper.h"
76 :
77 : #define ACT_IGNORE 1
78 : #define ACT_EXIT 2
79 : #define ACT_SYSTEM 3
80 : #define ACT_HIDE 4
81 : #ifdef SAL_ENABLE_CRASH_REPORT
82 : # define ACT_ABORT 5
83 : #else
84 : # define ACT_ABORT ACT_SYSTEM
85 : #endif
86 :
87 : #if defined HAVE_VALGRIND_HEADERS
88 : #include <valgrind/memcheck.h>
89 : #endif
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_HIDE, 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 :
169 151 : static void getExecutableName_Impl (rtl_String ** ppstrProgName)
170 : {
171 151 : rtl_uString * ustrProgFile = 0;
172 151 : osl_getExecutableFile (&ustrProgFile);
173 151 : if (ustrProgFile)
174 : {
175 150 : rtl_uString * ustrProgName = 0;
176 150 : osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName);
177 150 : if (ustrProgName != 0)
178 : {
179 300 : rtl_uString2String (
180 : ppstrProgName,
181 150 : rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName),
182 150 : osl_getThreadTextEncoding(),
183 : OUSTRING_TO_OSTRING_CVTFLAGS);
184 150 : rtl_uString_release (ustrProgName);
185 : }
186 150 : rtl_uString_release (ustrProgFile);
187 : }
188 151 : }
189 :
190 151 : static sal_Bool is_soffice_Impl (void)
191 : {
192 151 : sal_Int32 idx = -1;
193 151 : rtl_String * strProgName = 0;
194 :
195 151 : getExecutableName_Impl (&strProgName);
196 151 : if (strProgName)
197 : {
198 150 : idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice");
199 150 : rtl_string_release (strProgName);
200 : }
201 151 : return (idx != -1);
202 : }
203 :
204 151 : static sal_Bool InitSignal()
205 : {
206 : int i;
207 : struct sigaction act;
208 : struct sigaction oact;
209 : sigset_t unset;
210 :
211 151 : if (is_soffice_Impl())
212 : {
213 : sal_uInt32 argi;
214 : sal_uInt32 argc;
215 83 : rtl_uString *ustrCommandArg = 0;
216 :
217 83 : argc = osl_getCommandArgCount();
218 749 : for ( argi = 0; argi < argc; argi++ )
219 : {
220 666 : if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg))
221 : {
222 666 : if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean"))
223 : {
224 0 : bDoHardKill = sal_True;
225 0 : break;
226 : }
227 : }
228 : }
229 83 : if (ustrCommandArg)
230 : {
231 83 : rtl_uString_release (ustrCommandArg);
232 83 : ustrCommandArg = 0;
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 83 : bSetSEGVHandler = sal_True;
244 :
245 : // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
246 83 : bSetWINCHHandler = sal_True;
247 :
248 : // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
249 83 : bSetILLHandler = sal_True;
250 : }
251 :
252 : #ifdef DBG_UTIL
253 : bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = bDoHardKill = sal_False;
254 : #endif
255 :
256 151 : SignalListMutex = osl_createMutex();
257 :
258 151 : act.sa_handler = SignalHandlerFunction;
259 151 : act.sa_flags = SA_RESTART;
260 :
261 151 : sigfillset(&(act.sa_mask));
262 :
263 : /* Initialize the rest of the signals */
264 4681 : for (i = 0; i < NoSignals; ++i)
265 : {
266 : #if defined HAVE_VALGRIND_HEADERS
267 : if (Signals[i].Signal == SIGUSR2 && RUNNING_ON_VALGRIND)
268 : Signals[i].Action = ACT_IGNORE;
269 : #endif
270 :
271 : /* hack: stomcatd is attaching JavaVM which does not work with an sigaction(SEGV) */
272 4530 : if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV)
273 4462 : && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH)
274 4394 : && (bSetILLHandler || Signals[i].Signal != SIGILL))
275 : {
276 4326 : if (Signals[i].Action != ACT_SYSTEM)
277 : {
278 1593 : if (Signals[i].Action == ACT_HIDE)
279 : {
280 : struct sigaction ign;
281 :
282 302 : ign.sa_handler = SIG_IGN;
283 302 : ign.sa_flags = 0;
284 302 : sigemptyset(&ign.sa_mask);
285 :
286 302 : if (sigaction(Signals[i].Signal, &ign, &oact) == 0)
287 302 : Signals[i].Handler = oact.sa_handler;
288 : else
289 0 : Signals[i].Handler = SIG_DFL;
290 : }
291 : else
292 : {
293 1291 : if (sigaction(Signals[i].Signal, &act, &oact) == 0)
294 1291 : Signals[i].Handler = oact.sa_handler;
295 : else
296 0 : Signals[i].Handler = SIG_DFL;
297 : }
298 : }
299 : }
300 : }
301 :
302 : /* Clear signal mask inherited from parent process (on Mac OS X, upon a
303 : crash soffice re-execs itself from within the signal handler, so the
304 : second soffice would have the guilty signal blocked and would freeze upon
305 : encountering a similar crash again): */
306 151 : if (sigemptyset(&unset) < 0 ||
307 151 : pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0)
308 : {
309 : OSL_TRACE("sigemptyset or pthread_sigmask failed");
310 : }
311 :
312 151 : return sal_True;
313 : }
314 :
315 94 : static sal_Bool DeInitSignal()
316 : {
317 : int i;
318 : struct sigaction act;
319 :
320 94 : act.sa_flags = 0;
321 94 : sigemptyset(&(act.sa_mask));
322 :
323 : /* Initialize the rest of the signals */
324 2914 : for (i = NoSignals - 1; i >= 0; i--)
325 2820 : if (Signals[i].Action != ACT_SYSTEM)
326 : {
327 1034 : act.sa_handler = Signals[i].Handler;
328 :
329 1034 : sigaction(Signals[i].Signal, &act, NULL);
330 : }
331 :
332 94 : osl_destroyMutex(SignalListMutex);
333 :
334 94 : return sal_False;
335 : }
336 :
337 : #if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE)
338 :
339 : /*****************************************************************************/
340 : /* Generate MD5 checksum */
341 : /*****************************************************************************/
342 :
343 : static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
344 : {
345 : sal_uInt32 nBytesProcessed = 0;
346 :
347 : FILE *fp = fopen( filename, "r" );
348 :
349 : if ( fp )
350 : {
351 : rtlDigest digest = rtl_digest_createMD5();
352 :
353 : if ( digest )
354 : {
355 : size_t nBytesRead;
356 : sal_uInt8 buffer[4096];
357 : rtlDigestError error = rtl_Digest_E_None;
358 :
359 : while ( rtl_Digest_E_None == error &&
360 : 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
361 : {
362 : error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
363 : nBytesProcessed += nBytesRead;
364 : }
365 :
366 : if ( rtl_Digest_E_None == error )
367 : {
368 : error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
369 : }
370 :
371 : if ( rtl_Digest_E_None != error )
372 : nBytesProcessed = 0;
373 :
374 : rtl_digest_destroyMD5( digest );
375 : }
376 :
377 : fclose( fp );
378 : }
379 :
380 : return nBytesProcessed;
381 : }
382 :
383 : /*****************************************************************************/
384 : /* Call crash reporter */
385 : /*****************************************************************************/
386 :
387 : /* Helper function to encode and write a string to a stream */
388 :
389 : static int fputs_xml( const char *string, FILE *stream )
390 : {
391 : int result = 0;
392 :
393 : while ( result >= 0 && *string )
394 : {
395 : switch( *string )
396 : {
397 : case '&':
398 : result = fputs( "&", stream );
399 : break;
400 : case '<':
401 : result = fputs( "<", stream );
402 : break;
403 : case '>':
404 : result = fputs( ">", stream );
405 : break;
406 : default:
407 : result = fputc( *string, stream );
408 : break;
409 : }
410 :
411 : string++;
412 : }
413 :
414 : return result;
415 : }
416 : #endif
417 :
418 : /* Create intermediate files and run crash reporter */
419 :
420 : #if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \
421 : defined LINUX
422 :
423 : typedef struct
424 : {
425 : const char *name;
426 : ElfW(Off) offset;
427 : } dynamic_entry;
428 :
429 : static int
430 : callback(struct dl_phdr_info *info, size_t size, void *data)
431 : {
432 : const ElfW(Phdr) *pDynamic = NULL;
433 :
434 : if (size == sizeof(struct dl_phdr_info))
435 : {
436 : int i;
437 : for (i = 0; i < info->dlpi_phnum; ++i)
438 : {
439 : if (info->dlpi_phdr[i].p_type == PT_DYNAMIC)
440 : {
441 : pDynamic = &(info->dlpi_phdr[i]);
442 : break;
443 : }
444 : }
445 : }
446 :
447 : if (pDynamic)
448 : {
449 : char buffer[100];
450 : int len;
451 : char exe[PATH_MAX];
452 : const char *dsoname = info->dlpi_name;
453 :
454 : dynamic_entry* entry = (dynamic_entry*)data;
455 :
456 : if (strcmp(dsoname, "") == 0)
457 : {
458 : snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid());
459 : if ((len = readlink(buffer, exe, PATH_MAX)) != -1)
460 : {
461 : exe[len] = '\0';
462 : dsoname = exe;
463 : }
464 : }
465 :
466 : if (strcmp(dsoname, entry->name) == 0)
467 : {
468 : entry->offset = pDynamic->p_offset;
469 : return 1;
470 : }
471 : }
472 : return 0;
473 : }
474 :
475 : /* Get the location of the .dynamic section offset for the given elf file.
476 : * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo
477 : *
478 : * We want to know this value so that if the binaries have been modifed
479 : * by prelink then we can still process the call stack on server side
480 : * by comparing this value to that of an "un-prelinked but known to be
481 : * otherwise equivalent" version of those binaries and adjust the call
482 : * stack addresses by the differences between .dynamic addresses so as
483 : * to be able to map the prelinked addresses back to the unprelinked
484 : * addresses
485 : *
486 : * cmc@openoffice.org
487 : */
488 : static ElfW(Off)
489 : dynamic_section_offset(const char *name)
490 : {
491 : dynamic_entry entry;
492 :
493 : entry.name = name;
494 : entry.offset = 0;
495 :
496 : dl_iterate_phdr(callback, &entry);
497 :
498 : return entry.offset;
499 : }
500 : #endif
501 :
502 0 : static int ReportCrash( int Signal )
503 : {
504 : #ifdef SAL_ENABLE_CRASH_REPORT
505 :
506 : #define REPORTENV_PARAM "-crashreportenv:"
507 :
508 : static sal_Bool bCrashReporterExecuted = sal_False;
509 : sal_Bool bAutoCrashReport = sal_False;
510 :
511 : sal_uInt32 argi;
512 : sal_uInt32 argc;
513 : rtl_uString *ustrCommandArg = NULL;
514 :
515 : if ( !bErrorReportingEnabled )
516 : return -1;
517 :
518 : argc = osl_getCommandArgCount();
519 :
520 : for ( argi = 0; argi < argc; argi++ )
521 : {
522 : if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) )
523 : {
524 : if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--nocrashreport" ) )
525 : {
526 : rtl_uString_release( ustrCommandArg );
527 : return -1;
528 : }
529 : else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--autocrashreport" ) )
530 : {
531 : bAutoCrashReport = sal_True;
532 : }
533 : else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength(
534 : rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ),
535 : REPORTENV_PARAM, strlen(REPORTENV_PARAM) )
536 : )
537 : {
538 : rtl_uString *ustrEnvironment = NULL;
539 : rtl_String *strEnv = NULL;
540 :
541 : rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) );
542 :
543 : if ( ustrEnvironment )
544 : {
545 : rtl_uString2String(
546 : &strEnv,
547 : rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ),
548 : osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS
549 : );
550 :
551 : if ( strEnv )
552 : {
553 : putenv( rtl_string_getStr( strEnv ) );
554 : rtl_string_release( strEnv );
555 : }
556 :
557 : rtl_uString_release( ustrEnvironment );
558 : }
559 :
560 : }
561 :
562 : }
563 : }
564 :
565 : if ( ustrCommandArg )
566 : rtl_uString_release( ustrCommandArg );
567 :
568 : if ( !bCrashReporterExecuted )
569 : {
570 : int i;
571 : /* struct sigaction act; */
572 :
573 : for (i = 0; i < NoSignals; i++)
574 : {
575 : if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT )
576 : {
577 : int ret;
578 : char szShellCmd[512] = { '\0' };
579 : char *pXMLTempName = NULL;
580 : char *pStackTempName = NULL;
581 : char *pChecksumTempName = NULL;
582 :
583 : #ifdef INCLUDE_BACKTRACE
584 : char szXMLTempNameBuffer[L_tmpnam];
585 : char szChecksumTempNameBuffer[L_tmpnam];
586 : char szStackTempNameBuffer[L_tmpnam];
587 :
588 : void *stackframes[MAX_STACK_FRAMES];
589 : int iFrame;
590 : int nFrames = backtrace( stackframes, SAL_N_ELEMENTS(stackframes) );
591 :
592 : FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL;
593 : int fdxml, fdstk, fdchksum;
594 :
595 : strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) );
596 : strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) - strlen(szXMLTempNameBuffer) - 1 );
597 :
598 : strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) );
599 : strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) - strlen(szStackTempNameBuffer) - 1 );
600 :
601 : strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) );
602 : strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) - strlen(szChecksumTempNameBuffer) - 1 );
603 :
604 : fdxml = mkstemp(szXMLTempNameBuffer);
605 : fdstk = mkstemp(szStackTempNameBuffer);
606 : fdchksum = mkstemp(szChecksumTempNameBuffer);
607 :
608 : xmlout = fdopen( fdxml , "w" );
609 : stackout = fdopen( fdstk , "w" );
610 : checksumout = fdopen( fdchksum, "w" );
611 :
612 : pXMLTempName = szXMLTempNameBuffer;
613 : pStackTempName = szStackTempNameBuffer;
614 : pChecksumTempName = szChecksumTempNameBuffer;
615 :
616 :
617 : if ( xmlout && stackout && checksumout )
618 : {
619 : fprintf( xmlout, "<errormail:Stack type=\"%s\">\n", STACKTYPE );
620 :
621 : fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\n" );
622 :
623 : for ( iFrame = 0; iFrame < nFrames; iFrame++ )
624 : {
625 : Dl_info dl_info;
626 :
627 : fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":",
628 : SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) );
629 :
630 : fprintf( xmlout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"",
631 : iFrame,
632 : SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame])
633 : );
634 :
635 : memset( &dl_info, 0, sizeof(dl_info) );
636 :
637 : /* dladdr may fail */
638 : if ( dladdr( stackframes[iFrame], &dl_info) )
639 : {
640 : const char *dli_fname = NULL;
641 : char *dli_fdir = NULL;
642 : char szDirectory[PATH_MAX];
643 : char szCanonicDirectory[PATH_MAX];
644 :
645 : /* Don't expect that dladdr filled all members of dl_info */
646 :
647 : dli_fname = dl_info.dli_fname ? strrchr( dl_info.dli_fname, '/' ) : NULL;
648 : if ( dli_fname )
649 : {
650 : ++dli_fname;
651 : memcpy( szDirectory, dl_info.dli_fname, dli_fname - dl_info.dli_fname );
652 : szDirectory[dli_fname - dl_info.dli_fname] = 0;
653 :
654 : dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory;
655 :
656 : if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' )
657 : strcat( dli_fdir, "/" );
658 : }
659 : else
660 : dli_fname = dl_info.dli_fname;
661 :
662 : /* create checksum of library on stack */
663 : if ( dli_fname )
664 : {
665 : sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
666 :
667 : sal_uInt32 nBytesProcessed = calc_md5_checksum(
668 : dl_info.dli_fname, checksum, sizeof(checksum) );
669 : if ( nBytesProcessed )
670 : {
671 : int j;
672 :
673 : fprintf( checksumout, "<errormail:Checksum sum=\"0x" );
674 : for ( j = 0; j < 16; fprintf( checksumout, "%02X", checksum[j++] ) );
675 : fprintf( checksumout,
676 : "\" bytes=\"%lu\" file=\"%s\"/>\n",
677 : SAL_INT_CAST(
678 : unsigned long, nBytesProcessed),
679 : dli_fname );
680 : }
681 : }
682 :
683 : if ( dl_info.dli_fbase && dl_info.dli_fname )
684 : {
685 : #ifdef LINUX
686 : ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname);
687 : fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset);
688 : #endif
689 :
690 : fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x",
691 : dl_info.dli_fname,
692 : (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase
693 : );
694 :
695 : fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase );
696 : if ( dli_fname )
697 : fprintf( xmlout, " name=\"%s\"", dli_fname );
698 :
699 : if ( dli_fdir )
700 : fprintf( xmlout, " path=\"%s\"", dli_fdir );
701 :
702 : #ifdef LINUX
703 : fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset );
704 : #endif
705 : }
706 : else
707 : fprintf( stackout, " ????????" );
708 :
709 : if ( dl_info.dli_sname && dl_info.dli_saddr )
710 : {
711 : fputs( " (", stackout );
712 : fputs_xml( dl_info.dli_sname, stackout );
713 : fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)",
714 : (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr );
715 :
716 : fputs( " ordinal=\"", xmlout );
717 : fputs_xml( dl_info.dli_sname, xmlout );
718 : fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"",
719 : (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr );
720 : }
721 :
722 : }
723 : else /* dladdr failed */
724 : {
725 : fprintf( stackout, " ????????" );
726 : }
727 :
728 : fprintf( stackout, "\n" );
729 : fprintf( xmlout, "/>\n" );
730 :
731 : }
732 :
733 : fprintf( xmlout, "</errormail:Stack>\n" );
734 : fprintf( checksumout, "</errormail:Checksums>\n" );
735 : }
736 : else
737 : {
738 : pXMLTempName = NULL;
739 : pStackTempName = NULL;
740 : pChecksumTempName = NULL;
741 : }
742 :
743 : if ( stackout )
744 : fclose( stackout );
745 : if ( xmlout )
746 : fclose( xmlout );
747 : if ( checksumout )
748 : fclose( checksumout );
749 :
750 : if ( pXMLTempName && pChecksumTempName && pStackTempName )
751 : #endif /* INCLUDE_BACKTRACE */
752 : {
753 : rtl_uString * crashrep_url = NULL;
754 : rtl_uString * crashrep_path = NULL;
755 : rtl_String * crashrep_path_system = NULL;
756 : rtl_string2UString(
757 : &crashrep_url,
758 : RTL_CONSTASCII_USTRINGPARAM(
759 : "$BRAND_BASE_DIR/program/crashrep"),
760 : OSTRING_TO_OUSTRING_CVTFLAGS);
761 : rtl_bootstrap_expandMacros(&crashrep_url);
762 : osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path);
763 : rtl_uString2String(
764 : &crashrep_path_system,
765 : rtl_uString_getStr(crashrep_path),
766 : rtl_uString_getLength(crashrep_path),
767 : osl_getThreadTextEncoding(),
768 : (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
769 : | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR));
770 : rtl_uString_release(crashrep_url);
771 : rtl_uString_release(crashrep_path);
772 : #if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX)
773 : snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
774 : "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s",
775 : rtl_string_getStr(crashrep_path_system),
776 : getpid(),
777 : Signal,
778 : pXMLTempName,
779 : pChecksumTempName,
780 : pStackTempName,
781 : bAutoCrashReport ? " -send" : "" );
782 : #elif defined INCLUDE_BACKTRACE && defined SOLARIS
783 : snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
784 : "%s -p %d -s %d -xml %s -chksum %s -noui%s",
785 : rtl_string_getStr(crashrep_path_system),
786 : getpid(),
787 : Signal,
788 : pXMLTempName,
789 : pChecksumTempName,
790 : bAutoCrashReport ? " -send" : "" );
791 : #else
792 : snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd),
793 : "%s -p %d -s %d -noui%s",
794 : rtl_string_getStr(crashrep_path_system),
795 : getpid(), Signal, bAutoCrashReport ? " -send" : "" );
796 : #endif
797 : rtl_string_release(crashrep_path_system);
798 : }
799 :
800 : ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd );
801 :
802 : if ( pXMLTempName )
803 : unlink( pXMLTempName );
804 :
805 : if ( pStackTempName )
806 : unlink( pStackTempName );
807 :
808 : if ( pChecksumTempName )
809 : unlink( pChecksumTempName );
810 :
811 : if ( -1 != ret )
812 : {
813 : bCrashReporterExecuted = sal_True;
814 : return 1;
815 : }
816 : else
817 : return -1;
818 :
819 : }
820 : }
821 :
822 : return 0;
823 : }
824 :
825 : return 1;
826 : #else /* defined SAL_ENABLE_CRASH_REPORT */
827 : /* the utility crash_report is not build, so do the same as when
828 : the option -nocrashreport is used */
829 : (void) Signal; // avoid warnings
830 0 : return -1;
831 : #endif /* defined SAL_ENABLE_CRASH_REPORT */
832 : }
833 :
834 0 : static void PrintStack( int sig )
835 : {
836 : #ifdef INCLUDE_BACKTRACE
837 : void *buffer[MAX_STACK_FRAMES];
838 0 : int size = backtrace( buffer, SAL_N_ELEMENTS(buffer) );
839 : #endif
840 :
841 0 : fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
842 :
843 : #if defined( MACOSX ) && !defined( INCLUDE_BACKTRACE )
844 : fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
845 : #else
846 : #ifdef INCLUDE_BACKTRACE
847 0 : if ( size > 0 )
848 : {
849 0 : fputs( "Stack:\n", stderr );
850 0 : backtrace_symbols_fd( buffer, size, fileno(stderr) );
851 : }
852 : #endif
853 : #endif
854 0 : }
855 :
856 0 : static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
857 : {
858 0 : oslSignalHandlerImpl* pHandler = SignalList;
859 0 : oslSignalAction Action = osl_Signal_ActCallNextHdl;
860 :
861 0 : while (pHandler != NULL)
862 : {
863 0 : if ((Action = pHandler->Handler(pHandler->pData, pInfo))
864 : != osl_Signal_ActCallNextHdl)
865 0 : break;
866 :
867 0 : pHandler = pHandler->pNext;
868 : }
869 :
870 0 : return Action;
871 : }
872 :
873 0 : void CallSystemHandler(int Signal)
874 : {
875 : int i;
876 : struct sigaction act;
877 :
878 0 : for (i = 0; i < NoSignals; i++)
879 : {
880 0 : if (Signals[i].Signal == Signal)
881 0 : break;
882 : }
883 :
884 0 : if (i < NoSignals)
885 : {
886 0 : if ((Signals[i].Handler == NULL) ||
887 0 : (Signals[i].Handler == SIG_DFL) ||
888 0 : (Signals[i].Handler == SIG_IGN) ||
889 0 : (Signals[i].Handler == SIG_ERR))
890 : {
891 0 : switch (Signals[i].Action)
892 : {
893 : case ACT_EXIT: /* terminate */
894 : /* prevent dumping core on exit() */
895 0 : _exit(255);
896 : break;
897 :
898 : case ACT_ABORT: /* terminate witch core dump */
899 0 : ReportCrash( Signal );
900 0 : act.sa_handler = SIG_DFL;
901 0 : act.sa_flags = 0;
902 0 : sigemptyset(&(act.sa_mask));
903 0 : sigaction(SIGABRT, &act, NULL);
904 0 : PrintStack( Signal );
905 0 : abort();
906 : break;
907 :
908 : case ACT_IGNORE: /* ignore */
909 0 : break;
910 :
911 : default: /* should never happen */
912 : OSL_ASSERT(0);
913 : }
914 0 : }
915 : else
916 0 : (*Signals[i].Handler)(Signal);
917 : }
918 0 : }
919 :
920 : #if defined HAVE_VALGRIND_HEADERS
921 : static void DUMPCURRENTALLOCS()
922 : {
923 : VALGRIND_PRINTF( "=== start memcheck dump of active allocations ===\n" );
924 :
925 : #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
926 : # pragma GCC diagnostic push
927 : # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
928 : #endif
929 :
930 : VALGRIND_DO_LEAK_CHECK;
931 :
932 : #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
933 : # pragma GCC diagnostic pop
934 : #endif
935 :
936 : VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" );
937 : }
938 : #endif
939 :
940 : /*****************************************************************************/
941 : /* SignalHandlerFunction */
942 : /*****************************************************************************/
943 0 : void SignalHandlerFunction(int Signal)
944 : {
945 : oslSignalInfo Info;
946 : struct sigaction act;
947 :
948 0 : Info.UserSignal = Signal;
949 0 : Info.UserData = NULL;
950 :
951 0 : switch (Signal)
952 : {
953 : case SIGBUS:
954 : case SIGILL:
955 : case SIGSEGV:
956 : case SIGIOT:
957 : #if ( SIGIOT != SIGABRT )
958 : case SIGABRT:
959 : #endif
960 0 : Info.Signal = osl_Signal_AccessViolation;
961 0 : break;
962 :
963 : case -1:
964 0 : Info.Signal = osl_Signal_IntegerDivideByZero;
965 0 : break;
966 :
967 : case SIGFPE:
968 0 : Info.Signal = osl_Signal_FloatDivideByZero;
969 0 : break;
970 :
971 : case SIGINT:
972 : case SIGTERM:
973 : case SIGQUIT:
974 0 : Info.Signal = osl_Signal_Terminate;
975 0 : break;
976 :
977 : #if defined HAVE_VALGRIND_HEADERS
978 : case SIGUSR2:
979 : if (RUNNING_ON_VALGRIND)
980 : DUMPCURRENTALLOCS();
981 : Info.Signal = osl_Signal_System;
982 : break;
983 : #endif
984 :
985 : default:
986 0 : Info.Signal = osl_Signal_System;
987 0 : break;
988 : }
989 :
990 0 : ReportCrash( Signal );
991 :
992 : /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
993 0 : if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation))
994 0 : _exit(255);
995 : /* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
996 :
997 :
998 0 : switch (CallSignalHandler(&Info))
999 : {
1000 : case osl_Signal_ActCallNextHdl:
1001 0 : CallSystemHandler(Signal);
1002 0 : break;
1003 :
1004 : case osl_Signal_ActAbortApp:
1005 0 : ReportCrash( Signal );
1006 0 : act.sa_handler = SIG_DFL;
1007 0 : act.sa_flags = 0;
1008 0 : sigemptyset(&(act.sa_mask));
1009 0 : sigaction(SIGABRT, &act, NULL);
1010 0 : PrintStack( Signal );
1011 0 : abort();
1012 : break;
1013 :
1014 : case osl_Signal_ActKillApp:
1015 : /* prevent dumping core on exit() */
1016 0 : _exit(255);
1017 : break;
1018 : default:
1019 0 : break;
1020 : }
1021 0 : }
1022 :
1023 : /*****************************************************************************/
1024 : /* osl_addSignalHandler */
1025 : /*****************************************************************************/
1026 234 : oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
1027 : {
1028 : oslSignalHandlerImpl* pHandler;
1029 :
1030 : OSL_ASSERT(Handler != NULL);
1031 234 : if ( Handler == 0 )
1032 : {
1033 0 : return 0;
1034 : }
1035 :
1036 234 : if (! bInitSignal)
1037 151 : bInitSignal = InitSignal();
1038 :
1039 234 : pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl));
1040 :
1041 234 : if (pHandler != NULL)
1042 : {
1043 234 : pHandler->Handler = Handler;
1044 234 : pHandler->pData = pData;
1045 :
1046 234 : osl_acquireMutex(SignalListMutex);
1047 :
1048 234 : pHandler->pNext = SignalList;
1049 234 : SignalList = pHandler;
1050 :
1051 234 : osl_releaseMutex(SignalListMutex);
1052 :
1053 234 : return (pHandler);
1054 : }
1055 :
1056 0 : return (NULL);
1057 : }
1058 :
1059 : /*****************************************************************************/
1060 : /* osl_removeSignalHandler */
1061 : /*****************************************************************************/
1062 177 : sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
1063 : {
1064 177 : oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
1065 :
1066 : OSL_ASSERT(Handler != NULL);
1067 :
1068 177 : if (! bInitSignal)
1069 0 : bInitSignal = InitSignal();
1070 :
1071 177 : osl_acquireMutex(SignalListMutex);
1072 :
1073 177 : pHandler = SignalList;
1074 :
1075 354 : while (pHandler != NULL)
1076 : {
1077 177 : if (pHandler == Handler)
1078 : {
1079 177 : if (pPrevious)
1080 0 : pPrevious->pNext = pHandler->pNext;
1081 : else
1082 177 : SignalList = pHandler->pNext;
1083 :
1084 177 : osl_releaseMutex(SignalListMutex);
1085 :
1086 177 : if (SignalList == NULL)
1087 94 : bInitSignal = DeInitSignal();
1088 :
1089 177 : free(pHandler);
1090 :
1091 177 : return (sal_True);
1092 : }
1093 :
1094 0 : pPrevious = pHandler;
1095 0 : pHandler = pHandler->pNext;
1096 : }
1097 :
1098 0 : osl_releaseMutex(SignalListMutex);
1099 :
1100 0 : return (sal_False);
1101 : }
1102 :
1103 : /*****************************************************************************/
1104 : /* osl_raiseSignal */
1105 : /*****************************************************************************/
1106 0 : oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
1107 : {
1108 : oslSignalInfo Info;
1109 : oslSignalAction Action;
1110 :
1111 0 : if (! bInitSignal)
1112 0 : bInitSignal = InitSignal();
1113 :
1114 0 : osl_acquireMutex(SignalListMutex);
1115 :
1116 0 : Info.Signal = osl_Signal_User;
1117 0 : Info.UserSignal = UserSignal;
1118 0 : Info.UserData = UserData;
1119 :
1120 0 : Action = CallSignalHandler(&Info);
1121 :
1122 0 : osl_releaseMutex(SignalListMutex);
1123 :
1124 0 : return (Action);
1125 : }
1126 :
1127 : /*****************************************************************************/
1128 : /* osl_setErrorReporting */
1129 : /*****************************************************************************/
1130 83 : sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
1131 : {
1132 83 : sal_Bool bOld = bErrorReportingEnabled;
1133 83 : bErrorReportingEnabled = bEnable;
1134 :
1135 83 : return bOld;
1136 : }
1137 :
1138 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|