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