/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <ucontext.h>
#include <fenv.h>
#include <thread.h>
#include "fex_handler.h"
#if !defined(PC)
#if defined(REG_PC)
#else
#endif
#endif
{
return fp;
}
{
return 1;
}
int fex_get_log_depth(void)
{
int d;
d = log_depth;
return d;
}
int fex_set_log_depth(int d)
{
if (d < 0)
return 0;
log_depth = d;
return 1;
}
static struct exc_list {
char *addr;
unsigned long code;
int nstack;
#ifdef __sparcv9
#else
#endif
#ifdef _LP64
#else
#endif
/* look for a matching exc_list; return 1 if one is found,
otherwise add this one to the list and return 0 */
{
struct frame *f;
int i, n;
if (list) {
continue;
return 1;
continue;
n = 1;
n = 0;
break;
}
if (n)
return 1;
}
}
/* create a new exc_list structure and tack it on the list */
(n - 1) * sizeof(char *))) != NULL) {
for (i = 1; i < n; i++) {
}
if (list)
else
list = l;
}
return 0;
}
/*
* Warning: cleverness ahead
*
* In the following code, the use of sprintf+write rather than fprintf
* to send output to the log file is intentional. The reason is that
* fprintf is not async-signal-safe. "But," you protest, "SIGFPE is
* not an asynchronous signal! It's always handled by the same thread
* that executed the fpop that provoked it." That's true, but a prob-
* lem arises because (i) base conversion in fprintf can cause a fp
* exception and (ii) my signal handler acquires a mutex lock before
* sending output to the log file (so that outputs for entries from
* different threads aren't interspersed). Therefore, if the code
* were to use fprintf, a deadlock could occur as follows:
*
* Thread A Thread B
*
* Incurs a fp exception, Calls fprintf,
* acquires log_lock acquires file rmutex lock
*
* Calls fprintf, Incurs a fp exception,
* waits for file rmutex lock waits for log_lock
*
* (I could just verify that fprintf doesn't hold the rmutex lock while
* it's doing the base conversion, but since efficiency is of little
* concern here, I opted for the safe and dumb route.)
*/
{
int i;
(long)addr));
break;
} else {
(long)addr));
}
break;
}
}
{
char *stk;
int fd;
/* if logging is disabled, just return */
return;
}
/* get the frame pointer from the current context and
pop our own frame */
getcontext(&uc);
#else
#endif
return;
}
/* if we've already logged this message here, don't make an entry */
return;
}
/* make an entry */
}
"inexact result",
"division by zero",
"underflow",
"overflow",
"invalid operation (0/0)",
"invalid operation (inf-inf)",
"invalid operation (0*inf)",
"invalid operation (sqrt)",
"invalid operation (snan)",
"invalid operation (int)",
"invalid operation (cmp)"
};
void
int m, void *p)
{
int fd;
/* if logging is disabled, just return */
return;
}
/* get stack info */
#if defined(__sparc)
#else
#endif
/* if the handling mode is the default and this exception's
flag is already raised, don't make an entry */
if (m == FEX_NONSTOP) {
switch (e) {
case fex_inexact:
if (f & FE_INEXACT) {
return;
}
break;
case fex_underflow:
if (f & FE_UNDERFLOW) {
return;
}
break;
case fex_overflow:
if (f & FE_OVERFLOW) {
return;
}
break;
case fex_division:
if (f & FE_DIVBYZERO) {
return;
}
break;
default:
if (f & FE_INVALID) {
return;
}
break;
}
}
/* if we've already logged this exception at this address,
don't make an entry */
return;
}
/* make an entry */
}
switch (m) {
case FEX_NONSTOP:
break;
case FEX_ABORT:
break;
case FEX_NOHANDLER:
if (p == (void *)SIG_DFL) {
break;
}
else if (p == (void *)SIG_IGN) {
break;
}
/* fall through*/
default:
} else {
(long)p));
}
break;
}
}