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