Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : /* system headers */
31 : : #include "system.h"
32 : :
33 : : #define MAX_STACK_FRAMES 256
34 : :
35 : : #if defined( MACOSX )
36 : :
37 : : #if defined( INTEL )
38 : : #include "backtrace.h"
39 : : #define INCLUDE_BACKTRACE
40 : : #define STACKTYPE "MacOsX_X86"
41 : : #endif /* INTEL */
42 : :
43 : : #endif /* MACOSX */
44 : :
45 : : #ifdef LINUX
46 : : #include <execinfo.h>
47 : : #include <link.h>
48 : : #define INCLUDE_BACKTRACE
49 : : #define STACKTYPE "Linux"
50 : : #endif
51 : :
52 : : #ifdef SOLARIS
53 : :
54 : : #include "backtrace.h"
55 : : #define INCLUDE_BACKTRACE
56 : :
57 : : #if defined( SPARC )
58 : : #define STACKTYPE "Solaris_Sparc"
59 : : #elif defined( INTEL )
60 : : #define STACKTYPE "Solaris_X86"
61 : : #else
62 : : #define STACKTYPE "Solaris_Unknown"
63 : : #endif
64 : :
65 : : #endif /* defined SOLARIS */
66 : :
67 : : #include <osl/diagnose.h>
68 : : #include <osl/mutex.h>
69 : : #include <osl/signal.h>
70 : : #include <osl/process.h>
71 : : #include <osl/thread.h>
72 : : #include <sal/macros.h>
73 : : #include <rtl/bootstrap.h>
74 : : #include <rtl/digest.h>
75 : :
76 : : #include "file_path_helper.h"
77 : :
78 : : #define ACT_IGNORE 1
79 : : #define ACT_EXIT 2
80 : : #define ACT_SYSTEM 3
81 : : #define ACT_HIDE 4
82 : : #ifdef SAL_ENABLE_CRASH_REPORT
83 : : # define ACT_ABORT 5
84 : : #else
85 : : # define ACT_ABORT ACT_SYSTEM
86 : : #endif
87 : :
88 : : #if defined(HAVE_MEMCHECK_H)
89 : : #include <memcheck.h>
90 : : #endif
91 : :
92 : : typedef struct _oslSignalHandlerImpl
93 : : {
94 : : oslSignalHandlerFunction Handler;
95 : : void* pData;
96 : : struct _oslSignalHandlerImpl* pNext;
97 : : } oslSignalHandlerImpl;
98 : :
99 : : static struct SignalAction
100 : : {
101 : : int Signal;
102 : : int Action;
103 : : void (*Handler)(int);
104 : : } Signals[] =
105 : : {
106 : : { SIGHUP, ACT_HIDE, NULL }, /* hangup */
107 : : { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */
108 : : { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */
109 : : { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */
110 : : /* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/
111 : : { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */
112 : : #if ( SIGIOT != SIGABRT )
113 : : { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */
114 : : #endif
115 : : { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */
116 : : #ifdef SIGEMT
117 : : { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */
118 : : /* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/
119 : : /* SIGEMT may also be used by the profiler - so it is probably not a good
120 : : plan to have the new handler use this signal*/
121 : : #endif
122 : : { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */
123 : : { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */
124 : : { SIGBUS, ACT_ABORT, NULL }, /* bus error */
125 : : { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */
126 : : #ifdef SIGSYS
127 : : { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */
128 : : #endif
129 : : { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */
130 : : { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */
131 : : { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */
132 : : { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */
133 : : { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */
134 : : { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */
135 : : #ifdef SIGPWR
136 : : { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */
137 : : #endif
138 : : { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */
139 : : { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */
140 : : #ifdef SIGPOLL
141 : : { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occurred */
142 : : #endif
143 : : { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */
144 : : { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */
145 : : { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */
146 : : { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */
147 : : { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */
148 : : { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */
149 : : { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */
150 : : /*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do
151 : : not get taken by the new handler - the new handler does not pass on context
152 : : information which causes 'collect' to crash. This is a way of avoiding
153 : : what looks like a bug in the new handler*/
154 : : { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */
155 : : { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */
156 : : };
157 : : const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction);
158 : :
159 : : static sal_Bool bErrorReportingEnabled = sal_True;
160 : : static sal_Bool bInitSignal = sal_False;
161 : : static oslMutex SignalListMutex;
162 : : static oslSignalHandlerImpl* SignalList;
163 : : static sal_Bool bDoHardKill = sal_False;
164 : : static sal_Bool bSetSEGVHandler = sal_False;
165 : : static sal_Bool bSetWINCHHandler = sal_False;
166 : : static sal_Bool bSetILLHandler = sal_False;
167 : :
168 : : static void SignalHandlerFunction(int);
169 : :
170 : 322 : static void getExecutableName_Impl (rtl_String ** ppstrProgName)
171 : : {
172 : 322 : rtl_uString * ustrProgFile = 0;
173 : 322 : osl_getExecutableFile (&ustrProgFile);
174 [ + - ]: 322 : if (ustrProgFile)
175 : : {
176 : 322 : rtl_uString * ustrProgName = 0;
177 : 322 : osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName);
178 [ + - ]: 322 : if (ustrProgName != 0)
179 : : {
180 : 644 : rtl_uString2String (
181 : : ppstrProgName,
182 : 322 : rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName),
183 : 322 : osl_getThreadTextEncoding(),
184 : : OUSTRING_TO_OSTRING_CVTFLAGS);
185 : 322 : rtl_uString_release (ustrProgName);
186 : : }
187 : 322 : rtl_uString_release (ustrProgFile);
188 : : }
189 : 322 : }
190 : :
191 : 322 : static sal_Bool is_soffice_Impl (void)
192 : : {
193 : 322 : sal_Int32 idx = -1;
194 : 322 : rtl_String * strProgName = 0;
195 : :
196 : 322 : getExecutableName_Impl (&strProgName);
197 [ + - ]: 322 : if (strProgName)
198 : : {
199 : 322 : idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice");
200 : 322 : rtl_string_release (strProgName);
201 : : }
202 : 322 : return (idx != -1);
203 : : }
204 : :
205 : 322 : static sal_Bool InitSignal()
206 : : {
207 : : int i;
208 : : struct sigaction act;
209 : : struct sigaction oact;
210 : : sigset_t unset;
211 : :
212 [ + + ]: 322 : if (is_soffice_Impl())
213 : : {
214 : : sal_uInt32 argi;
215 : : sal_uInt32 argc;
216 : 158 : rtl_uString *ustrCommandArg = 0;
217 : :
218 : 158 : argc = osl_getCommandArgCount();
219 [ + + ]: 1426 : for ( argi = 0; argi < argc; argi++ )
220 : : {
221 [ + - ]: 1268 : if (osl_Process_E_None == osl_getCommandArg (argi, &ustrCommandArg))
222 : : {
223 [ - + ]: 1268 : if (0 == rtl_ustr_ascii_compare (rtl_uString_getStr (ustrCommandArg), "-bean"))
224 : : {
225 : 0 : bDoHardKill = sal_True;
226 : 0 : break;
227 : : }
228 : : }
229 : : }
230 [ + - ]: 158 : if (ustrCommandArg)
231 : : {
232 : 158 : rtl_uString_release (ustrCommandArg);
233 : 158 : ustrCommandArg = 0;
234 : : }
235 : :
236 : : // WORKAROUND FOR SEGV HANDLER CONFLICT
237 : : //
238 : : // the java jit needs SIGSEGV for proper work
239 : : // and we need SIGSEGV for the office crashguard
240 : : //
241 : : // TEMPORARY SOLUTION:
242 : : // the office sets the signal handler during startup
243 : : // java can than overwrite it, if needed
244 : 158 : bSetSEGVHandler = sal_True;
245 : :
246 : : // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
247 : 158 : bSetWINCHHandler = sal_True;
248 : :
249 : : // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
250 : 158 : bSetILLHandler = sal_True;
251 : : }
252 : :
253 : : #ifdef DBG_UTIL
254 : : bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = bDoHardKill = sal_False;
255 : : #endif
256 : :
257 : 322 : SignalListMutex = osl_createMutex();
258 : :
259 : 322 : act.sa_handler = SignalHandlerFunction;
260 : 322 : act.sa_flags = SA_RESTART;
261 : :
262 : 322 : sigfillset(&(act.sa_mask));
263 : :
264 : : /* Initialize the rest of the signals */
265 [ + + ]: 9982 : for (i = 0; i < NoSignals; ++i)
266 : : {
267 : : #if defined(HAVE_MEMCHECK_H)
268 : : if (Signals[i].Signal == SIGUSR2 && RUNNING_ON_VALGRIND)
269 : : Signals[i].Action = ACT_IGNORE;
270 : : #endif
271 : :
272 : : /* hack: stomcatd is attaching JavaVM wich dont work with an sigaction(SEGV) */
273 [ + + ][ + + ]: 9660 : if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV)
274 [ + + ][ + + ]: 9496 : && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH)
275 [ + + ][ + + ]: 9332 : && (bSetILLHandler || Signals[i].Signal != SIGILL))
276 : : {
277 [ + + ]: 9168 : if (Signals[i].Action != ACT_SYSTEM)
278 : : {
279 [ + + ]: 3378 : if (Signals[i].Action == ACT_HIDE)
280 : : {
281 : : struct sigaction ign;
282 : :
283 : 644 : ign.sa_handler = SIG_IGN;
284 : 644 : ign.sa_flags = 0;
285 : 644 : sigemptyset(&ign.sa_mask);
286 : :
287 [ + - ]: 644 : if (sigaction(Signals[i].Signal, &ign, &oact) == 0)
288 : 644 : Signals[i].Handler = oact.sa_handler;
289 : : else
290 : 644 : Signals[i].Handler = SIG_DFL;
291 : : }
292 : : else
293 : : {
294 [ + - ]: 2734 : if (sigaction(Signals[i].Signal, &act, &oact) == 0)
295 : 2734 : Signals[i].Handler = oact.sa_handler;
296 : : else
297 : 0 : Signals[i].Handler = SIG_DFL;
298 : : }
299 : : }
300 : : }
301 : : }
302 : :
303 : : /* Clear signal mask inherited from parent process (on Mac OS X, upon a
304 : : crash soffice re-execs itself from within the signal handler, so the
305 : : second soffice would have the guilty signal blocked and would freeze upon
306 : : encountering a similar crash again): */
307 [ + - ]: 322 : if (sigemptyset(&unset) < 0 ||
308 : 322 : pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0)
309 : : {
310 : : OSL_TRACE("sigemptyset or pthread_sigmask failed");
311 : : }
312 : :
313 : 322 : return sal_True;
314 : : }
315 : :
316 : 158 : static sal_Bool DeInitSignal()
317 : : {
318 : : int i;
319 : : struct sigaction act;
320 : :
321 : 158 : act.sa_flags = 0;
322 : 158 : sigemptyset(&(act.sa_mask));
323 : :
324 : : /* Initialize the rest of the signals */
325 [ + + ]: 4898 : for (i = NoSignals - 1; i >= 0; i--)
326 [ + + ]: 4740 : if (Signals[i].Action != ACT_SYSTEM)
327 : : {
328 : 1738 : act.sa_handler = Signals[i].Handler;
329 : :
330 : 1738 : sigaction(Signals[i].Signal, &act, NULL);
331 : : }
332 : :
333 : 158 : osl_destroyMutex(SignalListMutex);
334 : :
335 : 158 : return sal_False;
336 : : }
337 : :
338 : : #if defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE)
339 : :
340 : : /*****************************************************************************/
341 : : /* Generate MD5 checksum */
342 : : /*****************************************************************************/
343 : :
344 : : static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
345 : : {
346 : : sal_uInt32 nBytesProcessed = 0;
347 : :
348 : : FILE *fp = fopen( filename, "r" );
349 : :
350 : : if ( fp )
351 : : {
352 : : rtlDigest digest = rtl_digest_createMD5();
353 : :
354 : : if ( digest )
355 : : {
356 : : size_t nBytesRead;
357 : : sal_uInt8 buffer[4096];
358 : : rtlDigestError error = rtl_Digest_E_None;
359 : :
360 : : while ( rtl_Digest_E_None == error &&
361 : : 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
362 : : {
363 : : error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
364 : : nBytesProcessed += nBytesRead;
365 : : }
366 : :
367 : : if ( rtl_Digest_E_None == error )
368 : : {
369 : : error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
370 : : }
371 : :
372 : : if ( rtl_Digest_E_None != error )
373 : : nBytesProcessed = 0;
374 : :
375 : : rtl_digest_destroyMD5( digest );
376 : : }
377 : :
378 : : fclose( fp );
379 : : }
380 : :
381 : : return nBytesProcessed;
382 : : }
383 : :
384 : : /*****************************************************************************/
385 : : /* Call crash reporter */
386 : : /*****************************************************************************/
387 : :
388 : : /* Helper function to encode and write a string to a stream */
389 : :
390 : : static int fputs_xml( const char *string, FILE *stream )
391 : : {
392 : : int result = 0;
393 : :
394 : : while ( result >= 0 && *string )
395 : : {
396 : : switch( *string )
397 : : {
398 : : case '&':
399 : : result = fputs( "&", stream );
400 : : break;
401 : : case '<':
402 : : result = fputs( "<", stream );
403 : : break;
404 : : case '>':
405 : : result = fputs( ">", stream );
406 : : break;
407 : : default:
408 : : result = fputc( *string, stream );
409 : : break;
410 : : }
411 : :
412 : : string++;
413 : : }
414 : :
415 : : return result;
416 : : }
417 : : #endif
418 : :
419 : : /* Create intermediate files and run crash reporter */
420 : :
421 : : #define REPORTENV_PARAM "-crashreportenv:"
422 : :
423 : : #if defined SAL_ENABLE_CRASH_REPORT && defined INCLUDE_BACKTRACE && \
424 : : defined LINUX
425 : :
426 : : typedef struct
427 : : {
428 : : const char *name;
429 : : ElfW(Off) offset;
430 : : } dynamic_entry;
431 : :
432 : : static int
433 : : callback(struct dl_phdr_info *info, size_t size, void *data)
434 : : {
435 : : const ElfW(Phdr) *pDynamic = NULL;
436 : :
437 : : if (size == sizeof(struct dl_phdr_info))
438 : : {
439 : : int i;
440 : : for (i = 0; i < info->dlpi_phnum; ++i)
441 : : {
442 : : if (info->dlpi_phdr[i].p_type == PT_DYNAMIC)
443 : : {
444 : : pDynamic = &(info->dlpi_phdr[i]);
445 : : break;
446 : : }
447 : : }
448 : : }
449 : :
450 : : if (pDynamic)
451 : : {
452 : : char buffer[100];
453 : : int len;
454 : : char exe[PATH_MAX];
455 : : const char *dsoname = info->dlpi_name;
456 : :
457 : : dynamic_entry* entry = (dynamic_entry*)data;
458 : :
459 : : if (strcmp(dsoname, "") == 0)
460 : : {
461 : : snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid());
462 : : if ((len = readlink(buffer, exe, PATH_MAX)) != -1)
463 : : {
464 : : exe[len] = '\0';
465 : : dsoname = exe;
466 : : }
467 : : }
468 : :
469 : : if (strcmp(dsoname, entry->name) == 0)
470 : : {
471 : : entry->offset = pDynamic->p_offset;
472 : : return 1;
473 : : }
474 : : }
475 : : return 0;
476 : : }
477 : :
478 : : /* Get the location of the .dynamic section offset for the given elf file.
479 : : * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo
480 : : *
481 : : * We want to know this value so that if the binaries have been modifed
482 : : * by prelink then we can still process the call stack on server side
483 : : * by comparing this value to that of an "un-prelinked but known to be
484 : : * otherwise equivalent" version of those binaries and adjust the call
485 : : * stack addresses by the differences between .dynamic addresses so as
486 : : * to be able to map the prelinked addresses back to the unprelinked
487 : : * addresses
488 : : *
489 : : * cmc@openoffice.org
490 : : */
491 : : static ElfW(Off)
492 : : dynamic_section_offset(const char *name)
493 : : {
494 : : dynamic_entry entry;
495 : :
496 : : entry.name = name;
497 : : entry.offset = 0;
498 : :
499 : : dl_iterate_phdr(callback, &entry);
500 : :
501 : : return entry.offset;
502 : : }
503 : : #endif
504 : :
505 : 0 : static int ReportCrash( int Signal )
506 : : {
507 : : #ifdef SAL_ENABLE_CRASH_REPORT
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_MEMCHECK_H)
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_MEMCHECK_H)
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 : 480 : oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
1027 : : {
1028 : : oslSignalHandlerImpl* pHandler;
1029 : :
1030 : : OSL_ASSERT(Handler != NULL);
1031 [ - + ]: 480 : if ( Handler == 0 )
1032 : : {
1033 : 0 : return 0;
1034 : : }
1035 : :
1036 [ + + ]: 480 : if (! bInitSignal)
1037 : 322 : bInitSignal = InitSignal();
1038 : :
1039 : 480 : pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl));
1040 : :
1041 [ + - ]: 480 : if (pHandler != NULL)
1042 : : {
1043 : 480 : pHandler->Handler = Handler;
1044 : 480 : pHandler->pData = pData;
1045 : :
1046 : 480 : osl_acquireMutex(SignalListMutex);
1047 : :
1048 : 480 : pHandler->pNext = SignalList;
1049 : 480 : SignalList = pHandler;
1050 : :
1051 : 480 : osl_releaseMutex(SignalListMutex);
1052 : :
1053 : 480 : return (pHandler);
1054 : : }
1055 : :
1056 : 480 : return (NULL);
1057 : : }
1058 : :
1059 : : /*****************************************************************************/
1060 : : /* osl_removeSignalHandler */
1061 : : /*****************************************************************************/
1062 : 316 : sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
1063 : : {
1064 : 316 : oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
1065 : :
1066 : : OSL_ASSERT(Handler != NULL);
1067 : :
1068 [ - + ]: 316 : if (! bInitSignal)
1069 : 0 : bInitSignal = InitSignal();
1070 : :
1071 : 316 : osl_acquireMutex(SignalListMutex);
1072 : :
1073 : 316 : pHandler = SignalList;
1074 : :
1075 [ + - ]: 316 : while (pHandler != NULL)
1076 : : {
1077 [ + - ]: 316 : if (pHandler == Handler)
1078 : : {
1079 [ - + ]: 316 : if (pPrevious)
1080 : 0 : pPrevious->pNext = pHandler->pNext;
1081 : : else
1082 : 316 : SignalList = pHandler->pNext;
1083 : :
1084 : 316 : osl_releaseMutex(SignalListMutex);
1085 : :
1086 [ + + ]: 316 : if (SignalList == NULL)
1087 : 158 : bInitSignal = DeInitSignal();
1088 : :
1089 : 316 : free(pHandler);
1090 : :
1091 : 316 : return (sal_True);
1092 : : }
1093 : :
1094 : 0 : pPrevious = pHandler;
1095 : 0 : pHandler = pHandler->pNext;
1096 : : }
1097 : :
1098 : 0 : osl_releaseMutex(SignalListMutex);
1099 : :
1100 : 316 : 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 : 158 : sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
1131 : : {
1132 : 158 : sal_Bool bOld = bErrorReportingEnabled;
1133 : 158 : bErrorReportingEnabled = bEnable;
1134 : :
1135 : 158 : return bOld;
1136 : : }
1137 : :
1138 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|