comparison doodle/core/backtrace.d @ 103:345fb56d89fc

Blind checkpoint
author David Bryant <bagnose@gmail.com>
date Thu, 18 Nov 2010 12:00:02 +1030
parents 100dd23c7bdf
children 7abaf5c3959f
comparison
equal deleted inserted replaced
102:d04c3fe1822c 103:345fb56d89fc
1 module doodle.core.backtrace; 1 module doodle.core.backtrace;
2 2
3 // 3 //
4 // Provides support for a readable backtrace on a program crash. 4 // Register signal handlers and throw Error.
5 // 5 // Technically we shouldn't be throwing an exception from
6 // Everything is private - you build this into a library and 6 // a signal handler, but it happens to work.
7 // link to the library, and bingo (via static this).
8 //
9 // It works by registering a stacktrace handler with the runtime,
10 // which, unlike the default one, provides demangled symbols
11 // rather than just a list of addresses.
12 // 7 //
13 8
14 private { 9 private {
15
16 import core.stdc.signal; 10 import core.stdc.signal;
17 import core.stdc.stdlib : free;
18 import core.stdc.string : strlen;
19 import core.runtime;
20 import std.demangle;
21 import std.string; 11 import std.string;
22
23 extern (C) int backtrace(void**, size_t);
24 extern (C) char** backtrace_symbols(void**, int);
25 12
26 // signal handler for otherwise-fatal thread-specific signals 13 // signal handler for otherwise-fatal thread-specific signals
27 extern (C) void signalHandler(int sig) { 14 extern (C) void signalHandler(int sig) {
28 string name() { 15 string name() {
29 switch (sig) { 16 switch (sig) {
43 // set up shared signal handlers for fatal thread-specific signals 30 // set up shared signal handlers for fatal thread-specific signals
44 signal(SIGABRT, &signalHandler); 31 signal(SIGABRT, &signalHandler);
45 signal(SIGFPE, &signalHandler); 32 signal(SIGFPE, &signalHandler);
46 signal(SIGILL, &signalHandler); 33 signal(SIGILL, &signalHandler);
47 signal(SIGSEGV, &signalHandler); 34 signal(SIGSEGV, &signalHandler);
48 signal(SIGINT, &signalHandler); 35 signal(SIGINT, &signalHandler);
49 }
50
51 static this() {
52 // register our trace handler for each thread
53 Runtime.traceHandler = &traceHandler;
54 }
55
56 Throwable.TraceInfo traceHandler(void * ptr = null) {
57 return new TraceInfo;
58 }
59
60 class TraceInfo : Throwable.TraceInfo {
61 this() {
62 immutable MAXFRAMES = 128;
63 void*[MAXFRAMES] callstack;
64
65 numframes = backtrace(callstack.ptr, MAXFRAMES);
66 framelist = backtrace_symbols(callstack.ptr, numframes);
67 }
68
69 ~this() {
70 free(framelist);
71 }
72
73 override string toString() const { return null; } // Why does toString require overriding?
74
75 override int opApply(scope int delegate(ref char[]) dg) {
76 // NOTE: The first 5 frames with the current implementation are
77 // inside core.runtime and the object code, so eliminate
78 // these for readability.
79 immutable FIRSTFRAME = 5;
80 int ret = 0;
81
82 for(int i = FIRSTFRAME; i < numframes; ++i) {
83 char[] text = framelist[i][0 .. strlen(framelist[i])];
84
85 int a = text.lastIndexOf('(');
86 int b = text.lastIndexOf('+');
87
88 if (a != -1 && b != -1) {
89 ++a;
90 text = format("%s%s%s", text[0..a], demangle(text[a..b].idup), text[b..$]).dup;
91 }
92
93 ret = dg(text);
94 if (ret)
95 break;
96 }
97 return ret;
98 }
99
100 private:
101 int numframes;
102 char** framelist;
103 } 36 }
104 } 37 }