From 656bd9f942e13a2c63ccaea458132bca7d1ccceb Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Wed, 19 Nov 2014 14:29:54 +0100 Subject: signal.c -> signal.cxx Change-Id: I1d7f47b81e558a071a6beb52999d0bca185f02d5 --- sal/Library_sal.mk | 4 +- sal/osl/unx/signal.c | 1091 ------------------------------------------------ sal/osl/unx/signal.cxx | 1091 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1092 insertions(+), 1094 deletions(-) delete mode 100644 sal/osl/unx/signal.c create mode 100644 sal/osl/unx/signal.cxx (limited to 'sal') diff --git a/sal/Library_sal.mk b/sal/Library_sal.mk index 1469f82d9003..dbca766e1dff 100644 --- a/sal/Library_sal.mk +++ b/sal/Library_sal.mk @@ -169,6 +169,7 @@ $(eval $(call gb_Library_add_exception_objects,sal,\ sal/osl/unx/profile \ sal/osl/unx/readwrite_helper \ sal/osl/unx/security \ + sal/osl/unx/signal \ sal/osl/unx/socket \ sal/osl/unx/system \ sal/osl/unx/tempfile \ @@ -176,9 +177,6 @@ $(eval $(call gb_Library_add_exception_objects,sal,\ sal/osl/unx/time \ $(if $(filter DESKTOP,$(BUILD_TYPE)), sal/osl/unx/salinit) \ )) -$(eval $(call gb_Library_add_cobjects,sal, \ - sal/osl/unx/signal \ -)) # Note that the uunxapi.mm file just includes the uunxapi.cxx one ifeq ($(OS),MACOSX) diff --git a/sal/osl/unx/signal.c b/sal/osl/unx/signal.c deleted file mode 100644 index a2bd05aa185b..000000000000 --- a/sal/osl/unx/signal.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include - -#include - -/* system headers */ -#include "system.h" - -#if defined( MACOSX ) - -#if defined( INTEL ) -#include "backtrace.h" -#define INCLUDE_BACKTRACE -#if HAVE_FEATURE_CRASHDUMP -#define STACKTYPE "MacOsX_X86" -#endif -#endif /* INTEL */ - -#endif /* MACOSX */ - -#ifdef LINUX -#include -#include -#define INCLUDE_BACKTRACE -#if HAVE_FEATURE_CRASHDUMP -#define STACKTYPE "Linux" -#endif -#endif - -#ifdef SOLARIS - -#include "backtrace.h" -#define INCLUDE_BACKTRACE - -#if HAVE_FEATURE_CRASHDUMP -#if defined( SPARC ) -#define STACKTYPE "Solaris_Sparc" -#elif defined( INTEL ) -#define STACKTYPE "Solaris_X86" -#else -#define STACKTYPE "Solaris_Unknown" -#endif -#endif - -#endif /* defined SOLARIS */ - -#if defined INCLUDE_BACKTRACE -#define MAX_STACK_FRAMES 256 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "file_path_helper.h" - -#define ACT_IGNORE 1 -#define ACT_EXIT 2 -#define ACT_SYSTEM 3 -#define ACT_HIDE 4 -#if HAVE_FEATURE_CRASHDUMP -# define ACT_ABORT 5 -#else -# define ACT_ABORT ACT_SYSTEM -#endif - -#if defined HAVE_VALGRIND_HEADERS -#include -#endif - -typedef struct _oslSignalHandlerImpl -{ - oslSignalHandlerFunction Handler; - void* pData; - struct _oslSignalHandlerImpl* pNext; -} oslSignalHandlerImpl; - -static struct SignalAction -{ - int Signal; - int Action; - void (*Handler)(int); -} Signals[] = -{ - { SIGHUP, ACT_HIDE, NULL }, /* hangup */ - { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */ - { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */ - { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */ -/* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/ - { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */ -#if ( SIGIOT != SIGABRT ) - { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */ -#endif - { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */ -#ifdef SIGEMT - { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */ -/* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/ -/* SIGEMT may also be used by the profiler - so it is probably not a good -plan to have the new handler use this signal*/ -#endif - { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */ - { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */ - { SIGBUS, ACT_ABORT, NULL }, /* bus error */ - { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */ -#ifdef SIGSYS - { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */ -#endif - { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */ - { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */ - { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */ - { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */ - { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */ - { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */ -#ifdef SIGPWR - { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */ -#endif - { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */ - { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */ -#ifdef SIGPOLL - { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occurred */ -#endif - { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */ - { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */ - { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */ - { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */ - { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */ - { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */ - { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */ -/*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do -not get taken by the new handler - the new handler does not pass on context -information which causes 'collect' to crash. This is a way of avoiding -what looks like a bug in the new handler*/ - { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */ - { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */ -}; -const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction); - -static sal_Bool bErrorReportingEnabled = sal_True; -static sal_Bool bInitSignal = sal_False; -static oslMutex SignalListMutex; -static oslSignalHandlerImpl* SignalList; -static sal_Bool bSetSEGVHandler = sal_False; -static sal_Bool bSetWINCHHandler = sal_False; -static sal_Bool bSetILLHandler = sal_False; - -static void SignalHandlerFunction(int); - -static void getExecutableName_Impl (rtl_String ** ppstrProgName) -{ - rtl_uString * ustrProgFile = 0; - osl_getExecutableFile (&ustrProgFile); - if (ustrProgFile) - { - rtl_uString * ustrProgName = 0; - osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName); - if (ustrProgName != 0) - { - rtl_uString2String ( - ppstrProgName, - rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName), - osl_getThreadTextEncoding(), - OUSTRING_TO_OSTRING_CVTFLAGS); - rtl_uString_release (ustrProgName); - } - rtl_uString_release (ustrProgFile); - } -} - -static sal_Bool is_soffice_Impl (void) -{ - sal_Int32 idx = -1; - rtl_String * strProgName = 0; - - getExecutableName_Impl (&strProgName); - if (strProgName) - { - idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice"); - rtl_string_release (strProgName); - } - return (idx != -1); -} - -static sal_Bool InitSignal(void) -{ - int i; - struct sigaction act; - struct sigaction oact; - sigset_t unset; - - if (is_soffice_Impl()) - { - // WORKAROUND FOR SEGV HANDLER CONFLICT - // - // the java jit needs SIGSEGV for proper work - // and we need SIGSEGV for the office crashguard - // - // TEMPORARY SOLUTION: - // the office sets the signal handler during startup - // java can than overwrite it, if needed - bSetSEGVHandler = sal_True; - - // WORKAROUND FOR WINCH HANDLER (SEE ABOVE) - bSetWINCHHandler = sal_True; - - // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE) - bSetILLHandler = sal_True; - } - -#ifdef DBG_UTIL - bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = sal_False; -#endif - - SignalListMutex = osl_createMutex(); - - act.sa_handler = SignalHandlerFunction; - act.sa_flags = SA_RESTART; - - sigfillset(&(act.sa_mask)); - - /* Initialize the rest of the signals */ - for (i = 0; i < NoSignals; ++i) - { -#if defined HAVE_VALGRIND_HEADERS - if (Signals[i].Signal == SIGUSR2 && RUNNING_ON_VALGRIND) - Signals[i].Action = ACT_IGNORE; -#endif - - /* hack: stomcatd is attaching JavaVM which does not work with an sigaction(SEGV) */ - if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV) - && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH) - && (bSetILLHandler || Signals[i].Signal != SIGILL)) - { - if (Signals[i].Action != ACT_SYSTEM) - { - if (Signals[i].Action == ACT_HIDE) - { - struct sigaction ign; - - ign.sa_handler = SIG_IGN; - ign.sa_flags = 0; - sigemptyset(&ign.sa_mask); - - if (sigaction(Signals[i].Signal, &ign, &oact) == 0) - Signals[i].Handler = oact.sa_handler; - else - Signals[i].Handler = SIG_DFL; - } - else - { - if (sigaction(Signals[i].Signal, &act, &oact) == 0) - Signals[i].Handler = oact.sa_handler; - else - Signals[i].Handler = SIG_DFL; - } - } - } - } - - /* Clear signal mask inherited from parent process (on Mac OS X, upon a - crash soffice re-execs itself from within the signal handler, so the - second soffice would have the guilty signal blocked and would freeze upon - encountering a similar crash again): */ - if (sigemptyset(&unset) < 0 || - pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0) - { - OSL_TRACE("sigemptyset or pthread_sigmask failed"); - } - - return sal_True; -} - -static sal_Bool DeInitSignal(void) -{ - int i; - struct sigaction act; - - act.sa_flags = 0; - sigemptyset(&(act.sa_mask)); - - /* Initialize the rest of the signals */ - for (i = NoSignals - 1; i >= 0; i--) - if (Signals[i].Action != ACT_SYSTEM) - { - act.sa_handler = Signals[i].Handler; - - sigaction(Signals[i].Signal, &act, NULL); - } - - osl_destroyMutex(SignalListMutex); - - return sal_False; -} - -#if HAVE_FEATURE_CRASHDUMP && defined(INCLUDE_BACKTRACE) - -static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen ) -{ - sal_uInt32 nBytesProcessed = 0; - - FILE *fp = fopen( filename, "r" ); - - if ( fp ) - { - rtlDigest digest = rtl_digest_createMD5(); - - if ( digest ) - { - size_t nBytesRead; - sal_uInt8 buffer[4096]; - rtlDigestError error = rtl_Digest_E_None; - - while ( rtl_Digest_E_None == error && - 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) ) - { - error = rtl_digest_updateMD5( digest, buffer, nBytesRead ); - nBytesProcessed += nBytesRead; - } - - if ( rtl_Digest_E_None == error ) - { - error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen ); - } - - if ( rtl_Digest_E_None != error ) - nBytesProcessed = 0; - - rtl_digest_destroyMD5( digest ); - } - - fclose( fp ); - } - - return nBytesProcessed; -} - -/*****************************************************************************/ -/* Call crash reporter */ -/*****************************************************************************/ - -/* Helper function to encode and write a string to a stream */ - -static int fputs_xml( const char *string, FILE *stream ) -{ - int result = 0; - - while ( result >= 0 && *string ) - { - switch( *string ) - { - case '&': - result = fputs( "&", stream ); - break; - case '<': - result = fputs( "<", stream ); - break; - case '>': - result = fputs( ">", stream ); - break; - default: - result = fputc( *string, stream ); - break; - } - - string++; - } - - return result; -} -#endif - -/* Create intermediate files and run crash reporter */ - -#if HAVE_FEATURE_CRASHDUMP && defined INCLUDE_BACKTRACE && defined LINUX - -typedef struct -{ - const char *name; - ElfW(Off) offset; -} dynamic_entry; - -static int -callback(struct dl_phdr_info *info, size_t size, void *data) -{ - const ElfW(Phdr) *pDynamic = NULL; - - if (size == sizeof(struct dl_phdr_info)) - { - int i; - for (i = 0; i < info->dlpi_phnum; ++i) - { - if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) - { - pDynamic = &(info->dlpi_phdr[i]); - break; - } - } - } - - if (pDynamic) - { - char buffer[100]; - int len; - char exe[PATH_MAX]; - const char *dsoname = info->dlpi_name; - - dynamic_entry* entry = (dynamic_entry*)data; - - if (strcmp(dsoname, "") == 0) - { - snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid()); - if ((len = readlink(buffer, exe, PATH_MAX)) != -1) - { - exe[len] = '\0'; - dsoname = exe; - } - } - - if (strcmp(dsoname, entry->name) == 0) - { - entry->offset = pDynamic->p_offset; - return 1; - } - } - return 0; -} - -/* Get the location of the .dynamic section offset for the given elf file. - * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo - * - * We want to know this value so that if the binaries have been modified - * by prelink then we can still process the call stack on server side - * by comparing this value to that of an "un-prelinked but known to be - * otherwise equivalent" version of those binaries and adjust the call - * stack addresses by the differences between .dynamic addresses so as - * to be able to map the prelinked addresses back to the unprelinked - * addresses - * - * cmc@openoffice.org - */ -static ElfW(Off) -dynamic_section_offset(const char *name) -{ - dynamic_entry entry; - - entry.name = name; - entry.offset = 0; - - dl_iterate_phdr(callback, &entry); - - return entry.offset; -} -#endif - -static int ReportCrash( int Signal ) -{ -#if HAVE_FEATURE_CRASHDUMP - -#define REPORTENV_PARAM "-crashreportenv:" - - static sal_Bool bCrashReporterExecuted = sal_False; - sal_Bool bAutoCrashReport = sal_False; - - sal_uInt32 argi; - sal_uInt32 argc; - rtl_uString *ustrCommandArg = NULL; - - if ( !bErrorReportingEnabled ) - return -1; - - argc = osl_getCommandArgCount(); - - for ( argi = 0; argi < argc; argi++ ) - { - if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) ) - { - if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--nocrashreport" ) ) - { - rtl_uString_release( ustrCommandArg ); - return -1; - } - else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--autocrashreport" ) ) - { - bAutoCrashReport = sal_True; - } - else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( - rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ), - REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) - ) - { - rtl_uString *ustrEnvironment = NULL; - rtl_String *strEnv = NULL; - - rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) ); - - if ( ustrEnvironment ) - { - rtl_uString2String( - &strEnv, - rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ), - osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS - ); - - if ( strEnv ) - { - putenv( rtl_string_getStr( strEnv ) ); - rtl_string_release( strEnv ); - } - - rtl_uString_release( ustrEnvironment ); - } - - } - - } - } - - if ( ustrCommandArg ) - rtl_uString_release( ustrCommandArg ); - - if ( !bCrashReporterExecuted ) - { - int i; - /* struct sigaction act; */ - - for (i = 0; i < NoSignals; i++) - { - if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT ) - { - int ret; - char szShellCmd[512] = { '\0' }; - char *pXMLTempName = NULL; - char *pStackTempName = NULL; - char *pChecksumTempName = NULL; - -#ifdef INCLUDE_BACKTRACE - char szXMLTempNameBuffer[L_tmpnam]; - char szChecksumTempNameBuffer[L_tmpnam]; - char szStackTempNameBuffer[L_tmpnam]; - - void *stackframes[MAX_STACK_FRAMES]; - int iFrame; - int nFrames = backtrace( stackframes, SAL_N_ELEMENTS(stackframes) ); - - FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL; - int fdxml, fdstk, fdchksum; - - strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) ); - strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) - strlen(szXMLTempNameBuffer) - 1 ); - - strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) ); - strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) - strlen(szStackTempNameBuffer) - 1 ); - - strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) ); - strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) - strlen(szChecksumTempNameBuffer) - 1 ); - - fdxml = mkstemp(szXMLTempNameBuffer); - fdstk = mkstemp(szStackTempNameBuffer); - fdchksum = mkstemp(szChecksumTempNameBuffer); - - xmlout = fdopen( fdxml , "w" ); - stackout = fdopen( fdstk , "w" ); - checksumout = fdopen( fdchksum, "w" ); - - pXMLTempName = szXMLTempNameBuffer; - pStackTempName = szStackTempNameBuffer; - pChecksumTempName = szChecksumTempNameBuffer; - - if ( xmlout && stackout && checksumout ) - { - fprintf( xmlout, "\n", STACKTYPE ); - - fprintf( checksumout, "\n" ); - - for ( iFrame = 0; iFrame < nFrames; iFrame++ ) - { - Dl_info dl_info; - - fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":", - SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) ); - - fprintf( xmlout, "\n", - SAL_INT_CAST( - unsigned long, nBytesProcessed), - dli_fname ); - } - } - - if ( dl_info.dli_fbase && dl_info.dli_fname ) - { -#ifdef LINUX - ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname); - fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset); -#endif - - fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x", - dl_info.dli_fname, - (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase - ); - - fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase ); - if ( dli_fname ) - fprintf( xmlout, " name=\"%s\"", dli_fname ); - - if ( dli_fdir ) - fprintf( xmlout, " path=\"%s\"", dli_fdir ); - -#ifdef LINUX - fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset ); -#endif - } - else - fprintf( stackout, " ????????" ); - - if ( dl_info.dli_sname && dl_info.dli_saddr ) - { - fputs( " (", stackout ); - fputs_xml( dl_info.dli_sname, stackout ); - fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)", - (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr ); - - fputs( " ordinal=\"", xmlout ); - fputs_xml( dl_info.dli_sname, xmlout ); - fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"", - (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr ); - } - - } - else /* dladdr failed */ - { - fprintf( stackout, " ????????" ); - } - - fprintf( stackout, "\n" ); - fprintf( xmlout, "/>\n" ); - - } - - fprintf( xmlout, "\n" ); - fprintf( checksumout, "\n" ); - } - else - { - pXMLTempName = NULL; - pStackTempName = NULL; - pChecksumTempName = NULL; - } - - if ( stackout ) - fclose( stackout ); - if ( xmlout ) - fclose( xmlout ); - if ( checksumout ) - fclose( checksumout ); - - if ( pXMLTempName && pChecksumTempName && pStackTempName ) -#endif /* INCLUDE_BACKTRACE */ - { - rtl_uString * crashrep_url = NULL; - rtl_uString * crashrep_path = NULL; - rtl_String * crashrep_path_system = NULL; - rtl_string2UString( - &crashrep_url, - RTL_CONSTASCII_USTRINGPARAM( - "$BRAND_BASE_DIR/program/crashrep"), - OSTRING_TO_OUSTRING_CVTFLAGS); - rtl_bootstrap_expandMacros(&crashrep_url); - osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path); - rtl_uString2String( - &crashrep_path_system, - rtl_uString_getStr(crashrep_path), - rtl_uString_getLength(crashrep_path), - osl_getThreadTextEncoding(), - (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR - | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)); - rtl_uString_release(crashrep_url); - rtl_uString_release(crashrep_path); -#if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX) - snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd), - "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s", - rtl_string_getStr(crashrep_path_system), - getpid(), - Signal, - pXMLTempName, - pChecksumTempName, - pStackTempName, - bAutoCrashReport ? " -send" : "" ); -#elif defined INCLUDE_BACKTRACE && defined SOLARIS - snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd), - "%s -p %d -s %d -xml %s -chksum %s -noui%s", - rtl_string_getStr(crashrep_path_system), - getpid(), - Signal, - pXMLTempName, - pChecksumTempName, - bAutoCrashReport ? " -send" : "" ); -#else - snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd), - "%s -p %d -s %d -noui%s", - rtl_string_getStr(crashrep_path_system), - getpid(), Signal, bAutoCrashReport ? " -send" : "" ); -#endif - rtl_string_release(crashrep_path_system); - } - - ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd ); - - if ( pXMLTempName ) - unlink( pXMLTempName ); - - if ( pStackTempName ) - unlink( pStackTempName ); - - if ( pChecksumTempName ) - unlink( pChecksumTempName ); - - if ( -1 != ret ) - { - bCrashReporterExecuted = sal_True; - return 1; - } - else - return -1; - - } - } - - return 0; - } - - return 1; -#else /* HAVE_FEATURE_CRASHDUMP */ - /* the utility crash_report is not build, so do the same as when - the option -nocrashreport is used */ - (void) Signal; // avoid warnings - return -1; -#endif /* HAVE_FEATURE_CRASHDUMP */ -} - -static void PrintStack( int sig ) -{ -#ifdef INCLUDE_BACKTRACE - void *buffer[MAX_STACK_FRAMES]; - int size = backtrace( buffer, SAL_N_ELEMENTS(buffer) ); -#endif - - fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig ); - -#if defined( MACOSX ) && !defined( INCLUDE_BACKTRACE ) - fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" ); -#else -#ifdef INCLUDE_BACKTRACE - if ( size > 0 ) - { - fputs( "Stack:\n", stderr ); - backtrace_symbols_fd( buffer, size, fileno(stderr) ); - } -#endif -#endif -} - -static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) -{ - oslSignalHandlerImpl* pHandler = SignalList; - oslSignalAction Action = osl_Signal_ActCallNextHdl; - - while (pHandler != NULL) - { - if ((Action = pHandler->Handler(pHandler->pData, pInfo)) - != osl_Signal_ActCallNextHdl) - break; - - pHandler = pHandler->pNext; - } - - return Action; -} - -void CallSystemHandler(int Signal) -{ - int i; - struct sigaction act; - - for (i = 0; i < NoSignals; i++) - { - if (Signals[i].Signal == Signal) - break; - } - - if (i < NoSignals) - { - if ((Signals[i].Handler == NULL) || - (Signals[i].Handler == SIG_DFL) || - (Signals[i].Handler == SIG_IGN) || - (Signals[i].Handler == SIG_ERR)) - { - switch (Signals[i].Action) - { - case ACT_EXIT: /* terminate */ - /* prevent dumping core on exit() */ - _exit(255); - break; - - case ACT_ABORT: /* terminate witch core dump */ - ReportCrash( Signal ); - act.sa_handler = SIG_DFL; - act.sa_flags = 0; - sigemptyset(&(act.sa_mask)); - sigaction(SIGABRT, &act, NULL); - PrintStack( Signal ); - abort(); - break; - - case ACT_IGNORE: /* ignore */ - break; - - default: /* should never happen */ - OSL_ASSERT(0); - } - } - else - (*Signals[i].Handler)(Signal); - } -} - -#if defined HAVE_VALGRIND_HEADERS -static void DUMPCURRENTALLOCS(void) -{ - VALGRIND_PRINTF( "=== start memcheck dump of active allocations ===\n" ); - -#if __GNUC__ && !defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#endif - - VALGRIND_DO_LEAK_CHECK; - -#if __GNUC__ && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - - VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" ); -} -#endif - -void SignalHandlerFunction(int Signal) -{ - oslSignalInfo Info; - struct sigaction act; - - Info.UserSignal = Signal; - Info.UserData = NULL; - - switch (Signal) - { - case SIGBUS: - case SIGILL: - case SIGSEGV: - case SIGIOT: -#if ( SIGIOT != SIGABRT ) - case SIGABRT: -#endif - Info.Signal = osl_Signal_AccessViolation; - break; - - case -1: - Info.Signal = osl_Signal_IntegerDivideByZero; - break; - - case SIGFPE: - Info.Signal = osl_Signal_FloatDivideByZero; - break; - - case SIGINT: - case SIGTERM: - case SIGQUIT: - Info.Signal = osl_Signal_Terminate; - break; - -#if defined HAVE_VALGRIND_HEADERS - case SIGUSR2: - if (RUNNING_ON_VALGRIND) - DUMPCURRENTALLOCS(); - Info.Signal = osl_Signal_System; - break; -#endif - - default: - Info.Signal = osl_Signal_System; - break; - } - - ReportCrash( Signal ); - - switch (CallSignalHandler(&Info)) - { - case osl_Signal_ActCallNextHdl: - CallSystemHandler(Signal); - break; - - case osl_Signal_ActAbortApp: - ReportCrash( Signal ); - act.sa_handler = SIG_DFL; - act.sa_flags = 0; - sigemptyset(&(act.sa_mask)); - sigaction(SIGABRT, &act, NULL); - PrintStack( Signal ); - abort(); - break; - - case osl_Signal_ActKillApp: - /* prevent dumping core on exit() */ - _exit(255); - break; - default: - break; - } -} - -oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) -{ - oslSignalHandlerImpl* pHandler; - - OSL_ASSERT(Handler != NULL); - if ( Handler == 0 ) - { - return 0; - } - - if (! bInitSignal) - bInitSignal = InitSignal(); - - pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl)); - - if (pHandler != NULL) - { - pHandler->Handler = Handler; - pHandler->pData = pData; - - osl_acquireMutex(SignalListMutex); - - pHandler->pNext = SignalList; - SignalList = pHandler; - - osl_releaseMutex(SignalListMutex); - - return (pHandler); - } - - return (NULL); -} - -sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) -{ - oslSignalHandlerImpl *pHandler, *pPrevious = NULL; - - OSL_ASSERT(Handler != NULL); - - if (! bInitSignal) - bInitSignal = InitSignal(); - - osl_acquireMutex(SignalListMutex); - - pHandler = SignalList; - - while (pHandler != NULL) - { - if (pHandler == Handler) - { - if (pPrevious) - pPrevious->pNext = pHandler->pNext; - else - SignalList = pHandler->pNext; - - osl_releaseMutex(SignalListMutex); - - if (SignalList == NULL) - bInitSignal = DeInitSignal(); - - free(pHandler); - - return (sal_True); - } - - pPrevious = pHandler; - pHandler = pHandler->pNext; - } - - osl_releaseMutex(SignalListMutex); - - return (sal_False); -} - -oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) -{ - oslSignalInfo Info; - oslSignalAction Action; - - if (! bInitSignal) - bInitSignal = InitSignal(); - - osl_acquireMutex(SignalListMutex); - - Info.Signal = osl_Signal_User; - Info.UserSignal = UserSignal; - Info.UserData = UserData; - - Action = CallSignalHandler(&Info); - - osl_releaseMutex(SignalListMutex); - - return (Action); -} - -sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) -{ - sal_Bool bOld = bErrorReportingEnabled; - bErrorReportingEnabled = bEnable; - - return bOld; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/unx/signal.cxx b/sal/osl/unx/signal.cxx new file mode 100644 index 000000000000..49f0e119c867 --- /dev/null +++ b/sal/osl/unx/signal.cxx @@ -0,0 +1,1091 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +/* system headers */ +#include "system.h" + +#if defined( MACOSX ) + +#if defined( INTEL ) +#include "backtrace.h" +#define INCLUDE_BACKTRACE +#if HAVE_FEATURE_CRASHDUMP +#define STACKTYPE "MacOsX_X86" +#endif +#endif /* INTEL */ + +#endif /* MACOSX */ + +#ifdef LINUX +#include +#include +#define INCLUDE_BACKTRACE +#if HAVE_FEATURE_CRASHDUMP +#define STACKTYPE "Linux" +#endif +#endif + +#ifdef SOLARIS + +#include "backtrace.h" +#define INCLUDE_BACKTRACE + +#if HAVE_FEATURE_CRASHDUMP +#if defined( SPARC ) +#define STACKTYPE "Solaris_Sparc" +#elif defined( INTEL ) +#define STACKTYPE "Solaris_X86" +#else +#define STACKTYPE "Solaris_Unknown" +#endif +#endif + +#endif /* defined SOLARIS */ + +#if defined INCLUDE_BACKTRACE +#define MAX_STACK_FRAMES 256 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "file_path_helper.h" + +#define ACT_IGNORE 1 +#define ACT_EXIT 2 +#define ACT_SYSTEM 3 +#define ACT_HIDE 4 +#if HAVE_FEATURE_CRASHDUMP +# define ACT_ABORT 5 +#else +# define ACT_ABORT ACT_SYSTEM +#endif + +#if defined HAVE_VALGRIND_HEADERS +#include +#endif + +typedef struct _oslSignalHandlerImpl +{ + oslSignalHandlerFunction Handler; + void* pData; + struct _oslSignalHandlerImpl* pNext; +} oslSignalHandlerImpl; + +static struct SignalAction +{ + int Signal; + int Action; + void (*Handler)(int); +} Signals[] = +{ + { SIGHUP, ACT_HIDE, NULL }, /* hangup */ + { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */ + { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */ + { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */ +/* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/ + { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */ +#if ( SIGIOT != SIGABRT ) + { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */ +#endif + { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */ +#ifdef SIGEMT + { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */ +/* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/ +/* SIGEMT may also be used by the profiler - so it is probably not a good +plan to have the new handler use this signal*/ +#endif + { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */ + { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */ + { SIGBUS, ACT_ABORT, NULL }, /* bus error */ + { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */ +#ifdef SIGSYS + { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */ +#endif + { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */ + { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */ + { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */ + { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */ + { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */ + { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */ +#ifdef SIGPWR + { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */ +#endif + { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */ + { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */ +#ifdef SIGPOLL + { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occurred */ +#endif + { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */ + { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */ + { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */ + { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */ + { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */ + { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */ + { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */ +/*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do +not get taken by the new handler - the new handler does not pass on context +information which causes 'collect' to crash. This is a way of avoiding +what looks like a bug in the new handler*/ + { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */ + { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */ +}; +const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction); + +static bool bErrorReportingEnabled = true; +static bool bInitSignal = false; +static oslMutex SignalListMutex; +static oslSignalHandlerImpl* SignalList; +static bool bSetSEGVHandler = false; +static bool bSetWINCHHandler = false; +static bool bSetILLHandler = false; + +static void SignalHandlerFunction(int); + +static void getExecutableName_Impl (rtl_String ** ppstrProgName) +{ + rtl_uString * ustrProgFile = 0; + osl_getExecutableFile (&ustrProgFile); + if (ustrProgFile) + { + rtl_uString * ustrProgName = 0; + osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName); + if (ustrProgName != 0) + { + rtl_uString2String ( + ppstrProgName, + rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName), + osl_getThreadTextEncoding(), + OUSTRING_TO_OSTRING_CVTFLAGS); + rtl_uString_release (ustrProgName); + } + rtl_uString_release (ustrProgFile); + } +} + +static bool is_soffice_Impl (void) +{ + sal_Int32 idx = -1; + rtl_String * strProgName = 0; + + getExecutableName_Impl (&strProgName); + if (strProgName) + { + idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice"); + rtl_string_release (strProgName); + } + return (idx != -1); +} + +static bool InitSignal(void) +{ + int i; + struct sigaction act; + struct sigaction oact; + sigset_t unset; + + if (is_soffice_Impl()) + { + // WORKAROUND FOR SEGV HANDLER CONFLICT + // + // the java jit needs SIGSEGV for proper work + // and we need SIGSEGV for the office crashguard + // + // TEMPORARY SOLUTION: + // the office sets the signal handler during startup + // java can than overwrite it, if needed + bSetSEGVHandler = true; + + // WORKAROUND FOR WINCH HANDLER (SEE ABOVE) + bSetWINCHHandler = true; + + // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE) + bSetILLHandler = true; + } + +#ifdef DBG_UTIL + bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = false; +#endif + + SignalListMutex = osl_createMutex(); + + act.sa_handler = SignalHandlerFunction; + act.sa_flags = SA_RESTART; + + sigfillset(&(act.sa_mask)); + + /* Initialize the rest of the signals */ + for (i = 0; i < NoSignals; ++i) + { +#if defined HAVE_VALGRIND_HEADERS + if (Signals[i].Signal == SIGUSR2 && RUNNING_ON_VALGRIND) + Signals[i].Action = ACT_IGNORE; +#endif + + /* hack: stomcatd is attaching JavaVM which does not work with an sigaction(SEGV) */ + if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV) + && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH) + && (bSetILLHandler || Signals[i].Signal != SIGILL)) + { + if (Signals[i].Action != ACT_SYSTEM) + { + if (Signals[i].Action == ACT_HIDE) + { + struct sigaction ign; + + ign.sa_handler = SIG_IGN; + ign.sa_flags = 0; + sigemptyset(&ign.sa_mask); + + if (sigaction(Signals[i].Signal, &ign, &oact) == 0) + Signals[i].Handler = oact.sa_handler; + else + Signals[i].Handler = SIG_DFL; + } + else + { + if (sigaction(Signals[i].Signal, &act, &oact) == 0) + Signals[i].Handler = oact.sa_handler; + else + Signals[i].Handler = SIG_DFL; + } + } + } + } + + /* Clear signal mask inherited from parent process (on Mac OS X, upon a + crash soffice re-execs itself from within the signal handler, so the + second soffice would have the guilty signal blocked and would freeze upon + encountering a similar crash again): */ + if (sigemptyset(&unset) < 0 || + pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0) + { + OSL_TRACE("sigemptyset or pthread_sigmask failed"); + } + + return true; +} + +static bool DeInitSignal(void) +{ + int i; + struct sigaction act; + + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + + /* Initialize the rest of the signals */ + for (i = NoSignals - 1; i >= 0; i--) + if (Signals[i].Action != ACT_SYSTEM) + { + act.sa_handler = Signals[i].Handler; + + sigaction(Signals[i].Signal, &act, NULL); + } + + osl_destroyMutex(SignalListMutex); + + return false; +} + +#if HAVE_FEATURE_CRASHDUMP && defined(INCLUDE_BACKTRACE) + +static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen ) +{ + sal_uInt32 nBytesProcessed = 0; + + FILE *fp = fopen( filename, "r" ); + + if ( fp ) + { + rtlDigest digest = rtl_digest_createMD5(); + + if ( digest ) + { + size_t nBytesRead; + sal_uInt8 buffer[4096]; + rtlDigestError error = rtl_Digest_E_None; + + while ( rtl_Digest_E_None == error && + 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) ) + { + error = rtl_digest_updateMD5( digest, buffer, nBytesRead ); + nBytesProcessed += nBytesRead; + } + + if ( rtl_Digest_E_None == error ) + { + error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen ); + } + + if ( rtl_Digest_E_None != error ) + nBytesProcessed = 0; + + rtl_digest_destroyMD5( digest ); + } + + fclose( fp ); + } + + return nBytesProcessed; +} + +/*****************************************************************************/ +/* Call crash reporter */ +/*****************************************************************************/ + +/* Helper function to encode and write a string to a stream */ + +static int fputs_xml( const char *string, FILE *stream ) +{ + int result = 0; + + while ( result >= 0 && *string ) + { + switch( *string ) + { + case '&': + result = fputs( "&", stream ); + break; + case '<': + result = fputs( "<", stream ); + break; + case '>': + result = fputs( ">", stream ); + break; + default: + result = fputc( *string, stream ); + break; + } + + string++; + } + + return result; +} +#endif + +/* Create intermediate files and run crash reporter */ + +#if HAVE_FEATURE_CRASHDUMP && defined INCLUDE_BACKTRACE && defined LINUX + +typedef struct +{ + const char *name; + ElfW(Off) offset; +} dynamic_entry; + +static int +callback(struct dl_phdr_info *info, size_t size, void *data) +{ + const ElfW(Phdr) *pDynamic = NULL; + + if (size == sizeof(struct dl_phdr_info)) + { + int i; + for (i = 0; i < info->dlpi_phnum; ++i) + { + if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) + { + pDynamic = &(info->dlpi_phdr[i]); + break; + } + } + } + + if (pDynamic) + { + char buffer[100]; + int len; + char exe[PATH_MAX]; + const char *dsoname = info->dlpi_name; + + dynamic_entry* entry = (dynamic_entry*)data; + + if (strcmp(dsoname, "") == 0) + { + snprintf(buffer, sizeof(buffer), "/proc/%d/exe", getpid()); + if ((len = readlink(buffer, exe, PATH_MAX)) != -1) + { + exe[len] = '\0'; + dsoname = exe; + } + } + + if (strcmp(dsoname, entry->name) == 0) + { + entry->offset = pDynamic->p_offset; + return 1; + } + } + return 0; +} + +/* Get the location of the .dynamic section offset for the given elf file. + * i.e. same as the "Offset" value shown for DYNAMIC from readelf -l foo + * + * We want to know this value so that if the binaries have been modified + * by prelink then we can still process the call stack on server side + * by comparing this value to that of an "un-prelinked but known to be + * otherwise equivalent" version of those binaries and adjust the call + * stack addresses by the differences between .dynamic addresses so as + * to be able to map the prelinked addresses back to the unprelinked + * addresses + * + * cmc@openoffice.org + */ +static ElfW(Off) +dynamic_section_offset(const char *name) +{ + dynamic_entry entry; + + entry.name = name; + entry.offset = 0; + + dl_iterate_phdr(callback, &entry); + + return entry.offset; +} +#endif + +static int ReportCrash( int Signal ) +{ +#if HAVE_FEATURE_CRASHDUMP + +#define REPORTENV_PARAM "-crashreportenv:" + + static sal_Bool bCrashReporterExecuted = sal_False; + sal_Bool bAutoCrashReport = sal_False; + + sal_uInt32 argi; + sal_uInt32 argc; + rtl_uString *ustrCommandArg = NULL; + + if ( !bErrorReportingEnabled ) + return -1; + + argc = osl_getCommandArgCount(); + + for ( argi = 0; argi < argc; argi++ ) + { + if ( osl_Process_E_None == osl_getCommandArg( argi, &ustrCommandArg ) ) + { + if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--nocrashreport" ) ) + { + rtl_uString_release( ustrCommandArg ); + return -1; + } + else if ( 0 == rtl_ustr_ascii_compare( rtl_uString_getStr( ustrCommandArg ), "--autocrashreport" ) ) + { + bAutoCrashReport = sal_True; + } + else if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( + rtl_uString_getStr( ustrCommandArg ), rtl_uString_getLength( ustrCommandArg ), + REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) + ) + { + rtl_uString *ustrEnvironment = NULL; + rtl_String *strEnv = NULL; + + rtl_uString_newFromStr( &ustrEnvironment, rtl_uString_getStr( ustrCommandArg ) + strlen(REPORTENV_PARAM) ); + + if ( ustrEnvironment ) + { + rtl_uString2String( + &strEnv, + rtl_uString_getStr( ustrEnvironment ), rtl_uString_getLength( ustrEnvironment ), + osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS + ); + + if ( strEnv ) + { + putenv( rtl_string_getStr( strEnv ) ); + rtl_string_release( strEnv ); + } + + rtl_uString_release( ustrEnvironment ); + } + + } + + } + } + + if ( ustrCommandArg ) + rtl_uString_release( ustrCommandArg ); + + if ( !bCrashReporterExecuted ) + { + int i; + /* struct sigaction act; */ + + for (i = 0; i < NoSignals; i++) + { + if (Signals[i].Signal == Signal && Signals[i].Action == ACT_ABORT ) + { + int ret; + char szShellCmd[512] = { '\0' }; + char *pXMLTempName = NULL; + char *pStackTempName = NULL; + char *pChecksumTempName = NULL; + +#ifdef INCLUDE_BACKTRACE + char szXMLTempNameBuffer[L_tmpnam]; + char szChecksumTempNameBuffer[L_tmpnam]; + char szStackTempNameBuffer[L_tmpnam]; + + void *stackframes[MAX_STACK_FRAMES]; + int iFrame; + int nFrames = backtrace( stackframes, SAL_N_ELEMENTS(stackframes) ); + + FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL; + int fdxml, fdstk, fdchksum; + + strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) ); + strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) - strlen(szXMLTempNameBuffer) - 1 ); + + strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) ); + strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) - strlen(szStackTempNameBuffer) - 1 ); + + strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) ); + strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) - strlen(szChecksumTempNameBuffer) - 1 ); + + fdxml = mkstemp(szXMLTempNameBuffer); + fdstk = mkstemp(szStackTempNameBuffer); + fdchksum = mkstemp(szChecksumTempNameBuffer); + + xmlout = fdopen( fdxml , "w" ); + stackout = fdopen( fdstk , "w" ); + checksumout = fdopen( fdchksum, "w" ); + + pXMLTempName = szXMLTempNameBuffer; + pStackTempName = szStackTempNameBuffer; + pChecksumTempName = szChecksumTempNameBuffer; + + if ( xmlout && stackout && checksumout ) + { + fprintf( xmlout, "\n", STACKTYPE ); + + fprintf( checksumout, "\n" ); + + for ( iFrame = 0; iFrame < nFrames; iFrame++ ) + { + Dl_info dl_info; + + fprintf( stackout, "0x%" SAL_PRIxUINTPTR ":", + SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame]) ); + + fprintf( xmlout, "\n", + SAL_INT_CAST( + unsigned long, nBytesProcessed), + dli_fname ); + } + } + + if ( dl_info.dli_fbase && dl_info.dli_fname ) + { +#ifdef LINUX + ElfW(Off) dynamic_offset = dynamic_section_offset(dl_info.dli_fname); + fprintf( stackout, " 0x%" SAL_PRI_SIZET "x:", dynamic_offset); +#endif + + fprintf( stackout, " %s + 0x%" SAL_PRI_PTRDIFFT "x", + dl_info.dli_fname, + (char*)stackframes[iFrame] - (char*)dl_info.dli_fbase + ); + + fprintf( xmlout, " rel=\"0x%" SAL_PRI_PTRDIFFT "x\"", (char *)stackframes[iFrame] - (char *)dl_info.dli_fbase ); + if ( dli_fname ) + fprintf( xmlout, " name=\"%s\"", dli_fname ); + + if ( dli_fdir ) + fprintf( xmlout, " path=\"%s\"", dli_fdir ); + +#ifdef LINUX + fprintf( xmlout, " dynamicoffset=\"0x%" SAL_PRI_SIZET "x\"", dynamic_offset ); +#endif + } + else + fprintf( stackout, " ????????" ); + + if ( dl_info.dli_sname && dl_info.dli_saddr ) + { + fputs( " (", stackout ); + fputs_xml( dl_info.dli_sname, stackout ); + fprintf( stackout, " + 0x%" SAL_PRI_PTRDIFFT "x)", + (char*)stackframes[iFrame] - (char*)dl_info.dli_saddr ); + + fputs( " ordinal=\"", xmlout ); + fputs_xml( dl_info.dli_sname, xmlout ); + fprintf( xmlout, "+0x%" SAL_PRI_PTRDIFFT "x\"", + (char *)stackframes[iFrame] - (char *)dl_info.dli_saddr ); + } + + } + else /* dladdr failed */ + { + fprintf( stackout, " ????????" ); + } + + fprintf( stackout, "\n" ); + fprintf( xmlout, "/>\n" ); + + } + + fprintf( xmlout, "\n" ); + fprintf( checksumout, "\n" ); + } + else + { + pXMLTempName = NULL; + pStackTempName = NULL; + pChecksumTempName = NULL; + } + + if ( stackout ) + fclose( stackout ); + if ( xmlout ) + fclose( xmlout ); + if ( checksumout ) + fclose( checksumout ); + + if ( pXMLTempName && pChecksumTempName && pStackTempName ) +#endif /* INCLUDE_BACKTRACE */ + { + rtl_uString * crashrep_url = NULL; + rtl_uString * crashrep_path = NULL; + rtl_String * crashrep_path_system = NULL; + rtl_string2UString( + &crashrep_url, + RTL_CONSTASCII_USTRINGPARAM( + "$BRAND_BASE_DIR/program/crashrep"), + OSTRING_TO_OUSTRING_CVTFLAGS); + rtl_bootstrap_expandMacros(&crashrep_url); + osl_getSystemPathFromFileURL(crashrep_url, &crashrep_path); + rtl_uString2String( + &crashrep_path_system, + rtl_uString_getStr(crashrep_path), + rtl_uString_getLength(crashrep_path), + osl_getThreadTextEncoding(), + (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR + | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)); + rtl_uString_release(crashrep_url); + rtl_uString_release(crashrep_path); +#if defined INCLUDE_BACKTRACE && (defined LINUX || defined MACOSX) + snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd), + "%s -p %d -s %d -xml %s -chksum %s -stack %s -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), + Signal, + pXMLTempName, + pChecksumTempName, + pStackTempName, + bAutoCrashReport ? " -send" : "" ); +#elif defined INCLUDE_BACKTRACE && defined SOLARIS + snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd), + "%s -p %d -s %d -xml %s -chksum %s -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), + Signal, + pXMLTempName, + pChecksumTempName, + bAutoCrashReport ? " -send" : "" ); +#else + snprintf( szShellCmd, SAL_N_ELEMENTS(szShellCmd), + "%s -p %d -s %d -noui%s", + rtl_string_getStr(crashrep_path_system), + getpid(), Signal, bAutoCrashReport ? " -send" : "" ); +#endif + rtl_string_release(crashrep_path_system); + } + + ret = szShellCmd[0] == '\0' ? -1 : system( szShellCmd ); + + if ( pXMLTempName ) + unlink( pXMLTempName ); + + if ( pStackTempName ) + unlink( pStackTempName ); + + if ( pChecksumTempName ) + unlink( pChecksumTempName ); + + if ( -1 != ret ) + { + bCrashReporterExecuted = sal_True; + return 1; + } + else + return -1; + + } + } + + return 0; + } + + return 1; +#else /* HAVE_FEATURE_CRASHDUMP */ + /* the utility crash_report is not build, so do the same as when + the option -nocrashreport is used */ + (void) Signal; // avoid warnings + return -1; +#endif /* HAVE_FEATURE_CRASHDUMP */ +} + +static void PrintStack( int sig ) +{ +#ifdef INCLUDE_BACKTRACE + void *buffer[MAX_STACK_FRAMES]; + int size = backtrace( buffer, SAL_N_ELEMENTS(buffer) ); +#endif + + fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig ); + +#if defined( MACOSX ) && !defined( INCLUDE_BACKTRACE ) + fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" ); +#else +#ifdef INCLUDE_BACKTRACE + if ( size > 0 ) + { + fputs( "Stack:\n", stderr ); + backtrace_symbols_fd( buffer, size, fileno(stderr) ); + } +#endif +#endif +} + +static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo) +{ + oslSignalHandlerImpl* pHandler = SignalList; + oslSignalAction Action = osl_Signal_ActCallNextHdl; + + while (pHandler != NULL) + { + if ((Action = pHandler->Handler(pHandler->pData, pInfo)) + != osl_Signal_ActCallNextHdl) + break; + + pHandler = pHandler->pNext; + } + + return Action; +} + +void CallSystemHandler(int Signal) +{ + int i; + struct sigaction act; + + for (i = 0; i < NoSignals; i++) + { + if (Signals[i].Signal == Signal) + break; + } + + if (i < NoSignals) + { + if ((Signals[i].Handler == NULL) || + (Signals[i].Handler == SIG_DFL) || + (Signals[i].Handler == SIG_IGN) || + (Signals[i].Handler == SIG_ERR)) + { + switch (Signals[i].Action) + { + case ACT_EXIT: /* terminate */ + /* prevent dumping core on exit() */ + _exit(255); + break; + + case ACT_ABORT: /* terminate witch core dump */ + ReportCrash( Signal ); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + sigaction(SIGABRT, &act, NULL); + PrintStack( Signal ); + abort(); + break; + + case ACT_IGNORE: /* ignore */ + break; + + default: /* should never happen */ + OSL_ASSERT(false); + } + } + else + (*Signals[i].Handler)(Signal); + } +} + +#if defined HAVE_VALGRIND_HEADERS +static void DUMPCURRENTALLOCS(void) +{ + VALGRIND_PRINTF( "=== start memcheck dump of active allocations ===\n" ); + +#if __GNUC__ && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + + VALGRIND_DO_LEAK_CHECK; + +#if __GNUC__ && !defined(__clang__) +# pragma GCC diagnostic pop +#endif + + VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" ); +} +#endif + +void SignalHandlerFunction(int Signal) +{ + oslSignalInfo Info; + struct sigaction act; + + Info.UserSignal = Signal; + Info.UserData = NULL; + + switch (Signal) + { + case SIGBUS: + case SIGILL: + case SIGSEGV: + case SIGIOT: +#if ( SIGIOT != SIGABRT ) + case SIGABRT: +#endif + Info.Signal = osl_Signal_AccessViolation; + break; + + case -1: + Info.Signal = osl_Signal_IntegerDivideByZero; + break; + + case SIGFPE: + Info.Signal = osl_Signal_FloatDivideByZero; + break; + + case SIGINT: + case SIGTERM: + case SIGQUIT: + Info.Signal = osl_Signal_Terminate; + break; + +#if defined HAVE_VALGRIND_HEADERS + case SIGUSR2: + if (RUNNING_ON_VALGRIND) + DUMPCURRENTALLOCS(); + Info.Signal = osl_Signal_System; + break; +#endif + + default: + Info.Signal = osl_Signal_System; + break; + } + + ReportCrash( Signal ); + + switch (CallSignalHandler(&Info)) + { + case osl_Signal_ActCallNextHdl: + CallSystemHandler(Signal); + break; + + case osl_Signal_ActAbortApp: + ReportCrash( Signal ); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + sigaction(SIGABRT, &act, NULL); + PrintStack( Signal ); + abort(); + break; + + case osl_Signal_ActKillApp: + /* prevent dumping core on exit() */ + _exit(255); + break; + default: + break; + } +} + +oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData) +{ + oslSignalHandlerImpl* pHandler; + + OSL_ASSERT(Handler != NULL); + if ( Handler == 0 ) + { + return 0; + } + + if (! bInitSignal) + bInitSignal = InitSignal(); + + pHandler = (oslSignalHandlerImpl*) calloc(1, sizeof(oslSignalHandlerImpl)); + + if (pHandler != NULL) + { + pHandler->Handler = Handler; + pHandler->pData = pData; + + osl_acquireMutex(SignalListMutex); + + pHandler->pNext = SignalList; + SignalList = pHandler; + + osl_releaseMutex(SignalListMutex); + + return (pHandler); + } + + return (NULL); +} + +sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler) +{ + oslSignalHandlerImpl *pHandler, *pPrevious = NULL; + + OSL_ASSERT(Handler != NULL); + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + pHandler = SignalList; + + while (pHandler != NULL) + { + if (pHandler == Handler) + { + if (pPrevious) + pPrevious->pNext = pHandler->pNext; + else + SignalList = pHandler->pNext; + + osl_releaseMutex(SignalListMutex); + + if (SignalList == NULL) + bInitSignal = DeInitSignal(); + + free(pHandler); + + return (sal_True); + } + + pPrevious = pHandler; + pHandler = pHandler->pNext; + } + + osl_releaseMutex(SignalListMutex); + + return (sal_False); +} + +oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData) +{ + oslSignalInfo Info; + oslSignalAction Action; + + if (! bInitSignal) + bInitSignal = InitSignal(); + + osl_acquireMutex(SignalListMutex); + + Info.Signal = osl_Signal_User; + Info.UserSignal = UserSignal; + Info.UserData = UserData; + + Action = CallSignalHandler(&Info); + + osl_releaseMutex(SignalListMutex); + + return (Action); +} + +sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable ) +{ + bool bOld = bErrorReportingEnabled; + bErrorReportingEnabled = bEnable; + + return bOld; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit