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