annotate doodle/core/backtrace.d @ 105:7abaf5c3959f

Merge
author David Bryant <bagnose@gmail.com>
date Sun, 20 Feb 2011 22:27:06 +1030
parents ab745d8b10e5 345fb56d89fc
children bc5baa585b32
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
1 module doodle.core.backtrace;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
2
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
3 //
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
4 // Provides support for a readable backtrace on a program crash.
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
5 //
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
6 // Everything is private - you build this into a library and
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
7 // link to the library, and bingo (via static this).
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
8 //
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
9 // It works by registering a stacktrace handler with the runtime,
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
10 // which, unlike the default one, provides demangled symbols
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
11 // rather than just a list of addresses.
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
12 //
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
13
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
14 private {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
15
50
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
16 import core.stdc.signal;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
17 import core.stdc.stdlib : free;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
18 import core.stdc.string : strlen;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
19 import core.runtime;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
20 import std.demangle;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
21 import std.string;
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
22
50
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
23 extern (C) int backtrace(void**, size_t);
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
24 extern (C) char** backtrace_symbols(void**, int);
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
25
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
26 // signal handler for otherwise-fatal thread-specific signals
66
43cc2135ced0 Some code cleanups
"David Bryant <bagnose@gmail.com>"
parents: 50
diff changeset
27 extern (C) void signalHandler(int sig) {
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
28 string name() {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
29 switch (sig) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
30 case SIGSEGV: return "SIGSEGV";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
31 case SIGFPE: return "SIGFPE";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
32 case SIGILL: return "SIGILL";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
33 case SIGABRT: return "SIGABRT";
88
100dd23c7bdf Ch ch ch changes:
David Bryant <bagnose@gmail.com>
parents: 66
diff changeset
34 case SIGINT: return "SIGINT";
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
35 default: return "";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
36 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
37 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
38
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
39 throw new Error(format("Got signal %s %s", sig, name));
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
40 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
41
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
42 shared static this() {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
43 // set up shared signal handlers for fatal thread-specific signals
66
43cc2135ced0 Some code cleanups
"David Bryant <bagnose@gmail.com>"
parents: 50
diff changeset
44 signal(SIGABRT, &signalHandler);
43cc2135ced0 Some code cleanups
"David Bryant <bagnose@gmail.com>"
parents: 50
diff changeset
45 signal(SIGFPE, &signalHandler);
43cc2135ced0 Some code cleanups
"David Bryant <bagnose@gmail.com>"
parents: 50
diff changeset
46 signal(SIGILL, &signalHandler);
43cc2135ced0 Some code cleanups
"David Bryant <bagnose@gmail.com>"
parents: 50
diff changeset
47 signal(SIGSEGV, &signalHandler);
88
100dd23c7bdf Ch ch ch changes:
David Bryant <bagnose@gmail.com>
parents: 66
diff changeset
48 signal(SIGINT, &signalHandler);
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
49 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
50
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
51 static this() {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
52 // register our trace handler for each thread
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
53 Runtime.traceHandler = &traceHandler;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
54 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
55
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
56 Throwable.TraceInfo traceHandler(void * ptr = null) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
57 return new TraceInfo;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
58 }
50
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
59
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
60 class TraceInfo : Throwable.TraceInfo {
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
61 this() {
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
62 immutable MAXFRAMES = 128;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
63 void*[MAXFRAMES] callstack;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
64
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
65 numframes = backtrace(callstack.ptr, MAXFRAMES);
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
66 framelist = backtrace_symbols(callstack.ptr, numframes);
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
67 }
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
68
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
69 ~this() {
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
70 free(framelist);
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
71 }
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
72
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
73 override string toString() const { return null; } // Why does toString require overriding?
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
74
104
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
75 override int opApply( scope int delegate(ref char[]) dg) {
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
76 return opApply( (ref size_t, ref char[] buf)
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
77 {
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
78 return dg( buf );
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
79 } );
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
80 }
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
81
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
82
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
83 override int opApply(scope int delegate(ref size_t, ref char[]) dg) {
50
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
84 // NOTE: The first 5 frames with the current implementation are
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
85 // inside core.runtime and the object code, so eliminate
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
86 // these for readability.
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
87 immutable FIRSTFRAME = 5;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
88 int ret = 0;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
89
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
90 for(int i = FIRSTFRAME; i < numframes; ++i) {
104
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
91 size_t pos = i - FIRSTFRAME;
50
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
92 char[] text = framelist[i][0 .. strlen(framelist[i])];
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
93
104
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
94 auto a = text.lastIndexOf('(');
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
95 auto b = text.lastIndexOf('+');
50
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
96
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
97 if (a != -1 && b != -1) {
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
98 ++a;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
99 text = format("%s%s%s", text[0..a], demangle(text[a..b].idup), text[b..$]).dup;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
100 }
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
101
104
ab745d8b10e5 Updated to dmd 2.052
David Bryant <bagnose@gmail.com>
parents: 88
diff changeset
102 ret = dg(pos, text);
50
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
103 if (ret)
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
104 break;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
105 }
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
106 return ret;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
107 }
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
108
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
109 private:
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
110 int numframes;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
111 char** framelist;
dfa1e219eafe New version of backtrace based on the one in druntime.
daveb
parents: 45
diff changeset
112 }
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
113 }