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*/