19a9176627
2008/03/31 13:23:44 rt 1.35.64.1: #i87441# Change license header to LPGL v3.
954 lines
30 KiB
C
954 lines
30 KiB
C
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2008 by Sun Microsystems, Inc.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: signal.c,v $
|
|
* $Revision: 1.36 $
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
/* system headers */
|
|
#include "system.h"
|
|
|
|
#define MAX_STACK_FRAMES 256
|
|
|
|
#ifdef LINUX
|
|
#include <execinfo.h>
|
|
#define INCLUDE_BACKTRACE
|
|
#define STACKTYPE "Linux"
|
|
#endif
|
|
|
|
#ifdef SOLARIS
|
|
|
|
#include "backtrace.h"
|
|
#define INCLUDE_BACKTRACE
|
|
|
|
#if defined( SPARC )
|
|
#define STACKTYPE "Solaris_Sparc"
|
|
#elif defined( INTEL )
|
|
#define STACKTYPE "Solaris_X86"
|
|
#else
|
|
#define STACKTYPE "Solaris_Unknown"
|
|
#endif
|
|
|
|
#endif /* defined SOLARIS */
|
|
|
|
#include <osl/diagnose.h>
|
|
#include <osl/mutex.h>
|
|
#include <osl/signal.h>
|
|
#include <osl/process.h>
|
|
#include <osl/thread.h>
|
|
#include <rtl/digest.h>
|
|
|
|
#include "file_path_helper.h"
|
|
|
|
#define ACT_IGNORE 1
|
|
#define ACT_ABORT 2
|
|
#define ACT_EXIT 3
|
|
#define ACT_SYSTEM 4
|
|
#define ACT_HIDE 5
|
|
|
|
#define MAX_PATH_LEN 2048
|
|
|
|
typedef struct _oslSignalHandlerImpl
|
|
{
|
|
oslSignalHandlerFunction Handler;
|
|
void* pData;
|
|
struct _oslSignalHandlerImpl* pNext;
|
|
} oslSignalHandlerImpl;
|
|
|
|
static struct SignalAction
|
|
{
|
|
int Signal;
|
|
int Action;
|
|
void (*Handler)(int);
|
|
} Signals[] =
|
|
{
|
|
{ SIGHUP, ACT_IGNORE, 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 occured */
|
|
#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 bDoHardKill = sal_False;
|
|
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()
|
|
{
|
|
int i;
|
|
struct sigaction act;
|
|
struct sigaction oact;
|
|
|
|
if (is_soffice_Impl())
|
|
{
|
|
sal_uInt32 argi;
|
|
sal_uInt32 argc;
|
|
rtl_uString *ustrCommandArg = 0;
|
|
|
|
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), "-bean"))
|
|
{
|
|
bDoHardKill = sal_True;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ustrCommandArg)
|
|
{
|
|
rtl_uString_release (ustrCommandArg);
|
|
ustrCommandArg = 0;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
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++)
|
|
{
|
|
/* hack: stomcatd is attaching JavaVM wich dont 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return sal_True;
|
|
}
|
|
|
|
static sal_Bool DeInitSignal()
|
|
{
|
|
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 defined (SAL_ENABLE_CRASH_REPORT) && defined(INCLUDE_BACKTRACE)
|
|
/*****************************************************************************/
|
|
/* Generate MD5 checksum */
|
|
/*****************************************************************************/
|
|
|
|
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 */
|
|
|
|
#define REPORTENV_PARAM "-crashreportenv:"
|
|
|
|
static int ReportCrash( int Signal )
|
|
{
|
|
#ifdef SAL_ENABLE_CRASH_REPORT
|
|
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];
|
|
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, sizeof(stackframes)/sizeof(stackframes[0]));
|
|
|
|
FILE *xmlout = NULL, *stackout = NULL, *checksumout = NULL;
|
|
int fdxml, fdstk, fdchksum;
|
|
|
|
strncpy( szXMLTempNameBuffer, P_tmpdir, sizeof(szXMLTempNameBuffer) );
|
|
strncat( szXMLTempNameBuffer, "/crxmlXXXXXX", sizeof(szXMLTempNameBuffer) );
|
|
|
|
strncpy( szStackTempNameBuffer, P_tmpdir, sizeof(szStackTempNameBuffer) );
|
|
strncat( szStackTempNameBuffer, "/crstkXXXXXX", sizeof(szStackTempNameBuffer) );
|
|
|
|
strncpy( szChecksumTempNameBuffer, P_tmpdir, sizeof(szChecksumTempNameBuffer) );
|
|
strncat( szChecksumTempNameBuffer, "/crchkXXXXXX", sizeof(szChecksumTempNameBuffer) );
|
|
|
|
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, "<errormail:Stack type=\"%s\">\n", STACKTYPE );
|
|
|
|
fprintf( checksumout, "<errormail:Checksums type=\"MD5\">\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, "<errormail:StackInfo pos=\"%d\" ip=\"0x%" SAL_PRIxUINTPTR "\"",
|
|
iFrame,
|
|
SAL_INT_CAST(sal_uIntPtr, stackframes[iFrame])
|
|
);
|
|
|
|
memset( &dl_info, 0, sizeof(dl_info) );
|
|
|
|
/* dladdr may fail */
|
|
if ( dladdr( stackframes[iFrame], &dl_info) )
|
|
{
|
|
const char *dli_fname = NULL;
|
|
char *dli_fdir = NULL;
|
|
char szDirectory[PATH_MAX];
|
|
char szCanonicDirectory[PATH_MAX];
|
|
|
|
/* Don't expect that dladdr filled all members of dl_info */
|
|
|
|
dli_fname = dl_info.dli_fname ? strrchr( dl_info.dli_fname, '/' ) : NULL;
|
|
if ( dli_fname )
|
|
{
|
|
++dli_fname;
|
|
memcpy( szDirectory, dl_info.dli_fname, dli_fname - dl_info.dli_fname );
|
|
szDirectory[dli_fname - dl_info.dli_fname] = 0;
|
|
|
|
dli_fdir = realpath( szDirectory, szCanonicDirectory ) ? szCanonicDirectory : szDirectory;
|
|
|
|
if ( *dli_fdir && dli_fdir[ strlen(dli_fdir) - 1 ] != '/' )
|
|
strcat( dli_fdir, "/" );
|
|
}
|
|
else
|
|
dli_fname = dl_info.dli_fname;
|
|
|
|
/* create checksum of library on stack */
|
|
if ( dli_fname )
|
|
{
|
|
sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
|
|
|
|
sal_uInt32 nBytesProcessed = calc_md5_checksum(
|
|
dl_info.dli_fname, checksum, sizeof(checksum) );
|
|
if ( nBytesProcessed )
|
|
{
|
|
int j;
|
|
|
|
fprintf( checksumout, "<errormail:Checksum sum=\"0x" );
|
|
for ( j = 0; j < 16; fprintf( checksumout, "%02X", checksum[j++] ) );
|
|
fprintf( checksumout,
|
|
"\" bytes=\"%lu\" file=\"%s\"/>\n",
|
|
SAL_INT_CAST(
|
|
unsigned long, nBytesProcessed),
|
|
dli_fname );
|
|
}
|
|
}
|
|
|
|
if ( dl_info.dli_fbase && dl_info.dli_fname )
|
|
{
|
|
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 );
|
|
}
|
|
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, "</errormail:Stack>\n" );
|
|
fprintf( checksumout, "</errormail:Checksums>\n" );
|
|
}
|
|
else
|
|
{
|
|
pXMLTempName = NULL;
|
|
pStackTempName = NULL;
|
|
pChecksumTempName = NULL;
|
|
}
|
|
|
|
if ( stackout )
|
|
fclose( stackout );
|
|
if ( xmlout )
|
|
fclose( xmlout );
|
|
if ( checksumout )
|
|
fclose( checksumout );
|
|
|
|
#if defined( LINUX )
|
|
if ( pXMLTempName && pChecksumTempName && pStackTempName )
|
|
snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
|
|
"crash_report -p %d -s %d -xml %s -chksum %s -stack %s%s",
|
|
getpid(),
|
|
Signal,
|
|
pXMLTempName,
|
|
pChecksumTempName,
|
|
pStackTempName,
|
|
bAutoCrashReport ? " -noui -send" : " -noui" );
|
|
#elif defined ( SOLARIS )
|
|
if ( pXMLTempName && pChecksumTempName )
|
|
snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
|
|
"crash_report -p %d -s %d -xml %s -chksum %s%s",
|
|
getpid(),
|
|
Signal,
|
|
pXMLTempName,
|
|
pChecksumTempName,
|
|
bAutoCrashReport ? " -noui -send" : " -noui" );
|
|
#endif
|
|
|
|
#else /* defined INCLUDE BACKTRACE */
|
|
snprintf( szShellCmd, sizeof(szShellCmd)/sizeof(szShellCmd[0]),
|
|
"crash_report -p %d -s %d%s", getpid(), Signal, bAutoCrashReport ? " -noui -send" : " -noui" );
|
|
#endif /* defined INCLUDE BACKTRACE */
|
|
|
|
|
|
ret = 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 /* defined SAL_ENABLE_CRASH_REPORT */
|
|
/* 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 /* defined SAL_ENABLE_CRASH_REPORT */
|
|
}
|
|
|
|
static void PrintStack( int sig )
|
|
{
|
|
#ifndef MACOSX
|
|
void *buffer[MAX_STACK_FRAMES];
|
|
int size = backtrace( buffer, sizeof(buffer) / sizeof(buffer[0]) );
|
|
#endif
|
|
|
|
fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
|
|
|
|
#ifdef MACOSX
|
|
fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
|
|
#else
|
|
if ( size > 0 )
|
|
{
|
|
fputs( "Stack:\n", stderr );
|
|
backtrace_symbols_fd( buffer, size, fileno(stderr) );
|
|
}
|
|
#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);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* SignalHandlerFunction */
|
|
/*****************************************************************************/
|
|
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:
|
|
case SIGHUP:
|
|
Info.Signal = osl_Signal_Terminate;
|
|
break;
|
|
|
|
default:
|
|
Info.Signal = osl_Signal_System;
|
|
break;
|
|
}
|
|
|
|
ReportCrash( Signal );
|
|
|
|
/* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
|
if (bDoHardKill && (Info.Signal == osl_Signal_AccessViolation))
|
|
_exit(255);
|
|
/* Portal Demo HACK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* osl_addSignalHandler */
|
|
/*****************************************************************************/
|
|
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);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* osl_removeSignalHandler */
|
|
/*****************************************************************************/
|
|
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);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* osl_raiseSignal */
|
|
/*****************************************************************************/
|
|
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);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* osl_setErrorReporting */
|
|
/*****************************************************************************/
|
|
sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
|
|
{
|
|
sal_Bool bOld = bErrorReportingEnabled;
|
|
bErrorReportingEnabled = bEnable;
|
|
|
|
return bOld;
|
|
}
|