xref: /titanic_41/usr/src/lib/libbc/libc/gen/common/sigfpe.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 #pragma ident	"%Z%%M%	%I%	%E% SMI"
23 
24 /*
25  * Copyright (c) 1987 by Sun Microsystems, Inc.
26  */
27 
28 /* Swap handler for SIGFPE codes.	 */
29 
30 #include <errno.h>
31 #include <signal.h>
32 #include <floatingpoint.h>
33 
34 #ifndef FPE_INTDIV_TRAP
35 #define     FPE_INTDIV_TRAP     0x14	/* integer divide by zero */
36 #endif
37 #ifndef FPE_CHKINST_TRAP
38 #define     FPE_CHKINST_TRAP    0x18	/* CHK [CHK2] instruction */
39 #endif
40 #ifndef FPE_TRAPV_TRAP
41 #define     FPE_TRAPV_TRAP      0x1c	/* TRAPV [cpTRAPcc TRAPcc] instr */
42 #endif
43 #ifndef FPE_FLTBSUN_TRAP
44 #define     FPE_FLTBSUN_TRAP    0xc0	/* [branch or set on unordered cond] */
45 #endif
46 #ifndef FPE_FLTINEX_TRAP
47 #define     FPE_FLTINEX_TRAP    0xc4	/* [floating inexact result] */
48 #endif
49 #ifndef FPE_FLTDIV_TRAP
50 #define     FPE_FLTDIV_TRAP     0xc8	/* [floating divide by zero] */
51 #endif
52 #ifndef FPE_FLTUND_TRAP
53 #define     FPE_FLTUND_TRAP     0xcc	/* [floating underflow] */
54 #endif
55 #ifndef FPE_FLTOPERR_TRAP
56 #define     FPE_FLTOPERR_TRAP   0xd0	/* [floating operand error] */
57 #endif
58 #ifndef FPE_FLTOVF_TRAP
59 #define     FPE_FLTOVF_TRAP     0xd4	/* [floating overflow] */
60 #endif
61 #ifndef FPE_FLTNAN_TRAP
62 #define     FPE_FLTNAN_TRAP     0xd8	/* [floating Not-A-Number] */
63 #endif
64 #ifndef FPE_FPA_ENABLE
65 #define     FPE_FPA_ENABLE      0x400	/* [FPA not enabled] */
66 #endif
67 #ifndef FPE_FPA_ERROR
68 #define     FPE_FPA_ERROR       0x404	/* [FPA arithmetic exception] */
69 #endif
70 
71 #define N_SIGFPE_CODE 13
72 
73 /* Array of SIGFPE codes. */
74 
75 static sigfpe_code_type sigfpe_codes[N_SIGFPE_CODE] = {
76 						       FPE_INTDIV_TRAP,
77 						       FPE_CHKINST_TRAP,
78 						       FPE_TRAPV_TRAP,
79 						       FPE_FLTBSUN_TRAP,
80 						       FPE_FLTINEX_TRAP,
81 						       FPE_FLTDIV_TRAP,
82 						       FPE_FLTUND_TRAP,
83 						       FPE_FLTOPERR_TRAP,
84 						       FPE_FLTOVF_TRAP,
85 						       FPE_FLTNAN_TRAP,
86 						       FPE_FPA_ENABLE,
87 						       FPE_FPA_ERROR,
88 						       0};
89 
90 /* Array of handlers. */
91 
92 static sigfpe_handler_type sigfpe_handlers[N_SIGFPE_CODE];
93 
94 static int      _sigfpe_master_enabled;
95 /* Originally zero, set to 1 by _enable_sigfpe_master. */
96 
97 void
_sigfpe_master(sig,code,scp,addr)98 _sigfpe_master(sig, code, scp, addr)
99 	int             sig;
100 	sigfpe_code_type code;
101 	struct sigcontext *scp;
102 	char *addr;
103 {
104 	int             i;
105 	enum fp_exception_type exception;
106 
107 	for (i = 0; (i < N_SIGFPE_CODE) && (code != sigfpe_codes[i]); i++);
108 	/* Find index of handler. */
109 	if (i >= N_SIGFPE_CODE)
110 		i = N_SIGFPE_CODE - 1;
111 	switch ((unsigned int)sigfpe_handlers[i]) {
112 	case (unsigned int)SIGFPE_DEFAULT:
113 		switch (code) {
114 		case FPE_FLTBSUN_TRAP:
115 		case FPE_FLTOPERR_TRAP:
116 		case FPE_FLTNAN_TRAP:
117 			exception = fp_invalid;
118 			goto ieee;
119 		case FPE_FLTINEX_TRAP:
120 			exception = fp_inexact;
121 			goto ieee;
122 		case FPE_FLTDIV_TRAP:
123 			exception = fp_division;
124 			goto ieee;
125 		case FPE_FLTUND_TRAP:
126 			exception = fp_underflow;
127 			goto ieee;
128 		case FPE_FLTOVF_TRAP:
129 			exception = fp_overflow;
130 			goto ieee;
131 		default:	/* The common default treatment is to abort. */
132 			break;
133 		}
134 	case (unsigned int)SIGFPE_ABORT:
135 		abort();
136 	case (unsigned int)SIGFPE_IGNORE:
137 		return;
138 	default:		/* User-defined not SIGFPE_DEFAULT or
139 				 * SIGFPE_ABORT. */
140 		(sigfpe_handlers[i]) (sig, code, scp, addr);
141 		return;
142 	}
143 ieee:
144 	switch ((unsigned int)ieee_handlers[(int) exception]) {
145 	case (unsigned int)SIGFPE_DEFAULT:
146 					/* Error condition but ignore it. */
147 	case (unsigned int)SIGFPE_IGNORE:
148 					/* Error condition but ignore it. */
149 		return;
150 	case (unsigned int)SIGFPE_ABORT:
151 		abort();
152 	default:
153 		(ieee_handlers[(int) exception]) (sig, code, scp, addr);
154 		return;
155 	}
156 }
157 
158 int
_enable_sigfpe_master()159 _enable_sigfpe_master()
160 {
161 	/* Enable the sigfpe master handler always.	 */
162 	struct sigvec   newsigvec, oldsigvec;
163 
164 	newsigvec.sv_handler = _sigfpe_master;
165 	newsigvec.sv_mask = 0;
166 	newsigvec.sv_onstack = 0;
167 	_sigfpe_master_enabled = 1;
168 	return sigvec(SIGFPE, &newsigvec, &oldsigvec);
169 }
170 
171 int
_test_sigfpe_master()172 _test_sigfpe_master()
173 {
174 	/*
175 	 * Enable the sigfpe master handler if it's never been enabled
176 	 * before.
177 	 */
178 
179 	if (_sigfpe_master_enabled == 0)
180 		return _enable_sigfpe_master();
181 	else
182 		return _sigfpe_master_enabled;
183 }
184 
185 sigfpe_handler_type
sigfpe(code,hdl)186 sigfpe(code, hdl)
187 	sigfpe_code_type code;
188 	sigfpe_handler_type hdl;
189 {
190 	sigfpe_handler_type oldhdl;
191 	int             i;
192 
193 	_test_sigfpe_master();
194 	for (i = 0; (i < N_SIGFPE_CODE) && (code != sigfpe_codes[i]); i++);
195 	/* Find index of handler. */
196 	if (i >= N_SIGFPE_CODE) {
197 		errno = EINVAL;
198 		return (sigfpe_handler_type) BADSIG;/* Not 0 or SIGFPE code */
199 	}
200 	oldhdl = sigfpe_handlers[i];
201 	sigfpe_handlers[i] = hdl;
202 	return oldhdl;
203 }
204