Standard_Failure now holds an optional stack trace dump.
Added function Standard::StackTrace() dumping backtrace to the string.
SegvHandler within OSD_signal now appends backtrace to the message
if OSD::SignalStackTraceLength() is set to non-zero value
or environment variable "CSF_DEBUG_MODE" is set for debugging.
Added auxiliary macros Standard_NOINLINE disallowing function inlining.
Command "dsetsignal" has been extended by -strackTraceLength argument
for defining stack trace length within signals redirected to C++ exceptions.
Added "ddebugtraces" command for debugging purposes (adding stack traces to all exceptions).
// set signals
// *****************************************************************
OSD::SetSignal(Standard_False);
+ //OSD::SetSignalStackTraceLength (10);
#ifdef _WIN32
// in interactive mode, force Windows to report dll loading problems interactively
{
OSD_SignalMode aMode = OSD_SignalMode_Set;
Standard_Boolean aSetFPE = OSD::ToCatchFloatingSignals();
+ Standard_Integer aStackLen = OSD::SignalStackTraceLength();
// default for FPE signal is defined by CSF_FPE variable, if set
OSD_Environment aEnv("CSF_FPE");
else if (anArg == "default")
{
}
+ else if (anArgIter + 1 < theArgNb
+ && (anArg == "-stracktracelength"
+ || anArg == "-stracktracelen"
+ || anArg == "-stracklength"
+ || anArg == "-stracklen"))
+ {
+ aStackLen = Draw::Atoi (theArgVec[++anArgIter]);
+ }
else
{
Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
}
OSD::SetSignal(aMode, aSetFPE);
+ OSD::SetSignalStackTraceLength (aStackLen);
// report actual status in the end
const char* aModeStr = 0;
switch (OSD::SignalMode())
{
- default:
- case OSD_SignalMode_AsIs: aModeStr = "asis"; break;
- case OSD_SignalMode_Set: aModeStr = "set"; break;
- case OSD_SignalMode_SetUnhandled: aModeStr = "unhandled"; break;
- case OSD_SignalMode_Unset: aModeStr = "unset"; break;
+ default:
+ case OSD_SignalMode_AsIs: aModeStr = "asis"; break;
+ case OSD_SignalMode_Set: aModeStr = "set"; break;
+ case OSD_SignalMode_SetUnhandled: aModeStr = "unhandled"; break;
+ case OSD_SignalMode_Unset: aModeStr = "unset"; break;
}
theDI << "Signal mode: " << aModeStr << "\n"
- << "Catch FPE: " << (OSD::ToCatchFloatingSignals() ? "1" : "0") << "\n";
+ << "Catch FPE: " << (OSD::ToCatchFloatingSignals() ? "1" : "0") << "\n"
+ << "Stack Trace Length: " << aStackLen << "\n";
return 0;
}
return 0;
}
+//==============================================================================
+//function : ddebugtraces
+//purpose :
+//==============================================================================
+static int ddebugtraces (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
+{
+ if (theArgNb < 2)
+ {
+ theDI << Standard_Failure::DefaultStackTraceLength();
+ return 0;
+ }
+ else if (theArgNb != 2)
+ {
+ theDI << "Syntax error: wrong number of arguments";
+ return 1;
+ }
+
+ Standard_Failure::SetDefaultStackTraceLength (Draw::Atoi (theArgVec[1]));
+ return 0;
+}
+
//==============================================================================
//function : dputs
//purpose :
__FILE__, dmeminfo, g);
theCommands.Add("dperf","dperf [reset] -- show performance counters, reset if argument is provided",
__FILE__,dperf,g);
- theCommands.Add("dsetsignal","dsetsignal [{asis|set|unhandled|unset}=set] [{0|1|default=$CSF_FPE}]\n -- set OSD signal handler, with FPE option if argument is given",
+ theCommands.Add("dsetsignal",
+ "dsetsignal [{asIs|set|unhandled|unset}=set] [{0|1|default=$CSF_FPE}]"
+ "\n\t\t: [-strackTraceLength Length]"
+ "\n\t\t: Sets OSD signal handler, with FPE option if argument is given."
+ "\n\t\t: -strackTraceLength specifies length of stack trace to put into exceptions redirected from signals.",
__FILE__,dsetsignal,g);
theCommands.Add("dparallel",
__FILE__,decho,g);
theCommands.Add("dtracelevel", "dtracelevel [trace|info|warn|alarm|fail]",
__FILE__, dtracelevel, g);
+ theCommands.Add("ddebugtraces",
+ "ddebugtraces nbTraces"
+ "\n\t\t: Sets the number of lines for the stack trace within Standard_Failure constructor."
+ "\n\t\t: Intended for debug purposes.",
+ __FILE__, ddebugtraces, g);
theCommands.Add("dbreak", "raises Tcl exception if user has pressed Control-Break key",
__FILE__,dbreak,g);
//! not. If yes then raises Exception_CTRL_BREAK.
Standard_EXPORT static void ControlBreak();
+ //! Returns a length of stack trace to be put into exception redirected from signal;
+ //! 0 by default meaning no stack trace.
+ //! @sa Standard_Failure::GetStackString()
+ Standard_EXPORT static Standard_Integer SignalStackTraceLength();
+
+ //! Sets a length of stack trace to be put into exception redirected from signal.
+ Standard_EXPORT static void SetSignalStackTraceLength (Standard_Integer theLength);
+
};
#endif // _OSD_HeaderFile
}
aFailures = TCollection_AsciiString("Multiple exceptions:\n") + aFailures;
- throw Standard_ProgramError (aFailures.ToCString());
+ throw Standard_ProgramError (aFailures.ToCString(), NULL);
}
// =======================================================================
{
TCollection_AsciiString aMsg = TCollection_AsciiString (aFailure.DynamicType()->Name())
+ ": " + aFailure.GetMessageString();
- theFailure = new Standard_ProgramError (aMsg.ToCString());
+ theFailure = new Standard_ProgramError (aMsg.ToCString(), aFailure.GetStackString());
}
catch (std::exception& anStdException)
{
TCollection_AsciiString aMsg = TCollection_AsciiString (typeid(anStdException).name())
+ ": " + anStdException.what();
- theFailure = new Standard_ProgramError (aMsg.ToCString());
+ theFailure = new Standard_ProgramError (aMsg.ToCString(), NULL);
}
catch (...)
{
- theFailure = new Standard_ProgramError ("Error: Unknown exception");
+ theFailure = new Standard_ProgramError ("Error: Unknown exception", NULL);
}
}
#include <Standard_WarningDisableFunctionCast.hxx>
static OSD_SignalMode OSD_WasSetSignal = OSD_SignalMode_AsIs;
+static Standard_Integer OSD_SignalStackTraceLength = 0;
//=======================================================================
//function : SignalMode
return OSD_WasSetSignal;
}
+// =======================================================================
+// function : SignalStackTraceLength
+// purpose :
+// =======================================================================
+Standard_Integer OSD::SignalStackTraceLength()
+{
+ return OSD_SignalStackTraceLength;
+}
+
+// =======================================================================
+// function : SetSignalStackTraceLength
+// purpose :
+// =======================================================================
+void OSD::SetSignalStackTraceLength (Standard_Integer theLength)
+{
+ OSD_SignalStackTraceLength = theLength;
+}
+
#ifdef _WIN32
//---------------------------- Windows NT System --------------------------------
// used to forbid simultaneous execution of setting / executing handlers
static Standard_Mutex THE_SIGNAL_MUTEX;
-static LONG __fastcall _osd_raise ( DWORD, LPSTR );
+static LONG __fastcall _osd_raise (DWORD theCode, const char* theMsg, const char* theStack);
static BOOL WINAPI _osd_ctrl_break_handler ( DWORD );
#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
#ifdef OCC_CONVERT_SIGNALS
-#define THROW_OR_JUMP(Type,Message) Type::NewInstance(Message)->Jump()
+#define THROW_OR_JUMP(Type,Message,Stack) Type::NewInstance(Message,Stack)->Jump()
#else
-#define THROW_OR_JUMP(Type,Message) throw Type(Message)
+#define THROW_OR_JUMP(Type,Message,Stack) throw Type(Message,Stack)
#endif
//=======================================================================
//function : CallHandler
//purpose :
//=======================================================================
-static LONG CallHandler (DWORD dwExceptionCode,
- ptrdiff_t ExceptionInformation1,
- ptrdiff_t ExceptionInformation0)
+static LONG CallHandler (DWORD theExceptionCode,
+ EXCEPTION_POINTERS* theExcPtr)
{
- Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
-
- static wchar_t buffer[2048];
-
- int flterr = 0;
+ ptrdiff_t ExceptionInformation1 = 0, ExceptionInformation0 = 0;
+ if (theExcPtr != NULL)
+ {
+ ExceptionInformation1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
+ ExceptionInformation0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
+ }
- buffer[0] = '\0' ;
+ Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
+ static char aBuffer[2048];
-// std::cout << "CallHandler " << dwExceptionCode << std::endl ;
- switch ( dwExceptionCode ) {
+ bool isFloatErr = false;
+ aBuffer[0] = '\0';
+ switch (theExceptionCode)
+ {
case EXCEPTION_FLT_DENORMAL_OPERAND:
-// std::cout << "CallHandler : EXCEPTION_FLT_DENORMAL_OPERAND:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT DENORMAL OPERAND");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT DENORMAL OPERAND");
+ isFloatErr = true;
+ break;
+ }
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
-// std::cout << "CallHandler : EXCEPTION_FLT_DIVIDE_BY_ZERO:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT DIVIDE BY ZERO");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT DIVIDE BY ZERO");
+ isFloatErr = true;
+ break;
+ }
case EXCEPTION_FLT_INEXACT_RESULT:
-// std::cout << "CallHandler : EXCEPTION_FLT_INEXACT_RESULT:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT INEXACT RESULT");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT INEXACT RESULT");
+ isFloatErr = true;
+ break;
+ }
case EXCEPTION_FLT_INVALID_OPERATION:
-// std::cout << "CallHandler : EXCEPTION_FLT_INVALID_OPERATION:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT INVALID OPERATION");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT INVALID OPERATION");
+ isFloatErr = true;
+ break;
+ }
case EXCEPTION_FLT_OVERFLOW:
-// std::cout << "CallHandler : EXCEPTION_FLT_OVERFLOW:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT OVERFLOW");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT OVERFLOW");
+ isFloatErr = true;
+ break;
+ }
case EXCEPTION_FLT_STACK_CHECK:
-// std::cout << "CallHandler : EXCEPTION_FLT_STACK_CHECK:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT STACK CHECK");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT STACK CHECK");
+ isFloatErr = true;
+ break;
+ }
case EXCEPTION_FLT_UNDERFLOW:
-// std::cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT UNDERFLOW");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT UNDERFLOW");
+ isFloatErr = true;
+ break;
+ }
case STATUS_FLOAT_MULTIPLE_TRAPS:
-// std::cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)");
+ isFloatErr = true;
+ break;
+ }
case STATUS_FLOAT_MULTIPLE_FAULTS:
-// std::cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"FLT MULTIPLE FAULTS");
- flterr = 1 ;
- break ;
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "FLT MULTIPLE FAULTS");
+ isFloatErr = true;
+ break;
+ }
case STATUS_NO_MEMORY:
-// std::cout << "CallHandler : STATUS_NO_MEMORY:" << std::endl ;
- THROW_OR_JUMP (OSD_Exception_STATUS_NO_MEMORY, "MEMORY ALLOCATION ERROR ( no room in the process heap )");
+ {
+ THROW_OR_JUMP (OSD_Exception_STATUS_NO_MEMORY, "MEMORY ALLOCATION ERROR ( no room in the process heap )", NULL);
break;
+ }
case EXCEPTION_ACCESS_VIOLATION:
-// std::cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << std::endl ;
- StringCchPrintfW (buffer, _countof(buffer), L"%s%s%s0x%.8p%s%s%s", L"ACCESS VIOLATION",
- fMsgBox ? L"\n" : L" ", L"at address ",
- ExceptionInformation1 ,
- L" during '",
- ExceptionInformation0 ? L"WRITE" : L"READ",
- L"' operation");
+ {
+ _snprintf_s (aBuffer, sizeof(aBuffer), _TRUNCATE, "%s%s%s0x%.8p%s%s%s", "ACCESS VIOLATION",
+ fMsgBox ? "\n" : " ",
+ "at address ", (void* )ExceptionInformation1,
+ " during '", ExceptionInformation0 ? "WRITE" : "READ", "' operation");
break;
+ }
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
-// std::cout << "CallHandler : EXCEPTION_ARRAY_BOUNDS_EXCEEDED:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"ARRAY BOUNDS EXCEEDED");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "ARRAY BOUNDS EXCEEDED");
break;
+ }
case EXCEPTION_DATATYPE_MISALIGNMENT:
-// std::cout << "CallHandler : EXCEPTION_DATATYPE_MISALIGNMENT:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"DATATYPE MISALIGNMENT");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "DATATYPE MISALIGNMENT");
break;
-
+ }
case EXCEPTION_ILLEGAL_INSTRUCTION:
-// std::cout << "CallHandler : EXCEPTION_ILLEGAL_INSTRUCTION:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"ILLEGAL INSTRUCTION");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "ILLEGAL INSTRUCTION");
break;
-
+ }
case EXCEPTION_IN_PAGE_ERROR:
-// std::cout << "CallHandler : EXCEPTION_IN_PAGE_ERROR:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"IN_PAGE ERROR");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "IN_PAGE ERROR");
break;
-
+ }
case EXCEPTION_INT_DIVIDE_BY_ZERO:
-// std::cout << "CallHandler : EXCEPTION_INT_DIVIDE_BY_ZERO:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"INTEGER DIVISION BY ZERO");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "INTEGER DIVISION BY ZERO");
break;
-
+ }
case EXCEPTION_INT_OVERFLOW:
-// std::cout << "CallHandler : EXCEPTION_INT_OVERFLOW:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"INTEGER OVERFLOW");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "INTEGER OVERFLOW");
break;
-
+ }
case EXCEPTION_INVALID_DISPOSITION:
-// std::cout << "CallHandler : EXCEPTION_INVALID_DISPOSITION:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"INVALID DISPOSITION");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "INVALID DISPOSITION");
break;
-
+ }
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
-// std::cout << "CallHandler : EXCEPTION_NONCONTINUABLE_EXCEPTION:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"NONCONTINUABLE EXCEPTION");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "NONCONTINUABLE EXCEPTION");
break;
-
+ }
case EXCEPTION_PRIV_INSTRUCTION:
-// std::cout << "CallHandler : EXCEPTION_PRIV_INSTRUCTION:" << std::endl ;
- StringCchCopyW (buffer, _countof(buffer), L"PRIVELEGED INSTRUCTION ENCOUNTERED");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "PRIVELEGED INSTRUCTION ENCOUNTERED");
break;
-
+ }
case EXCEPTION_STACK_OVERFLOW:
-// std::cout << "CallHandler : EXCEPTION_STACK_OVERFLOW:" << std::endl ;
+ {
#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) && !defined(OCCT_UWP)
- // try recovering from stack overflow: available in MS VC++ 7.0
+ // try recovering from stack overflow: available in MS VC++ 7.0
if (!_resetstkoflw())
- StringCchCopyW (buffer, _countof(buffer), L"Unrecoverable STACK OVERFLOW");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "Unrecoverable STACK OVERFLOW");
+ }
else
#endif
- StringCchCopyW (buffer, _countof(buffer), L"STACK OVERFLOW");
+ {
+ strcat_s (aBuffer, sizeof(aBuffer), "STACK OVERFLOW");
+ }
break;
-
+ }
default:
- StringCchPrintfW (buffer, _countof(buffer), L"unknown exception code 0x%x, params 0x%p 0x%p",
- dwExceptionCode, ExceptionInformation1, ExceptionInformation0 );
-
- } // end switch
+ {
+ _snprintf_s (aBuffer, sizeof(aBuffer), _TRUNCATE, "unknown exception code 0x%x, params 0x%p 0x%p",
+ theExceptionCode, (void* )ExceptionInformation1, (void* )ExceptionInformation0);
+ }
+ }
// reset FPE state (before message box, otherwise it may fail to show up)
- if ( flterr ) {
+ if (isFloatErr)
+ {
OSD::SetFloatingSignal (Standard_True);
}
-#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
- // provide message to the user with possibility to stop
- size_t idx;
- StringCchLengthW (buffer, _countof(buffer),&idx);
- if ( idx && fMsgBox && dwExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION ) {
- MessageBeep ( MB_ICONHAND );
- int aChoice = ::MessageBoxW (0, buffer, L"OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
+ const int aStackLength = OSD_SignalStackTraceLength;
+ const int aStackBufLen = Max (aStackLength * 200, 2048);
+ char* aStackBuffer = aStackLength != 0 ? (char* )alloca (aStackBufLen) : NULL;
+ if (aStackBuffer != NULL)
+ {
+ memset (aStackBuffer, 0, aStackBufLen);
+ Standard::StackTrace (aStackBuffer, aStackBufLen, aStackLength, theExcPtr->ContextRecord);
+ }
+
+#if !defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
+ // provide message to the user with possibility to stop
+ if (aBuffer[0] != '\0'
+ && fMsgBox
+ && theExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION)
+ {
+ MessageBeep (MB_ICONHAND);
+ char aMsgBoxBuffer[2048];
+ strcat_s (aMsgBoxBuffer, sizeof(aMsgBoxBuffer), aBuffer);
+ if (aStackBuffer != NULL)
+ {
+ strcat_s (aMsgBoxBuffer, sizeof(aMsgBoxBuffer), aStackBuffer);
+ }
+ int aChoice = ::MessageBoxA (0, aMsgBoxBuffer, "OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
if (aChoice == IDRETRY)
{
_osd_debug();
DebugBreak();
- } else if (aChoice == IDABORT)
- exit(0xFFFF);
+ }
+ else if (aChoice == IDABORT)
+ {
+ exit (0xFFFF);
+ }
}
#endif
- char aBufferA[2048];
- WideCharToMultiByte(CP_UTF8, 0, buffer, -1, aBufferA, sizeof(aBufferA), NULL, NULL);
- return _osd_raise(dwExceptionCode, aBufferA);
+ return _osd_raise (theExceptionCode, aBuffer, aStackBuffer);
}
//=======================================================================
std::cout << "signal error" << std::endl ;
switch( sub_code ) {
case _FPE_INVALID :
- CallHandler( EXCEPTION_FLT_INVALID_OPERATION ,0,0) ;
+ CallHandler (EXCEPTION_FLT_INVALID_OPERATION, NULL);
break ;
case _FPE_DENORMAL :
- CallHandler( EXCEPTION_FLT_DENORMAL_OPERAND ,0,0) ;
+ CallHandler (EXCEPTION_FLT_DENORMAL_OPERAND, NULL);
break ;
case _FPE_ZERODIVIDE :
- CallHandler( EXCEPTION_FLT_DIVIDE_BY_ZERO ,0,0) ;
+ CallHandler (EXCEPTION_FLT_DIVIDE_BY_ZERO, NULL);
break ;
case _FPE_OVERFLOW :
- CallHandler( EXCEPTION_FLT_OVERFLOW ,0,0) ;
+ CallHandler (EXCEPTION_FLT_OVERFLOW, NULL);
break ;
case _FPE_UNDERFLOW :
- CallHandler( EXCEPTION_FLT_UNDERFLOW ,0,0) ;
+ CallHandler (EXCEPTION_FLT_UNDERFLOW, NULL);
break ;
case _FPE_INEXACT :
- CallHandler( EXCEPTION_FLT_INEXACT_RESULT ,0,0) ;
+ CallHandler (EXCEPTION_FLT_INEXACT_RESULT, NULL);
break ;
default:
std::cout << "SIGWntHandler(default) -> throw Standard_NumericError(\"Floating Point Error\");" << std::endl;
- THROW_OR_JUMP (Standard_NumericError, "Floating Point Error");
+ THROW_OR_JUMP (Standard_NumericError, "Floating Point Error", NULL);
break ;
}
break ;
case SIGSEGV :
if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
std::cout << "signal error" << std::endl ;
- CallHandler( EXCEPTION_ACCESS_VIOLATION ,0,0) ;
+ CallHandler (EXCEPTION_ACCESS_VIOLATION, NULL);
break ;
case SIGILL :
if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
std::cout << "signal error" << std::endl ;
- CallHandler( EXCEPTION_ILLEGAL_INSTRUCTION ,0,0) ;
+ CallHandler (EXCEPTION_ILLEGAL_INSTRUCTION, NULL);
break ;
default:
std::cout << "SIGWntHandler unexpected signal : " << signum << std::endl ;
static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
{
Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
- ptrdiff_t info1 = 0, info0 = 0;
- if ( theExcPtr ) {
- info1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
- info0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
- }
- CallHandler(theCode, info1, info0);
+ CallHandler (theCode, theExcPtr);
}
#endif
//=======================================================================
static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
{
- DWORD dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
-
- return CallHandler (dwExceptionCode,
- lpXP->ExceptionRecord->ExceptionInformation[1],
- lpXP->ExceptionRecord->ExceptionInformation[0]);
+ DWORD dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
+ return CallHandler (dwExceptionCode, lpXP);
}
//=======================================================================
{
std::cout << "Environment variable CSF_DEBUG_MODE setted.\n";
fMsgBox = Standard_True;
+ if (OSD_SignalStackTraceLength == 0)
+ {
+ // enable stack trace if CSF_DEBUG_MODE is set
+ OSD_SignalStackTraceLength = 10;
+ }
}
else
{
//============================================================================
//==== _osd_raise
//============================================================================
-static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
+static LONG __fastcall _osd_raise (DWORD theCode, const char* theMsg, const char* theStack)
{
- if (msg[0] == '\x03') ++msg;
+ const char* aMsg = theMsg;
+ if (aMsg[0] == '\x03')
+ {
+ ++aMsg;
+ }
- switch (dwCode)
+ switch (theCode)
{
case EXCEPTION_ACCESS_VIOLATION:
- THROW_OR_JUMP (OSD_Exception_ACCESS_VIOLATION, msg);
+ THROW_OR_JUMP (OSD_Exception_ACCESS_VIOLATION, aMsg, theStack);
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- THROW_OR_JUMP (OSD_Exception_ARRAY_BOUNDS_EXCEEDED, msg);
+ THROW_OR_JUMP (OSD_Exception_ARRAY_BOUNDS_EXCEEDED, aMsg, theStack);
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
- THROW_OR_JUMP (Standard_ProgramError, msg);
+ THROW_OR_JUMP (Standard_ProgramError, aMsg, theStack);
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
- THROW_OR_JUMP (OSD_Exception_ILLEGAL_INSTRUCTION, msg);
+ THROW_OR_JUMP (OSD_Exception_ILLEGAL_INSTRUCTION, aMsg, theStack);
break;
case EXCEPTION_IN_PAGE_ERROR:
- THROW_OR_JUMP (OSD_Exception_IN_PAGE_ERROR, msg);
+ THROW_OR_JUMP (OSD_Exception_IN_PAGE_ERROR, aMsg, theStack);
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
- THROW_OR_JUMP (Standard_DivideByZero, msg);
+ THROW_OR_JUMP (Standard_DivideByZero, aMsg, theStack);
break;
case EXCEPTION_INT_OVERFLOW:
- THROW_OR_JUMP (OSD_Exception_INT_OVERFLOW, msg);
+ THROW_OR_JUMP (OSD_Exception_INT_OVERFLOW, aMsg, theStack);
break;
case EXCEPTION_INVALID_DISPOSITION:
- THROW_OR_JUMP (OSD_Exception_INVALID_DISPOSITION, msg);
+ THROW_OR_JUMP (OSD_Exception_INVALID_DISPOSITION, aMsg, theStack);
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- THROW_OR_JUMP (OSD_Exception_NONCONTINUABLE_EXCEPTION, msg);
+ THROW_OR_JUMP (OSD_Exception_NONCONTINUABLE_EXCEPTION, aMsg, theStack);
break;
case EXCEPTION_PRIV_INSTRUCTION:
- THROW_OR_JUMP (OSD_Exception_PRIV_INSTRUCTION, msg);
+ THROW_OR_JUMP (OSD_Exception_PRIV_INSTRUCTION, aMsg, theStack);
break;
case EXCEPTION_STACK_OVERFLOW:
- THROW_OR_JUMP (OSD_Exception_STACK_OVERFLOW, msg);
+ THROW_OR_JUMP (OSD_Exception_STACK_OVERFLOW, aMsg, theStack);
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- THROW_OR_JUMP (Standard_DivideByZero, msg);
+ THROW_OR_JUMP (Standard_DivideByZero, aMsg, theStack);
break;
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_OVERFLOW:
- THROW_OR_JUMP (Standard_Overflow, msg);
+ THROW_OR_JUMP (Standard_Overflow, aMsg, theStack);
break;
case EXCEPTION_FLT_UNDERFLOW:
- THROW_OR_JUMP (Standard_Underflow, msg);
+ THROW_OR_JUMP (Standard_Underflow, aMsg, theStack);
break;
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_INEXACT_RESULT:
case STATUS_FLOAT_MULTIPLE_TRAPS:
case STATUS_FLOAT_MULTIPLE_FAULTS:
- THROW_OR_JUMP (Standard_NumericError, msg);
+ THROW_OR_JUMP (Standard_NumericError, aMsg, theStack);
break;
default:
break;
- } // end switch
+ }
return EXCEPTION_EXECUTE_HANDLER;
-} // end _osd_raise
+}
#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
//============================================================================
#ifdef SA_SIGINFO
static void SegvHandler(const int theSignal,
- siginfo_t *ip,
+ siginfo_t* theSigInfo,
const Standard_Address theContext)
{
- (void)theSignal; // silence GCC warnings
+ (void)theSignal;
(void)theContext;
+ if (theSigInfo != NULL)
+ {
+ sigset_t set;
+ sigemptyset (&set);
+ sigaddset (&set, SIGSEGV);
+ sigprocmask (SIG_UNBLOCK, &set, NULL);
+ void* anAddress = theSigInfo->si_addr;
+ {
+ char aMsg[100];
+ sprintf (aMsg, "SIGSEGV 'segmentation violation' detected. Address %lx.", (long )anAddress);
+
+ const int aStackLength = OSD_SignalStackTraceLength;
+ const int aStackBufLen = Max (aStackLength * 200, 2048);
+ char* aStackBuffer = aStackLength != 0 ? (char* )alloca (aStackBufLen) : NULL;
+ if (aStackBuffer != NULL)
+ {
+ memset (aStackBuffer, 0, aStackBufLen);
+ Standard::StackTrace (aStackBuffer, aStackBufLen, aStackLength);
+ }
-// std::cout << "OSD::SegvHandler activated(SA_SIGINFO)" << std::endl ;
- if ( ip != NULL ) {
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, SIGSEGV);
- sigprocmask (SIG_UNBLOCK, &set, NULL) ;
- void *address = ip->si_addr ;
- {
- char Msg[100];
- sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",
- (long ) address ) ;
- OSD_SIGSEGV::NewInstance(Msg)->Jump();
- }
+ OSD_SIGSEGV::NewInstance (aMsg, aStackBuffer)->Jump();
+ }
}
#ifdef OCCT_DEBUG
- else {
- std::cout << "Wrong undefined address." << std::endl ;
+ else
+ {
+ std::cout << "Wrong undefined address." << std::endl;
}
#endif
- exit(SIGSEGV);
+ exit (SIGSEGV);
}
#elif defined (_hpux) || defined(HPUX)
// pour version 09.07
static void SegvHandler(const int theSignal,
- siginfo_t *ip,
+ siginfo_t* theSigInfo,
const Standard_Address theContext)
{
- unsigned long Space ;
- unsigned long Offset ;
- char Msg[100] ;
-
- if ( theContext != NULL ) {
- Space = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr20 ;
- Offset = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr21 ;
-// std::cout << "Wrong address = " << hex(Offset) << std::endl ;
+ if (theContext != NULL)
+ {
+ unsigned long aSpace = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr20;
+ unsigned long anOffset = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr21;
{
- sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",Offset) ;
- OSD_SIGSEGV::Jump(Msg);
-// scp->sc_pcoq_head = scp->sc_pcoq_tail ; Permettrait de continuer a
-// scp->sc_pcoq_tail = scp->sc_pcoq_tail + 0x4 ; l'intruction suivant le segv.
+ char aMsg[100];
+ sprintf (aMsg, "SIGSEGV 'segmentation violation' detected. Address %lx", anOffset);
+ OSD_SIGSEGV::NewInstance (aMsg)->Jump();
}
}
#ifdef OCCT_DEBUG
- else {
- std::cout << "Wrong undefined address." << std::endl ;
+ else
+ {
+ std::cout << "Wrong undefined address." << std::endl;
}
#endif
- exit(SIGSEGV);
+ exit (SIGSEGV);
}
#endif
return 0;
}
+//! Auxiliary functions for printing synthetic backtrace
+class MyTestInterface : public Standard_Transient
+{
+public:
+ virtual int Standard_NOINLINE testMethod3 (int* theIntPtr, bool theToPrintStack) = 0;
+};
+
+class MyTestClass : public MyTestInterface
+{
+public:
+ MyTestClass() {}
+ virtual int Standard_NOINLINE testMethod3 (int* theIntPtr, bool theToPrintStack)
+ {
+ if (theToPrintStack)
+ {
+ char aMsg[4096] = {};
+ Standard::StackTrace (aMsg, 4096, 10);
+ std::cout << aMsg << "\n";
+ return 0;
+ }
+ *theIntPtr = 4;
+ return *theIntPtr;
+ }
+};
+
+static int Standard_NOINLINE myTestFunction2 (int* theIntPtr, bool theToPrintStack)
+{
+ Handle(MyTestInterface) aTest = new MyTestClass();
+ return aTest->testMethod3 (theIntPtr, theToPrintStack);
+}
+
+static void Standard_NOINLINE myTestFunction1 (bool theToPrintStack)
+{
+ int* anIntPtr = NULL;
+ myTestFunction2 (anIntPtr, theToPrintStack);
+}
+
+static Standard_NOINLINE Standard_Integer OCC30762 (Draw_Interpretor& theDI,
+ Standard_Integer theNbArgs,
+ const char** )
+{
+ if (theNbArgs != 1)
+ {
+ theDI << "Syntax error: wrong number of arguments";
+ return 1;
+ }
+
+ // just print stack
+ std::cout << "Test normal backtrace...\n";
+ myTestFunction1 (true);
+
+ // test access violation
+ {
+ try
+ {
+ OCC_CATCH_SIGNALS
+ std::cout << "Test segmentation Fault...\n";
+ myTestFunction1 (false);
+ std::cout << "Error: writing by NULL address - no exception is raised!\n";
+ }
+ #ifdef _WIN32
+ catch (OSD_Exception_ACCESS_VIOLATION const& aSegException)
+ #else
+ catch (OSD_SIGSEGV const& aSegException)
+ #endif
+ {
+ theDI << " Caught (";
+ theDI << aSegException.GetMessageString();
+ theDI << aSegException.GetStackString();
+ theDI << ")... OK\n";
+ }
+ catch (Standard_Failure const& anException)
+ {
+ theDI << " Caught (";
+ theDI << anException.GetMessageString();
+ theDI << anException.GetStackString();
+ theDI << ")... KO\n";
+ }
+ }
+ return 0;
+}
+
//! Auxiliary functor.
struct TestParallelFunctor
{
theCommands.Add("OCC5698", "OCC5698 wire", __FILE__, OCC5698, group);
theCommands.Add("OCC6143", "OCC6143 catching signals", __FILE__, OCC6143, group);
theCommands.Add("OCC30775", "OCC30775 catching signals in threads", __FILE__, OCC30775, group);
+ theCommands.Add("OCC30762", "OCC30762 printing backtrace", __FILE__, OCC30762, group);
theCommands.Add("OCC7141", "OCC7141 [nCount] aPath", __FILE__, OCC7141, group);
theCommands.Add("OCC7372", "OCC7372", __FILE__, OCC7372, group);
theCommands.Add("OCC8169", "OCC8169 edge1 edge2 plane", __FILE__, OCC8169, group);
Standard_ShortReal.hxx
Standard_Size.hxx
Standard_SStream.hxx
+Standard_StackTrace.cxx
Standard_Std.hxx
Standard_Stream.hxx
Standard_Strtod.cxx
//! Returns non-zero if some memory has been actually freed.
Standard_EXPORT static Standard_Integer Purge();
+ //! Appends backtrace to a message buffer.
+ //! Stack information might be incomplete in case of stripped binaries.
+ //! Implementation details:
+ //! - Not implemented for Android, iOS, QNX and UWP platforms.
+ //! - On non-Windows platform, this function is a wrapper to backtrace() system call.
+ //! - On Windows (Win32) platform, the function loads DbgHelp.dll dynamically,
+ //! and no stack will be provided if this or companion libraries (SymSrv.dll, SrcSrv.dll, etc.) will not be found;
+ //! .pdb symbols should be provided on Windows platform to retrieve a meaningful stack;
+ //! only x86_64 CPU architecture is currently implemented.
+ //! @param theBuffer [in] [out] message buffer to extend
+ //! @param theBufferSize [in] message buffer size
+ //! @param theNbTraces [in] maximum number of stack traces
+ //! @param theContext [in] optional platform-dependent frame context;
+ //! in case of DbgHelp (Windows) should be a pointer to CONTEXT
+ //! @param theNbTopSkip [in] number of traces on top of the stack to skip
+ //! @return TRUE on success
+ Standard_EXPORT static Standard_Boolean StackTrace (char* theBuffer,
+ const int theBufferSize,
+ const int theNbTraces,
+ void* theContext = NULL,
+ const int theNbTopSkip = 0);
+
};
// include definition of handle to make it always visible
void Throw () const Standard_OVERRIDE { throw *this; } \
public: \
C1() : C2() {} \
- C1(const Standard_CString theMessage) : C2(theMessage) {} \
+ C1(Standard_CString theMessage) : C2(theMessage) {} \
+ C1(Standard_CString theMessage, Standard_CString theStackTrace) \
+ : C2 (theMessage, theStackTrace) {} \
static void Raise(const Standard_CString theMessage = "") { \
Handle(C1) _E = new C1; \
_E->Reraise(theMessage); \
Handle(C1) _E = new C1; \
_E->Reraise (theMessage); \
} \
- static Handle(C1) NewInstance(const Standard_CString theMessage = "") { return new C1(theMessage); } \
+ static Handle(C1) NewInstance(Standard_CString theMessage = "") { return new C1(theMessage); } \
+ static Handle(C1) NewInstance(Standard_CString theMessage, Standard_CString theStackTrace) { return new C1(theMessage, theStackTrace); } \
DEFINE_STANDARD_RTTI_INLINE(C1,C2) \
};
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
+#include <Standard_Failure.hxx>
#include <Standard_ErrorHandler.hxx>
-#include <Standard_Failure.hxx>
#include <Standard_Macro.hxx>
#include <Standard_NoSuchObject.hxx>
#include <Standard_PCharacter.hxx>
#include <Standard_TypeMismatch.hxx>
#include <string.h>
+
IMPLEMENT_STANDARD_RTTIEXT(Standard_Failure,Standard_Transient)
-static Standard_CString allocate_message(const Standard_CString AString)
+namespace
{
- Standard_CString aStr = 0;
- if(AString) {
- const Standard_Size aLen = strlen(AString);
- aStr = (Standard_CString) malloc(aLen+sizeof(Standard_Integer)+1);
- if (aStr) {
- Standard_PCharacter pStr=(Standard_PCharacter)aStr;
- strcpy(pStr+sizeof(Standard_Integer),AString);
- *((Standard_Integer*)aStr) = 1;
- }
+ //! Global last failure object returned by Standard_Failure::Caught().
+ static Standard_THREADLOCAL Handle(Standard_Failure) Standard_Failure_RaisedError;
+
+ //! Global parameter defining default length of stack trace.
+ static Standard_Integer Standard_Failure_DefaultStackTraceLength = 0;
+}
+
+// =======================================================================
+// function : StringRef::allocate_message
+// purpose :
+// =======================================================================
+Standard_Failure::StringRef* Standard_Failure::StringRef::allocate_message (const Standard_CString theString)
+{
+ if (theString == NULL
+ || *theString == '\0')
+ {
+ return NULL;
}
- return aStr;
+
+ const Standard_Size aLen = strlen (theString);
+ StringRef* aStrPtr = (StringRef* )malloc (aLen + sizeof(Standard_Integer) + 1);
+ if (aStrPtr != NULL)
+ {
+ strcpy ((char* )&aStrPtr->Message[0], theString);
+ aStrPtr->Counter = 1;
+ }
+ return aStrPtr;
}
-static Standard_CString copy_message(Standard_CString aMessage)
+// =======================================================================
+// function : StringRef::copy_message
+// purpose :
+// =======================================================================
+Standard_Failure::StringRef* Standard_Failure::StringRef::copy_message (Standard_Failure::StringRef* theString)
{
- Standard_CString aStr = 0;
- if(aMessage) {
- aStr = aMessage;
- (*((Standard_Integer*)aStr))++;
+ if (theString == NULL)
+ {
+ return NULL;
}
- return aStr;
+
+ ++theString->Counter;
+ return theString;
}
-static void deallocate_message(Standard_CString aMessage)
+// =======================================================================
+// function : StringRef::deallocate_message
+// purpose :
+// =======================================================================
+void Standard_Failure::StringRef::deallocate_message (Standard_Failure::StringRef* theString)
{
- if(aMessage) {
- (*((Standard_Integer*)aMessage))--;
- if(*((Standard_Integer*)aMessage)==0)
- free((void*)aMessage);
+ if (theString != NULL)
+ {
+ if (--theString->Counter == 0)
+ {
+ free ((void* )theString);
+ }
}
}
-// ******************************************************************
-// Standard_Failure *
-// ******************************************************************
-static Standard_THREADLOCAL Handle(Standard_Failure) RaisedError;
+// =======================================================================
+// function : Standard_Failure
+// purpose :
+// =======================================================================
+Standard_Failure::Standard_Failure()
+: myMessage (NULL),
+ myStackTrace (NULL)
+{
+ const Standard_Integer aStackLength = Standard_Failure_DefaultStackTraceLength;
+ if (aStackLength > 0)
+ {
+ int aStackBufLen = Max (aStackLength * 200, 2048);
+ char* aStackBuffer = (char* )alloca (aStackBufLen);
+ if (aStackBuffer != NULL)
+ {
+ memset (aStackBuffer, 0, aStackBufLen);
+ if (Standard::StackTrace (aStackBuffer, aStackBufLen, aStackLength, NULL, 1))
+ {
+ myStackTrace = StringRef::allocate_message (aStackBuffer);
+ }
+ }
+ }
+}
-// ------------------------------------------------------------------
-//
-// ------------------------------------------------------------------
-Standard_Failure::Standard_Failure ()
-: myMessage(NULL)
+// =======================================================================
+// function : Standard_Failure
+// purpose :
+// =======================================================================
+Standard_Failure::Standard_Failure (const Standard_CString theDesc)
+: myMessage (NULL),
+ myStackTrace (NULL)
{
+ myMessage = StringRef::allocate_message (theDesc);
+ const Standard_Integer aStackLength = Standard_Failure_DefaultStackTraceLength;
+ if (aStackLength > 0)
+ {
+ int aStackBufLen = Max (aStackLength * 200, 2048);
+ char* aStackBuffer = (char* )alloca (aStackBufLen);
+ if (aStackBuffer != NULL)
+ {
+ memset (aStackBuffer, 0, aStackBufLen);
+ Standard::StackTrace (aStackBuffer, aStackBufLen, aStackLength, NULL, 1);
+ myStackTrace = StringRef::allocate_message (aStackBuffer);
+ }
+ }
}
-// ------------------------------------------------------------------
-// Create returns mutable Failure;
-// ------------------------------------------------------------------
-Standard_Failure::Standard_Failure (const Standard_CString AString)
-: myMessage(NULL)
+// =======================================================================
+// function : Standard_Failure
+// purpose :
+// =======================================================================
+Standard_Failure::Standard_Failure (const Standard_CString theDesc,
+ const Standard_CString theStackTrace)
+: myMessage (NULL),
+ myStackTrace (NULL)
{
- myMessage = allocate_message(AString);
+ myMessage = StringRef::allocate_message (theDesc);
+ myStackTrace = StringRef::allocate_message (theStackTrace);
}
-Standard_Failure::Standard_Failure (const Standard_Failure& theFailure)
-: Standard_Transient(theFailure)
+// =======================================================================
+// function : Standard_Failure
+// purpose :
+// =======================================================================
+Standard_Failure::Standard_Failure (const Standard_Failure& theFailure)
+: Standard_Transient (theFailure),
+ myMessage (NULL),
+ myStackTrace (NULL)
{
- myMessage = copy_message(theFailure.myMessage);
+ myMessage = StringRef::copy_message (theFailure.myMessage);
+ myStackTrace = StringRef::copy_message (theFailure.myStackTrace);
}
+// =======================================================================
+// function : ~Standard_Failure
+// purpose :
+// =======================================================================
Standard_Failure::~Standard_Failure()
{
- deallocate_message(myMessage);
+ StringRef::deallocate_message (myMessage);
+ StringRef::deallocate_message (myStackTrace);
}
-void Standard_Failure::SetMessageString(const Standard_CString AString)
+// =======================================================================
+// function : GetMessageString
+// purpose :
+// =======================================================================
+Standard_CString Standard_Failure::GetMessageString() const
{
- if ( AString == GetMessageString() ) return;
- deallocate_message(myMessage);
- myMessage = allocate_message(AString);
+ return myMessage != NULL
+ ? myMessage->GetMessage()
+ : "";
}
-// ------------------------------------------------------------------
-// Caught (myclass) returns mutable Failure raises NoSuchObject ;
-// ------------------------------------------------------------------
-Handle(Standard_Failure) Standard_Failure::Caught()
+// =======================================================================
+// function : SetMessageString
+// purpose :
+// =======================================================================
+void Standard_Failure::SetMessageString (const Standard_CString theDesc)
{
- return RaisedError ;
+ if (theDesc == GetMessageString())
+ {
+ return;
+ }
+
+ StringRef::deallocate_message (myMessage);
+ myMessage = StringRef::allocate_message (theDesc);
}
-// ------------------------------------------------------------------
-// Raise (myclass; aMessage: CString = "") ;
-// ------------------------------------------------------------------
-void Standard_Failure::Raise (const Standard_CString AString)
+// =======================================================================
+// function : GetStackString
+// purpose :
+// =======================================================================
+Standard_CString Standard_Failure::GetStackString() const
+{
+ return myStackTrace != NULL
+ ? myStackTrace->GetMessage()
+ : "";
+}
+
+// =======================================================================
+// function : SetStackString
+// purpose :
+// =======================================================================
+void Standard_Failure::SetStackString (const Standard_CString theStack)
+{
+ if (theStack == GetStackString())
+ {
+ return;
+ }
+
+ StringRef::deallocate_message (myStackTrace);
+ myStackTrace = StringRef::allocate_message (theStack);
+}
+
+// =======================================================================
+// function : Caught
+// purpose :
+// =======================================================================
+Handle(Standard_Failure) Standard_Failure::Caught()
+{
+ return Standard_Failure_RaisedError;
+}
+
+// =======================================================================
+// function : Raise
+// purpose :
+// =======================================================================
+void Standard_Failure::Raise (const Standard_CString theDesc)
{
- Handle(Standard_Failure) E = new Standard_Failure() ;
- E->Reraise (AString) ;
+ Handle(Standard_Failure) aFailure = new Standard_Failure();
+ aFailure->Reraise (theDesc);
}
-// ------------------------------------------------------------------
-// Raise(myclass; aReason: in out SStream) ;
-// ------------------------------------------------------------------
-void Standard_Failure::Raise (const Standard_SStream& AReason)
+// =======================================================================
+// function : Raise
+// purpose :
+// =======================================================================
+void Standard_Failure::Raise (const Standard_SStream& theReason)
{
- Handle(Standard_Failure) E = new Standard_Failure();
- E->Reraise (AReason);
+ Handle(Standard_Failure) aFailure = new Standard_Failure();
+ aFailure->Reraise (theReason);
}
-// ------------------------------------------------------------------
-// Reraise (me: mutable; aMessage: CString) ;
-// ------------------------------------------------------------------
-void Standard_Failure::Reraise (const Standard_CString AString)
+// =======================================================================
+// function : Reraise
+// purpose :
+// =======================================================================
+void Standard_Failure::Reraise (const Standard_CString theDesc)
{
- SetMessageString(AString);
+ SetMessageString (theDesc);
Reraise();
}
-void Standard_Failure::Reraise (const Standard_SStream& AReason)
+// =======================================================================
+// function : Reraise
+// purpose :
+// =======================================================================
+void Standard_Failure::Reraise (const Standard_SStream& theReason)
{
- SetMessageString(AReason.str().c_str());
+ SetMessageString (theReason.str().c_str());
Reraise();
}
-void Standard_Failure::Reraise ()
+// =======================================================================
+// function : Reraise
+// purpose :
+// =======================================================================
+void Standard_Failure::Reraise()
{
- RaisedError = this;
+ Standard_Failure_RaisedError = this;
Throw();
}
+// =======================================================================
+// function : Jump
+// purpose :
+// =======================================================================
void Standard_Failure::Jump()
{
#if defined (OCC_CONVERT_SIGNALS)
Standard_ErrorHandler::Error (this);
Standard_ErrorHandler::Abort (this);
#else
- RaisedError = this;
+ Standard_Failure_RaisedError = this;
Throw();
#endif
}
-
-// ------------------------------------------------------------------
-// Throw (me) is virtual ;
-// ------------------------------------------------------------------
+// =======================================================================
+// function : Throw
+// purpose :
+// =======================================================================
void Standard_Failure::Throw() const
{
throw *this;
}
-// ------------------------------------------------------------------
-// Print (me; s: in out OStream) returns OStream;
-// ------------------------------------------------------------------
-void Standard_Failure::Print (Standard_OStream& AStream) const
+// =======================================================================
+// function : Print
+// purpose :
+// =======================================================================
+void Standard_Failure::Print (Standard_OStream& theStream) const
+{
+ if (myMessage != NULL)
+ {
+ theStream << DynamicType() << ": " << GetMessageString();
+ }
+ else
+ {
+ theStream << DynamicType();
+ }
+ if (myStackTrace != NULL)
+ {
+ theStream << GetStackString();
+ }
+}
+
+// =======================================================================
+// function : NewInstance
+// purpose :
+// =======================================================================
+Handle(Standard_Failure) Standard_Failure::NewInstance (Standard_CString theString)
{
-if(myMessage){
- AStream << DynamicType() << ": " << GetMessageString();
- }
- else {
- AStream << DynamicType();
- }
+ return new Standard_Failure (theString);
}
-Handle(Standard_Failure) Standard_Failure::NewInstance(const Standard_CString AString)
+// =======================================================================
+// function : NewInstance
+// purpose :
+// =======================================================================
+Handle(Standard_Failure) Standard_Failure::NewInstance (Standard_CString theMessage,
+ Standard_CString theStackTrace)
{
- return new Standard_Failure(AString) ;
+ return new Standard_Failure (theMessage, theStackTrace);
}
-//=======================================================================
-//function : GetMessageString
-//purpose : Returns error message
-//=======================================================================
-Standard_CString Standard_Failure::GetMessageString () const
+// =======================================================================
+// function : GetNbStackTraces
+// purpose :
+// =======================================================================
+Standard_Integer Standard_Failure::DefaultStackTraceLength()
{
- return (myMessage ? myMessage+sizeof(Standard_Integer) : "");
+ return Standard_Failure_DefaultStackTraceLength;
}
+// =======================================================================
+// function : SetNbStackTraces
+// purpose :
+// =======================================================================
+void Standard_Failure::SetDefaultStackTraceLength (Standard_Integer theNbStackTraces)
+{
+ Standard_Failure_DefaultStackTraceLength = theNbStackTraces;
+}
#ifndef _Standard_Failure_HeaderFile
#define _Standard_Failure_HeaderFile
-#include <Standard.hxx>
#include <Standard_Type.hxx>
#include <Standard_CString.hxx>
#include <Standard_Transient.hxx>
#include <Standard_OStream.hxx>
#include <Standard_SStream.hxx>
-class Standard_NoSuchObject;
-
-class Standard_Failure;
DEFINE_STANDARD_HANDLE(Standard_Failure, Standard_Transient)
-
//! Forms the root of the entire exception hierarchy.
class Standard_Failure : public Standard_Transient
{
-
public:
-
-
//! Creates a status object of type "Failure".
Standard_EXPORT Standard_Failure();
Standard_EXPORT Standard_Failure (const Standard_Failure& f);
//! Creates a status object of type "Failure".
- Standard_EXPORT Standard_Failure(const Standard_CString aString);
+ //! @param theDesc [in] exception description
+ Standard_EXPORT Standard_Failure (const Standard_CString theDesc);
+
+ //! Creates a status object of type "Failure" with stack trace.
+ //! @param theDesc [in] exception description
+ //! @param theStackTrace [in] associated stack trace
+ Standard_EXPORT Standard_Failure (const Standard_CString theDesc,
+ const Standard_CString theStackTrace);
//! Assignment operator
Standard_EXPORT Standard_Failure& operator= (const Standard_Failure& f);
-
+
//! Destructor
Standard_EXPORT ~Standard_Failure();
Standard_EXPORT virtual Standard_CString GetMessageString() const;
//! Sets error message
- Standard_EXPORT virtual void SetMessageString (const Standard_CString aMessage);
-
+ Standard_EXPORT virtual void SetMessageString (const Standard_CString theMessage);
+
+ //! Returns the stack trace string
+ Standard_EXPORT virtual Standard_CString GetStackString() const;
+
+ //! Sets the stack trace string
+ Standard_EXPORT virtual void SetStackString (const Standard_CString theStack);
+
Standard_EXPORT void Reraise();
Standard_EXPORT void Reraise (const Standard_CString aMessage);
//! Reraises a caught exception and changes its error message.
Standard_EXPORT void Reraise (const Standard_SStream& aReason);
-
+
+public:
+
//! Raises an exception of type "Failure" and associates
//! an error message to it. The message can be printed
//! in an exception handler.
//! at run-time.
Standard_EXPORT static void Raise (const Standard_SStream& aReason);
- //! Used to construct an instance of the exception object
- //! as a handle. Shall be used to protect against possible
- //! construction of exception object in C stack -- that is
- //! dangerous since some of methods require that object
- //! was allocated dynamically.
- Standard_EXPORT static Handle(Standard_Failure) NewInstance (const Standard_CString aMessage);
-
+ //! Used to construct an instance of the exception object as a handle.
+ //! Shall be used to protect against possible construction of exception object in C stack,
+ //! which is dangerous since some of methods require that object was allocated dynamically.
+ Standard_EXPORT static Handle(Standard_Failure) NewInstance (Standard_CString theMessage);
+
+ //! Used to construct an instance of the exception object as a handle.
+ Standard_EXPORT static Handle(Standard_Failure) NewInstance (Standard_CString theMessage,
+ Standard_CString theStackTrace);
+
+ //! Returns the default length of stack trace to be captured by Standard_Failure constructor;
+ //! 0 by default meaning no stack trace.
+ Standard_EXPORT static Standard_Integer DefaultStackTraceLength();
+
+ //! Sets default length of stack trace to be captured by Standard_Failure constructor.
+ Standard_EXPORT static void SetDefaultStackTraceLength (Standard_Integer theNbStackTraces);
+
+public:
+
//! Used to throw CASCADE exception from C signal handler.
//! On platforms that do not allow throwing C++ exceptions
//! from this handler (e.g. Linux), uses longjump to get to
Standard_DEPRECATED("This method is deprecated (not thread-safe), use standard C++ mechanism instead")
Standard_EXPORT static Handle(Standard_Failure) Caught();
-
-
DEFINE_STANDARD_RTTIEXT(Standard_Failure,Standard_Transient)
protected:
-
//! Used only if standard C++ exceptions are used.
//! Throws exception of the same type as this by C++ throw,
//! and stores current object as last thrown exception,
//! to be accessible by method Caught()
Standard_EXPORT virtual void Throw() const;
+private:
+ //! Reference-counted string,
+ //! Memory block is allocated with an extra 4-byte header (int representing number of references)
+ //! using low-level malloc() to avoid exceptions.
+ struct StringRef
+ {
+ Standard_Integer Counter;
+ Standard_Character Message[1];
-private:
+ //! Return message string.
+ Standard_CString GetMessage() const { return (Standard_CString )&Message[0]; }
+ //! Allocate reference-counted message string.
+ static StringRef* allocate_message (Standard_CString theString);
- Standard_CString myMessage;
+ //! Copy reference-counted message string.
+ static StringRef* copy_message (StringRef* theString);
+
+ //! Release reference-counted message string.
+ static void deallocate_message (StringRef* theString);
+ };
+
+private:
+ StringRef* myMessage;
+ StringRef* myStackTrace;
};
-inline Standard_OStream& operator << (Standard_OStream& AStream,
- const Handle(Standard_Failure)& AFailure)
+// =======================================================================
+// function : operator<<
+// purpose :
+// =======================================================================
+inline Standard_OStream& operator<< (Standard_OStream& theStream,
+ const Handle(Standard_Failure)& theFailure)
{
- AFailure->Print(AStream);
- return AStream;
+ theFailure->Print (theStream);
+ return theStream;
}
-inline Standard_OStream& operator << (Standard_OStream& AStream,
- const Standard_Failure& AFailure)
+// =======================================================================
+// function : operator<<
+// purpose :
+// =======================================================================
+inline Standard_OStream& operator<< (Standard_OStream& theStream,
+ const Standard_Failure& theFailure)
{
- AFailure.Print(AStream);
- return AStream;
+ theFailure.Print (theStream);
+ return theStream;
}
#endif // _Standard_Failure_HeaderFile
#define Standard_UNUSED
#endif
+//! @def Standard_NOINLINE
+//! Macro for disallowing function inlining.
+//! Expands to "__attribute__((noinline))" on GCC and CLang.
+#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)))
+ #define Standard_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+ #define Standard_NOINLINE __declspec(noinline)
+#else
+ #define Standard_NOINLINE
+#endif
+
//! @def Standard_THREADLOCAL
//! Define Standard_THREADLOCAL modifier as C++11 thread_local keyword where it is available.
#if defined(__clang__)
// global instance must be allocated at load-time
static Handle(Standard_OutOfMemory) anOutOfMemInstance = new Standard_OutOfMemory;
-Handle(Standard_OutOfMemory) Standard_OutOfMemory::NewInstance(const Standard_CString theMessage)
+Handle(Standard_OutOfMemory) Standard_OutOfMemory::NewInstance (Standard_CString theMessage)
{
anOutOfMemInstance->SetMessageString (theMessage);
return anOutOfMemInstance;
}
+Handle(Standard_OutOfMemory) Standard_OutOfMemory::NewInstance (Standard_CString theMessage,
+ Standard_CString theStackTrace)
+{
+ anOutOfMemInstance->SetMessageString (theMessage);
+ anOutOfMemInstance->SetStackString (theStackTrace);
+ return anOutOfMemInstance;
+}
+
//=======================================================================
//function : Throw
//purpose :
Standard_EXPORT static void Raise(Standard_SStream& theMessage);
//! Returns global instance of exception
- Standard_EXPORT static Handle(Standard_OutOfMemory) NewInstance(const Standard_CString theMessage = "");
+ Standard_EXPORT static Handle(Standard_OutOfMemory) NewInstance (Standard_CString theMessage = "");
+
+ //! Returns global instance of exception
+ Standard_EXPORT static Handle(Standard_OutOfMemory) NewInstance (Standard_CString theMessage,
+ Standard_CString theStackTrace);
DEFINE_STANDARD_RTTIEXT(Standard_OutOfMemory,Standard_ProgramError)
--- /dev/null
+// Created on: 2020-11-30
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Standard.hxx>
+
+#include <Message.hxx>
+#include <Standard_Mutex.hxx>
+
+#if defined(__APPLE__)
+ #import <TargetConditionals.h>
+#endif
+
+#if defined(__EMSCRIPTEN__)
+ #include <emscripten/emscripten.h>
+#elif defined(__ANDROID__)
+ //#include <unwind.h>
+#elif defined(__QNX__)
+ //#include <backtrace.h> // requires linking to libbacktrace
+#elif !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
+ #include <execinfo.h>
+#elif defined(_WIN32) && !defined(OCCT_UWP)
+
+#include <Standard_WarningsDisable.hxx>
+ #include <dbghelp.h>
+#include <Standard_WarningsRestore.hxx>
+
+//! This is a wrapper of DbgHelp library loaded dynamically.
+//! DbgHelp is coming with Windows SDK, so that technically it is always available.
+//! However, it's usage requires extra steps:
+//! - .pdb files are necessary to resolve function names;
+//! Normal release DLLs without PDBs will show no much useful info.
+//! - DbgHelp.dll and friends (SymSrv.dll, SrcSrv.dll) should be packaged with application;
+//! DbgHelp.dll coming with system might be of other incompatible version
+//! (some applications load it dynamically to avoid packaging extra DLL,
+//! with a extra hacks determining library version)
+class Standard_DbgHelper
+{
+public: // dbgHelp.dll function types
+
+ typedef BOOL (WINAPI *SYMINITIALIZEPROC) (HANDLE, PCSTR, BOOL);
+ typedef BOOL (WINAPI *STACKWALK64PROC) (DWORD, HANDLE, HANDLE, LPSTACKFRAME64,
+ PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
+ PFUNCTION_TABLE_ACCESS_ROUTINE64,
+ PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
+ typedef BOOL (WINAPI *SYMCLEANUPPROC) (HANDLE);
+ typedef BOOL (WINAPI *SYMFROMADDRPROC) (HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
+
+public:
+
+ //! Return global instance.
+ static Standard_DbgHelper& GetDbgHelper()
+ {
+ static Standard_DbgHelper aDbgHelper;
+ return aDbgHelper;
+ }
+
+ //! Return global mutex.
+ static Standard_Mutex& Mutex()
+ {
+ static Standard_Mutex THE_MUTEX_LOCK;
+ return THE_MUTEX_LOCK;
+ }
+
+public:
+
+ SYMINITIALIZEPROC SymInitialize;
+ SYMCLEANUPPROC SymCleanup;
+ STACKWALK64PROC StackWalk64;
+ PFUNCTION_TABLE_ACCESS_ROUTINE64 SymFunctionTableAccess64;
+ PGET_MODULE_BASE_ROUTINE64 SymGetModuleBase64;
+ SYMFROMADDRPROC SymFromAddr;
+
+ //! Return TRUE if library has been loaded.
+ bool IsLoaded() const { return myDbgHelpLib != NULL; }
+
+ //! Return loading error message.
+ const char* ErrorMessage() const { return myError; }
+
+private:
+
+ //! Main constructor.
+ Standard_DbgHelper()
+ : SymInitialize (NULL),
+ SymCleanup (NULL),
+ StackWalk64 (NULL),
+ SymFunctionTableAccess64 (NULL),
+ SymGetModuleBase64 (NULL),
+ SymFromAddr (NULL),
+ myDbgHelpLib (LoadLibraryW (L"DbgHelp.dll")),
+ myError (NULL)
+ {
+ if (myDbgHelpLib == NULL)
+ {
+ myError = "Standard_DbgHelper, Failed to load DbgHelp.dll";
+ return;
+ }
+
+ if ((SymInitialize = (SYMINITIALIZEPROC) GetProcAddress (myDbgHelpLib, "SymInitialize")) == NULL)
+ {
+ myError = "Standard_DbgHelper, Function not found in DbgHelp.dll: SymInitialize";
+ unload();
+ return;
+ }
+ if ((SymCleanup = (SYMCLEANUPPROC) GetProcAddress (myDbgHelpLib, "SymCleanup")) == NULL)
+ {
+ myError = "Standard_DbgHelper, Function not found in DbgHelp.dll: SymCleanup";
+ unload();
+ return;
+ }
+ if ((StackWalk64 = (STACKWALK64PROC) GetProcAddress (myDbgHelpLib, "StackWalk64")) == NULL)
+ {
+ myError = "Standard_DbgHelper, Function not found in DbgHelp.dll: StackWalk64";
+ unload();
+ return;
+ }
+ if ((SymFunctionTableAccess64 = (PFUNCTION_TABLE_ACCESS_ROUTINE64) GetProcAddress (myDbgHelpLib, "SymFunctionTableAccess64")) == NULL)
+ {
+ myError = "Standard_DbgHelper, Function not found in DbgHelp.dll: SymFunctionTableAccess64";
+ unload();
+ return;
+ }
+ if ((SymGetModuleBase64 = (PGET_MODULE_BASE_ROUTINE64) GetProcAddress (myDbgHelpLib, "SymGetModuleBase64")) == NULL)
+ {
+ myError = "Standard_DbgHelper, Function not found in DbgHelp.dll: SymGetModuleBase64";
+ unload();
+ return;
+ }
+ if ((SymFromAddr = (SYMFROMADDRPROC) GetProcAddress (myDbgHelpLib, "SymFromAddr")) == NULL)
+ {
+ myError = "Standard_DbgHelper, Function not found in DbgHelp.dll: SymFromAddr";
+ unload();
+ return;
+ }
+ }
+
+ //! Destructor.
+ ~Standard_DbgHelper()
+ {
+ // we could unload library here, but don't do it as it is kept loaded
+ //unload();
+ }
+
+ //! Unload library.
+ void unload()
+ {
+ if (myDbgHelpLib != NULL)
+ {
+ FreeLibrary (myDbgHelpLib);
+ myDbgHelpLib = NULL;
+ }
+ }
+
+private:
+
+ Standard_DbgHelper (const Standard_DbgHelper& );
+ Standard_DbgHelper& operator= (const Standard_DbgHelper& );
+
+private:
+
+ HMODULE myDbgHelpLib; //!< handle to DbgHelp
+ const char* myError; //!< loading error message
+
+};
+
+#endif
+
+//=======================================================================
+//function : StackTrace
+//purpose :
+//=======================================================================
+Standard_Boolean Standard::StackTrace (char* theBuffer,
+ const int theBufferSize,
+ const int theNbTraces = 10,
+ void* theContext,
+ const int theNbTopSkip)
+{
+ (void )theContext;
+ if (theBufferSize < 1
+ || theNbTraces < 1
+ || theBuffer == NULL
+ || theNbTopSkip < 0)
+ {
+ return false;
+ }
+
+#if defined(__EMSCRIPTEN__)
+ // theNbTraces is ignored
+ // EM_LOG_JS_STACK?
+ return emscripten_get_callstack (EM_LOG_C_STACK | EM_LOG_DEMANGLE | EM_LOG_NO_PATHS | EM_LOG_FUNC_PARAMS, theBuffer, theBufferSize) > 0;
+#elif defined(__ANDROID__)
+ Message::SendTrace ("Standard::StackTrace() is not implemented for this platform");
+ return false;
+#elif defined(__QNX__)
+ // bt_get_backtrace()
+ Message::SendTrace ("Standard::StackTrace() is not implemented for this platform");
+ return false;
+#elif defined(OCCT_UWP) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
+ Message::SendTrace ("Standard::StackTrace() is not implemented for this platform");
+ return false;
+#elif defined(_WIN32)
+ // Each CPU architecture requires manual stack frame setup,
+ // and 32-bit version requires also additional hacks to retrieve current context;
+ // this implementation currently covers only x86_64 architecture.
+#if defined(_M_X64)
+ int aNbTraces = theNbTraces;
+ const HANDLE anHProcess = GetCurrentProcess();
+ const HANDLE anHThread = GetCurrentThread();
+ CONTEXT aCtx;
+ if (theContext != NULL)
+ {
+ memcpy (&aCtx, theContext, sizeof(aCtx));
+ }
+ else
+ {
+ ++aNbTraces;
+ memset (&aCtx, 0, sizeof(aCtx));
+ aCtx.ContextFlags = CONTEXT_FULL;
+ RtlCaptureContext (&aCtx);
+ }
+
+ // DbgHelp is not thread-safe library, hence global lock is used for serial access
+ Standard_Mutex::Sentry aSentry (Standard_DbgHelper::Mutex());
+ Standard_DbgHelper& aDbgHelp = Standard_DbgHelper::GetDbgHelper();
+ if (!aDbgHelp.IsLoaded())
+ {
+ strcat_s (theBuffer, theBufferSize, "\n==Backtrace==\n");
+ strcat_s (theBuffer, theBufferSize, aDbgHelp.ErrorMessage());
+ strcat_s (theBuffer, theBufferSize, "\n=============");
+ return false;
+ }
+
+ aDbgHelp.SymInitialize (anHProcess, NULL, TRUE);
+
+ DWORD anImage = 0;
+ STACKFRAME64 aStackFrame;
+ memset (&aStackFrame, 0, sizeof(aStackFrame));
+
+ anImage = IMAGE_FILE_MACHINE_AMD64;
+ aStackFrame.AddrPC.Offset = aCtx.Rip;
+ aStackFrame.AddrPC.Mode = AddrModeFlat;
+ aStackFrame.AddrFrame.Offset = aCtx.Rsp;
+ aStackFrame.AddrFrame.Mode = AddrModeFlat;
+ aStackFrame.AddrStack.Offset = aCtx.Rsp;
+ aStackFrame.AddrStack.Mode = AddrModeFlat;
+
+ char aModBuffer[MAX_PATH] = {};
+ char aSymBuffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
+ SYMBOL_INFO* aSymbol = (SYMBOL_INFO*) aSymBuffer;
+ aSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+ aSymbol->MaxNameLen = MAX_SYM_NAME;
+
+ int aTopSkip = theNbTopSkip + 1; // skip this function call and specified extra number
+ strcat_s (theBuffer, theBufferSize, "\n==Backtrace==");
+ for (int aLineIter = 0; aLineIter < aNbTraces; ++aLineIter)
+ {
+ BOOL aRes = aDbgHelp.StackWalk64 (anImage, anHProcess, anHThread,
+ &aStackFrame, &aCtx, NULL,
+ aDbgHelp.SymFunctionTableAccess64, aDbgHelp.SymGetModuleBase64, NULL);
+ if (!aRes)
+ {
+ break;
+ }
+
+ if (theContext == NULL && aTopSkip > 0)
+ {
+ --aTopSkip;
+ continue;
+ }
+ if (aStackFrame.AddrPC.Offset == 0)
+ {
+ break;
+ }
+
+ strcat_s (theBuffer, theBufferSize, "\n");
+
+ const DWORD64 aModuleBase = aDbgHelp.SymGetModuleBase64 (anHProcess, aStackFrame.AddrPC.Offset);
+ if (aModuleBase != 0
+ && GetModuleFileNameA ((HINSTANCE) aModuleBase, aModBuffer, MAX_PATH))
+ {
+ strcat_s (theBuffer, theBufferSize, aModBuffer);
+ }
+
+ DWORD64 aDisp = 0;
+ strcat_s (theBuffer, theBufferSize, "(");
+ if (aDbgHelp.SymFromAddr (anHProcess, aStackFrame.AddrPC.Offset, &aDisp, aSymbol))
+ {
+ strcat_s (theBuffer, theBufferSize, aSymbol->Name);
+ }
+ else
+ {
+ strcat_s (theBuffer, theBufferSize, "???");
+ }
+ strcat_s (theBuffer, theBufferSize, ")");
+ }
+ strcat_s (theBuffer, theBufferSize, "\n=============");
+
+ aDbgHelp.SymCleanup (anHProcess);
+ return true;
+#else
+ Message::SendTrace ("Standard::StackTrace() is not implemented for this CPU architecture");
+ return false;
+#endif
+#else
+ const int aTopSkip = theNbTopSkip + 1; // skip this function call and specified extra number
+ int aNbTraces = theNbTraces + aTopSkip;
+ void** aStackArr = (void** )alloca (sizeof(void*) * aNbTraces);
+ if (aStackArr == NULL)
+ {
+ return false;
+ }
+
+ aNbTraces = ::backtrace (aStackArr, aNbTraces);
+ if (aNbTraces <= 1)
+ {
+ return false;
+ }
+
+ aNbTraces -= aTopSkip;
+ char** aStrings = ::backtrace_symbols (aStackArr + aTopSkip, aNbTraces);
+ if (aStrings == NULL)
+ {
+ return false;
+ }
+
+ const size_t aLenInit = strlen (theBuffer);
+ size_t aLimit = (size_t) theBufferSize - aLenInit - 1;
+ if (aLimit > 14)
+ {
+ strcat (theBuffer, "\n==Backtrace==");
+ aLimit -= 14;
+ }
+ for (int aLineIter = 0; aLineIter < aNbTraces; ++aLineIter)
+ {
+ const size_t aLen = strlen (aStrings[aLineIter]);
+ if (aLen + 1 >= aLimit)
+ {
+ break;
+ }
+
+ strcat (theBuffer, "\n");
+ strcat (theBuffer, aStrings[aLineIter]);
+ aLimit -= aLen + 1;
+ }
+ free (aStrings);
+ if (aLimit > 14)
+ {
+ strcat (theBuffer, "\n=============");
+ }
+ return true;
+#endif
+}
--- /dev/null
+puts "================"
+puts "0030762: Foundation Classes - include backtrace within OSD_SIGSEGV on Linux"
+puts "================"
+puts ""
+
+pload QAcommands
+
+dsetsignal set -strackTraceLength 10
+set IsDone [catch {set aResult [OCC30762]} result]
+
+if { ${IsDone} != 0 } {
+ puts "result = ${result}"
+ puts "Error: command raised exception"
+} else {
+ if { [string first "testMethod3" $aResult] != -1 } {
+ puts "OK test case"
+ } else {
+ # stack trace might be missing due to stripped symbols or optimized code
+ #puts "Error: backtrace is not printed"
+ puts "Warning: backtrace is not printed"
+ }
+}