summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixel <pixel@nobis-crew.org>2011-11-21 13:27:53 -0800
committerPixel <pixel@nobis-crew.org>2011-11-21 13:27:53 -0800
commite10639753d7dbd368f5edc2555d75c4b5905ba3b (patch)
tree34b6c4bc2990f48de30d26486426558d643e7ac8
parent071e7f07901309a38c8cb5311aaecaa46c0c3542 (diff)
GeneralException() will now trace the callstack and store this, for debugging purposes.
-rw-r--r--Makefile7
-rw-r--r--includes/Exceptions.h11
-rw-r--r--includes/HttpServer.h2
-rw-r--r--includes/Main.h3
-rw-r--r--src/Exceptions.cc81
-rw-r--r--src/HttpServer.cc10
-rw-r--r--src/Task.cc3
-rw-r--r--tests/test-Http.cc21
8 files changed, 126 insertions, 12 deletions
diff --git a/Makefile b/Makefile
index dcdd255..3854f07 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,8 @@ BINEXT = bin
CPPFLAGS += -fno-strict-aliasing
ifeq ($(DEBUG),)
-CPPFLAGS += -O3 -DNDEBUG
+CPPFLAGS += -g -O3 -DNDEBUG
+LDFLAGS += -g
else
CPPFLAGS += -g -DDEBUG -DEV_VERIFY=3
LDFLAGS += -g
@@ -90,7 +91,7 @@ endif
ifeq ($(SYSTEM),Linux)
CPPFLAGS += -fPIC
- LDFLAGS += -fPIC
+ LDFLAGS += -fPIC -rdynamic
LIBS += pthread dl
CONFIG_H = linux-config.h
ARCH_FLAGS = -march=i686 -m32
@@ -110,6 +111,8 @@ vpath %.cc src:tests
vpath %.c libcoro:libeio:libev:win32/pthreads-win32:win32/iconv:win32/regex
BALAU_SOURCES = \
+Exceptions.cc \
+\
Local.cc \
Threads.cc \
\
diff --git a/includes/Exceptions.h b/includes/Exceptions.h
index 0563090..c397265 100644
--- a/includes/Exceptions.h
+++ b/includes/Exceptions.h
@@ -3,22 +3,27 @@
#include <typeinfo>
#include <cxxabi.h>
#include <BString.h>
+#include <vector>
namespace Balau {
class GeneralException {
public:
- GeneralException(const char * msg) : m_msg(::strdup(msg)) { }
- GeneralException(const String & msg) : m_msg(msg.strdup()) { }
- GeneralException(const GeneralException & e) : m_msg(strdup(e.m_msg)) { }
+ GeneralException(const char * msg) : m_msg(::strdup(msg)) { genTrace(); }
+ GeneralException(const String & msg) : m_msg(msg.strdup()) { genTrace(); }
+ GeneralException(const GeneralException & e) : m_msg(strdup(e.m_msg)), m_trace(e.m_trace) { }
~GeneralException() { if (m_msg) free(m_msg); }
const char * getMsg() const { return m_msg; }
+ const std::vector<String> getTrace() const { return m_trace; }
protected:
GeneralException() : m_msg(0) { }
void setMsg(char * msg) { if (m_msg) free(m_msg); m_msg = msg; }
+ void genTrace();
+
private:
char * m_msg;
+ std::vector<String> m_trace;
};
static inline void * malloc(size_t size) throw (GeneralException) {
diff --git a/includes/HttpServer.h b/includes/HttpServer.h
index f78a816..51c119c 100644
--- a/includes/HttpServer.h
+++ b/includes/HttpServer.h
@@ -27,7 +27,7 @@ class HttpServer {
void unref() { if (Atomic::Decrement(&m_refCount) == 0) delete this; }
void ref() { Atomic::Increment(&m_refCount); }
void registerMe(HttpServer * server) { server->registerAction(this); }
- virtual bool Do(HttpServer * server, Http::Request & req, ActionMatch & match, IO<Handle> out) = 0;
+ virtual bool Do(HttpServer * server, Http::Request & req, ActionMatch & match, IO<Handle> out) throw (GeneralException) = 0;
private:
Regex m_regex, m_host;
volatile int m_refCount;
diff --git a/includes/Main.h b/includes/Main.h
index 5fa64c1..1c902ec 100644
--- a/includes/Main.h
+++ b/includes/Main.h
@@ -88,6 +88,9 @@ class Main {
catch (GeneralException e) {
m_status = STOPPING;
Printer::log(M_ERROR | M_ALERT, "The application caused an exception: %s", e.getMsg());
+ std::vector<String> trace = e.getTrace();
+ for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
+ Printer::log(M_DEBUG, "%s", i->to_charp());
r = -1;
}
catch (...) {
diff --git a/src/Exceptions.cc b/src/Exceptions.cc
new file mode 100644
index 0000000..94de408
--- /dev/null
+++ b/src/Exceptions.cc
@@ -0,0 +1,81 @@
+#include "Exceptions.h"
+
+#define MAXTRACE 128
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+void Balau::GeneralException::genTrace() {
+ // taken from http://stackoverflow.com/questions/5693192/win32-backtrace-from-c-code
+ unsigned int i;
+ void * stack[MAXTRACE];
+ unsigned short frames;
+ SYMBOL_INFO * symbol;
+ HANDLE process;
+
+ process = GetCurrentProcess();
+
+ SymInitialize(process, NULL, TRUE);
+
+ frames = CaptureStackBackTrace(0, MAXTRACE, stack, NULL);
+ symbol = (SYMBOL_INFO *) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
+ symbol->MaxNameLen = 255;
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+
+ for (i = 0; i < frames; i++) {
+ SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
+
+ int status;
+ String line;
+ char * demangled = abi::__cxa_demangle(symbol->Name, 0, 0, &status);
+ line.set("%i: 0x%08x (%s)", i, symbol->Address, status == 0 ? demangled : symbol->Name);
+ free(demangled);
+ m_trace.push_back(line);
+ }
+
+ free(symbol);
+}
+
+#else
+
+#include <execinfo.h>
+#include <dlfcn.h>
+
+void Balau::GeneralException::genTrace() {
+ void * trace[MAXTRACE];
+ int n = backtrace(trace, MAXTRACE);
+ char ** symbols = backtrace_symbols(trace, MAXTRACE);
+
+ if (!symbols)
+ return;
+
+ String line;
+ for (int i = 0; i < n; i++)
+ line += String().set("%08x ", trace[i]);
+
+ m_trace.push_back(line);
+ Dl_info info;
+
+ for (int i = 0; i < n; i++) {
+ int status;
+ String line;
+ dladdr(trace[i], &info);
+ long dist = ((char *) trace[i]) - ((char *) info.dli_saddr);
+ char * demangled;
+ if (info.dli_sname) {
+ demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, &status);
+ } else {
+ demangled = NULL;
+ }
+ line.set("%i: %s(%s%c0x%x) [0x%08x]", i, info.dli_fname, info.dli_sname ? (demangled ? (status == 0 ? demangled : info.dli_sname) : info.dli_sname) : "??", dist < 0 ? '-' : '+', dist < 0 ? -dist : dist, trace[i]);
+ m_trace.push_back(line);
+ if (demangled)
+ free(demangled);
+ }
+
+ free(symbols);
+}
+
+
+#endif
diff --git a/src/HttpServer.cc b/src/HttpServer.cc
index 18dc6c8..7df6406 100644
--- a/src/HttpServer.cc
+++ b/src/HttpServer.cc
@@ -7,6 +7,7 @@ class OutputCheck : public Balau::Handle {
public:
OutputCheck(Balau::IO<Balau::Handle> h) : m_h(h), m_wrote(false) { Assert(m_h->canWrite()); m_name.set("OutputCheck(%s)", m_h->getName()); }
virtual void close() throw (Balau::GeneralException) { m_h->close(); }
+ virtual bool isClosed() { return m_h->isClosed(); }
virtual bool isEOF() { return m_h->isEOF(); }
virtual bool canWrite() { return true; }
virtual const char * getName() { return m_name.to_charp(); }
@@ -429,7 +430,7 @@ bool Balau::HttpWorker::handleClient() {
HttpServer::ActionFound f = m_server->findAction(uri.to_charp(), host.to_charp());
if (f.first) {
- IO<OutputCheck> out(m_socket);
+ IO<OutputCheck> out(new OutputCheck(m_socket));
Http::Request req;
req.method = method;
req.host = host;
@@ -443,13 +444,16 @@ bool Balau::HttpWorker::handleClient() {
persistent = false;
}
catch (GeneralException e) {
- Balau::Printer::elog(Balau::E_HTTPSERVER, "%s got an exception while processing its request: `%s'", m_name.to_charp(), e.getMsg());
+ Printer::log(M_ERROR, "%s got an exception while processing its request: `%s'", m_name.to_charp(), e.getMsg());
+ std::vector<String> trace = e.getTrace();
+ for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
+ Printer::log(M_DEBUG, "%s", i->to_charp());
if (!out->wrote())
send500(e.getMsg());
return false;
}
catch (...) {
- Balau::Printer::elog(Balau::E_HTTPSERVER, "%s got an un unknow exception while processing its request: `%s'", m_name.to_charp());
+ Printer::log(M_ERROR, "%s got an unknow exception while processing its request: `%s'", m_name.to_charp());
if (!out->wrote())
send500("unknow exception");
return false;
diff --git a/src/Task.cc b/src/Task.cc
index 6a94267..5623698 100644
--- a/src/Task.cc
+++ b/src/Task.cc
@@ -61,6 +61,9 @@ void Balau::Task::coroutine() {
}
catch (GeneralException & e) {
Printer::log(M_WARNING, "Task %s at %p caused an exception: `%s' - stopping.", getName(), this, e.getMsg());
+ std::vector<String> trace = e.getTrace();
+ for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
+ Printer::log(M_DEBUG, "%s", i->to_charp());
m_status = FAULTED;
}
catch (...) {
diff --git a/tests/test-Http.cc b/tests/test-Http.cc
index de3c6f3..15ef7de 100644
--- a/tests/test-Http.cc
+++ b/tests/test-Http.cc
@@ -10,10 +10,10 @@ using namespace Balau;
class TestAction : public HttpServer::Action {
public:
TestAction() : Action(Regexes::any) { }
- virtual bool Do(HttpServer * server, Http::Request & req, HttpServer::Action::ActionMatch & match, IO<Handle> out);
+ virtual bool Do(HttpServer * server, Http::Request & req, HttpServer::Action::ActionMatch & match, IO<Handle> out) throw (GeneralException);
};
-bool TestAction::Do(HttpServer * server, Http::Request & req, HttpServer::Action::ActionMatch & match, IO<Handle> out) {
+bool TestAction::Do(HttpServer * server, Http::Request & req, HttpServer::Action::ActionMatch & match, IO<Handle> out) throw (GeneralException) {
static const char str[] =
"HTTP/1.1 200 Found\r\n"
"Content-Type: text/html; charset=UTF-8\r\n"
@@ -36,7 +36,20 @@ bool TestAction::Do(HttpServer * server, Http::Request & req, HttpServer::Action
return true;
}
+Balau::Regex testFailureURL("^/failure.html$");
+
+class TestFailure : public HttpServer::Action {
+ public:
+ TestFailure() : Action(testFailureURL) { }
+ virtual bool Do(HttpServer * server, Http::Request & req, HttpServer::Action::ActionMatch & match, IO<Handle> out) throw (GeneralException);
+};
+
+bool TestFailure::Do(HttpServer * server, Http::Request & req, HttpServer::Action::ActionMatch & match, IO<Handle> out) throw (GeneralException) {
+ throw GeneralException("Test...");
+}
+
void MainTask::Do() {
+ Printer::enable(M_DEBUG);
Printer::log(M_STATUS, "Test::Http running.");
Thread * tms[4];
@@ -45,8 +58,10 @@ void MainTask::Do() {
tms[i] = TaskMan::createThreadedTaskMan();
HttpServer * s = new HttpServer();
- TestAction * a = new TestAction();
+ HttpServer::Action * a = new TestAction();
+ HttpServer::Action * f = new TestFailure();
a->registerMe(s);
+ f->registerMe(s);
s->setPort(8080);
s->setLocal("localhost");
s->start();