Print this page
11210 libm should be cstyle(1ONBLD) clean


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */

  25 /*
  26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 #undef lint
  31 #include <signal.h>
  32 #include <siginfo.h>
  33 #include <ucontext.h>
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <unistd.h>
  37 #include <thread.h>
  38 #include <math.h>
  39 #if defined(__SUNPRO_C)
  40 #include <sunmath.h>
  41 #endif
  42 #include <fenv.h>
  43 #include "fex_handler.h"
  44 #include "fenv_inlines.h"
  45 
  46 #if defined(__sparc) && !defined(__sparcv9)
  47 #include <sys/procfs.h>
  48 #endif
  49 
  50 /* 2.x signal.h doesn't declare sigemptyset or sigismember
  51    if they're #defined (see sys/signal.h) */


  52 extern int sigemptyset(sigset_t *);
  53 extern int sigismember(const sigset_t *, int);
  54 
  55 /* external globals */
  56 void (*__mt_fex_sync)() = NULL; /* for synchronization with libmtsk */
  57 #pragma weak __mt_fex_sync
  58 
  59 void (*__libm_mt_fex_sync)() = NULL; /* new, improved version of above */
  60 #pragma weak __libm_mt_fex_sync
  61 
  62 /* private variables */
  63 static fex_handler_t main_handlers;
  64 static int handlers_initialized = 0;
  65 static thread_key_t handlers_key;
  66 static mutex_t handlers_key_lock = DEFAULTMUTEX;
  67 
  68 static struct sigaction oact = { 0, SIG_DFL };
  69 static mutex_t hdlr_lock = DEFAULTMUTEX;
  70 static int hdlr_installed = 0;
  71 
  72 /* private const data */
  73 static const int te_bit[FEX_NUM_EXC] = {
  74         1 << fp_trap_inexact,
  75         1 << fp_trap_division,
  76         1 << fp_trap_underflow,
  77         1 << fp_trap_overflow,
  78         1 << fp_trap_invalid,
  79         1 << fp_trap_invalid,
  80         1 << fp_trap_invalid,
  81         1 << fp_trap_invalid,
  82         1 << fp_trap_invalid,
  83         1 << fp_trap_invalid,
  84         1 << fp_trap_invalid,
  85         1 << fp_trap_invalid
  86 };
  87 
  88 /*
  89 *  Return the traps to be enabled given the current handling modes
  90 *  and flags
  91 */
  92 static int
  93 __fex_te_needed(struct fex_handler_data *thr_handlers, unsigned long fsr)
  94 {
  95         int             i, ex, te;
  96 
  97         /* set traps for handling modes */
  98         te = 0;

  99         for (i = 0; i < FEX_NUM_EXC; i++)
 100                 if (thr_handlers[i].__mode != FEX_NONSTOP)
 101                         te |= te_bit[i];
 102 
 103         /* add traps for retrospective diagnostics */

 104         if (fex_get_log()) {
 105                 ex = (int)__fenv_get_ex(fsr);

 106                 if (!(ex & FE_INEXACT))
 107                         te |= (1 << fp_trap_inexact);

 108                 if (!(ex & FE_UNDERFLOW))
 109                         te |= (1 << fp_trap_underflow);

 110                 if (!(ex & FE_OVERFLOW))
 111                         te |= (1 << fp_trap_overflow);

 112                 if (!(ex & FE_DIVBYZERO))
 113                         te |= (1 << fp_trap_division);

 114                 if (!(ex & FE_INVALID))
 115                         te |= (1 << fp_trap_invalid);
 116         }
 117 
 118         return te;
 119 }
 120 
 121 /*
 122 *  The following function synchronizes with libmtsk (SPARC only, for now)
 123 */
 124 static void
 125 __fex_sync_with_libmtsk(int begin, int master)
 126 {
 127         static fenv_t master_env;
 128         static int env_initialized = 0;
 129         static mutex_t env_lock = DEFAULTMUTEX;
 130 
 131         if (begin) {
 132                 mutex_lock(&env_lock);

 133                 if (master) {
 134                         (void) fegetenv(&master_env);
 135                         env_initialized = 1;
 136                 }
 137                 else if (env_initialized)
 138                         (void) fesetenv(&master_env);
 139                 mutex_unlock(&env_lock);
 140         }
 141         else if (master && fex_get_log())


 142                 __fex_update_te();

 143 }
 144 
 145 /*
 146 *  The following function may be used for synchronization with any
 147 *  internal project that manages multiple threads
 148 */
 149 enum __libm_mt_fex_sync_actions {
 150         __libm_mt_fex_start_master = 0,
 151         __libm_mt_fex_start_slave,
 152         __libm_mt_fex_finish_master,
 153         __libm_mt_fex_finish_slave
 154 };
 155 
 156 struct __libm_mt_fex_sync_data {
 157         fenv_t  master_env;
 158         int             initialized;
 159         mutex_t lock;
 160 };
 161 
 162 static void
 163 __fex_sync_with_threads(enum __libm_mt_fex_sync_actions action,
 164         struct __libm_mt_fex_sync_data *thr_env)
 165 {
 166         switch (action) {
 167         case __libm_mt_fex_start_master:
 168                 mutex_lock(&thr_env->lock);
 169                 (void) fegetenv(&thr_env->master_env);
 170                 thr_env->initialized = 1;
 171                 mutex_unlock(&thr_env->lock);
 172                 break;
 173 
 174         case __libm_mt_fex_start_slave:
 175                 mutex_lock(&thr_env->lock);

 176                 if (thr_env->initialized)
 177                         (void) fesetenv(&thr_env->master_env);

 178                 mutex_unlock(&thr_env->lock);
 179                 break;
 180 
 181         case __libm_mt_fex_finish_master:
 182 #if defined(__x86)
 183                 __fex_update_te();
 184 #else
 185                 if (fex_get_log())
 186                         __fex_update_te();
 187 #endif
 188                 break;
 189 
 190         case __libm_mt_fex_finish_slave:
 191 #if defined(__x86)
 192                 /* clear traps, making all accrued flags visible in status word */



 193                 {
 194                         unsigned long   fsr;

 195                         __fenv_getfsr(&fsr);
 196                         __fenv_set_te(fsr, 0);
 197                         __fenv_setfsr(&fsr);
 198                 }
 199 #endif
 200                 break;
 201         }
 202 }
 203 
 204 #if defined(__sparc)
 205 
 206 /*
 207 *  Code for setting or clearing interval mode on US-III and above.
 208 *  This is embedded as data so we don't have to mark the library
 209 *  as a v8plusb/v9b object.  (I could have just used one entry and
 210 *  modified the second word to set the bits I want, but that would
 211 *  have required another mutex.)
 212 */
 213 static const unsigned int siam[][2] = {
 214         { 0x81c3e008, 0x81b01020 }, /* retl, siam 0 */
 215         { 0x81c3e008, 0x81b01024 }, /* retl, siam 4 */
 216         { 0x81c3e008, 0x81b01025 }, /* retl, siam 5 */
 217         { 0x81c3e008, 0x81b01026 }, /* retl, siam 6 */
 218         { 0x81c3e008, 0x81b01027 }  /* retl, siam 7 */
 219 };
 220 
 221 /*
 222 *  If a handling mode is in effect, apply it; otherwise invoke the
 223 *  saved handler
 224 */
 225 static void
 226 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
 227 {
 228         struct fex_handler_data *thr_handlers;
 229         struct sigaction        act;

 230         void                    (*handler)(), (*siamp)();

 231         int                     mode, i;
 232         enum fex_exception      e;
 233         fex_info_t              info;
 234         unsigned long           fsr, tmpfsr, addr;
 235         unsigned int            gsr;
 236 
 237         /* determine which exception occurred */
 238         switch (sip->si_code) {
 239         case FPE_FLTDIV:
 240                 e = fex_division;
 241                 break;
 242         case FPE_FLTOVF:
 243                 e = fex_overflow;
 244                 break;
 245         case FPE_FLTUND:
 246                 e = fex_underflow;
 247                 break;
 248         case FPE_FLTRES:
 249                 e = fex_inexact;
 250                 break;
 251         case FPE_FLTINV:

 252                 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
 253                         goto not_ieee;

 254                 break;
 255         default:
 256                 /* not an IEEE exception */
 257                 goto not_ieee;
 258         }
 259 
 260         /* get the handling mode */
 261         mode = FEX_NOHANDLER;
 262         handler = oact.sa_handler; /* for log; just looking, no need to lock */
 263         thr_handlers = __fex_get_thr_handlers();

 264         if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
 265                 mode = thr_handlers[(int)e].__mode;
 266                 handler = thr_handlers[(int)e].__handler;
 267         }
 268 
 269         /* make an entry in the log of retro. diag. if need be */
 270         i = ((int)uap->uc_mcontext.fpregs.fpu_fsr >> 5) & 0x1f;
 271         __fex_mklog(uap, (char *)sip->si_addr, i, e, mode, (void *)handler);
 272 
 273         /* handle the exception based on the mode */
 274         if (mode == FEX_NOHANDLER)
 275                 goto not_ieee;
 276         else if (mode == FEX_ABORT)
 277                 abort();
 278         else if (mode == FEX_SIGNAL) {
 279                 handler(sig, sip, uap);
 280                 return;
 281         }
 282 
 283         /* custom or nonstop mode; disable traps and clear flags */
 284         __fenv_getfsr(&fsr);
 285         __fenv_set_te(fsr, 0);
 286         __fenv_set_ex(fsr, 0);
 287 
 288         /* if interval mode was set, clear it, then substitute the
 289            interval rounding direction and clear ns mode in the fsr */


 290 #ifdef __sparcv9
 291         gsr = uap->uc_mcontext.asrs[3];
 292 #else
 293         gsr = 0;

 294         if (uap->uc_mcontext.xrs.xrs_id == XRS_ID)
 295                 gsr = (*(unsigned long long*)((prxregset_t*)uap->uc_mcontext.
 296                     xrs.xrs_ptr)->pr_un.pr_v8p.pr_filler);

 297 #endif
 298         gsr = (gsr >> 25) & 7;

 299         if (gsr & 4) {
 300                 siamp = (void (*)()) siam[0];
 301                 siamp();
 302                 tmpfsr = fsr;
 303                 fsr = (fsr & ~0xc0400000ul) | ((gsr & 3) << 30);
 304         }

 305         __fenv_setfsr(&fsr);
 306 
 307         /* decode the operation */
 308         __fex_get_op(sip, uap, &info);
 309 
 310         /* if a custom mode handler is installed, invoke it */
 311         if (mode == FEX_CUSTOM) {
 312                 /* if we got here from feraiseexcept, pass dummy info */
 313                 addr = (unsigned long)sip->si_addr;
 314                 if (addr >= (unsigned long)feraiseexcept &&
 315                     addr < (unsigned long)fetestexcept) {

 316                         info.op = fex_other;
 317                         info.op1.type = info.op2.type = info.res.type =
 318                             fex_nodata;
 319                 }
 320 
 321                 /* restore interval mode if it was set, and put the original
 322                    rounding direction and ns mode back in the fsr */


 323                 if (gsr & 4) {
 324                         __fenv_setfsr(&tmpfsr);
 325                         siamp = (void (*)()) siam[1 + (gsr & 3)];
 326                         siamp();
 327                 }
 328 
 329                 handler(1 << (int)e, &info);
 330 
 331                 /* restore modes in case the user's handler changed them */
 332                 if (gsr & 4) {
 333                         siamp = (void (*)()) siam[0];
 334                         siamp();
 335                 }

 336                 __fenv_setfsr(&fsr);
 337         }
 338 
 339         /* stuff the result */
 340         __fex_st_result(sip, uap, &info);
 341 
 342         /* "or" in any exception flags and update traps */
 343         fsr = uap->uc_mcontext.fpregs.fpu_fsr;
 344         fsr |= ((info.flags & 0x1f) << 5);
 345         i = __fex_te_needed(thr_handlers, fsr);
 346         __fenv_set_te(fsr, i);
 347         uap->uc_mcontext.fpregs.fpu_fsr = fsr;
 348         return;
 349 
 350 not_ieee:
 351         /* revert to the saved handler (if any) */
 352         mutex_lock(&hdlr_lock);
 353         act = oact;
 354         mutex_unlock(&hdlr_lock);

 355         switch ((unsigned long)act.sa_handler) {
 356         case (unsigned long)SIG_DFL:
 357                 /* simulate trap with no handler installed */
 358                 sigaction(SIGFPE, &act, NULL);
 359                 kill(getpid(), SIGFPE);
 360                 break;
 361 #if !defined(__lint)
 362         case (unsigned long)SIG_IGN:
 363                 break;
 364 #endif
 365         default:
 366                 act.sa_handler(sig, sip, uap);
 367         }
 368 }
 369 
 370 #elif defined(__x86)
 371 
 372 #if defined(__amd64)
 373 #define test_sse_hw     1
 374 #else
 375 extern int _sse_hw;

 376 #define test_sse_hw     _sse_hw
 377 #endif
 378 
 379 #if !defined(REG_PC)
 380 #define REG_PC  EIP
 381 #endif
 382 
 383 /*
 384 *  If a handling mode is in effect, apply it; otherwise invoke the
 385 *  saved handler
 386 */
 387 static void
 388 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
 389 {
 390         struct fex_handler_data *thr_handlers;
 391         struct sigaction        act;

 392         void                    (*handler)() = NULL, (*simd_handler[4])();

 393         int                     mode, simd_mode[4], i, len, accrued, *ap;
 394         unsigned int            cwsw, oldcwsw, mxcsr, oldmxcsr;
 395         enum fex_exception      e, simd_e[4];
 396         fex_info_t              info, simd_info[4];
 397         unsigned long           addr;
 398         siginfo_t               osip = *sip;
 399         sseinst_t               inst;
 400 
 401         /* check for an exception caused by an SSE instruction */
 402         if (!(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 0x80)) {
 403                 len = __fex_parse_sse(uap, &inst);

 404                 if (len == 0)
 405                         goto not_ieee;
 406 
 407                 /* disable all traps and clear flags */
 408                 __fenv_getcwsw(&oldcwsw);
 409                 cwsw = (oldcwsw & ~0x3f) | 0x003f0000;
 410                 __fenv_setcwsw(&cwsw);
 411                 __fenv_getmxcsr(&oldmxcsr);
 412                 mxcsr = (oldmxcsr & ~0x3f) | 0x1f80;
 413                 __fenv_setmxcsr(&mxcsr);
 414 
 415                 if ((int)inst.op & SIMD) {
 416                         __fex_get_simd_op(uap, &inst, simd_e, simd_info);
 417 
 418                         thr_handlers = __fex_get_thr_handlers();
 419                         addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
 420                         accrued = uap->uc_mcontext.fpregs.fp_reg_set.
 421                             fpchip_state.mxcsr;

 422 
 423                         e = (enum fex_exception)-1;
 424                         mode = FEX_NONSTOP;

 425                         for (i = 0; i < 4; i++) {
 426                                 if ((int)simd_e[i] < 0)
 427                                         continue;
 428 
 429                                 e = simd_e[i];
 430                                 simd_mode[i] = FEX_NOHANDLER;
 431                                 simd_handler[i] = oact.sa_handler;

 432                                 if (thr_handlers &&
 433                                     thr_handlers[(int)e].__mode !=
 434                                     FEX_NOHANDLER) {
 435                                         simd_mode[i] =
 436                                             thr_handlers[(int)e].__mode;
 437                                         simd_handler[i] =
 438                                             thr_handlers[(int)e].__handler;
 439                                 }

 440                                 accrued &= ~te_bit[(int)e];

 441                                 switch (simd_mode[i]) {
 442                                 case FEX_ABORT:
 443                                         mode = FEX_ABORT;
 444                                         break;
 445                                 case FEX_SIGNAL:

 446                                         if (mode != FEX_ABORT)
 447                                                 mode = FEX_SIGNAL;

 448                                         handler = simd_handler[i];
 449                                         break;
 450                                 case FEX_NOHANDLER:

 451                                         if (mode != FEX_ABORT && mode !=
 452                                             FEX_SIGNAL)
 453                                                 mode = FEX_NOHANDLER;

 454                                         break;
 455                                 }
 456                         }

 457                         if (e == (enum fex_exception)-1) {
 458                                 __fenv_setcwsw(&oldcwsw);
 459                                 __fenv_setmxcsr(&oldmxcsr);
 460                                 goto not_ieee;
 461                         }
 462                         accrued |= uap->uc_mcontext.fpregs.fp_reg_set.
 463                             fpchip_state.status;


 464                         ap = __fex_accrued();
 465                         accrued |= *ap;
 466                         accrued &= 0x3d;
 467 
 468                         for (i = 0; i < 4; i++) {
 469                                 if ((int)simd_e[i] < 0)
 470                                         continue;
 471 
 472                                 __fex_mklog(uap, (char *)addr, accrued,
 473                                     simd_e[i], simd_mode[i],
 474                                     (void *)simd_handler[i]);
 475                         }
 476 
 477                         if (mode == FEX_NOHANDLER) {
 478                                 __fenv_setcwsw(&oldcwsw);
 479                                 __fenv_setmxcsr(&oldmxcsr);
 480                                 goto not_ieee;
 481                         } else if (mode == FEX_ABORT) {
 482                                 abort();
 483                         } else if (mode == FEX_SIGNAL) {
 484                                 __fenv_setcwsw(&oldcwsw);
 485                                 __fenv_setmxcsr(&oldmxcsr);
 486                                 handler(sig, &osip, uap);
 487                                 return;
 488                         }
 489 
 490                         *ap = 0;

 491                         for (i = 0; i < 4; i++) {
 492                                 if ((int)simd_e[i] < 0)
 493                                         continue;
 494 
 495                                 if (simd_mode[i] == FEX_CUSTOM) {
 496                                         handler(1 << (int)simd_e[i],
 497                                             &simd_info[i]);
 498                                         __fenv_setcwsw(&cwsw);
 499                                         __fenv_setmxcsr(&mxcsr);
 500                                 }
 501                         }
 502 
 503                         __fex_st_simd_result(uap, &inst, simd_e, simd_info);

 504                         for (i = 0; i < 4; i++) {
 505                                 if ((int)simd_e[i] < 0)
 506                                         continue;
 507 
 508                                 accrued |= simd_info[i].flags;
 509                         }
 510 
 511                         if ((int)inst.op & INTREG) {
 512                                 /* set MMX mode */
 513 #if defined(__amd64)
 514                                 uap->uc_mcontext.fpregs.fp_reg_set.
 515                                     fpchip_state.sw &= ~0x3800;
 516                                 uap->uc_mcontext.fpregs.fp_reg_set.
 517                                     fpchip_state.fctw = 0;
 518 #else
 519                                 uap->uc_mcontext.fpregs.fp_reg_set.
 520                                     fpchip_state.state[1] &= ~0x3800;
 521                                 uap->uc_mcontext.fpregs.fp_reg_set.
 522                                     fpchip_state.state[2] = 0;
 523 #endif
 524                         }
 525                 } else {
 526                         e = __fex_get_sse_op(uap, &inst, &info);

 527                         if ((int)e < 0) {
 528                                 __fenv_setcwsw(&oldcwsw);
 529                                 __fenv_setmxcsr(&oldmxcsr);
 530                                 goto not_ieee;
 531                         }
 532 
 533                         mode = FEX_NOHANDLER;
 534                         handler = oact.sa_handler;
 535                         thr_handlers = __fex_get_thr_handlers();

 536                         if (thr_handlers && thr_handlers[(int)e].__mode !=
 537                             FEX_NOHANDLER) {
 538                                 mode = thr_handlers[(int)e].__mode;
 539                                 handler = thr_handlers[(int)e].__handler;
 540                         }
 541 
 542                         addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
 543                         accrued = uap->uc_mcontext.fpregs.fp_reg_set.
 544                             fpchip_state.mxcsr & ~te_bit[(int)e];
 545                         accrued |= uap->uc_mcontext.fpregs.fp_reg_set.
 546                             fpchip_state.status;


 547                         ap = __fex_accrued();
 548                         accrued |= *ap;
 549                         accrued &= 0x3d;
 550                         __fex_mklog(uap, (char *)addr, accrued, e, mode,
 551                             (void *)handler);
 552 
 553                         if (mode == FEX_NOHANDLER) {
 554                                 __fenv_setcwsw(&oldcwsw);
 555                                 __fenv_setmxcsr(&oldmxcsr);
 556                                 goto not_ieee;
 557                         } else if (mode == FEX_ABORT) {
 558                                 abort();
 559                         } else if (mode == FEX_SIGNAL) {
 560                                 __fenv_setcwsw(&oldcwsw);
 561                                 __fenv_setmxcsr(&oldmxcsr);
 562                                 handler(sig, &osip, uap);
 563                                 return;
 564                         } else if (mode == FEX_CUSTOM) {
 565                                 *ap = 0;

 566                                 if (addr >= (unsigned long)feraiseexcept &&
 567                                     addr < (unsigned long)fetestexcept) {
 568                                         info.op = fex_other;
 569                                         info.op1.type = info.op2.type =
 570                                             info.res.type = fex_nodata;
 571                                 }

 572                                 handler(1 << (int)e, &info);
 573                                 __fenv_setcwsw(&cwsw);
 574                                 __fenv_setmxcsr(&mxcsr);
 575                         }
 576 
 577                         __fex_st_sse_result(uap, &inst, e, &info);
 578                         accrued |= info.flags;
 579 
 580 #if defined(__amd64)
 581                         /*
 582                          * In 64-bit mode, the 32-bit convert-to-integer
 583                          * instructions zero the upper 32 bits of the
 584                          * destination.  (We do this here and not in
 585                          * __fex_st_sse_result because __fex_st_sse_result
 586                          * can be called from __fex_st_simd_result, too.)
 587                          */
 588                         if (inst.op == cvtss2si || inst.op == cvttss2si ||
 589                             inst.op == cvtsd2si || inst.op == cvttsd2si)
 590                                 inst.op1->i[1] = 0;
 591 #endif
 592                 }
 593 
 594                 /* advance the pc past the SSE instruction */
 595                 uap->uc_mcontext.gregs[REG_PC] += len;
 596                 goto update_state;
 597         }
 598 
 599         /* determine which exception occurred */
 600         __fex_get_x86_exc(sip, uap);

 601         switch (sip->si_code) {
 602         case FPE_FLTDIV:
 603                 e = fex_division;
 604                 break;
 605         case FPE_FLTOVF:
 606                 e = fex_overflow;
 607                 break;
 608         case FPE_FLTUND:
 609                 e = fex_underflow;
 610                 break;
 611         case FPE_FLTRES:
 612                 e = fex_inexact;
 613                 break;
 614         case FPE_FLTINV:

 615                 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
 616                         goto not_ieee;

 617                 break;
 618         default:
 619                 /* not an IEEE exception */
 620                 goto not_ieee;
 621         }
 622 
 623         /* get the handling mode */
 624         mode = FEX_NOHANDLER;
 625         handler = oact.sa_handler; /* for log; just looking, no need to lock */
 626         thr_handlers = __fex_get_thr_handlers();

 627         if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
 628                 mode = thr_handlers[(int)e].__mode;
 629                 handler = thr_handlers[(int)e].__handler;
 630         }
 631 
 632         /* make an entry in the log of retro. diag. if need be */
 633 #if defined(__amd64)
 634         addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set.
 635             fpchip_state.rip;
 636 #else
 637         addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set.
 638             fpchip_state.state[3];
 639 #endif
 640         accrued = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 
 641             ~te_bit[(int)e];

 642         if (test_sse_hw)
 643                 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 644                     mxcsr;

 645         ap = __fex_accrued();
 646         accrued |= *ap;
 647         accrued &= 0x3d;
 648         __fex_mklog(uap, (char *)addr, accrued, e, mode, (void *)handler);
 649 
 650         /* handle the exception based on the mode */
 651         if (mode == FEX_NOHANDLER)
 652                 goto not_ieee;
 653         else if (mode == FEX_ABORT)
 654                 abort();
 655         else if (mode == FEX_SIGNAL) {
 656                 handler(sig, &osip, uap);
 657                 return;
 658         }
 659 
 660         /* disable all traps and clear flags */
 661         __fenv_getcwsw(&cwsw);
 662         cwsw = (cwsw & ~0x3f) | 0x003f0000;
 663         __fenv_setcwsw(&cwsw);

 664         if (test_sse_hw) {
 665                 __fenv_getmxcsr(&mxcsr);
 666                 mxcsr = (mxcsr & ~0x3f) | 0x1f80;
 667                 __fenv_setmxcsr(&mxcsr);
 668         }

 669         *ap = 0;
 670 
 671         /* decode the operation */
 672         __fex_get_op(sip, uap, &info);
 673 
 674         /* if a custom mode handler is installed, invoke it */
 675         if (mode == FEX_CUSTOM) {
 676                 /* if we got here from feraiseexcept, pass dummy info */
 677                 if (addr >= (unsigned long)feraiseexcept &&
 678                     addr < (unsigned long)fetestexcept) {
 679                         info.op = fex_other;
 680                         info.op1.type = info.op2.type = info.res.type =
 681                             fex_nodata;
 682                 }
 683 
 684                 handler(1 << (int)e, &info);
 685 
 686                 /* restore modes in case the user's handler changed them */
 687                 __fenv_setcwsw(&cwsw);

 688                 if (test_sse_hw)
 689                         __fenv_setmxcsr(&mxcsr);
 690         }
 691 
 692         /* stuff the result */
 693         __fex_st_result(sip, uap, &info);
 694         accrued |= info.flags;
 695 
 696 update_state:
 697         accrued &= 0x3d;
 698         i = __fex_te_needed(thr_handlers, accrued);
 699         *ap = accrued & i;
 700 #if defined(__amd64)
 701         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw &= ~0x3d;
 702         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= (accrued & ~i);
 703         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw |= 0x3d;
 704         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw &= ~i;
 705 #else
 706         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] &= ~0x3d;
 707         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] |=
 708             (accrued & ~i);
 709         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] |= 0x3d;
 710         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] &= ~i;
 711 #endif

 712         if (test_sse_hw) {
 713                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~0x3d;
 714                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr |=
 715                     0x1e80 | (accrued & ~i);
 716                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &=
 717                     ~(i << 7);
 718         }

 719         return;
 720 
 721 not_ieee:
 722         /* revert to the saved handler (if any) */
 723         mutex_lock(&hdlr_lock);
 724         act = oact;
 725         mutex_unlock(&hdlr_lock);

 726         switch ((unsigned long)act.sa_handler) {
 727         case (unsigned long)SIG_DFL:
 728                 /* simulate trap with no handler installed */
 729                 sigaction(SIGFPE, &act, NULL);
 730                 kill(getpid(), SIGFPE);
 731                 break;
 732 #if !defined(__lint)
 733         case (unsigned long)SIG_IGN:
 734                 break;
 735 #endif
 736         default:
 737                 act.sa_handler(sig, &osip, uap);
 738         }
 739 }
 740 
 741 #else
 742 #error Unknown architecture
 743 #endif
 744 
 745 /*
 746 *  Return a pointer to the thread-specific handler data, and
 747 *  initialize it if necessary
 748 */
 749 struct fex_handler_data *
 750 __fex_get_thr_handlers()
 751 {
 752         struct fex_handler_data *ptr;
 753         unsigned long                   fsr;
 754         int                                             i, te;
 755 
 756         if (thr_main()) {
 757                 if (!handlers_initialized) {
 758                         /* initialize to FEX_NOHANDLER if trap is enabled,
 759                            FEX_NONSTOP if trap is disabled */


 760                         __fenv_getfsr(&fsr);
 761                         te = (int)__fenv_get_te(fsr);

 762                         for (i = 0; i < FEX_NUM_EXC; i++)
 763                                 main_handlers[i].__mode =
 764                                         ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP);

 765                         handlers_initialized = 1;
 766                 }
 767                 return main_handlers;
 768         }
 769         else {
 770                 ptr = NULL;
 771                 mutex_lock(&handlers_key_lock);

 772                 if (thr_getspecific(handlers_key, (void **)&ptr) != 0 &&
 773                         thr_keycreate(&handlers_key, free) != 0) {
 774                         mutex_unlock(&handlers_key_lock);
 775                         return NULL;
 776                 }

 777                 mutex_unlock(&handlers_key_lock);

 778                 if (!ptr) {
 779                         if ((ptr = (struct fex_handler_data *)
 780                                 malloc(sizeof(fex_handler_t))) == NULL) {
 781                                 return NULL;
 782                         }
 783                         if (thr_setspecific(handlers_key, (void *)ptr) != 0) {
 784                                 (void)free(ptr);
 785                                 return NULL;
 786                         }
 787                         /* initialize to FEX_NOHANDLER if trap is enabled,
 788                            FEX_NONSTOP if trap is disabled */



 789                         __fenv_getfsr(&fsr);
 790                         te = (int)__fenv_get_te(fsr);

 791                         for (i = 0; i < FEX_NUM_EXC; i++)
 792                                 ptr[i].__mode = ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP);

 793                 }
 794                 return ptr;

 795         }
 796 }
 797 
 798 /*
 799 *  Update the trap enable bits according to the selected modes
 800 */
 801 void
 802 __fex_update_te()
 803 {
 804         struct fex_handler_data *thr_handlers;
 805         struct sigaction                act, tmpact;
 806         sigset_t                                blocked;
 807         unsigned long                   fsr;
 808         int                                             te;
 809 
 810         /* determine which traps are needed */
 811         thr_handlers = __fex_get_thr_handlers();
 812         __fenv_getfsr(&fsr);
 813         te = __fex_te_needed(thr_handlers, fsr);
 814 
 815         /* install __fex_hdlr as necessary */
 816         if (!hdlr_installed && te) {
 817                 act.sa_handler = __fex_hdlr;
 818                 sigemptyset(&act.sa_mask);
 819                 act.sa_flags = SA_SIGINFO;
 820                 sigaction(SIGFPE, &act, &tmpact);
 821                 if (tmpact.sa_handler != __fex_hdlr)
 822                 {
 823                         mutex_lock(&hdlr_lock);
 824                         oact = tmpact;
 825                         mutex_unlock(&hdlr_lock);
 826                 }

 827                 hdlr_installed = 1;
 828         }
 829 
 830         /* set the new trap enable bits (only if SIGFPE is not blocked) */
 831         if (sigprocmask(0, NULL, &blocked) == 0 &&
 832                 !sigismember(&blocked, SIGFPE)) {
 833                 __fenv_set_te(fsr, te);
 834                 __fenv_setfsr(&fsr);
 835         }
 836 
 837         /* synchronize with libmtsk */
 838         __mt_fex_sync = __fex_sync_with_libmtsk;
 839 
 840         /* synchronize with other projects */
 841         __libm_mt_fex_sync = __fex_sync_with_threads;
 842 }


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  28  * Use is subject to license terms.
  29  */
  30 
  31 #undef lint
  32 #include <signal.h>
  33 #include <siginfo.h>
  34 #include <ucontext.h>
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <unistd.h>
  38 #include <thread.h>
  39 #include <math.h>
  40 #if defined(__SUNPRO_C)
  41 #include <sunmath.h>
  42 #endif
  43 #include <fenv.h>
  44 #include "fex_handler.h"
  45 #include "fenv_inlines.h"
  46 
  47 #if defined(__sparc) && !defined(__sparcv9)
  48 #include <sys/procfs.h>
  49 #endif
  50 
  51 /*
  52  * 2.x signal.h doesn't declare sigemptyset or sigismember
  53  * if they're #define'd (see sys/signal.h)
  54  */
  55 extern int sigemptyset(sigset_t *);
  56 extern int sigismember(const sigset_t *, int);
  57 
  58 /* external globals */
  59 void (*__mt_fex_sync)() = NULL;         /* for synchronization with libmtsk */
  60 #pragma weak __mt_fex_sync
  61 
  62 void (*__libm_mt_fex_sync)() = NULL;    /* new, improved version of above */
  63 #pragma weak __libm_mt_fex_sync
  64 
  65 /* private variables */
  66 static fex_handler_t main_handlers;
  67 static int handlers_initialized = 0;
  68 static thread_key_t handlers_key;
  69 static mutex_t handlers_key_lock = DEFAULTMUTEX;

  70 static struct sigaction oact = { 0, SIG_DFL };
  71 static mutex_t hdlr_lock = DEFAULTMUTEX;
  72 static int hdlr_installed = 0;
  73 
  74 /* private const data */
  75 static const int te_bit[FEX_NUM_EXC] = {
  76         1 << fp_trap_inexact, 1 << fp_trap_division, 1 << fp_trap_underflow,
  77         1 << fp_trap_overflow, 1 << fp_trap_invalid, 1 << fp_trap_invalid,
  78         1 << fp_trap_invalid, 1 << fp_trap_invalid, 1 << fp_trap_invalid,
  79         1 << fp_trap_invalid, 1 << fp_trap_invalid, 1 << fp_trap_invalid








  80 };
  81 
  82 /*
  83  *  Return the traps to be enabled given the current handling modes
  84  *  and flags
  85  */
  86 static int
  87 __fex_te_needed(struct fex_handler_data *thr_handlers, unsigned long fsr)
  88 {
  89         int i, ex, te;
  90 
  91         /* set traps for handling modes */
  92         te = 0;
  93 
  94         for (i = 0; i < FEX_NUM_EXC; i++)
  95                 if (thr_handlers[i].__mode != FEX_NONSTOP)
  96                         te |= te_bit[i];
  97 
  98         /* add traps for retrospective diagnostics */
  99 
 100         if (fex_get_log()) {
 101                 ex = (int)__fenv_get_ex(fsr);
 102 
 103                 if (!(ex & FE_INEXACT))
 104                         te |= (1 << fp_trap_inexact);
 105 
 106                 if (!(ex & FE_UNDERFLOW))
 107                         te |= (1 << fp_trap_underflow);
 108 
 109                 if (!(ex & FE_OVERFLOW))
 110                         te |= (1 << fp_trap_overflow);
 111 
 112                 if (!(ex & FE_DIVBYZERO))
 113                         te |= (1 << fp_trap_division);
 114 
 115                 if (!(ex & FE_INVALID))
 116                         te |= (1 << fp_trap_invalid);
 117         }
 118 
 119         return (te);
 120 }
 121 
 122 /*
 123  *  The following function synchronizes with libmtsk (SPARC only, for now)
 124  */
 125 static void
 126 __fex_sync_with_libmtsk(int begin, int master)
 127 {
 128         static fenv_t master_env;
 129         static int env_initialized = 0;
 130         static mutex_t env_lock = DEFAULTMUTEX;
 131 
 132         if (begin) {
 133                 mutex_lock(&env_lock);
 134 
 135                 if (master) {
 136                         (void) fegetenv(&master_env);
 137                         env_initialized = 1;
 138                 } else if (env_initialized) {

 139                         (void) fesetenv(&master_env);

 140                 }
 141 
 142                 mutex_unlock(&env_lock);
 143         } else if (master && fex_get_log()) {
 144                 __fex_update_te();
 145         }
 146 }
 147 
 148 /*
 149  *  The following function may be used for synchronization with any
 150  *  internal project that manages multiple threads
 151  */
 152 enum __libm_mt_fex_sync_actions {
 153         __libm_mt_fex_start_master = 0, __libm_mt_fex_start_slave,
 154         __libm_mt_fex_finish_master, __libm_mt_fex_finish_slave


 155 };
 156 
 157 struct __libm_mt_fex_sync_data {
 158         fenv_t master_env;
 159         int initialized;
 160         mutex_t lock;
 161 };
 162 
 163 static void
 164 __fex_sync_with_threads(enum __libm_mt_fex_sync_actions action, struct
 165     __libm_mt_fex_sync_data *thr_env)
 166 {
 167         switch (action) {
 168         case __libm_mt_fex_start_master:
 169                 mutex_lock(&thr_env->lock);
 170                 (void) fegetenv(&thr_env->master_env);
 171                 thr_env->initialized = 1;
 172                 mutex_unlock(&thr_env->lock);
 173                 break;
 174 
 175         case __libm_mt_fex_start_slave:
 176                 mutex_lock(&thr_env->lock);
 177 
 178                 if (thr_env->initialized)
 179                         (void) fesetenv(&thr_env->master_env);
 180 
 181                 mutex_unlock(&thr_env->lock);
 182                 break;
 183 
 184         case __libm_mt_fex_finish_master:
 185 #if defined(__x86)
 186                 __fex_update_te();
 187 #else
 188                 if (fex_get_log())
 189                         __fex_update_te();
 190 #endif
 191                 break;
 192 
 193         case __libm_mt_fex_finish_slave:
 194 #if defined(__x86)
 195                 /*
 196                  * clear traps, making all accrued flags visible in status
 197                  * word
 198                  */
 199                 {
 200                         unsigned long fsr;
 201 
 202                         __fenv_getfsr(&fsr);
 203                         __fenv_set_te(fsr, 0);
 204                         __fenv_setfsr(&fsr);
 205                 }
 206 #endif
 207                 break;
 208         }
 209 }
 210 
 211 #if defined(__sparc)

 212 /*
 213  *  Code for setting or clearing interval mode on US-III and above.
 214  *  This is embedded as data so we don't have to mark the library
 215  *  as a v8plusb/v9b object.  (I could have just used one entry and
 216  *  modified the second word to set the bits I want, but that would
 217  *  have required another mutex.)
 218  */
 219 static const unsigned int siam[][2] = {
 220         { 0x81c3e008, 0x81b01020 },     /* retl, siam 0 */
 221         { 0x81c3e008, 0x81b01024 },     /* retl, siam 4 */
 222         { 0x81c3e008, 0x81b01025 },     /* retl, siam 5 */
 223         { 0x81c3e008, 0x81b01026 },     /* retl, siam 6 */
 224         { 0x81c3e008, 0x81b01027 }      /* retl, siam 7 */
 225 };
 226 
 227 /*
 228  *  If a handling mode is in effect, apply it; otherwise invoke the
 229  *  saved handler
 230  */
 231 static void
 232 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
 233 {
 234         struct fex_handler_data *thr_handlers;
 235         struct sigaction act;
 236 
 237         void (*handler)(), (*siamp)();
 238 
 239         int mode, i;
 240         enum fex_exception e;
 241         fex_info_t info;
 242         unsigned long fsr, tmpfsr, addr;
 243         unsigned int gsr;
 244 
 245         /* determine which exception occurred */
 246         switch (sip->si_code) {
 247         case FPE_FLTDIV:
 248                 e = fex_division;
 249                 break;
 250         case FPE_FLTOVF:
 251                 e = fex_overflow;
 252                 break;
 253         case FPE_FLTUND:
 254                 e = fex_underflow;
 255                 break;
 256         case FPE_FLTRES:
 257                 e = fex_inexact;
 258                 break;
 259         case FPE_FLTINV:
 260 
 261                 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
 262                         goto not_ieee;
 263 
 264                 break;
 265         default:
 266                 /* not an IEEE exception */
 267                 goto not_ieee;
 268         }
 269 
 270         /* get the handling mode */
 271         mode = FEX_NOHANDLER;
 272         handler = oact.sa_handler; /* for log; just looking, no need to lock */
 273         thr_handlers = __fex_get_thr_handlers();
 274 
 275         if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
 276                 mode = thr_handlers[(int)e].__mode;
 277                 handler = thr_handlers[(int)e].__handler;
 278         }
 279 
 280         /* make an entry in the log of retro. diag. if need be */
 281         i = ((int)uap->uc_mcontext.fpregs.fpu_fsr >> 5) & 0x1f;
 282         __fex_mklog(uap, (char *)sip->si_addr, i, e, mode, (void *)handler);
 283 
 284         /* handle the exception based on the mode */
 285         if (mode == FEX_NOHANDLER) {
 286                 goto not_ieee;
 287         } else if (mode == FEX_ABORT) {
 288                 abort();
 289         } else if (mode == FEX_SIGNAL) {
 290                 handler(sig, sip, uap);
 291                 return;
 292         }
 293 
 294         /* custom or nonstop mode; disable traps and clear flags */
 295         __fenv_getfsr(&fsr);
 296         __fenv_set_te(fsr, 0);
 297         __fenv_set_ex(fsr, 0);
 298 
 299         /*
 300          * if interval mode was set, clear it, then substitute the interval
 301          * rounding direction and clear ns mode in the fsr
 302          */
 303 #ifdef __sparcv9
 304         gsr = uap->uc_mcontext.asrs[3];
 305 #else
 306         gsr = 0;
 307 
 308         if (uap->uc_mcontext.xrs.xrs_id == XRS_ID)
 309                 gsr = (*(unsigned long long *)
 310                     ((prxregset_t *)uap->uc_mcontext.xrs.xrs_ptr)->pr_un.
 311                     pr_v8p.pr_filler);
 312 #endif
 313         gsr = (gsr >> 25) & 7;
 314 
 315         if (gsr & 4) {
 316                 siamp = (void (*)())siam[0];
 317                 siamp();
 318                 tmpfsr = fsr;
 319                 fsr = (fsr & ~0xc0400000ul) | ((gsr & 3) << 30);
 320         }
 321 
 322         __fenv_setfsr(&fsr);
 323 
 324         /* decode the operation */
 325         __fex_get_op(sip, uap, &info);
 326 
 327         /* if a custom mode handler is installed, invoke it */
 328         if (mode == FEX_CUSTOM) {
 329                 /* if we got here from feraiseexcept, pass dummy info */
 330                 addr = (unsigned long)sip->si_addr;
 331 
 332                 if (addr >= (unsigned long)feraiseexcept && addr < (unsigned
 333                     long)fetestexcept) {
 334                         info.op = fex_other;
 335                         info.op1.type = info.op2.type = info.res.type =
 336                             fex_nodata;
 337                 }
 338 
 339                 /*
 340                  * restore interval mode if it was set, and put the original
 341                  * rounding direction and ns mode back in the fsr
 342                  */
 343                 if (gsr & 4) {
 344                         __fenv_setfsr(&tmpfsr);
 345                         siamp = (void (*)())siam[1 + (gsr & 3)];
 346                         siamp();
 347                 }
 348 
 349                 handler(1 << (int)e, &info);
 350 
 351                 /* restore modes in case the user's handler changed them */
 352                 if (gsr & 4) {
 353                         siamp = (void (*)())siam[0];
 354                         siamp();
 355                 }
 356 
 357                 __fenv_setfsr(&fsr);
 358         }
 359 
 360         /* stuff the result */
 361         __fex_st_result(sip, uap, &info);
 362 
 363         /* "or" in any exception flags and update traps */
 364         fsr = uap->uc_mcontext.fpregs.fpu_fsr;
 365         fsr |= ((info.flags & 0x1f) << 5);
 366         i = __fex_te_needed(thr_handlers, fsr);
 367         __fenv_set_te(fsr, i);
 368         uap->uc_mcontext.fpregs.fpu_fsr = fsr;
 369         return;
 370 
 371 not_ieee:
 372         /* revert to the saved handler (if any) */
 373         mutex_lock(&hdlr_lock);
 374         act = oact;
 375         mutex_unlock(&hdlr_lock);
 376 
 377         switch ((unsigned long)act.sa_handler) {
 378         case (unsigned long)SIG_DFL:
 379                 /* simulate trap with no handler installed */
 380                 sigaction(SIGFPE, &act, NULL);
 381                 kill(getpid(), SIGFPE);
 382                 break;
 383 #if !defined(__lint)
 384         case (unsigned long)SIG_IGN:
 385                 break;
 386 #endif
 387         default:
 388                 act.sa_handler(sig, sip, uap);
 389         }
 390 }

 391 #elif defined(__x86)

 392 #if defined(__amd64)
 393 #define test_sse_hw             1
 394 #else
 395 extern int _sse_hw;
 396 
 397 #define test_sse_hw             _sse_hw
 398 #endif
 399 
 400 #if !defined(REG_PC)
 401 #define REG_PC                  EIP
 402 #endif
 403 
 404 /*
 405  *  If a handling mode is in effect, apply it; otherwise invoke the
 406  *  saved handler
 407  */
 408 static void
 409 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
 410 {
 411         struct fex_handler_data *thr_handlers;
 412         struct sigaction act;
 413 
 414         void (*handler)() = NULL, (*simd_handler[4])();
 415 
 416         int mode, simd_mode[4], i, len, accrued, *ap;
 417         unsigned int cwsw, oldcwsw, mxcsr, oldmxcsr;
 418         enum fex_exception e, simd_e[4];
 419         fex_info_t info, simd_info[4];
 420         unsigned long addr;
 421         siginfo_t osip = *sip;
 422         sseinst_t inst;
 423 
 424         /* check for an exception caused by an SSE instruction */
 425         if (!(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 0x80)) {
 426                 len = __fex_parse_sse(uap, &inst);
 427 
 428                 if (len == 0)
 429                         goto not_ieee;
 430 
 431                 /* disable all traps and clear flags */
 432                 __fenv_getcwsw(&oldcwsw);
 433                 cwsw = (oldcwsw & ~0x3f) | 0x003f0000;
 434                 __fenv_setcwsw(&cwsw);
 435                 __fenv_getmxcsr(&oldmxcsr);
 436                 mxcsr = (oldmxcsr & ~0x3f) | 0x1f80;
 437                 __fenv_setmxcsr(&mxcsr);
 438 
 439                 if ((int)inst.op & SIMD) {
 440                         __fex_get_simd_op(uap, &inst, simd_e, simd_info);
 441 
 442                         thr_handlers = __fex_get_thr_handlers();
 443                         addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
 444                         accrued =
 445                             uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 446                             mxcsr;
 447 
 448                         e = (enum fex_exception)-1;
 449                         mode = FEX_NONSTOP;
 450 
 451                         for (i = 0; i < 4; i++) {
 452                                 if ((int)simd_e[i] < 0)
 453                                         continue;
 454 
 455                                 e = simd_e[i];
 456                                 simd_mode[i] = FEX_NOHANDLER;
 457                                 simd_handler[i] = oact.sa_handler;
 458 
 459                                 if (thr_handlers &&
 460                                     thr_handlers[(int)e].__mode !=
 461                                     FEX_NOHANDLER) {
 462                                         simd_mode[i] =
 463                                             thr_handlers[(int)e].__mode;
 464                                         simd_handler[i] =
 465                                             thr_handlers[(int)e].__handler;
 466                                 }
 467 
 468                                 accrued &= ~te_bit[(int)e];
 469 
 470                                 switch (simd_mode[i]) {
 471                                 case FEX_ABORT:
 472                                         mode = FEX_ABORT;
 473                                         break;
 474                                 case FEX_SIGNAL:
 475 
 476                                         if (mode != FEX_ABORT)
 477                                                 mode = FEX_SIGNAL;
 478 
 479                                         handler = simd_handler[i];
 480                                         break;
 481                                 case FEX_NOHANDLER:
 482 
 483                                         if (mode != FEX_ABORT && mode !=
 484                                             FEX_SIGNAL)
 485                                                 mode = FEX_NOHANDLER;
 486 
 487                                         break;
 488                                 }
 489                         }
 490 
 491                         if (e == (enum fex_exception)-1) {
 492                                 __fenv_setcwsw(&oldcwsw);
 493                                 __fenv_setmxcsr(&oldmxcsr);
 494                                 goto not_ieee;
 495                         }
 496 
 497                         accrued |=
 498                             uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 499                             status;
 500                         ap = __fex_accrued();
 501                         accrued |= *ap;
 502                         accrued &= 0x3d;
 503 
 504                         for (i = 0; i < 4; i++) {
 505                                 if ((int)simd_e[i] < 0)
 506                                         continue;
 507 
 508                                 __fex_mklog(uap, (char *)addr, accrued,
 509                                     simd_e[i], simd_mode[i],
 510                                     (void *)simd_handler[i]);
 511                         }
 512 
 513                         if (mode == FEX_NOHANDLER) {
 514                                 __fenv_setcwsw(&oldcwsw);
 515                                 __fenv_setmxcsr(&oldmxcsr);
 516                                 goto not_ieee;
 517                         } else if (mode == FEX_ABORT) {
 518                                 abort();
 519                         } else if (mode == FEX_SIGNAL) {
 520                                 __fenv_setcwsw(&oldcwsw);
 521                                 __fenv_setmxcsr(&oldmxcsr);
 522                                 handler(sig, &osip, uap);
 523                                 return;
 524                         }
 525 
 526                         *ap = 0;
 527 
 528                         for (i = 0; i < 4; i++) {
 529                                 if ((int)simd_e[i] < 0)
 530                                         continue;
 531 
 532                                 if (simd_mode[i] == FEX_CUSTOM) {
 533                                         handler(1 << (int)simd_e[i],
 534                                             &simd_info[i]);
 535                                         __fenv_setcwsw(&cwsw);
 536                                         __fenv_setmxcsr(&mxcsr);
 537                                 }
 538                         }
 539 
 540                         __fex_st_simd_result(uap, &inst, simd_e, simd_info);
 541 
 542                         for (i = 0; i < 4; i++) {
 543                                 if ((int)simd_e[i] < 0)
 544                                         continue;
 545 
 546                                 accrued |= simd_info[i].flags;
 547                         }
 548 
 549                         if ((int)inst.op & INTREG) {
 550                                 /* set MMX mode */
 551 #if defined(__amd64)
 552                                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 553                                     sw &= ~0x3800;
 554                                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 555                                     fctw = 0;
 556 #else
 557                                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 558                                     state[1] &= ~0x3800;
 559                                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 560                                     state[2] = 0;
 561 #endif
 562                         }
 563                 } else {
 564                         e = __fex_get_sse_op(uap, &inst, &info);
 565 
 566                         if ((int)e < 0) {
 567                                 __fenv_setcwsw(&oldcwsw);
 568                                 __fenv_setmxcsr(&oldmxcsr);
 569                                 goto not_ieee;
 570                         }
 571 
 572                         mode = FEX_NOHANDLER;
 573                         handler = oact.sa_handler;
 574                         thr_handlers = __fex_get_thr_handlers();
 575 
 576                         if (thr_handlers && thr_handlers[(int)e].__mode !=
 577                             FEX_NOHANDLER) {
 578                                 mode = thr_handlers[(int)e].__mode;
 579                                 handler = thr_handlers[(int)e].__handler;
 580                         }
 581 
 582                         addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
 583                         accrued =
 584                             uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 585                             mxcsr & ~te_bit[(int)e];
 586                         accrued |=
 587                             uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
 588                             status;
 589                         ap = __fex_accrued();
 590                         accrued |= *ap;
 591                         accrued &= 0x3d;
 592                         __fex_mklog(uap, (char *)addr, accrued, e, mode,
 593                             (void *)handler);
 594 
 595                         if (mode == FEX_NOHANDLER) {
 596                                 __fenv_setcwsw(&oldcwsw);
 597                                 __fenv_setmxcsr(&oldmxcsr);
 598                                 goto not_ieee;
 599                         } else if (mode == FEX_ABORT) {
 600                                 abort();
 601                         } else if (mode == FEX_SIGNAL) {
 602                                 __fenv_setcwsw(&oldcwsw);
 603                                 __fenv_setmxcsr(&oldmxcsr);
 604                                 handler(sig, &osip, uap);
 605                                 return;
 606                         } else if (mode == FEX_CUSTOM) {
 607                                 *ap = 0;
 608 
 609                                 if (addr >= (unsigned long)feraiseexcept &&
 610                                     addr < (unsigned long)fetestexcept) {
 611                                         info.op = fex_other;
 612                                         info.op1.type = info.op2.type =
 613                                             info.res.type = fex_nodata;
 614                                 }
 615 
 616                                 handler(1 << (int)e, &info);
 617                                 __fenv_setcwsw(&cwsw);
 618                                 __fenv_setmxcsr(&mxcsr);
 619                         }
 620 
 621                         __fex_st_sse_result(uap, &inst, e, &info);
 622                         accrued |= info.flags;
 623 
 624 #if defined(__amd64)
 625                         /*
 626                          * In 64-bit mode, the 32-bit convert-to-integer
 627                          * instructions zero the upper 32 bits of the
 628                          * destination.  (We do this here and not in
 629                          * __fex_st_sse_result because __fex_st_sse_result
 630                          * can be called from __fex_st_simd_result, too.)
 631                          */
 632                         if (inst.op == cvtss2si || inst.op == cvttss2si ||
 633                             inst.op == cvtsd2si || inst.op == cvttsd2si)
 634                                 inst.op1->i[1] = 0;
 635 #endif
 636                 }
 637 
 638                 /* advance the pc past the SSE instruction */
 639                 uap->uc_mcontext.gregs[REG_PC] += len;
 640                 goto update_state;
 641         }
 642 
 643         /* determine which exception occurred */
 644         __fex_get_x86_exc(sip, uap);
 645 
 646         switch (sip->si_code) {
 647         case FPE_FLTDIV:
 648                 e = fex_division;
 649                 break;
 650         case FPE_FLTOVF:
 651                 e = fex_overflow;
 652                 break;
 653         case FPE_FLTUND:
 654                 e = fex_underflow;
 655                 break;
 656         case FPE_FLTRES:
 657                 e = fex_inexact;
 658                 break;
 659         case FPE_FLTINV:
 660 
 661                 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
 662                         goto not_ieee;
 663 
 664                 break;
 665         default:
 666                 /* not an IEEE exception */
 667                 goto not_ieee;
 668         }
 669 
 670         /* get the handling mode */
 671         mode = FEX_NOHANDLER;
 672         handler = oact.sa_handler; /* for log; just looking, no need to lock */
 673         thr_handlers = __fex_get_thr_handlers();
 674 
 675         if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
 676                 mode = thr_handlers[(int)e].__mode;
 677                 handler = thr_handlers[(int)e].__handler;
 678         }
 679 
 680         /* make an entry in the log of retro. diag. if need be */
 681 #if defined(__amd64)
 682         addr = (unsigned
 683             long)uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rip;
 684 #else
 685         addr = (unsigned
 686             long)uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[3];
 687 #endif
 688         accrued = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status &
 689             ~te_bit[(int)e];
 690 
 691         if (test_sse_hw)
 692                 accrued |=
 693                     uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr;
 694 
 695         ap = __fex_accrued();
 696         accrued |= *ap;
 697         accrued &= 0x3d;
 698         __fex_mklog(uap, (char *)addr, accrued, e, mode, (void *)handler);
 699 
 700         /* handle the exception based on the mode */
 701         if (mode == FEX_NOHANDLER) {
 702                 goto not_ieee;
 703         } else if (mode == FEX_ABORT) {
 704                 abort();
 705         } else if (mode == FEX_SIGNAL) {
 706                 handler(sig, &osip, uap);
 707                 return;
 708         }
 709 
 710         /* disable all traps and clear flags */
 711         __fenv_getcwsw(&cwsw);
 712         cwsw = (cwsw & ~0x3f) | 0x003f0000;
 713         __fenv_setcwsw(&cwsw);
 714 
 715         if (test_sse_hw) {
 716                 __fenv_getmxcsr(&mxcsr);
 717                 mxcsr = (mxcsr & ~0x3f) | 0x1f80;
 718                 __fenv_setmxcsr(&mxcsr);
 719         }
 720 
 721         *ap = 0;
 722 
 723         /* decode the operation */
 724         __fex_get_op(sip, uap, &info);
 725 
 726         /* if a custom mode handler is installed, invoke it */
 727         if (mode == FEX_CUSTOM) {
 728                 /* if we got here from feraiseexcept, pass dummy info */
 729                 if (addr >= (unsigned long)feraiseexcept && addr < (unsigned
 730                     long)fetestexcept) {
 731                         info.op = fex_other;
 732                         info.op1.type = info.op2.type = info.res.type =
 733                             fex_nodata;
 734                 }
 735 
 736                 handler(1 << (int)e, &info);
 737 
 738                 /* restore modes in case the user's handler changed them */
 739                 __fenv_setcwsw(&cwsw);
 740 
 741                 if (test_sse_hw)
 742                         __fenv_setmxcsr(&mxcsr);
 743         }
 744 
 745         /* stuff the result */
 746         __fex_st_result(sip, uap, &info);
 747         accrued |= info.flags;
 748 
 749 update_state:
 750         accrued &= 0x3d;
 751         i = __fex_te_needed(thr_handlers, accrued);
 752         *ap = accrued & i;
 753 #if defined(__amd64)
 754         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw &= ~0x3d;
 755         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= (accrued & ~i);
 756         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw |= 0x3d;
 757         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw &= ~i;
 758 #else
 759         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] &= ~0x3d;
 760         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] |= (accrued &
 761             ~i);
 762         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] |= 0x3d;
 763         uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] &= ~i;
 764 #endif
 765 
 766         if (test_sse_hw) {
 767                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~0x3d;
 768                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr |=
 769                     0x1e80 | (accrued & ~i);
 770                 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~(i <<
 771                     7);
 772         }
 773 
 774         return;
 775 
 776 not_ieee:
 777         /* revert to the saved handler (if any) */
 778         mutex_lock(&hdlr_lock);
 779         act = oact;
 780         mutex_unlock(&hdlr_lock);
 781 
 782         switch ((unsigned long)act.sa_handler) {
 783         case (unsigned long)SIG_DFL:
 784                 /* simulate trap with no handler installed */
 785                 sigaction(SIGFPE, &act, NULL);
 786                 kill(getpid(), SIGFPE);
 787                 break;
 788 #if !defined(__lint)
 789         case (unsigned long)SIG_IGN:
 790                 break;
 791 #endif
 792         default:
 793                 act.sa_handler(sig, &osip, uap);
 794         }
 795 }

 796 #else
 797 #error Unknown architecture
 798 #endif
 799 
 800 /*
 801  *  Return a pointer to the thread-specific handler data, and
 802  *  initialize it if necessary
 803  */
 804 struct fex_handler_data *
 805 __fex_get_thr_handlers()
 806 {
 807         struct fex_handler_data *ptr;
 808         unsigned long fsr;
 809         int i, te;
 810 
 811         if (thr_main()) {
 812                 if (!handlers_initialized) {
 813                         /*
 814                          * initialize to FEX_NOHANDLER if trap is enabled,
 815                          * FEX_NONSTOP if trap is disabled
 816                          */
 817                         __fenv_getfsr(&fsr);
 818                         te = (int)__fenv_get_te(fsr);
 819 
 820                         for (i = 0; i < FEX_NUM_EXC; i++)
 821                                 main_handlers[i].__mode = ((te & te_bit[i]) ?
 822                                     FEX_NOHANDLER : FEX_NONSTOP);
 823 
 824                         handlers_initialized = 1;
 825                 }
 826 
 827                 return (main_handlers);
 828         } else {
 829                 ptr = NULL;
 830                 mutex_lock(&handlers_key_lock);
 831 
 832                 if (thr_getspecific(handlers_key, (void **)&ptr) != 0 &&
 833                     thr_keycreate(&handlers_key, free) != 0) {
 834                         mutex_unlock(&handlers_key_lock);
 835                         return (NULL);
 836                 }
 837 
 838                 mutex_unlock(&handlers_key_lock);
 839 
 840                 if (!ptr) {
 841                         if ((ptr = malloc(sizeof (fex_handler_t))) == NULL)
 842                                 return (NULL);
 843 

 844                         if (thr_setspecific(handlers_key, (void *)ptr) != 0) {
 845                                 (void) free(ptr);
 846                                 return (NULL);
 847                         }
 848 
 849                         /*
 850                          * initialize to FEX_NOHANDLER if trap is enabled,
 851                          * FEX_NONSTOP if trap is disabled
 852                          */
 853                         __fenv_getfsr(&fsr);
 854                         te = (int)__fenv_get_te(fsr);
 855 
 856                         for (i = 0; i < FEX_NUM_EXC; i++)
 857                                 ptr[i].__mode = ((te & te_bit[i]) ?
 858                                     FEX_NOHANDLER : FEX_NONSTOP);
 859                 }
 860 
 861                 return (ptr);
 862         }
 863 }
 864 
 865 /*
 866  *  Update the trap enable bits according to the selected modes
 867  */
 868 void
 869 __fex_update_te()
 870 {
 871         struct fex_handler_data *thr_handlers;
 872         struct sigaction act, tmpact;
 873         sigset_t blocked;
 874         unsigned long fsr;
 875         int te;
 876 
 877         /* determine which traps are needed */
 878         thr_handlers = __fex_get_thr_handlers();
 879         __fenv_getfsr(&fsr);
 880         te = __fex_te_needed(thr_handlers, fsr);
 881 
 882         /* install __fex_hdlr as necessary */
 883         if (!hdlr_installed && te) {
 884                 act.sa_handler = __fex_hdlr;
 885                 sigemptyset(&act.sa_mask);
 886                 act.sa_flags = SA_SIGINFO;
 887                 sigaction(SIGFPE, &act, &tmpact);
 888 
 889                 if (tmpact.sa_handler != __fex_hdlr) {
 890                         mutex_lock(&hdlr_lock);
 891                         oact = tmpact;
 892                         mutex_unlock(&hdlr_lock);
 893                 }
 894 
 895                 hdlr_installed = 1;
 896         }
 897 
 898         /* set the new trap enable bits (only if SIGFPE is not blocked) */
 899         if (sigprocmask(0, NULL, &blocked) == 0 && !sigismember(&blocked,
 900             SIGFPE)) {
 901                 __fenv_set_te(fsr, te);
 902                 __fenv_setfsr(&fsr);
 903         }
 904 
 905         /* synchronize with libmtsk */
 906         __mt_fex_sync = __fex_sync_with_libmtsk;
 907 
 908         /* synchronize with other projects */
 909         __libm_mt_fex_sync = __fex_sync_with_threads;
 910 }