annotate dlib/CrashHandler.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 2cc604139636
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
1 /**
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
2 A simple runtime crash handler which collects various informations about
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
3 the crash such as registers, stack traces, and loaded modules.
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
4
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
5 TODO:
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
6 * Threading support
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
7 * Stack dumps
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
8
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
9 Authors:
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
10 Jeremie Pelletier
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
11
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
12 License:
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
13 Public Domain
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
14 */
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
15 module dlib.CrashHandler;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
16
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
17 debug = CrashHandler;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
18
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
19 import std.c.stdio;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
20 import dbg.Debug;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
21 import dbg.ui.CrashWindow;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
22
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
23 version(X86) {}
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
24 else static assert(0, "Unsupported architecture.");
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
25
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
26 version(DigitalMars) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
27 //import dlib.dmd.ErrorHandling;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
28 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
29 else static assert(0, "Unsupported compiler.");
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
30
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
31 version(Windows) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
32 import win32.windows;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
33 import win32.psapi;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
34 //import sys.windows.Memory;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
35 //import dlib.Module;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
36 import dbg.image.PE;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
37 import dbg.symbol.CodeView;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
38 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
39 else version(Posix) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
40 import sys.posix.ucontext;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
41 import std.c.signal;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
42 import std.c.stdlib : free, exit, EXIT_FAILURE;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
43 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
44 else static assert(0, "Unsupported platform.");
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
45
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
46 /**
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
47 Register the crash handler
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
48 */
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
49 void CrashHandlerInit() {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
50 version(Windows) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
51 //SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
52 SetErrorMode(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
53 SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
54 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
55 else version(Posix) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
56 sigaction_t sa;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
57 sa.sa_handler = cast(sighandler_t)&SignalHandler;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
58 sigemptyset(&sa.sa_mask);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
59 sa.sa_flags = SA_RESTART | SA_SIGINFO;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
60
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
61 sigaction(SIGILL, &sa, null);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
62 sigaction(SIGFPE, &sa, null);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
63 sigaction(SIGSEGV, &sa, null);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
64 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
65 else static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
66 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
67
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
68 /**
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
69 Information collected by the crash handler
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
70 */
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
71 struct CrashInfo {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
72 struct Registers {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
73 version(X86) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
74 uint EAX, EBX, ECX, EDX;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
75 uint EDI, ESI;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
76 uint EBP, ESP;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
77 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
78 else static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
79 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
80
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
81 struct Module {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
82 string fileName;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
83 ushort[4] fileVersion;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
84 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
85
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
86 Throwable error;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
87 string moduleName;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
88 Registers registers;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
89 size_t[] backtrace;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
90 Module[] modules;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
91
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
92 void Dump() {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
93 // TODO: support more dump methods
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
94 ShowCrashWindow(&this);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
95 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
96
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
97 /**
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
98 Formats the crash info as plain-text
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
99 */
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
100 string toString() {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
101 string text;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
102 char[255] buffer = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
103 uint len = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
104
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
105 text ~= error.toString();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
106 text ~= "\r\n\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
107
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
108 version(X86) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
109 with(registers) len = snprintf(buffer.ptr, buffer.length,
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
110 " Registers:\r\n" ~
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
111 "========================================\r\n" ~
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
112 " EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\r\n" ~
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
113 " EDI=0x%08X ESI=0x%08X EBP=0x%08X ESP=0x%08X\r\n",
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
114 EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
115 );
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
116 text ~= buffer[0 .. len] ~ "\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
117 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
118 else static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
119
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
120 text ~= " Stack Trace:\r\n" ~
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
121 "========================================\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
122
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
123 scope auto frames = new StackFrameInfo[backtrace.length];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
124 ResolveStackFrames(frames);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
125
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
126 foreach(ref frame; frames) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
127 //len = snprintf(buffer.ptr, buffer.length, "%p", frame.va);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
128 //text ~= " " ~ buffer[0 .. len] ~ ": " ~ frame.moduleName ~ "\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
129
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
130 //with(frame.symbol) if(name.length) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
131 // len = snprintf(buffer.ptr, buffer.length, "%X", offset);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
132 // text ~= " " ~ name ~ " @ 0x" ~ buffer[0 .. len] ~ "\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
133 //}
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
134
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
135 with(frame.fileLine) if(line) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
136 len = snprintf(buffer.ptr, buffer.length, "%u", line);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
137 text ~= " " ~ file ~ ":" ~ buffer[0 .. len] ~ "\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
138 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
139
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
140 //text ~= "\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
141 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
142 /+
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
143 text ~= " Loaded Modules:\r\n" ~
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
144 "========================================\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
145
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
146 foreach(mod; modules) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
147 len = snprintf(buffer.ptr, buffer.length, "%hu.%hu.%hu.%hu",
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
148 mod.fileVersion[0], mod.fileVersion[1],
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
149 mod.fileVersion[2], mod.fileVersion[3]);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
150
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
151 text ~= " " ~ mod.fileName ~ "\r\n " ~ buffer[0 .. len] ~ "\r\n";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
152 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
153 +/
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
154 text ~= '\0';
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
155
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
156 return text;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
157 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
158
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
159 private:
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
160
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
161 struct StackFrameInfo {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
162 size_t va;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
163 string moduleName;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
164 SymbolInfo symbol;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
165 FileLineInfo fileLine;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
166 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
167
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
168 struct DebugImage {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
169 DebugImage* next;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
170 string moduleName;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
171 size_t baseAddress;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
172 uint rvaOffset;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
173 IExecutableImage exeModule;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
174 ISymbolicDebugInfo debugInfo;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
175 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
176
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
177 version(X86) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
178 void ResolveStackFrames(StackFrameInfo[] frames) const {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
179 StackFrameInfo* frame = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
180 DebugImage* imageList, image = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
181 char[255] buffer = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
182 uint len = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
183 uint rva = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
184
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
185 version(Windows) MEMORY_BASIC_INFORMATION mbi = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
186
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
187 foreach(i, va; backtrace) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
188 frame = &frames[i];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
189 frame.va = va;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
190
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
191 version(Windows) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
192 // mbi.Allocation base is the handle to stack frame's module
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
193 VirtualQuery(cast(void*)va, &mbi, MEMORY_BASIC_INFORMATION.sizeof);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
194 if(!mbi.AllocationBase) break;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
195
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
196 image = imageList;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
197 while(image) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
198 if(image.baseAddress == cast(size_t)mbi.AllocationBase) break;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
199 image = image.next;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
200 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
201
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
202 if(!image) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
203 image = new DebugImage;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
204
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
205 with(*image) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
206 next = imageList;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
207 imageList = image;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
208 baseAddress = cast(size_t)mbi.AllocationBase;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
209
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
210 len = GetModuleFileNameA(cast(HMODULE)baseAddress, buffer.ptr, buffer.length);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
211 moduleName = buffer[0 .. len].idup;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
212
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
213 exeModule = new PEImage(moduleName);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
214 rvaOffset = baseAddress + exeModule.codeOffset;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
215 debugInfo = exeModule.debugInfo;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
216 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
217 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
218 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
219 else static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
220
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
221 frame.moduleName = image.moduleName;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
222
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
223 if(!image.debugInfo) continue;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
224
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
225 rva = va - image.rvaOffset;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
226
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
227 with(image.debugInfo) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
228 frame.symbol = ResolveSymbol(rva);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
229 frame.fileLine = ResolveFileLine(rva);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
230 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
231 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
232
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
233 while(imageList) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
234 image = imageList.next;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
235 delete imageList.debugInfo;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
236 delete imageList.exeModule;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
237 delete imageList;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
238 imageList = image;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
239 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
240 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
241 } // version(X86)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
242 else static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
243 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
244
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
245 // ----------------------------------------------------------------------------
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
246 // W i n d o w s C r a s h H a n d l e r
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
247 // ----------------------------------------------------------------------------
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
248
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
249 version(Windows) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
250
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
251 extern(C) Throwable _d_translate_se_to_d_exception(EXCEPTION_RECORD* exception_record);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
252
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
253 /**
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
254 D exceptions are built on top of Windows' SEH, a simple registered callback
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
255 will catch any exceptions unwinding past a thread's entry point.
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
256 */
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
257 extern(Windows)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
258 int UnhandledExceptionHandler(EXCEPTION_POINTERS* e) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
259 CrashInfo crashInfo = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
260 char[256] buffer = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
261 uint len = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
262 size_t ip = void, bp = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
263
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
264 try {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
265 with(crashInfo) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
266
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
267 version(DigitalMars)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
268 error = _d_translate_se_to_d_exception(e.ExceptionRecord);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
269 else
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
270 static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
271
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
272 len = GetModuleFileNameA(GetModuleHandle(null), buffer.ptr, buffer.length);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
273 moduleName = buffer[0 .. len].idup;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
274
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
275 version(X86) with(*e.ContextRecord) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
276 with(registers) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
277 EAX = Eax, EBX = Ebx, ECX = Ecx, EDX = Edx;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
278 EDI = Edi, ESI = Esi;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
279 EBP = Ebp, ESP = Esp;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
280 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
281
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
282 ip = Eip;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
283 bp = Ebp;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
284 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
285 else static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
286
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
287 backtrace = null;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
288 while(ip) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
289 backtrace ~= ip;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
290
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
291 ip = cast(size_t)*(cast(void**)bp + 1);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
292 bp = cast(size_t)*cast(void**)bp;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
293 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
294
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
295 HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
296 0, GetCurrentProcessId());
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
297
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
298 if(process == INVALID_HANDLE_VALUE) SystemException();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
299 scope(exit) if(!CloseHandle(process)) SystemException();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
300
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
301 scope HMODULE[] hmodules = new HMODULE[64];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
302 uint size = HMODULE.sizeof * hmodules.length;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
303 uint sizeNeeded = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
304 uint nModules = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
305
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
306 GetModules:
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
307 if(!EnumProcessModules(process, hmodules.ptr, size, &sizeNeeded))
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
308 SystemException();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
309
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
310 nModules = sizeNeeded / HMODULE.sizeof;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
311
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
312 if(sizeNeeded > size) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
313 hmodules.length = nModules;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
314 size = sizeNeeded;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
315 goto GetModules;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
316 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
317
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
318 Module mod = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
319 char[] versionInfo;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
320 VS_FIXEDFILEINFO* fixedVersionInfo = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
321
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
322 modules = null;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
323 foreach(i; 0 .. nModules) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
324 len = GetModuleFileNameA(hmodules[i], buffer.ptr, buffer.length);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
325 mod.fileName = buffer[0 .. len].idup;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
326
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
327 sizeNeeded = GetFileVersionInfoSizeA(buffer.ptr, &size);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
328
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
329 if(sizeNeeded) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
330 if(versionInfo.length < sizeNeeded) versionInfo.length = sizeNeeded;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
331
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
332 if(!GetFileVersionInfoA(buffer.ptr, 0, versionInfo.length, versionInfo.ptr))
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
333 SystemException();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
334
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
335 if(!VerQueryValueA(versionInfo.ptr, cast(char*)"\\".ptr, cast(void**)&fixedVersionInfo, &size))
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
336 SystemException();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
337
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
338 with(*fixedVersionInfo) with(mod) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
339 fileVersion[0] = HIWORD(dwProductVersionMS);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
340 fileVersion[1] = LOWORD(dwProductVersionMS);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
341 fileVersion[2] = HIWORD(dwProductVersionLS);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
342 fileVersion[3] = LOWORD(dwProductVersionLS);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
343 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
344 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
345 else {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
346 mod.fileVersion[] = 0;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
347 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
348
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
349 modules ~= mod;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
350 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
351
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
352 } // with(crashInfo)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
353
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
354 crashInfo.Dump();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
355 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
356 catch(Throwable e) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
357 debug MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Exception Handler Error!", MB_ICONERROR | MB_OK);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
358 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
359
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
360 return EXCEPTION_EXECUTE_HANDLER;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
361 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
362
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
363 } // version(Windows)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
364
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
365 // ----------------------------------------------------------------------------
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
366 // P o s i x C r a s h H a n d l e r
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
367 // ----------------------------------------------------------------------------
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
368
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
369 else version(Posix) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
370
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
371 /**
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
372 This handler catches system signals and throws the appropriate D exception.
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
373 The exception will unwind down to the thread's entry point where it is catched
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
374 and sent to UnhandledExceptionHandler().
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
375 */
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
376 extern(C)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
377 void SignalHandler(int signum, siginfo_t* siginfo, ucontext_t* ucontext) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
378 string msg = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
379
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
380 switch(signum) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
381 case SIGILL: msg = "Illegal instruction"; break;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
382 case SIGFPE: msg = "Floating-point exception"; break;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
383 case SIGSEGV: msg = "Segmentation fault"; break;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
384 default: msg = "Unknown signal";
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
385 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
386
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
387 SystemException e = new SystemException(msg);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
388
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
389 e._context = ucontext;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
390 e.GetBackTrace();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
391
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
392 // The kernel fixed the stack frame to make us believe we called this
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
393 // routine ourselves, with the nasty side effect of losing the faulty
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
394 // routine's address. The undocumented parameter ucontext contains our
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
395 // lost EIP.
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
396 version(X86) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
397 // It should be the 3rd frame:
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
398 // SignalHandler() -> GetBackTrace() -> backtrace()
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
399 if(e._backtrace.length > 2)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
400 e._backtrace[2] = cast(void*)ucontext.uc_mcontext.gregs[REG_EIP];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
401 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
402 else static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
403
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
404 throw e;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
405 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
406
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
407 /**
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
408 This handler is called when an exception unwinds down to the thread's entry
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
409 point, which should catch it and manually call this routine.
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
410 */
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
411 void UnhandledExceptionHandler(Throwable e) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
412 ErrorReport crashInfo = void;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
413
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
414 with(crashInfo) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
415 assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
416 /+error = e;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
417
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
418 // Get the module filename
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
419 // TODO
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
420
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
421 // Dump the general purpose registers
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
422 if(e._context) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
423 gregset_t gregs = e._context.uc_mcontext.gregs;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
424
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
425 version(X86) {
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
426 registers.Eax = gregs[REG_EAX];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
427 registers.Ebx = gregs[REG_EBX];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
428 registers.Ecx = gregs[REG_ECX];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
429 registers.Edx = gregs[REG_EDX];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
430 registers.Edi = gregs[REG_EDI];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
431 registers.Esi = gregs[REG_ESI];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
432 registers.Ebp = gregs[REG_EBP];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
433 registers.Esp = gregs[REG_ESP];
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
434 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
435 else static assert(0);
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
436 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
437
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
438 // Dump stack backtrace
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
439 addresses = e._backtrace;
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
440
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
441 // Dump the loaded modules
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
442 // TODO+/
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
443
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
444 } // with(crashInfo)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
445
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
446 crashInfo.Dump();
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
447 }
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
448
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
449 } // version(Posix)
10317f0c89a5 Initial commit
korDen
parents:
diff changeset
450 else static assert(0);