module backtrace; // // Provides support for a readable backtrace on a program crash. // // Everything is private - you build this into a library and // link to the library, and bingo (via static this). // // It works by registering a stacktrace handler with the runtime, // which, unlike the default one, provides demangled symbols // rather than just a list of addresses. // private { import core.stdc.signal; import core.stdc.stdlib : free; import core.stdc.string : strlen; import core.runtime; import std.demangle; import std.string; extern (C) int backtrace(void**, size_t); extern (C) char** backtrace_symbols(void**, int); // signal handler for otherwise-fatal thread-specific signals extern (C) void signal_handler(int sig) { string name() { switch (sig) { case SIGSEGV: return "SIGSEGV"; case SIGFPE: return "SIGFPE"; case SIGILL: return "SIGILL"; case SIGABRT: return "SIGABRT"; default: return ""; } } throw new Error(format("Got signal %s %s", sig, name)); } shared static this() { // set up shared signal handlers for fatal thread-specific signals signal(SIGABRT, &signal_handler); signal(SIGFPE, &signal_handler); signal(SIGILL, &signal_handler); signal(SIGSEGV, &signal_handler); } static this() { // register our trace handler for each thread Runtime.traceHandler = &traceHandler; } Throwable.TraceInfo traceHandler(void * ptr = null) { return new TraceInfo; } class TraceInfo : Throwable.TraceInfo { this() { immutable MAXFRAMES = 128; void*[MAXFRAMES] callstack; numframes = backtrace(callstack.ptr, MAXFRAMES); framelist = backtrace_symbols(callstack.ptr, numframes); } ~this() { free(framelist); } override string toString() const { return null; } // Why does toString require overriding? override int opApply(scope int delegate(ref char[]) dg) { // NOTE: The first 5 frames with the current implementation are // inside core.runtime and the object code, so eliminate // these for readability. immutable FIRSTFRAME = 5; int ret = 0; for(int i = FIRSTFRAME; i < numframes; ++i) { char[] text = framelist[i][0 .. strlen(framelist[i])]; int a = text.lastIndexOf('('); int b = text.lastIndexOf('+'); if (a != -1 && b != -1) { ++a; text = format("%s%s%s", text[0..a], demangle(text[a..b].idup), text[b..$]).dup; } ret = dg(text); if (ret) break; } return ret; } private: int numframes; char** framelist; } }