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