Utils: Add backtrace to exception message in SENF_DEBUG builds
g0dil [Wed, 2 Apr 2008 09:16:16 +0000 (09:16 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@774 270642c3-0616-0410-b53a-bc976706d245

Utils/Exception.cc
Utils/Exception.cci
Utils/Exception.hh
Utils/Exception.test.cc
config.hh
senfscons/SENFSCons.py

index f94be75..c86dade 100644 (file)
 //#include "Exception.ih"
 
 // Custom includes
+#include <execinfo.h>
+#include <sstream>
+#include "../config.hh"
+#include "impl/demangle.h"
 
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
@@ -44,6 +48,38 @@ prefix_ char const * senf::Exception::what()
     return message_.c_str();
 }
 
+#ifdef SENF_DEBUG
+prefix_ void senf::Exception::addBacktrace()
+{
+    void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
+    unsigned nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
+    char ** symbols = ::backtrace_symbols(entries, nEntries);
+    
+    std::stringstream ss;
+    ss << "\nException at\n";
+    for (unsigned i=0; i<nEntries; ++i) {
+        std::string sym (symbols[i]);
+        std::string::size_type fnStart (sym.find("("));
+        if (fnStart != std::string::npos) {
+            std::string::size_type fnEnd (sym.find(")",fnStart+1));
+            if (fnEnd != std::string::npos) {
+                std::string fn (sym,fnStart+1, fnEnd-fnStart-1);
+                char * demangled ( ::cplus_demangle(fn.c_str(), 
+                                                    DMGL_TYPES|DMGL_AUTO) );
+                if (demangled) {
+                    ss << "  " << demangled << "( ... )" << std::string(sym,fnEnd+1) << "\n";
+                    continue;
+                }
+            }
+        }
+        ss << "  " << sym << "\n";
+    }
+    ss << "-- \n" << message_;
+    message_ = ss.str();
+    free(symbols);
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::SystemException
 
index b745f80..1b611a2 100644 (file)
 
 prefix_ senf::Exception::Exception(std::string const & description)
     : message_(description)
-{}
+{
+#ifdef SENF_DEBUG
+    addBacktrace();
+#endif
+}
 
 prefix_ std::string const & senf::Exception::message()
     const
index 5f00926..fefe136 100644 (file)
     struct FooException : public senf::Exception
     { FooException() : senf::Exception("Foo hit the fan") {} };
     \endcode
+
+    If SENF is compiled in debug mode (SENF_DEBUG is defined), the exception message will
+    automatically include a stack backtrace. For this to work, you need to add the
+    <tt>-rdynamic</tt> option to all link commands. This feature depends on <tt>gcc</tt> and
+    the GNU-libc.
  */
 
 namespace senf {
@@ -117,6 +122,9 @@ namespace senf {
                                              exceptions. */
 
     private:
+#ifdef SENF_DEBUG
+        void addBacktrace();
+#endif
         std::string message_;
     };
 
index d390062..9a29f71 100644 (file)
@@ -51,7 +51,11 @@ BOOST_AUTO_UNIT_TEST(errnoException)
     catch (senf::SystemException & e) {
         BOOST_CHECK_EQUAL( e.errorNumber(), ENOENT );
         BOOST_CHECK_EQUAL( e.errorString(), "No such file or directory" );
-        BOOST_CHECK_EQUAL( e.what(), "[No such file or directory] ::open()\nmore\nx=1\ny=2" );
+        std::string what (e.what());
+        std::string::size_type pos (what.find("-- \n"));
+        if (pos != std::string::npos)
+            what = std::string(what, pos+4);
+        BOOST_CHECK_EQUAL( what, "[No such file or directory] ::open()\nmore\nx=1\ny=2" );
     }
 }
 
index 44dddeb..c4459cd 100644 (file)
--- a/config.hh
+++ b/config.hh
 #         define SENF_SENFLOG_LIMIT senf::log::NOTICE
 #     endif
 # endif
+#
+# ifndef SENF_DEBUG_BACKTRACE_NUMCALLERS
+#     define SENF_DEBUG_BACKTRACE_NUMCALLERS 64
+# endif
 # 
 # ///////////////////////////////hh.e////////////////////////////////////////
 # endif
index 7956bc3..d31c844 100644 (file)
@@ -253,7 +253,7 @@ def MakeEnvironment():
         #          CPPDEFINES = [ '_GLIBCXX_DEBUG' ],
         env.Append(CXXFLAGS = [ '-O0', '-g', '-fno-inline' ],
                    CPPDEFINES = [ 'SENF_DEBUG' ],
-                   LINKFLAGS = [ '-g' ])
+                   LINKFLAGS = [ '-g', '-rdynamic' ])
 
     env.Append(CPPDEFINES = [ '$EXTRA_DEFINES' ],
                LIBS = [ '$EXTRA_LIBS' ],