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