Mercurial > projects > doodle
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 } |