2   Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 
    5 #ifndef ATHENASERVICES_FPEAUDIT_LINUX_ICC
 
    6 #define ATHENASERVICES_FPEAUDIT_LINUX_ICC 1
 
   14 #include "GaudiKernel/MsgStream.h"
 
   23 #include <cxxabi.h> // for demangling
 
   24 #include <link.h>   // for following code in shared libraries
 
   26 // signal handler needs C linkage 
 
   31     void fpe_sig_action( int /*sig*/, siginfo_t *si, void *puc )
 
   34       // Pre-MT code had this.  If the handler had been disabled,
 
   35       // this would fall back to the previous behavior on a signal,
 
   36       // which would usually mean a crash.  However, this would not really
 
   37       // be expected to happen, since exceptions are masked when the
 
   38       // handler is disabled.  However, with MT, it would be possible
 
   39       // for a signal to be generated if it happens in a different
 
   40       // thread than the one in which the handler was disabled.
 
   41       // As we probably never really want to go to the fallback
 
   42       // behavior (since that would well mean a crash), just disable
 
   45       // call old handlers if too many exceptions occured in this job
 
   46       if ( s_handlerDisabled )
 
   48           if (s_oldactHandler.sa_flags & SA_SIGINFO) {
 
   49             if (s_oldactHandler.sa_handler) s_oldactHandler.sa_sigaction(sig,si,puc);
 
   51             if (s_oldactHandler.sa_handler) s_oldactHandler.sa_handler(sig);
 
   56       // modify mcontext_t struct to reset FPE exception mask
 
   57       ucontext_t *uc = (ucontext_t *)puc;
 
   59       // not all FPEs classified correctly
 
   60       std::cerr << "\n   Caught FPE " << si->si_code << " (";
 
   63         case FPE_INTDIV: std::cerr << "integer divide by zero"; break;
 
   64         case FPE_INTOVF: std::cerr << "integer overflow"; break;
 
   65         case FPE_FLTDIV: std::cerr << "floating point divide by zero"; break;
 
   66         case FPE_FLTOVF: std::cerr << "floating point overflow"; break;
 
   67         case FPE_FLTUND: std::cerr << "floating point underflow"; break;
 
   68         case FPE_FLTRES: std::cerr << "floating point inexact result"; break;
 
   69         case FPE_FLTINV: std::cerr << "floating point invalid operation"; break;
 
   70         case FPE_FLTSUB: std::cerr << "subscript out of range"; break;
 
   73       std::cerr << ") at address " << si->si_addr << ")\n";
 
   76       // stack trace is later printed in FPEAuditor::report_fpe()
 
   77       if ( si->si_code == FPE_FLTDIV )
 
   79           nptrs = backtrace(s_tlsdata.s_array_D, 100);
 
   80           std::cerr << "   backtrace() returned " << nptrs << " addresses\n\n";
 
   82             s_tlsdata.s_array_D[nptrs]=NULL;
 
   84       else if ( si->si_code == FPE_FLTOVF )
 
   86           nptrs = backtrace(s_tlsdata.s_array_O, 100);
 
   87           std::cerr << "   backtrace() returned " << nptrs << " addresses\n\n";
 
   89             s_tlsdata.s_array_O[nptrs]=NULL;
 
   93           nptrs = backtrace(s_tlsdata.s_array_I, 100);
 
   94           std::cerr << "   backtrace() returned " << nptrs << " addresses\n\n";
 
   96             s_tlsdata.s_array_I[nptrs]=NULL;
 
   99       // reset FPE mask of the context where FPE occured
 
  100 #if defined(__linux__) && defined(__i386__)
 
  101 #if !defined(X86_FXSR_MAGIC)
 
  102 #define X86_FXSR_MAGIC 0x0000
 
  106 #if defined(__linux__)
 
  107 #if defined(__x86_64__)
 
  108       mcontext_t *mc = &uc->uc_mcontext;
 
  109       fpregset_t fpstate = mc->fpregs;
 
  110       fpstate->mxcsr = 0x1F80;
 
  111       fpstate->swd &= ~0xFF;
 
  112 #elif defined(__i386__)
 
  113       mcontext_t *mc = &uc->uc_mcontext;
 
  114       fpregset_t fpstate = mc->fpregs;
 
  115       if ((fpstate->status >> 16) == X86_FXSR_MAGIC)
 
  116         ((struct _fpstate*)fpstate)->mxcsr = 0x1F80;
 
  117       fpstate->sw &= ~0xFF;
 
  121 #if defined(__amd64__) && defined(__x86_64__) || defined(__i386__)
 
  122 #define FPU_EXCEPTION_MASK 0x3f
 
  125        * x86 FPU Status Word:
 
  127        * 0..5  ->      Exception flags  (see x86 FPU Control Word)
 
  128        * 6     -> SF   Stack Fault
 
  129        * 7     -> ES   Error Summary Status
 
  131 #define FPU_STATUS_FLAGS 0xff
 
  134        * MXCSR Control and Status Register:
 
  136        * 0..5  ->      Exception flags (see x86 FPU Control Word)
 
  137        * 6     -> DAZ  Denormals Are Zero
 
  138        * 7..12 ->      Exception mask (see x86 FPU Control Word)
 
  140 #define SSE_STATUS_FLAGS   FPU_EXCEPTION_MASK
 
  141 #define SSE_EXCEPTION_MASK (FPU_EXCEPTION_MASK << 7)
 
  143 #if defined(__i386__)
 
  145        * It seems that we have no access to mxcsr on Linux. libc
 
  146        * seems to be translating cw/sw to mxcsr.
 
  148       unsigned long int *cw = &uc->uc_mcontext.fpregs->cw;
 
  149       *cw |= FPU_EXCEPTION_MASK;
 
  151       unsigned long int *sw = &uc->uc_mcontext.fpregs->sw;
 
  152       *sw &= ~FPU_STATUS_FLAGS;
 
  154 #if defined(__amd64__) && defined(__x86_64__)  && !defined(__APPLE__)
 
  155       __uint16_t *cw = &uc->uc_mcontext.fpregs->cwd;
 
  156       *cw |= FPU_EXCEPTION_MASK;
 
  158       __uint16_t *sw = &uc->uc_mcontext.fpregs->swd;
 
  159       *sw &= ~FPU_STATUS_FLAGS;
 
  161       __uint32_t *mxcsr = &uc->uc_mcontext.fpregs->mxcsr;
 
  162       *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
 
  163       *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
 
  164       //      fprintf(stderr, "in 64 bit code\n");
 
  170      * Implement unmask_fpe() and check_fpe() based on CPU/OS combination
 
  173 #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) && !defined(__CYGWIN__)
 
  178       __asm__ __volatile__("fclex");
 
  179       __asm__ __volatile__("fstcw %0" : "=m"(cw));
 
  180       // std::cout << "mask fpe: " << std::hex << cw << std::dec << "\n";
 
  181       cw |= (0x01|0x04|0x08);   /* mask IM, ZM, OM */
 
  182       __asm__ __volatile__("fldcw %0" : : "m"(cw));
 
  183       // std::cout << "mask fpe: " << std::hex << cw << std::dec << "\n";
 
  189       __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr));
 
  190       mxcsr |= 0x0680; /* clear exn flags, unmask OM, ZM, IM (not PM, UM, DM) */
 
  191       __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr));
 
  194     void unmask_x87(void)
 
  197       __asm__ __volatile__("fstcw %0" : "=m"(cw));
 
  198       // std::cout << "unmask fpe: " << std::hex << cw << std::dec << "\n";
 
  199       cw &= ~(0x01|0x04|0x08);   /* unmask IM, ZM, OM */
 
  200       __asm__ __volatile__("fldcw %0" : : "m"(cw));
 
  201       // std::cout << "unmask fpe: " << std::hex << cw << std::dec << "\n";
 
  204     void unmask_sse2(void)
 
  207       __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr));
 
  208       mxcsr &= ~(0x003F|0x0680); /* clear exn flags, unmask OM, ZM, IM (not PM, UM, DM) */
 
  209       __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr));
 
  212 #if defined(__x86_64__)
 
  214     inline int cpu_has_sse2(void) { return 1; }
 
  216 #else /* !__x86_64__ */
 
  219      * Check if an x86-32 processor has SSE2.
 
  221     static unsigned int xor_eflags(unsigned int mask)
 
  223       unsigned int eax, edx;
 
  225       eax = mask;                 /* eax = mask */
 
  227               "popl %0\n\t"       /* edx = original EFLAGS */
 
  228               "xorl %0, %1\n\t"   /* eax = mask ^ EFLAGS */
 
  230               "popfl\n\t"         /* new EFLAGS = mask ^ original EFLAGS */
 
  232               "popl %1\n\t"       /* eax = new EFLAGS */
 
  233               "xorl %0, %1\n\t"   /* eax = new EFLAGS ^ old EFLAGS */
 
  235               "popfl"             /* restore original EFLAGS */
 
  236               : "=d"(edx), "=a"(eax)
 
  241     static __inline__ unsigned int cpuid_eax(unsigned int op)
 
  243       unsigned int eax, save_ebx;
 
  245       /* In PIC mode i386 reserves EBX. So we must save
 
  246          and restore it ourselves to not upset gcc. */
 
  251               : "=a"(eax), "=m"(save_ebx)
 
  257     static __inline__ unsigned int cpuid_edx(unsigned int op)
 
  259       unsigned int eax, edx, save_ebx;
 
  261       /* In PIC mode i386 reserves EBX. So we must save
 
  262          and restore it ourselves to not upset gcc. */
 
  267               : "=a"(eax), "=d"(edx), "=m"(save_ebx)
 
  273     /* The AC bit, bit #18, is a new bit introduced in the EFLAGS
 
  274      * register on the Intel486 processor to generate alignment
 
  275      * faults. This bit cannot be set on the Intel386 processor.
 
  277     static __inline__ int is_386(void)
 
  279       return ((xor_eflags(1<<18) >> 18) & 1) == 0;
 
  282     /* Newer x86 processors have a CPUID instruction, as indicated by
 
  283      * the ID bit (#21) in EFLAGS being modifiable.
 
  285     static __inline__ int has_CPUID(void)
 
  287       return (xor_eflags(1<<21) >> 21) & 1;
 
  290     int cpu_has_sse2(void)
 
  292       unsigned int maxlev, features;
 
  293       static int has_sse2 = -1;
 
  303       maxlev = cpuid_eax(0);
 
  304       /* Intel A-step Pentium had a preliminary version of CPUID.
 
  305          It also didn't have SSE2. */
 
  306       if ((maxlev & 0xFFFFFF00) == 0x0500)
 
  308       /* If max level is zero then CPUID cannot report any features. */
 
  311       features = cpuid_edx(1);
 
  312       has_sse2 = (features & (1 << 26)) != 0;
 
  316 #endif /* !__x86_64__ */
 
  327     void unmask_fpe(void)
 
  334     // printing of stacktrace including inlined functions. needs debug symbols
 
  335     // uses libbdf and libiberty from gdb, which currently seemed to have a
 
  336     // small memory leak (gdb 7.4.1)
 
  337     void resolve(void *address, MsgStream& msg, bool print=false)
 
  346       if (dladdr (address, &info) && info.dli_fname && info.dli_fname[0])
 
  349           ibfd = bfd_openr(info.dli_fname, NULL);
 
  353               fprintf(stderr,"bfd_openr error\n");
 
  357           if (!bfd_check_format_matches(ibfd, bfd_object, &matching))
 
  359               fprintf(stderr,"format_matches\n");
 
  363           nsize = bfd_get_symtab_upper_bound (ibfd);
 
  364           symtab = (asymbol **)malloc(nsize);
 
  365           /*nsyms =*/ bfd_canonicalize_symtab(ibfd, symtab);
 
  367           text = bfd_get_section_by_name(ibfd, ".text");
 
  371             offset = ((long)address) - text->vma;
 
  373           if (strstr (info.dli_fname, ".so") != 0)
 
  375               unsigned long libaddr = (unsigned long) info.dli_fbase;
 
  376               unsigned long addr = (unsigned long)address;
 
  378                 offset = addr - libaddr - text->vma;
 
  391               bool found = bfd_find_nearest_line(ibfd, text, symtab, offset, &file, &func, &line);
 
  393               // dli_sname can be null.  If we try to write that
 
  394               // to a MsgStream, the stream will misbehave (all subsequent
 
  395               // messages will be blank).
 
  396               const char* dli_sname = info.dli_sname;
 
  398                 dli_sname = "(null)";
 
  404                       // from http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
 
  405                       realname = abi::__cxa_demangle(func ? func : info.dli_sname, 0, 0, &status);
 
  409                             fprintf(stderr,"%s : %s (%s,%u)\n",first ? "  in function" : "  included from", realname, file, line);
 
  411                             msg << ( first ? "  in function" : "  included from" ) << " : " << realname << " (" << file << ":" << line << ")\n";
 
  416                             fprintf(stderr,"%s : %s (%s,%u)\n", first ? "  in function" : "  included from", func ? func : dli_sname, file, line);
 
  418                             msg << ( first ? "  in function" : "  included from" )
 
  420                                 << ( func ? func : dli_sname )
 
  421                                 << " (" << file << ":" << line << ")\n";
 
  426                       found = bfd_find_inliner_info (ibfd, &file, &func, &line);
 
  433             fprintf(stderr,"  in library : %s",info.dli_fname);
 
  435             msg << "  in library : " << info.dli_fname;
 
  442 #endif /* !ATHENASERVICES_FPEAUDIT_LINUX_ICC*/