sptk



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Exception stack traces



Attached is a patch that allows to print stack trace from exception handlers
that catch CException-derived exceptions (did I use word "exception" enough time
while describing this exception handler enhancement?)

In order to enable it, one has to be using g++ to compile SPTK, and
one has to pass --enable-stacktrace option to configure. Otherwise
all this functionality becomes noop.

The interface is rather simple - stack trace info is collected automagically at the moment exception object is created, and handler can use printStackTrace(std::ostream&)
function to output the exception.

Now, one thing that is missing, is printing out of the trace in case exception wasn't caugt. I am pretty sure it is doable, but don't see _much_ point in bothering. If one wants that kind
of thing, just enclose whole main function in try-catch block.

Of course that wouldn't address exception in static object constructor, but such exceptions
are bad idea anyways.

Another TODO, is obviously writing similar functionality for VC++ (which is possible - I know
for sure - I just don't have tools to debug that).

OK to put it in?

--
Ilya A. Volynets-Evenbakh
Total Knowledge. CTO
http://www.total-knowledge.com

diff --git a/configure.in b/configure.in
--- a/configure.in
+++ b/configure.in
@@ -63,6 +63,7 @@ AC_ARG_ENABLE(excel,    [  --enable-exce
 AC_ARG_ENABLE(odbc,     [  --enable-odbc           use ODBC if installed (default=yes)])
 AC_ARG_ENABLE(fltk,     [  --enable-fltk           use FLTK if installed (default=yes)])
 AC_ARG_ENABLE(examples, [  --enable-examples	   build examples (default=no)])
+AC_ARG_ENABLE(stacktrace,[  --enable-stacktrace	    enable stack traces in exception handlers(default=yes)])
 
 if test x$enable_debug = xyes; then
     DEBUGFLAG="-g3 -O0"
@@ -192,6 +193,12 @@ AC_SUBST(POSTBUILD)
 AC_CHECK_LIB(pthread,pthread_rwlock_timedrdlock,AC_DEFINE(HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK,[1],[Have pthread_rwlock_timedrdlock]))
 AC_CHECK_LIB(pthread,pthread_rwlock_timedwrlock,AC_DEFINE(HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK,[1],[Have pthread_rwlock_timedwrlock]))
 
+AC_LANG(C++) dnl switch over to C++, since cxxabi.h is C++ file
+AC_CHECK_HEADERS(execinfo.h cxxabi.h,[], [enable_stacktrace=no])
+if test x"$enable_stacktrace" = xno; then
+    AC_DEFINE(SPTK_STACK_TRACE, [1], [Enable stack traces in exceptions])
+fi
+
 dnl Write all of the files...
 AC_CONFIG_HEADERS(sptk3/sptk-config.h)
 AC_OUTPUT(Makefile sptk3/Makefile sptk3/excel/Makefile sptk3/xml/Makefile examples/Makefile .themes.sptk/Makefile)
@@ -236,6 +243,12 @@ else
    echo "Debug info:     generated ($DEBUGFLAG)"
 fi
 
+if test x"$enable_stacktrace" = x"no"; then
+   echo "Stack traces:   disabled"
+else
+   echo "Stack traces:   enabled"
+fi
+
 if test x$enable_examples = xyes; then
     echo "Examples:	built"
 else
diff --git a/sptk3/CException.h b/sptk3/CException.h
--- a/sptk3/CException.h
+++ b/sptk3/CException.h
@@ -39,6 +39,10 @@ class SP_EXPORT CException : public std:
    std::string m_text;         ///< The exception text
    std::string m_description;  ///< The extended error information
    std::string m_fullMessage;  ///< The complete error information combining everything together
+#ifdef SPTK_EXCEPTION_TRACE
+   typedef __gnu_cxx::slist<std::string> trace_t;
+   trace_t trace; ///< The list of functions on call stack at time of exception creation
+#endif /* SPTK_EXCEPTION_TRACE */
 public:
    /// Constructor
    /// @param text std::string, the exception text
@@ -64,6 +68,10 @@ public:
 
    /// Returns exception description
    std::string description() const { return m_description; }
+
+   /// Pritnts functions that where on call stack
+   /// at the time exception was thrown
+   void printStackTrace(std::ostream& os);
 };
 
 #define throwException(msg) throw CException(msg,__FILE__,__LINE__)
diff --git a/src/CException.cpp b/src/CException.cpp
--- a/src/CException.cpp
+++ b/src/CException.cpp
@@ -27,6 +27,11 @@
 
 #include <sptk3/CException.h>
 #include <sptk3/CStrings.h>
+#ifdef SPTK_EXCEPTION_TRACE
+#include <execinfo.h>
+#include <iostream>
+#include <cxxabi.h>
+#endif /* SPTK_EXCEPTION_TRACE*/
 
 using namespace std;
 
@@ -42,4 +47,41 @@ CException::CException(string text,strin
 
    if (!m_description.empty())
       m_fullMessage += "\n" + m_description;
+
+#ifdef SPTK_EXCEPTION_TRACE
+   {
+	void * array[MAX_TRACE];
+	int nSize = backtrace(array, MAX_TRACE);
+	char ** symbols = backtrace_symbols(array, nSize);
+	for(int i=0;i<nSize;i++){
+		std::string s(symbols[i]);
+		std::string::size_type sz=0,p=s.find('('),p2=std::string::npos;
+		if(p!=std::string::npos){
+			p2=s.find('+',++p);
+		}
+		char* dmName=0;
+		int st=-1;
+		if(p!=std::string::npos && p2!=std::string::npos) {
+			std::string s2=(s.substr(p,p2-p));
+			dmName=abi::__cxa_demangle(s2.c_str(),NULL,&sz,&st);
+		}
+		if(dmName&&st==0){
+			s.replace(p,p2-p,dmName,sz);
+			free(dmName);
+		}
+		trace.push_front(s);
+	}
+	free(symbols);
+   }
+#endif /* SPTK_EXCEPTION_TRACE */
+}
+
+void CException::printStackTrace(std::ostream& os)
+{
+#ifdef SPTK_EXCEPTION_TRACE
+   os<<getMsg()<<":\n";
+   for(trace_t::iterator i=trace.begin();i!=trace.end();i++){
+      os<<*i<<std::endl;
+   }
+#endif /* SPTK_EXCEPTION_TRACE */
 }

List hosted by Total Knowledge

Authoright © Total Knowledge: 2005