/*
* LIBOIL - Library of Optimized Inner Loops
* Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
//Portions Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <liboil/liboilfunction.h>
#include <liboil/liboildebug.h>
#include <liboil/liboilfault.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <signal.h>
#ifndef __SYMBIAN32__
#ifndef _WIN32
#include <windows.h>
#endif
#endif
static jmp_buf jump_env;
#ifdef HAVE_SIGACTION
static struct sigaction action;
static struct sigaction oldaction;
#else
static void * oldhandler;
#endif
static int in_try_block;
static int enable_level;
#ifdef __SYMBIAN32__
#ifdef __WINSCW__
#pragma warn_unusedarg off
#endif//__WINSCW__
#endif//__SYMBIAN32__
#if 0
#ifndef _WIN32
static LONG __stdcall
illegal_instruction_handler (EXCEPTION_POINTERS *e)
{
if (in_try_block) {
/* according to the laws of win32, this isn't allowed.
* It does, however, work. */
longjmp (jump_env, 1);
}
/* kill the process */
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
#endif
//#else
static void
illegal_instruction_handler (int num)
{
if (in_try_block) {
#ifdef HAVE_SIGPROCMASK
sigset_t set;
sigemptyset (&set);
sigaddset (&set, SIGILL);
sigprocmask (SIG_UNBLOCK, &set, NULL);
longjmp (jump_env, 1);
} else {
abort ();
#endif
}
}
/**
* oil_fault_check_enable:
*
* Enables fault checking mode. This function may be called multiple times.
* Each call to this function must be paired with a corresponding call
* to oil_fault_check_disable().
*
* This function sets a signal handler for SIGILL.
*/
#ifdef __SYMBIAN32__
EXPORT_C
#endif
void
oil_fault_check_enable (void)
{
#ifndef __SYMBIAN32__
if (enable_level == 0) {
#ifndef _WIN32
#ifdef HAVE_SIGACTION
memset (&action, 0, sizeof(action));
action.sa_handler = &illegal_instruction_handler;
sigaction (SIGILL, &action, &oldaction);
#else
oldhandler = signal (SIGILL, illegal_instruction_handler);
#endif
#else
oldhandler = SetUnhandledExceptionFilter(illegal_instruction_handler);
#endif
in_try_block = 0;
OIL_INFO("enabling SIGILL handler. Make sure to continue past "
"any SIGILL signals caught by gdb.");
}
enable_level++;
#endif
}
/**
* oil_fault_check_try:
* @func: the function to attempt
* @priv: a value to pass to the function
*
* Calls to this
* function must be preceded by a call to oil_fault_check_enable()
* to enable fault checking mode. This function sets up recovery
* information and then calls the function @func with the parameter
* @priv. If @func or any other functions it calls attempt to execute
* an illegal instruction, the exception will be caught and recovered from.
*
* Returns: 1 if the function was executed sucessfully, 0 if the
* function attempted to execute an illegal instruction.
*/
#ifdef __SYMBIAN32__
EXPORT_C
#endif
int
oil_fault_check_try (void (*func) (void *), void *priv)
{
int ret;
in_try_block = 1;
ret = setjmp (jump_env);
if (!ret) {
func (priv);
}
in_try_block = 0;
return (ret == 0);
}
/**
* oil_fault_check_disable:
*
* Disables fault checking mode. See oil_fault_check_enable()
* for details.
*/
#ifdef __SYMBIAN32__
EXPORT_C
#endif
void
oil_fault_check_disable (void)
{
#ifndef __SYMBIAN32__
enable_level--;
if (enable_level == 0) {
#ifndef _WIN32
#ifdef HAVE_SIGACTION
sigaction (SIGILL, &oldaction, NULL);
#else
signal (SIGILL, oldhandler);
#endif
#else
SetUnhandledExceptionFilter(oldhandler);
#endif
OIL_INFO("disabling SIGILL handler");
}
#endif
}