summaryrefslogtreecommitdiff
path: root/usr/src/lib/libbc/libc/gen/common/sigfpe.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libbc/libc/gen/common/sigfpe.c')
-rw-r--r--usr/src/lib/libbc/libc/gen/common/sigfpe.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/usr/src/lib/libbc/libc/gen/common/sigfpe.c b/usr/src/lib/libbc/libc/gen/common/sigfpe.c
new file mode 100644
index 0000000000..24b24eb95f
--- /dev/null
+++ b/usr/src/lib/libbc/libc/gen/common/sigfpe.c
@@ -0,0 +1,203 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright (c) 1987 by Sun Microsystems, Inc.
+ */
+
+/* Swap handler for SIGFPE codes. */
+
+#include <errno.h>
+#include <signal.h>
+#include <floatingpoint.h>
+
+#ifndef FPE_INTDIV_TRAP
+#define FPE_INTDIV_TRAP 0x14 /* integer divide by zero */
+#endif
+#ifndef FPE_CHKINST_TRAP
+#define FPE_CHKINST_TRAP 0x18 /* CHK [CHK2] instruction */
+#endif
+#ifndef FPE_TRAPV_TRAP
+#define FPE_TRAPV_TRAP 0x1c /* TRAPV [cpTRAPcc TRAPcc] instr */
+#endif
+#ifndef FPE_FLTBSUN_TRAP
+#define FPE_FLTBSUN_TRAP 0xc0 /* [branch or set on unordered cond] */
+#endif
+#ifndef FPE_FLTINEX_TRAP
+#define FPE_FLTINEX_TRAP 0xc4 /* [floating inexact result] */
+#endif
+#ifndef FPE_FLTDIV_TRAP
+#define FPE_FLTDIV_TRAP 0xc8 /* [floating divide by zero] */
+#endif
+#ifndef FPE_FLTUND_TRAP
+#define FPE_FLTUND_TRAP 0xcc /* [floating underflow] */
+#endif
+#ifndef FPE_FLTOPERR_TRAP
+#define FPE_FLTOPERR_TRAP 0xd0 /* [floating operand error] */
+#endif
+#ifndef FPE_FLTOVF_TRAP
+#define FPE_FLTOVF_TRAP 0xd4 /* [floating overflow] */
+#endif
+#ifndef FPE_FLTNAN_TRAP
+#define FPE_FLTNAN_TRAP 0xd8 /* [floating Not-A-Number] */
+#endif
+#ifndef FPE_FPA_ENABLE
+#define FPE_FPA_ENABLE 0x400 /* [FPA not enabled] */
+#endif
+#ifndef FPE_FPA_ERROR
+#define FPE_FPA_ERROR 0x404 /* [FPA arithmetic exception] */
+#endif
+
+#define N_SIGFPE_CODE 13
+
+/* Array of SIGFPE codes. */
+
+static sigfpe_code_type sigfpe_codes[N_SIGFPE_CODE] = {
+ FPE_INTDIV_TRAP,
+ FPE_CHKINST_TRAP,
+ FPE_TRAPV_TRAP,
+ FPE_FLTBSUN_TRAP,
+ FPE_FLTINEX_TRAP,
+ FPE_FLTDIV_TRAP,
+ FPE_FLTUND_TRAP,
+ FPE_FLTOPERR_TRAP,
+ FPE_FLTOVF_TRAP,
+ FPE_FLTNAN_TRAP,
+ FPE_FPA_ENABLE,
+ FPE_FPA_ERROR,
+ 0};
+
+/* Array of handlers. */
+
+static sigfpe_handler_type sigfpe_handlers[N_SIGFPE_CODE];
+
+static int _sigfpe_master_enabled;
+/* Originally zero, set to 1 by _enable_sigfpe_master. */
+
+void
+_sigfpe_master(sig, code, scp, addr)
+ int sig;
+ sigfpe_code_type code;
+ struct sigcontext *scp;
+ char *addr;
+{
+ int i;
+ enum fp_exception_type exception;
+
+ for (i = 0; (i < N_SIGFPE_CODE) && (code != sigfpe_codes[i]); i++);
+ /* Find index of handler. */
+ if (i >= N_SIGFPE_CODE)
+ i = N_SIGFPE_CODE - 1;
+ switch ((unsigned int)sigfpe_handlers[i]) {
+ case (unsigned int)SIGFPE_DEFAULT:
+ switch (code) {
+ case FPE_FLTBSUN_TRAP:
+ case FPE_FLTOPERR_TRAP:
+ case FPE_FLTNAN_TRAP:
+ exception = fp_invalid;
+ goto ieee;
+ case FPE_FLTINEX_TRAP:
+ exception = fp_inexact;
+ goto ieee;
+ case FPE_FLTDIV_TRAP:
+ exception = fp_division;
+ goto ieee;
+ case FPE_FLTUND_TRAP:
+ exception = fp_underflow;
+ goto ieee;
+ case FPE_FLTOVF_TRAP:
+ exception = fp_overflow;
+ goto ieee;
+ default: /* The common default treatment is to abort. */
+ break;
+ }
+ case (unsigned int)SIGFPE_ABORT:
+ abort();
+ case (unsigned int)SIGFPE_IGNORE:
+ return;
+ default: /* User-defined not SIGFPE_DEFAULT or
+ * SIGFPE_ABORT. */
+ (sigfpe_handlers[i]) (sig, code, scp, addr);
+ return;
+ }
+ieee:
+ switch ((unsigned int)ieee_handlers[(int) exception]) {
+ case (unsigned int)SIGFPE_DEFAULT:
+ /* Error condition but ignore it. */
+ case (unsigned int)SIGFPE_IGNORE:
+ /* Error condition but ignore it. */
+ return;
+ case (unsigned int)SIGFPE_ABORT:
+ abort();
+ default:
+ (ieee_handlers[(int) exception]) (sig, code, scp, addr);
+ return;
+ }
+}
+
+int
+_enable_sigfpe_master()
+{
+ /* Enable the sigfpe master handler always. */
+ struct sigvec newsigvec, oldsigvec;
+
+ newsigvec.sv_handler = _sigfpe_master;
+ newsigvec.sv_mask = 0;
+ newsigvec.sv_onstack = 0;
+ _sigfpe_master_enabled = 1;
+ return sigvec(SIGFPE, &newsigvec, &oldsigvec);
+}
+
+int
+_test_sigfpe_master()
+{
+ /*
+ * Enable the sigfpe master handler if it's never been enabled
+ * before.
+ */
+
+ if (_sigfpe_master_enabled == 0)
+ return _enable_sigfpe_master();
+ else
+ return _sigfpe_master_enabled;
+}
+
+sigfpe_handler_type
+sigfpe(code, hdl)
+ sigfpe_code_type code;
+ sigfpe_handler_type hdl;
+{
+ sigfpe_handler_type oldhdl;
+ int i;
+
+ _test_sigfpe_master();
+ for (i = 0; (i < N_SIGFPE_CODE) && (code != sigfpe_codes[i]); i++);
+ /* Find index of handler. */
+ if (i >= N_SIGFPE_CODE) {
+ errno = EINVAL;
+ return (sigfpe_handler_type) BADSIG;/* Not 0 or SIGFPE code */
+ }
+ oldhdl = sigfpe_handlers[i];
+ sigfpe_handlers[i] = hdl;
+ return oldhdl;
+}