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