Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:58:18

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // G4FPEDetection
0027 //
0028 // Description:
0029 //
0030 // This global method should be used on LINUX/gcc or MacOS/clang platforms
0031 // for activating NaN detection and FPE signals, and forcing abortion of
0032 // the application at the time these are detected.
0033 // Meant to be used for debug purposes, can be activated by compiling the
0034 // "run" module with the flag G4FPE_DEBUG set in the environment.
0035 
0036 // Author: G.Cosmo, 14 July 2010 - First version
0037 // --------------------------------------------------------------------
0038 #ifndef G4FPEDetection_hh
0039 #define G4FPEDetection_hh 1
0040 
0041 #include <iostream>
0042 #include <stdlib.h> /* abort(), exit() */
0043 
0044 #ifdef __linux__
0045 #  if(defined(__GNUC__) && !defined(__clang__))
0046 #    include <csignal>
0047 #    include <features.h>
0048 #    include <fenv.h>
0049 // for G4StackBacktrace()
0050 #    include <cxxabi.h>
0051 #    include <execinfo.h>
0052 
0053 struct sigaction termaction, oldaction;
0054 
0055 static void G4StackBackTrace()
0056 {
0057 //   from http://linux.die.net/man/3/backtrace_symbols_fd
0058 #    define BSIZE 50
0059   void* buffer[BSIZE];
0060   int nptrs      = backtrace(buffer, BSIZE);
0061   char** strings = backtrace_symbols(buffer, nptrs);
0062   if(strings == NULL)
0063   {
0064     perror("backtrace_symbols");
0065     return;
0066   }
0067   std::cerr << std::endl << "Call Stack:" << std::endl;
0068   for(int j = 0; j < nptrs; j++)
0069   {
0070     std::cerr << nptrs - j - 1 << ": ";
0071     char* mangled_start = strchr(strings[j], '(') + 1;
0072     if(mangled_start)
0073       *(mangled_start - 1) = '\0';
0074     char* mangled_end = strchr(mangled_start, '+');
0075     if(mangled_end)
0076       *mangled_end = '\0';
0077     int status     = 0;
0078     char* realname = 0;
0079     if(mangled_end && strlen(mangled_start))
0080       realname = abi::__cxa_demangle(mangled_start, 0, 0, &status);
0081     if(realname)
0082     {
0083       std::cerr << strings[j] << " : " << realname << std::endl;
0084       free(realname);
0085     }
0086     else
0087     {
0088       std::cerr << strings[j] << std::endl;
0089     }
0090   }
0091   free(strings);
0092   // c++filt can demangle:
0093   // http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
0094   //-------------------------------------------------------------------
0095 }
0096 
0097 static void TerminationSignalHandler(int sig, siginfo_t* sinfo,
0098                                      void* /* context */)
0099 {
0100   std::cerr << "ERROR: " << sig;
0101   std::string message = "Floating-point exception (FPE).";
0102 
0103   if(sinfo)
0104   {
0105     switch(sinfo->si_code)
0106     {
0107 #    ifdef FPE_NOOP /* BUG: MacOS uses this instead of INTDIV */
0108       case FPE_NOOP:
0109 #    endif
0110       case FPE_INTDIV:
0111         message = "Integer divide by zero.";
0112         break;
0113       case FPE_INTOVF:
0114         message = "Integer overflow.";
0115         break;
0116       case FPE_FLTDIV:
0117         message = "Floating point divide by zero.";
0118         break;
0119       case FPE_FLTOVF:
0120         message = "Floating point overflow.";
0121         break;
0122       case FPE_FLTUND:
0123         message = "Floating point underflow.";
0124         break;
0125       case FPE_FLTRES:
0126         message = "Floating point inexact result.";
0127         break;
0128       case FPE_FLTINV:
0129         message = "Floating point invalid operation.";
0130         break;
0131       case FPE_FLTSUB:
0132         message = "Subscript out of range.";
0133         break;
0134       default:
0135         message = "Unknown error.";
0136         break;
0137     }
0138   }
0139   std::cerr << " - " << message << std::endl;
0140   G4StackBackTrace();
0141   ::abort();
0142 }
0143 
0144 static void InvalidOperationDetection()
0145 {
0146   std::cout << std::endl
0147             << "        "
0148             << "############################################" << std::endl
0149             << "        "
0150             << "!!! WARNING - FPE detection is activated !!!" << std::endl
0151             << "        "
0152             << "############################################" << std::endl;
0153 
0154   (void) feenableexcept(FE_DIVBYZERO);
0155   (void) feenableexcept(FE_INVALID);
0156   //(void) feenableexcept( FE_OVERFLOW );
0157   //(void) feenableexcept( FE_UNDERFLOW );
0158 
0159   sigfillset(&termaction.sa_mask);
0160   sigdelset(&termaction.sa_mask, SIGFPE);
0161   termaction.sa_sigaction = TerminationSignalHandler;
0162   termaction.sa_flags     = SA_SIGINFO;
0163   sigaction(SIGFPE, &termaction, &oldaction);
0164 }
0165 
0166 #  else /* Not GCC */
0167 
0168 static void InvalidOperationDetection() { ; }
0169 
0170 #  endif
0171 
0172 #elif defined(__MACH__) /* MacOS */
0173 
0174 #  include <fenv.h>
0175 #  include <signal.h>
0176 
0177 //#define DEFINED_PPC      (defined(__ppc__) || defined(__ppc64__))
0178 //#define DEFINED_INTEL    (defined(__i386__) || defined(__x86_64__))
0179 
0180 #  if(defined(__ppc__) || defined(__ppc64__))  // PPC
0181 
0182 #    define FE_EXCEPT_SHIFT 22  // shift flags right to get masks
0183 #    define FM_ALL_EXCEPT FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT
0184 
0185 static inline int feenableexcept(unsigned int excepts)
0186 {
0187   static fenv_t fenv;
0188   unsigned int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT,
0189                old_excepts;  // all previous masks
0190 
0191   if(fegetenv(&fenv))
0192   {
0193     return -1;
0194   }
0195   old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
0196   fenv        = (fenv & ~new_excepts) | new_excepts;
0197 
0198   return (fesetenv(&fenv) ? -1 : old_excepts);
0199 }
0200 
0201 static inline int fedisableexcept(unsigned int excepts)
0202 {
0203   static fenv_t fenv;
0204   unsigned int still_on = ~((excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT),
0205                old_excepts;  // previous masks
0206 
0207   if(fegetenv(&fenv))
0208   {
0209     return -1;
0210   }
0211   old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
0212   fenv &= still_on;
0213 
0214   return (fesetenv(&fenv) ? -1 : old_excepts);
0215 }
0216 
0217 #  elif(defined(__i386__) || defined(__x86_64__))  // INTEL
0218 
0219 static inline int feenableexcept(unsigned int excepts)
0220 {
0221   static fenv_t fenv;
0222   unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
0223                old_excepts;  // previous masks
0224 
0225   if(fegetenv(&fenv))
0226   {
0227     return -1;
0228   }
0229   old_excepts = fenv.__control & FE_ALL_EXCEPT;
0230 
0231   // unmask
0232   //
0233   fenv.__control &= ~new_excepts;
0234   fenv.__mxcsr &= ~(new_excepts << 7);
0235 
0236   return (fesetenv(&fenv) ? -1 : old_excepts);
0237 }
0238 
0239 static inline int fedisableexcept(unsigned int excepts)
0240 {
0241   static fenv_t fenv;
0242   unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
0243                old_excepts;  // all previous masks
0244 
0245   if(fegetenv(&fenv))
0246   {
0247     return -1;
0248   }
0249   old_excepts = fenv.__control & FE_ALL_EXCEPT;
0250 
0251   // mask
0252   //
0253   fenv.__control |= new_excepts;
0254   fenv.__mxcsr |= new_excepts << 7;
0255 
0256   return (fesetenv(&fenv) ? -1 : old_excepts);
0257 }
0258 
0259 #  elif(defined(__arm) || defined(__arm64) || defined(__aarch64__))  // Apple Silicon
0260 
0261 #    define FE_EXCEPT_SHIFT 22  // shift flags right to get masks
0262 #    define FM_ALL_EXCEPT FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT
0263 
0264 static inline int feenableexcept(unsigned int excepts)
0265 {
0266   static fenv_t fenv;
0267   unsigned int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT,
0268                old_excepts;  // all previous masks
0269 
0270   if(fegetenv(&fenv))
0271   {
0272     return -1;
0273   }
0274   old_excepts = (fenv.__fpcr & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
0275   fenv.__fpcr = (fenv.__fpcr & ~new_excepts) | new_excepts;
0276 
0277   return (fesetenv(&fenv) ? -1 : old_excepts);
0278 }
0279 
0280 static inline int fedisableexcept(unsigned int excepts)
0281 {
0282   static fenv_t fenv;
0283   unsigned int still_on = ~((excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT),
0284                old_excepts;  // previous masks
0285 
0286   if(fegetenv(&fenv))
0287   {
0288     return -1;
0289   }
0290   old_excepts = (fenv.__fpcr & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
0291   fenv.__fpcr = fenv.__fpcr | still_on;
0292 
0293   return (fesetenv(&fenv) ? -1 : old_excepts);
0294 }
0295 
0296 #  endif          /* PPC or INTEL or Apple Silicon enabling */
0297 
0298 static void TerminationSignalHandler(int sig, siginfo_t* sinfo,
0299                                      void* /* context */)
0300 {
0301   std::cerr << "ERROR: " << sig;
0302   std::string message = "Floating-point exception (FPE).";
0303 
0304   if(sinfo)
0305   {
0306     switch(sinfo->si_code)
0307     {
0308 #  ifdef FPE_NOOP /* BUG: MacOS uses this instead of INTDIV */
0309       case FPE_NOOP:
0310 #  endif
0311       case FPE_INTDIV:
0312         message = "Integer divide by zero.";
0313         break;
0314       case FPE_INTOVF:
0315         message = "Integer overflow.";
0316         break;
0317       case FPE_FLTDIV:
0318         message = "Floating point divide by zero.";
0319         break;
0320       case FPE_FLTOVF:
0321         message = "Floating point overflow.";
0322         break;
0323       case FPE_FLTUND:
0324         message = "Floating point underflow.";
0325         break;
0326       case FPE_FLTRES:
0327         message = "Floating point inexact result.";
0328         break;
0329       case FPE_FLTINV:
0330         message = "Floating point invalid operation.";
0331         break;
0332       case FPE_FLTSUB:
0333         message = "Subscript out of range.";
0334         break;
0335       default:
0336         message = "Unknown error.";
0337         break;
0338     }
0339   }
0340 
0341   std::cerr << " - " << message << std::endl;
0342 
0343   ::abort();
0344 }
0345 
0346 static void InvalidOperationDetection()
0347 {
0348   struct sigaction termaction, oldaction;
0349 
0350   std::cout << std::endl
0351             << "        "
0352             << "############################################" << std::endl
0353             << "        "
0354             << "!!! WARNING - FPE detection is activated !!!" << std::endl
0355             << "        "
0356             << "############################################" << std::endl;
0357 
0358   feenableexcept(FE_DIVBYZERO);
0359   feenableexcept(FE_INVALID);
0360   // fedisableexcept( FE_OVERFLOW  );
0361   // fedisableexcept( FE_UNDERFLOW );
0362 
0363   sigfillset(&termaction.sa_mask);
0364   sigdelset(&termaction.sa_mask, SIGFPE);
0365   termaction.sa_sigaction = TerminationSignalHandler;
0366   termaction.sa_flags     = SA_SIGINFO;
0367   sigaction(SIGFPE, &termaction, &oldaction);
0368 }
0369 
0370 #else /* Not Linux, nor MacOS ... */
0371 
0372 static void InvalidOperationDetection() { ; }
0373 
0374 #endif /* Linux or MacOS */
0375 
0376 #endif /* G4FPEDetection_hh */