From 995be41cfb2fce2d06361c4b9667281855b4afbf Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Sun, 22 Jun 2014 09:25:10 +0200
Subject: [PATCH] compute backtrace for exception, print for SIGSEGV

---
 alib2/src/AlibException.cpp      | 20 ++++++-
 alib2/src/AlibException.h        |  7 +++
 alib2/src/std/sigsegvHandler.cpp | 24 +++++++++
 alib2/src/std/sigsegvHandler.h   | 22 ++++++++
 alib2/src/std/stacktrace.h       | 92 ++++++++++++++++++++++++++++++++
 5 files changed, 163 insertions(+), 2 deletions(-)
 create mode 100644 alib2/src/std/sigsegvHandler.cpp
 create mode 100644 alib2/src/std/sigsegvHandler.h
 create mode 100644 alib2/src/std/stacktrace.h

diff --git a/alib2/src/AlibException.cpp b/alib2/src/AlibException.cpp
index 5940c1155f..2f7103eb10 100644
--- a/alib2/src/AlibException.cpp
+++ b/alib2/src/AlibException.cpp
@@ -7,14 +7,26 @@
 
 #include "AlibException.h"
 
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+
+#include <execinfo.h>
+#include "std/stacktrace.h"
+
 namespace alib {
 
 AlibException::AlibException ( ) {
+	this->backtrace = std::stacktrace();
 
+	this->whatMessage += this->backtrace;
 }
 
-AlibException::AlibException ( const std::string & cause ) {
+AlibException::AlibException ( const std::string & cause ) : AlibException() {
 	this->cause = cause;
+	
+	this->whatMessage += this->cause;
 }
 
 AlibException::~AlibException ( ) noexcept {
@@ -22,11 +34,15 @@ AlibException::~AlibException ( ) noexcept {
 }
 
 const char * AlibException::what ( ) const noexcept {
-	return cause.c_str ( );
+	return whatMessage.c_str ( );
 }
 
 const std::string & AlibException::getCause ( ) const {
 	return cause;
 }
 
+const std::string & AlibException::getBacktrace ( ) const {
+	return backtrace;
+}
+
 } /* namespace alib */
diff --git a/alib2/src/AlibException.h b/alib2/src/AlibException.h
index 9c33fd60cb..fe9cb78d6d 100644
--- a/alib2/src/AlibException.h
+++ b/alib2/src/AlibException.h
@@ -21,6 +21,8 @@ class AlibException : public std::exception {
 protected:
 
 	std::string cause;
+	std::string backtrace;
+	std::string whatMessage;
 public:
 
 	AlibException ( );
@@ -37,6 +39,11 @@ public:
 	 */
 	const std::string & getCause ( ) const;
 
+	/**
+	 * @return reason why the exception occured
+	 */
+	const std::string & getBacktrace ( ) const;
+	
 };
 
 } /* namespace alib */
diff --git a/alib2/src/std/sigsegvHandler.cpp b/alib2/src/std/sigsegvHandler.cpp
new file mode 100644
index 0000000000..f44194af74
--- /dev/null
+++ b/alib2/src/std/sigsegvHandler.cpp
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <execinfo.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "sigsegvHandler.h"
+#include "stacktrace.h"
+#include <iostream>
+
+namespace std {
+
+void SigsegvHandler::handler(int sig) {
+	std::cout << std::stacktrace() << std::endl;
+	exit(1);
+}
+
+SigsegvHandler::SigsegvHandler() {
+	signal(SIGSEGV, SigsegvHandler::handler);
+}
+
+SigsegvHandler SigsegvHandler::HANDLER;
+
+} /* namespace std */
diff --git a/alib2/src/std/sigsegvHandler.h b/alib2/src/std/sigsegvHandler.h
new file mode 100644
index 0000000000..a0603fdd0b
--- /dev/null
+++ b/alib2/src/std/sigsegvHandler.h
@@ -0,0 +1,22 @@
+#ifndef ITOS_H_
+#define ITOS_H_
+
+#include <sstream>
+#include <string>
+
+namespace std {
+
+class SigsegvHandler {
+	static void handler(int);
+
+protected:
+
+	SigsegvHandler();
+
+	static SigsegvHandler HANDLER;
+
+};
+
+} /* namespace std */
+
+#endif /* ITOS_H_ */
diff --git a/alib2/src/std/stacktrace.h b/alib2/src/std/stacktrace.h
new file mode 100644
index 0000000000..53740bd4fd
--- /dev/null
+++ b/alib2/src/std/stacktrace.h
@@ -0,0 +1,92 @@
+// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
+// published under the WTFPL v2.0
+
+#ifndef _STACKTRACE_H_
+#define _STACKTRACE_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <execinfo.h>
+#include <cxxabi.h>
+
+#include <sstream>
+#include <string>
+
+namespace std {
+
+/** Print a demangled stack backtrace of the caller function to FILE* out. */
+static inline string stacktrace(unsigned int max_frames = 1000) {
+	stringstream ss;
+	ss << "stack trace:" << endl;
+
+	// storage array for stack trace address data
+	void** addrlist = (void**) malloc( (max_frames + 1 ) * sizeof(void*) );
+
+	// retrieve current stack addresses
+	int addrlen = backtrace(addrlist, max_frames);
+
+	if (addrlen == 0) {
+		ss << "  <empty, possibly corrupt>" << endl;
+		free(addrlist);
+		return std::move(ss).str();
+	}
+
+	// resolve addresses into strings containing "filename(function+address)",
+	// this array must be free()-ed
+	char** symbollist = backtrace_symbols(addrlist, addrlen);
+
+	// allocate string which will be filled with the demangled function name
+	size_t funcnamesize = 256;
+	char* funcname = (char*)malloc(funcnamesize);
+
+	// iterate over the returned symbol lines. skip the first, it is the
+	// address of this function.
+	for (int i = 1; i < addrlen; i++) {
+		char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
+
+		// find parentheses and +address offset surrounding the mangled name:
+		// module(function+0x15c) [0x8048a6d]
+		for (char *p = symbollist[i]; *p; ++p) {
+			if (*p == '(')
+				begin_name = p;
+			else if (*p == '+')
+				begin_offset = p;
+			else if (*p == ')' && begin_offset) {
+				end_offset = p;
+				break;
+			}
+		}
+
+		if (begin_name && begin_offset && end_offset && begin_name < begin_offset) {
+			*begin_name++ = '\0';
+			*begin_offset++ = '\0';
+			*end_offset = '\0';
+
+			// mangled name is now in [begin_name, begin_offset) and caller
+			// offset in [begin_offset, end_offset). now apply
+			// __cxa_demangle():
+
+			int status;
+			char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
+			if (status == 0) {
+				funcname = ret; // use possibly realloc()-ed string
+				ss << "  " << symbollist[i] << " : " << funcname << "+" << begin_offset << endl;
+			} else {
+				// demangling failed. Output function name as a C function with
+				// no arguments.
+				ss << "  " << symbollist[i] << " : " << begin_name << "()+" << begin_offset << endl;
+			}
+		} else {
+			// couldn't parse the line? print the whole line.
+			ss << "  " << symbollist[i] << endl;
+		}
+	}
+	free(funcname);
+	free(symbollist);
+	free(addrlist);
+	return std::move(ss).str();
+}
+
+} /* namespace std */
+
+#endif // _STACKTRACE_H_
-- 
GitLab