0026937: Eliminate NO_CXX_EXCEPTION macro support
[occt.git] / src / OSD / OSD_signal.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14
15 #include <OSD.hxx>
16 #include <OSD_Exception_CTRL_BREAK.hxx>
17 #include <Standard_DivideByZero.hxx>
18 #include <Standard_Overflow.hxx>
19
20 #ifdef _WIN32
21 //---------------------------- Windows NT System --------------------------------
22
23 #define STRICT
24 #ifdef NOUSER
25 #undef NOUSER
26 #endif
27 #ifdef NONLS
28 #undef NONLS
29 #endif
30 #include <windows.h>
31
32 #include <Strsafe.h>
33
34 #ifndef STATUS_FLOAT_MULTIPLE_FAULTS
35   // <ntstatus.h>
36   #define STATUS_FLOAT_MULTIPLE_FAULTS     (0xC00002B4L)
37   #define STATUS_FLOAT_MULTIPLE_TRAPS      (0xC00002B5L)
38 #endif
39
40 #include <OSD_Exception_ACCESS_VIOLATION.hxx>
41 #include <OSD_Exception_ARRAY_BOUNDS_EXCEEDED.hxx>
42 #include <OSD_Exception_ILLEGAL_INSTRUCTION.hxx>
43 #include <OSD_Exception_IN_PAGE_ERROR.hxx>
44 #include <OSD_Exception_INT_DIVIDE_BY_ZERO.hxx>
45 #include <OSD_Exception_INT_OVERFLOW.hxx>
46 #include <OSD_Exception_INVALID_DISPOSITION.hxx>
47 #include <OSD_Exception_NONCONTINUABLE_EXCEPTION.hxx>
48 #include <OSD_Exception_PRIV_INSTRUCTION.hxx>
49 #include <OSD_Exception_STACK_OVERFLOW.hxx>
50 #include <OSD_Exception_STATUS_NO_MEMORY.hxx>
51
52 #include <OSD_Environment.hxx>
53 #include <Standard_Underflow.hxx>
54 #include <Standard_ProgramError.hxx>
55 #include <Standard_Mutex.hxx>
56
57 #include <OSD_WNT_1.hxx>
58
59 #ifdef _MSC_VER
60 #include <eh.h>
61 #include <malloc.h>
62 #endif
63
64 #include <process.h>
65 #include <signal.h>
66 #include <float.h>
67
68 static Standard_Boolean fCtrlBrk;
69 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
70 static Standard_Boolean fMsgBox;
71 static Standard_Boolean fFltExceptions;
72 static Standard_Boolean fDbgLoaded;
73
74 // used to forbid simultaneous execution of setting / executing handlers
75 static Standard_Mutex THE_SIGNAL_MUTEX;
76
77 static LONG __fastcall _osd_raise ( DWORD, LPSTR );
78 static BOOL WINAPI     _osd_ctrl_break_handler ( DWORD );
79
80 #ifndef OCCT_UWP
81 static LONG _osd_debug   ( void );
82 #endif
83
84 //# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW )
85 # define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
86
87 //=======================================================================
88 //function : CallHandler
89 //purpose  :
90 //=======================================================================
91 static LONG CallHandler (DWORD dwExceptionCode,
92                          ptrdiff_t ExceptionInformation1,
93                          ptrdiff_t ExceptionInformation0)
94 {
95   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
96
97   static wchar_t         buffer[2048];
98
99   int                  flterr = 0;
100
101   buffer[0] = '\0' ;
102
103 // cout << "CallHandler " << dwExceptionCode << endl ;
104   switch ( dwExceptionCode ) {
105     case EXCEPTION_FLT_DENORMAL_OPERAND:
106 //      cout << "CallHandler : EXCEPTION_FLT_DENORMAL_OPERAND:" << endl ;
107       StringCchCopyW (buffer, _countof(buffer), L"FLT DENORMAL OPERAND");
108       flterr = 1 ;
109       break ;
110     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
111 //      cout << "CallHandler : EXCEPTION_FLT_DIVIDE_BY_ZERO:" << endl ;
112       StringCchCopyW (buffer, _countof(buffer), L"FLT DIVIDE BY ZERO");
113       flterr = 1 ;
114       break ;
115     case EXCEPTION_FLT_INEXACT_RESULT:
116 //      cout << "CallHandler : EXCEPTION_FLT_INEXACT_RESULT:" << endl ;
117       StringCchCopyW (buffer, _countof(buffer), L"FLT INEXACT RESULT");
118       flterr = 1 ;
119       break ;
120     case EXCEPTION_FLT_INVALID_OPERATION:
121 //      cout << "CallHandler : EXCEPTION_FLT_INVALID_OPERATION:" << endl ;
122       StringCchCopyW (buffer, _countof(buffer), L"FLT INVALID OPERATION");
123       flterr = 1 ;
124       break ;
125     case EXCEPTION_FLT_OVERFLOW:
126 //      cout << "CallHandler : EXCEPTION_FLT_OVERFLOW:" << endl ;
127       StringCchCopyW (buffer, _countof(buffer), L"FLT OVERFLOW");
128       flterr = 1 ;
129       break ;
130     case EXCEPTION_FLT_STACK_CHECK:
131 //      cout << "CallHandler : EXCEPTION_FLT_STACK_CHECK:" << endl ;
132       StringCchCopyW (buffer, _countof(buffer), L"FLT STACK CHECK");
133       flterr = 1 ;
134       break ;
135     case EXCEPTION_FLT_UNDERFLOW:
136 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
137       StringCchCopyW (buffer, _countof(buffer), L"FLT UNDERFLOW");
138       flterr = 1 ;
139       break ;
140     case STATUS_FLOAT_MULTIPLE_TRAPS:
141 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
142       StringCchCopyW (buffer, _countof(buffer), L"FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)");
143       flterr = 1 ;
144       break ;
145     case STATUS_FLOAT_MULTIPLE_FAULTS:
146 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
147       StringCchCopyW (buffer, _countof(buffer), L"FLT MULTIPLE FAULTS");
148       flterr = 1 ;
149       break ;
150     case STATUS_NO_MEMORY:
151 //      cout << "CallHandler : STATUS_NO_MEMORY:" << endl ;
152       throw OSD_Exception_STATUS_NO_MEMORY (  "MEMORY ALLOCATION ERROR ( no room in the process heap )"  );
153     case EXCEPTION_ACCESS_VIOLATION:
154 //      cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << endl ;
155       StringCchPrintfW (buffer, _countof(buffer), L"%s%s%s0x%.8p%s%s%s", L"ACCESS VIOLATION",
156                  fMsgBox ? L"\n" : L" ", L"at address ",
157                  ExceptionInformation1 ,
158                  L" during '",
159                  ExceptionInformation0 ? L"WRITE" : L"READ",
160                  L"' operation");
161       break;
162     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
163 //      cout << "CallHandler : EXCEPTION_ARRAY_BOUNDS_EXCEEDED:" << endl ;
164       StringCchCopyW (buffer, _countof(buffer), L"ARRAY BOUNDS EXCEEDED");
165       break;
166     case EXCEPTION_DATATYPE_MISALIGNMENT:
167 //      cout << "CallHandler : EXCEPTION_DATATYPE_MISALIGNMENT:" << endl ;
168       StringCchCopyW (buffer, _countof(buffer), L"DATATYPE MISALIGNMENT");
169       break;
170
171     case EXCEPTION_ILLEGAL_INSTRUCTION:
172 //      cout << "CallHandler : EXCEPTION_ILLEGAL_INSTRUCTION:" << endl ;
173       StringCchCopyW (buffer, _countof(buffer), L"ILLEGAL INSTRUCTION");
174       break;
175
176     case EXCEPTION_IN_PAGE_ERROR:
177 //      cout << "CallHandler : EXCEPTION_IN_PAGE_ERROR:" << endl ;
178       StringCchCopyW (buffer, _countof(buffer), L"IN_PAGE ERROR");
179       break;
180
181     case EXCEPTION_INT_DIVIDE_BY_ZERO:
182 //      cout << "CallHandler : EXCEPTION_INT_DIVIDE_BY_ZERO:" << endl ;
183       StringCchCopyW (buffer, _countof(buffer), L"INTEGER DIVISION BY ZERO");
184       break;
185
186     case EXCEPTION_INT_OVERFLOW:
187 //      cout << "CallHandler : EXCEPTION_INT_OVERFLOW:" << endl ;
188       StringCchCopyW (buffer, _countof(buffer), L"INTEGER OVERFLOW");
189       break;
190
191     case EXCEPTION_INVALID_DISPOSITION:
192 //      cout << "CallHandler : EXCEPTION_INVALID_DISPOSITION:" << endl ;
193       StringCchCopyW (buffer, _countof(buffer), L"INVALID DISPOSITION");
194       break;
195
196     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
197 //      cout << "CallHandler : EXCEPTION_NONCONTINUABLE_EXCEPTION:" << endl ;
198       StringCchCopyW (buffer, _countof(buffer), L"NONCONTINUABLE EXCEPTION");
199       break;
200
201     case EXCEPTION_PRIV_INSTRUCTION:
202 //      cout << "CallHandler : EXCEPTION_PRIV_INSTRUCTION:" << endl ;
203       StringCchCopyW (buffer, _countof(buffer), L"PRIVELEGED INSTRUCTION ENCOUNTERED");
204       break;
205
206     case EXCEPTION_STACK_OVERFLOW:
207 //      cout << "CallHandler : EXCEPTION_STACK_OVERFLOW:" << endl ;
208 #if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) && !defined(OCCT_UWP)
209     // try recovering from stack overflow: available in MS VC++ 7.0
210       if (!_resetstkoflw())
211         StringCchCopyW (buffer, _countof(buffer), L"Unrecoverable STACK OVERFLOW");
212       else
213 #endif
214       StringCchCopyW (buffer, _countof(buffer), L"STACK OVERFLOW");
215       break;
216
217     default:
218       StringCchPrintfW (buffer, _countof(buffer), L"unknown exception code 0x%x, params 0x%p 0x%p",
219                 dwExceptionCode, ExceptionInformation1, ExceptionInformation0 );
220
221   }  // end switch
222
223  // provide message to the user with possibility to stop
224   size_t idx;
225   StringCchLengthW (buffer, _countof(buffer),&idx);
226   if ( idx && fMsgBox && dwExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION ) {
227      // reset FP operations before message box, otherwise it may fail to show up
228     _fpreset();
229     _clearfp();
230
231 #ifndef OCCT_UWP
232     MessageBeep ( MB_ICONHAND );
233     int aChoice = ::MessageBoxW (0, buffer, L"OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
234     if (aChoice == IDRETRY)
235     {
236       _osd_debug();
237       DebugBreak();
238     } else if (aChoice == IDABORT)
239       exit(0xFFFF);
240 #endif
241   }
242
243   // reset FPE state
244   if ( flterr ) {
245     if ( !fFltExceptions ) return EXCEPTION_EXECUTE_HANDLER;
246    _fpreset () ;
247    _clearfp() ;
248    _controlfp ( 0, _OSD_FPX ) ;          // JR add :
249 //     cout << "OSD::WntHandler _controlfp( 0, _OSD_FPX ) " << hex << _controlfp(0,0) << dec << endl ;
250   }
251
252   char aBufferA[2048];
253   WideCharToMultiByte(CP_UTF8, 0, buffer, -1, aBufferA, sizeof(aBufferA), NULL, NULL);
254   return _osd_raise(dwExceptionCode, aBufferA);
255 }
256
257 //=======================================================================
258 //function : SIGWntHandler
259 //purpose  : Will only be used if user calls ::raise() function with
260 //           signal type set in OSD::SetSignal() - SIGSEGV, SIGFPE, SIGILL
261 //           (the latter will likely be removed in the future)
262 //=======================================================================
263 static void SIGWntHandler (int signum, int sub_code)
264 {
265   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
266   switch( signum ) {
267     case SIGFPE :
268       if ( signal( signum , (void(*)(int))SIGWntHandler ) == SIG_ERR )
269         cout << "signal error" << endl ;
270       switch( sub_code ) {
271         case _FPE_INVALID :
272           CallHandler( EXCEPTION_FLT_INVALID_OPERATION ,0,0) ;
273           break ;
274         case _FPE_DENORMAL :
275           CallHandler( EXCEPTION_FLT_DENORMAL_OPERAND ,0,0) ;
276           break ;
277         case _FPE_ZERODIVIDE :
278           CallHandler( EXCEPTION_FLT_DIVIDE_BY_ZERO ,0,0) ;
279           break ;
280         case _FPE_OVERFLOW :
281           CallHandler( EXCEPTION_FLT_OVERFLOW ,0,0) ;
282           break ;
283         case _FPE_UNDERFLOW :
284           CallHandler( EXCEPTION_FLT_UNDERFLOW ,0,0) ;
285           break ;
286         case _FPE_INEXACT :
287           CallHandler( EXCEPTION_FLT_INEXACT_RESULT ,0,0) ;
288           break ;
289         default:
290           cout << "SIGWntHandler(default) -> throw Standard_NumericError(\"Floating Point Error\");" << endl;
291           throw Standard_NumericError("Floating Point Error");
292           break ;
293       }
294       break ;
295     case SIGSEGV :
296       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
297         cout << "signal error" << endl ;
298       CallHandler( EXCEPTION_ACCESS_VIOLATION ,0,0) ;
299       break ;
300     case SIGILL :
301       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
302         cout << "signal error" << endl ;
303       CallHandler( EXCEPTION_ILLEGAL_INSTRUCTION ,0,0) ;
304       break ;
305     default:
306       cout << "SIGWntHandler unexpected signal : " << signum << endl ;
307       break ;
308   }
309 #ifndef OCCT_UWP
310   DebugBreak ();
311 #endif
312 }
313 #endif
314
315 //=======================================================================
316 //function : TranslateSE
317 //purpose  : Translate Structural Exceptions into C++ exceptions
318 //           Will be used when user's code is compiled with /EHa option
319 //=======================================================================
320 #ifdef _MSC_VER
321 // If this file compiled with the default MSVC options for exception
322 // handling (/GX or /EHsc) then the following warning is issued:
323 //   warning C4535: calling _set_se_translator() requires /EHa
324 // However it is correctly inserted and used when user's code compiled with /EHa.
325 // So, here we disable the warning.
326 #pragma warning (disable:4535)
327
328 static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
329 {
330   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
331   ptrdiff_t info1 = 0, info0 = 0;
332   if ( theExcPtr ) {
333     info1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
334     info0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
335   }
336   CallHandler(theCode, info1, info0);
337 }
338 #endif
339
340 //=======================================================================
341 //function : WntHandler
342 //purpose  : Will be used when user's code is compiled with /EHs
343 //           option and unless user sets his own exception handler with
344 //           ::SetUnhandledExceptionFilter().
345 //=======================================================================
346 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
347 static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
348 {
349   DWORD               dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
350
351   return CallHandler (dwExceptionCode,
352                       lpXP->ExceptionRecord->ExceptionInformation[1],
353                       lpXP->ExceptionRecord->ExceptionInformation[0]);
354 }
355 #endif
356
357 //=======================================================================
358 //function : SetSignal
359 //purpose  :
360 //=======================================================================
361 void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
362 {
363 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
364   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
365 #if !defined(OCCT_UWP) || defined(NTDDI_WIN10_TH2)
366   LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFilter;
367
368   OSD_Environment env ("CSF_DEBUG_MODE");
369   TCollection_AsciiString val = env.Value();
370   if (!env.Failed())
371   {
372     cout << "Environment variable CSF_DEBUG_MODE setted.\n";
373     fMsgBox = Standard_True;
374   }
375   else
376   {
377     fMsgBox = Standard_False;
378   }
379
380   // Set exception handler (ignored when running under debugger). It will be used in most cases
381   // when user's code is compiled with /EHs
382   // Replaces the existing top-level exception filter for all existing and all future threads
383   // in the calling process
384   aPreviousFilter = ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
385 #endif // NTDDI_WIN10_TH2
386
387   // Signal handlers will only be used when the method ::raise() will be used
388   // Handlers must be set for every thread
389   if (signal (SIGSEGV, (void(*)(int))SIGWntHandler) == SIG_ERR)
390     cout << "signal(OSD::SetSignal) error\n";
391   if (signal (SIGFPE,  (void(*)(int))SIGWntHandler) == SIG_ERR)
392     cout << "signal(OSD::SetSignal) error\n";
393   if (signal (SIGILL,  (void(*)(int))SIGWntHandler) == SIG_ERR)
394     cout << "signal(OSD::SetSignal) error\n";
395
396   // Set Ctrl-C and Ctrl-Break handler
397   fCtrlBrk = Standard_False;
398 #ifndef OCCT_UWP
399   SetConsoleCtrlHandler (&_osd_ctrl_break_handler, TRUE);
400 #endif
401 #ifdef _MSC_VER
402 //  _se_translator_function pOldSeFunc =
403   _set_se_translator (TranslateSE);
404 #endif
405
406   fFltExceptions = theFloatingSignal;
407   if (theFloatingSignal)
408   {
409     _controlfp (0, _OSD_FPX);        // JR add :
410   }
411   else {
412     _controlfp (_OSD_FPX, _OSD_FPX); // JR add :
413   }
414 #endif
415 }  // end OSD :: SetSignal
416
417 //============================================================================
418 //==== ControlBreak
419 //============================================================================
420 void OSD::ControlBreak () {
421   if ( fCtrlBrk ) {
422     fCtrlBrk = Standard_False;
423     throw OSD_Exception_CTRL_BREAK ( "*** INTERRUPT ***" );
424   }
425 }  // end OSD :: ControlBreak
426 #if !defined(__MINGW32__) && !defined(__CYGWIN32__)
427 #ifndef OCCT_UWP
428 //============================================================================
429 //==== _osd_ctrl_break_handler
430 //============================================================================
431 static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
432   if ( dwCode == CTRL_C_EVENT || dwCode == CTRL_BREAK_EVENT ) {
433     MessageBeep ( MB_ICONEXCLAMATION );
434     fCtrlBrk = Standard_True;
435   } else
436     exit ( 254 );
437
438   return TRUE;
439 }  // end _osd_ctrl_break_handler
440 #endif
441 //============================================================================
442 //==== _osd_raise
443 //============================================================================
444 static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
445 {
446   if (msg[0] == '\x03') ++msg;
447
448   switch (dwCode)
449   {
450     case EXCEPTION_ACCESS_VIOLATION:
451       throw OSD_Exception_ACCESS_VIOLATION(msg);
452       break;
453     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
454       throw OSD_Exception_ARRAY_BOUNDS_EXCEEDED(msg);
455       break;
456     case EXCEPTION_DATATYPE_MISALIGNMENT:
457       throw Standard_ProgramError(msg);
458       break;
459     case EXCEPTION_ILLEGAL_INSTRUCTION:
460       throw OSD_Exception_ILLEGAL_INSTRUCTION(msg);
461       break;
462     case EXCEPTION_IN_PAGE_ERROR:
463       throw OSD_Exception_IN_PAGE_ERROR(msg);
464       break;
465     case EXCEPTION_INT_DIVIDE_BY_ZERO:
466       throw Standard_DivideByZero(msg);
467       break;
468     case EXCEPTION_INT_OVERFLOW:
469       throw OSD_Exception_INT_OVERFLOW(msg);
470       break;
471     case EXCEPTION_INVALID_DISPOSITION:
472       throw OSD_Exception_INVALID_DISPOSITION(msg);
473       break;
474     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
475       throw OSD_Exception_NONCONTINUABLE_EXCEPTION(msg);
476       break;
477     case EXCEPTION_PRIV_INSTRUCTION:
478       throw OSD_Exception_PRIV_INSTRUCTION(msg);
479       break;
480     case EXCEPTION_STACK_OVERFLOW:
481       throw OSD_Exception_STACK_OVERFLOW(msg);
482       break;
483     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
484       throw Standard_DivideByZero(msg);
485       break;
486     case EXCEPTION_FLT_STACK_CHECK:
487     case EXCEPTION_FLT_OVERFLOW:
488       throw Standard_Overflow(msg);
489       break;
490     case EXCEPTION_FLT_UNDERFLOW:
491       throw Standard_Underflow(msg);
492       break;
493     case EXCEPTION_FLT_INVALID_OPERATION:
494     case EXCEPTION_FLT_DENORMAL_OPERAND:
495     case EXCEPTION_FLT_INEXACT_RESULT:
496     case STATUS_FLOAT_MULTIPLE_TRAPS:
497     case STATUS_FLOAT_MULTIPLE_FAULTS:
498       throw Standard_NumericError(msg);
499       break;
500     default:
501       break;
502   }  // end switch
503   return EXCEPTION_EXECUTE_HANDLER;
504 }  // end _osd_raise
505
506 //============================================================================
507 //==== _osd_debug
508 //============================================================================
509 #ifndef OCCT_UWP
510 LONG _osd_debug ( void ) {
511
512   LONG action ;
513
514   if ( !fDbgLoaded ) {
515
516     HKEY                hKey = NULL;
517     HANDLE              hEvent = INVALID_HANDLE_VALUE;
518     DWORD               dwKeyType;
519     DWORD               dwValueLen;
520     TCHAR               keyValue[ MAX_PATH ];
521     TCHAR               cmdLine[ MAX_PATH ];
522     SECURITY_ATTRIBUTES sa;
523     PROCESS_INFORMATION pi;
524     STARTUPINFO         si;
525
526     __try {
527
528       if (  RegOpenKey (
529               HKEY_LOCAL_MACHINE,
530               TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ),
531               &hKey
532             ) != ERROR_SUCCESS
533       ) __leave;
534
535       dwValueLen = sizeof ( keyValue );
536
537       if (  RegQueryValueEx (
538              hKey, TEXT( "Debugger" ), NULL, &dwKeyType, ( unsigned char* )keyValue, &dwValueLen
539             ) != ERROR_SUCCESS
540       ) __leave;
541
542       sa.nLength              = sizeof ( SECURITY_ATTRIBUTES );
543       sa.lpSecurityDescriptor = NULL;
544       sa.bInheritHandle       = TRUE;
545
546       if (   (  hEvent = CreateEvent ( &sa, TRUE, FALSE, NULL )  ) == NULL   ) __leave;
547
548       StringCchPrintf(cmdLine, _countof(cmdLine), keyValue, GetCurrentProcessId(), hEvent);
549
550       ZeroMemory (  &si, sizeof ( STARTUPINFO )  );
551
552       si.cb      = sizeof ( STARTUPINFO );
553       si.dwFlags = STARTF_FORCEONFEEDBACK;
554
555   //   cout << "_osd_debug -> CreateProcess" << endl ;
556       if (  !CreateProcess (
557               NULL, cmdLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
558               NULL, NULL, &si, &pi
559              )
560       ) __leave;
561
562   //   cout << "_osd_debug -> WaitForSingleObject " << endl ;
563       WaitForSingleObject ( hEvent, INFINITE );
564   //   cout << "_osd_debug <- WaitForSingleObject -> CloseHandle " << endl ;
565
566       CloseHandle ( pi.hProcess );
567       CloseHandle ( pi.hThread  );
568
569   //   cout << "_osd_debug fDbgLoaded  " << endl ;
570       fDbgLoaded = TRUE;
571
572     }  // end __try
573
574     __finally {
575
576 //   cout << "_osd_debug -> CloseHandle(hKey) " << endl ;
577       if ( hKey   != INVALID_HANDLE_VALUE ) CloseHandle ( hKey   );
578 //   cout << "_osd_debug -> CloseHandle(hEvent) " << endl ;
579       if ( hEvent != INVALID_HANDLE_VALUE ) CloseHandle ( hEvent );
580 //   cout << "_osd_debug end __finally " << endl ;
581
582     }  // end __finally
583
584   }  /* end if */
585
586   action = fDbgLoaded ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
587 // cout << "_osd_debug return " << action << " EXCEPTION_CONTINUE_EXECUTION("
588 //      << EXCEPTION_CONTINUE_EXECUTION << ")" << endl ;
589   return action ;
590
591 }  // end _osd_debug
592
593 #endif
594 #endif
595 #else
596
597 //---------- All Systems except Windows NT : ----------------------------------
598
599 # include <stdio.h>
600
601 #include <OSD_WhoAmI.hxx>
602 #include <OSD_SIGHUP.hxx>
603 #include <OSD_SIGINT.hxx>
604 #include <OSD_SIGQUIT.hxx>
605 #include <OSD_SIGILL.hxx>
606 #include <OSD_SIGKILL.hxx>
607 #include <OSD_SIGBUS.hxx>
608 #include <OSD_SIGSEGV.hxx>
609 #include <OSD_SIGSYS.hxx>
610 #include <Standard_NumericError.hxx>
611
612 #include <Standard_ErrorHandler.hxx>
613
614 // POSIX threads
615 #include <pthread.h>
616
617 #ifdef __linux__
618 #include <fenv.h>
619 static Standard_Boolean fFltExceptions = Standard_False;
620 #endif
621
622 // variable signalling that Control-C has been pressed (SIGINT signal)
623 static Standard_Boolean fCtrlBrk;
624
625 //const OSD_WhoAmI Iam = OSD_WPackage;
626
627 typedef void (ACT_SIGIO_HANDLER)(void) ;
628 ACT_SIGIO_HANDLER *ADR_ACT_SIGIO_HANDLER = NULL ;
629
630 #ifdef DECOSF1
631 typedef void (* SIG_PFV) (int);
632 #endif
633
634 #ifdef __GNUC__
635 # include <stdlib.h>
636 # include <stdio.h>
637 #else
638 #  ifdef SA_SIGINFO 
639 #    ifndef _AIX
640 #  include <sys/siginfo.h>
641 #     endif
642 #  endif
643 #endif
644 typedef void (* SIG_PFV) (int);
645
646 #include <signal.h>
647
648 #if !defined(__ANDROID__) && !defined(__QNX__)
649   #include <sys/signal.h>
650 #endif
651
652 //============================================================================
653 //==== Handler
654 //====     Catche the differents signals:
655 //====          1- The Fatal signals, which cause the end of process:
656 //====          2- The exceptions which are "signaled" by Raise.
657 //====     The Fatal Signals:
658 //====        SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGKILL, SIGBUS, SIGSYS
659 //====     The Exceptions:
660 //====        SIGFPE
661 //====         (SUN versions)
662 //====           FPE_INTOVF_TRAP    // ..... integer overflow
663 //====           FPE_INTDIV_TRAP    // ..... integer divide by zero
664 //====           FPE_FLTINEX_TRAP   // ..... [floating inexact result]
665 //====           FPE_FLTDIV_TRAP    // ..... [floating divide by zero]
666 //====           FPE_FLTUND_TRAP    // ..... [floating underflow]
667 //====           FPE_FLTOPER_TRAP   // ..... [floating inexact result]
668 //====           FPE_FLTOVF_TRAP    // ..... [floating overflow]
669 //==== SIGSEGV is handled by "SegvHandler()"
670 //============================================================================
671 #ifdef SA_SIGINFO
672 static void Handler (const int theSignal, siginfo_t */*theSigInfo*/, const Standard_Address /*theContext*/)
673 #else
674 static void Handler (const int theSignal)
675 #endif
676 {
677   struct sigaction oldact, act;
678   // re-install the signal
679   if ( ! sigaction (theSignal, NULL, &oldact) ) {
680     // cout << " signal is " << theSignal << " handler is " <<  oldact.sa_handler << endl;
681     if (sigaction (theSignal, &oldact, &act)) perror ("sigaction");
682   }
683   else {
684     perror ("sigaction");
685   }
686
687   // cout << "OSD::Handler: signal " << (int) theSignal << " occured inside a try block " <<  endl ;
688   if ( ADR_ACT_SIGIO_HANDLER != NULL )
689     (*ADR_ACT_SIGIO_HANDLER)() ;
690 #ifdef __linux__
691   if (fFltExceptions)
692     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
693     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
694 #endif
695   sigset_t set;
696   sigemptyset(&set);
697   switch (theSignal) {
698   case SIGHUP:
699     OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump();
700     exit(SIGHUP);
701     break;
702   case SIGINT:
703     // For safe handling of Control-C as stop event, arm a variable but do not
704     // generate longjump (we are out of context anyway)
705     fCtrlBrk = Standard_True;
706     // OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump();
707     // exit(SIGINT);
708     break;
709   case SIGQUIT:
710     OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump();
711     exit(SIGQUIT);
712     break;
713   case SIGILL:
714     OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump();
715     exit(SIGILL);
716     break;
717   case SIGKILL:
718     OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump();
719     exit(SIGKILL);
720     break;
721   case SIGBUS:
722     sigaddset(&set, SIGBUS);
723     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
724     OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump();
725     exit(SIGBUS);
726     break;
727   case SIGSEGV:
728     OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
729     exit(SIGSEGV);
730     break;
731 #ifdef SIGSYS
732   case SIGSYS:
733     OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump();
734     exit(SIGSYS);
735     break;
736 #endif
737   case SIGFPE:
738     sigaddset(&set, SIGFPE);
739     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
740 #ifdef DECOSF1
741     // Pour DEC/OSF1 SIGFPE = Division par zero.
742     Standard_DivideByZero::NewInstance('')->Jump;
743     break;
744 #endif
745 #if (!defined (__sun)) && (!defined(SOLARIS))
746     Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
747     break;
748 #else
749     // Reste SOLARIS
750     if (aSigInfo) {
751       switch(aSigInfo->si_code) {
752       case FPE_FLTDIV_TRAP :
753         Standard_DivideByZero::NewInstance("Floating Divide By Zero")->Jump();
754         break;
755       case FPE_INTDIV_TRAP :
756         Standard_DivideByZero::NewInstance("Integer Divide By Zero")->Jump();
757         break;
758       case FPE_FLTOVF_TRAP :
759         Standard_Overflow::NewInstance("Floating Overflow")->Jump();
760         break;
761       case FPE_INTOVF_TRAP :
762         Standard_Overflow::NewInstance("Integer Overflow")->Jump();
763         break;
764       case FPE_FLTUND_TRAP :
765         Standard_NumericError::NewInstance("Floating Underflow")->Jump();
766         break;
767       case FPE_FLTRES_TRAP:
768         Standard_NumericError::NewInstance("Floating Point Inexact Result")->Jump();
769         break;
770       case FPE_FLTINV_TRAP :
771         Standard_NumericError::NewInstance("Invalid Floating Point Operation")->Jump();
772         break;
773       default:
774         Standard_NumericError::NewInstance("Numeric Error")->Jump();
775         break;
776       }
777     } else {
778       Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
779     }
780 #endif
781     break;
782 #if defined (__sgi) || defined(IRIX)
783   case SIGTRAP:
784     sigaddset(&set, SIGTRAP);
785     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
786     Standard_DivideByZero::NewInstance("SIGTRAP IntegerDivideByZero")->Jump(); break;
787 #endif
788   default:
789 #ifdef OCCT_DEBUG
790     cout << "Unexpected signal " << theSignal << endl ;
791 #endif
792     break;
793   }
794 }
795
796 //============================================================================
797 //==== SegvHandler
798 //============================================================================
799 #ifdef SA_SIGINFO
800
801 static void SegvHandler(const int theSignal,
802                         siginfo_t *ip,
803                         const Standard_Address theContext)
804 {
805   (void)theSignal; // silence GCC warnings
806   (void)theContext;
807
808 #ifdef __linux__
809   if (fFltExceptions)
810     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
811     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
812 #endif
813 //  cout << "OSD::SegvHandler activated(SA_SIGINFO)" << endl ;
814   if ( ip != NULL ) {
815      sigset_t set;
816      sigemptyset(&set);
817      sigaddset(&set, SIGSEGV);
818      sigprocmask (SIG_UNBLOCK, &set, NULL) ;
819      void *address = ip->si_addr ;
820      {
821        char Msg[100];
822        sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",
823          (long ) address ) ;
824        OSD_SIGSEGV::NewInstance(Msg)->Jump();
825      }
826   }
827 #ifdef OCCT_DEBUG
828   else {
829     cout << "Wrong undefined address." << endl ;
830   }
831 #endif
832   exit(SIGSEGV);
833 }
834
835 #elif defined (_hpux) || defined(HPUX)
836 // Not ACTIVE ? SA_SIGINFO is defined on SUN, OSF, SGI and HP (and Linux) !
837 // pour version 09.07
838
839 static void SegvHandler(const int theSignal,
840                         siginfo_t *ip,
841                         const Standard_Address theContext)
842 {
843   unsigned long Space  ;
844   unsigned long Offset ;
845   char Msg[100] ;
846
847   if ( theContext != NULL ) {
848     Space = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr20 ;
849     Offset = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr21 ;
850 //    cout << "Wrong address = " << hex(Offset) << endl ;
851     {
852       sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",Offset) ;
853       OSD_SIGSEGV::Jump(Msg);
854 //    scp->sc_pcoq_head = scp->sc_pcoq_tail ;       Permettrait de continuer a
855 //    scp->sc_pcoq_tail = scp->sc_pcoq_tail + 0x4 ; l'intruction suivant le segv.
856     }
857   }
858 #ifdef OCCT_DEBUG
859   else {
860     cout << "Wrong undefined address." << endl ;
861   }
862 #endif
863   exit(SIGSEGV);
864 }
865
866 #endif
867
868 //============================================================================
869 //==== SetSignal 
870 //====     Set the differents signals:
871 //============================================================================
872
873 void OSD::SetSignal(const Standard_Boolean aFloatingSignal) 
874 {
875   static int first_time = 3 ;
876   struct sigaction act, oact;
877   int              stat = 0;
878
879   if( aFloatingSignal ) {
880     //==== Enable the floating point exceptions ===============
881 #if defined (__sun) || defined (SOLARIS)
882     sigfpe_handler_type PHandler = (sigfpe_handler_type) Handler ;
883     stat = ieee_handler("set", "invalid",  PHandler);
884     stat = ieee_handler("set", "division", PHandler) || stat;
885     stat = ieee_handler("set", "overflow", PHandler) || stat;
886
887     //stat = ieee_handler("set", "underflow", PHandler) || stat;
888     //stat = ieee_handler("set", "inexact", PHandler) || stat;
889
890     if (stat) {
891 #ifdef OCCT_DEBUG
892       cerr << "ieee_handler does not work !!! KO " << endl;
893 #endif
894     }
895 #elif defined (__linux__)
896     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
897     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
898     fFltExceptions = Standard_True;
899 #endif
900   }
901   else if ( first_time & 1 ) {
902 //    cout << "SetSignal( Standard_False ) is not implemented..." << endl ;
903     first_time = first_time & (~ 1) ;
904   }
905
906 #if defined (sgi) || defined (IRIX )
907  if ( first_time & 2 ) {
908    char *TRAP_FPE = getenv("TRAP_FPE") ;
909    if ( TRAP_FPE == NULL ) {
910 #ifdef OCCT_DEBUG
911      cout << "On SGI you must set TRAP_FPE environment variable : " << endl ;
912      cout << "set env(TRAP_FPE) \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\" or" << endl ;
913      cout << "setenv TRAP_FPE \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\"" << endl ;
914 #endif
915 //     exit(1) ;
916      first_time = first_time & (~ 2) ;
917    }
918  }
919 #endif
920
921   //==== Save the old Signal Handler, and set the new one ===================
922
923   sigemptyset(&act.sa_mask) ;
924
925 #ifdef SA_RESTART
926   act.sa_flags   = SA_RESTART ;
927 #else
928   act.sa_flags   = 0 ;
929 #endif
930 #ifdef SA_SIGINFO
931   act.sa_flags = act.sa_flags | SA_SIGINFO ;
932   act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ Handler;
933 #else
934   act.sa_handler = /*(SIG_PFV)*/ Handler;
935 #endif
936
937   //==== Always detected the signal "SIGFPE" =================================
938   stat = sigaction(SIGFPE,&act,&oact);   // ...... floating point exception 
939   if (stat) {
940 #ifdef OCCT_DEBUG
941      cerr << "sigaction does not work !!! KO " << endl;
942 #endif
943      perror("sigaction ");
944   }
945
946   //==== Detected the only the "free" signals ================================
947   sigaction(SIGHUP,&act,&oact);    // ...... hangup  
948
949 #ifdef OBJS
950   if(oact.sa_handler) 
951         sigaction(SIGHUP,&oact,&oact);
952 #endif
953
954   sigaction(SIGINT,&act,&oact);   // ...... interrupt   
955
956 #ifdef OBJS
957   if(oact.sa_handler) 
958         sigaction(SIGINT,&oact,&oact);
959 #endif
960             
961   sigaction(SIGQUIT,&act,&oact);  // ...... quit
962
963 #ifdef OBJS
964   if(oact.sa_handler) 
965         sigaction(SIGQUIT,&oact,&oact);
966 #endif
967
968   sigaction(SIGILL,&act,&oact);   // ...... illegal instruction 
969
970 #ifdef OBJS
971   if(oact.sa_handler) 
972         sigaction(SIGILL,&oact,&oact);
973 #endif
974
975   sigaction(SIGBUS,&act,&oact);   // ...... bus error 
976
977 #ifdef OBJS
978   if(oact.sa_handler) 
979         sigaction(SIGBUS,&oact,&oact);
980 #endif
981
982 #if !defined(__linux__)
983   sigaction(SIGSYS,&act,&oact);   // ...... bad argument to system call
984
985 # ifdef OBJS
986   if(oact.sa_handler) 
987         sigaction(SIGSYS,&oact,&oact);
988 # endif
989 #endif
990
991 #if defined (__sgi) || defined(IRIX)
992   sigaction(SIGTRAP,&act,&oact);   // Integer Divide By Zero (IRIX)
993
994 # ifdef OBJS
995   if(oact.sa_handler) 
996         sigaction(SIGTRAP,&oact,&oact);
997 # endif
998 #endif
999
1000 #ifdef SA_SIGINFO
1001   act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler;
1002 #else
1003   act.sa_handler = /*(SIG_PFV)*/ SegvHandler;
1004 #endif
1005
1006   if ( sigaction( SIGSEGV , &act , &oact ) )  // ...... segmentation violation
1007     perror("OSD::SetSignal sigaction( SIGSEGV , &act , &oact ) ") ;
1008
1009 #ifdef OBJS
1010   if(oact.sa_handler) 
1011         sigaction(SIGSEGV,&oact,&oact);
1012 #endif
1013 #if defined(__osf__) || defined(DECOSF1)
1014    struct sigaction action, prev_action;
1015    action.sa_handler = SIG_IGN;
1016    action.sa_mask = 0;
1017    action.sa_flags = 0;
1018    
1019    if (sigaction (SIGFPE, &action, &prev_action) == -1) {
1020      perror ("sigaction");
1021      exit (1);
1022    }
1023 #endif
1024
1025 }
1026
1027 //============================================================================
1028 //==== ControlBreak 
1029 //============================================================================
1030
1031 void OSD :: ControlBreak () 
1032 {
1033   if ( fCtrlBrk ) {
1034     fCtrlBrk = Standard_False;
1035     throw OSD_Exception_CTRL_BREAK("*** INTERRUPT ***");
1036   }
1037 }
1038
1039 #endif