Mercurial > projects > ddmd
annotate dbg/CallStackInfo.d @ 189:a4c9de8e39b3
Now compileable with dmd2.053
author | Abscissa |
---|---|
date | Wed, 08 Jun 2011 02:21:32 -0400 |
parents | 43073c7c7769 |
children | 52188e7e3fb5 |
rev | line source |
---|---|
70 | 1 /** |
2 A simple runtime crash handler which collects various informations about | |
3 the crash such as registers, stack traces, and loaded modules. | |
4 | |
5 TODO: | |
6 * Threading support | |
7 * Stack dumps | |
8 | |
9 Authors: | |
10 Jeremie Pelletier | |
11 | |
12 License: | |
13 Public Domain | |
14 */ | |
15 module dbg.CallStackInfo; | |
16 | |
17 import dbg.Debug; | |
18 import dbg.image.PE; | |
19 | |
20 import core.stdc.stdio; | |
21 import core.sys.windows.windows; | |
22 | |
189 | 23 import rt.deh; |
24 | |
70 | 25 class CallStackInfo |
26 { | |
27 this(EXCEPTION_POINTERS* e = null) | |
28 { | |
29 size_t[16] buff; | |
30 size_t[] backtrace = buff[]; | |
31 size_t numTraces = 0; | |
32 | |
33 bool skipFirst = false; | |
34 | |
35 size_t ip = void, bp = void; | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
36 version(Windows) { |
70 | 37 if (e !is null) { |
38 ip = e.ContextRecord.Eip; | |
39 bp = e.ContextRecord.Ebp; | |
40 | |
41 error = _d_translate_se_to_d_exception(e.ExceptionRecord); | |
42 append(backtrace, numTraces, ip); | |
43 } else { | |
44 asm { | |
45 mov bp, EBP; | |
46 } | |
47 } | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
48 } |
70 | 49 |
50 while (true) { | |
51 ip = cast(size_t)*(cast(void**)bp + 1); | |
52 if (ip == 0) break; | |
53 | |
54 append(backtrace, numTraces, ip); | |
55 | |
56 bp = cast(size_t)*cast(void**)bp; | |
57 } | |
58 | |
59 frames = new StackFrameInfo[numTraces]; | |
60 ResolveStackFrames(backtrace[0..numTraces], frames); | |
61 } | |
62 | |
63 Throwable error; | |
64 StackFrameInfo[] frames; | |
65 | |
79 | 66 override string toString() |
67 { | |
70 | 68 string text; |
69 | |
70 if (error !is null) { | |
71 text ~= error.toString() ~ "\n"; | |
72 } | |
73 | |
74 text ~= "Stack trace:\n------------------\n"; | |
75 char buffer[128]; | |
79 | 76 foreach(ref frame; frames) |
77 { | |
78 with(frame.fileLine) if(line) | |
79 { | |
70 | 80 auto len = snprintf(buffer.ptr, buffer.length, "%u", line); |
81 text ~= file ~ ":" ~ buffer[0 .. len] ~ "\r\n"; | |
82 } | |
83 } | |
84 | |
85 text ~= '\0'; | |
86 | |
87 return text; | |
88 } | |
89 | |
79 | 90 void dump() |
91 { | |
70 | 92 if (error !is null) { |
93 printf("%.*s\n", error.toString()); | |
94 } | |
95 | |
96 printf("Stack trace:\n------------------\n"); | |
97 foreach(ref frame; frames) { | |
98 with(frame.fileLine) if (line) { | |
99 printf("%.*s:%d\r\n", file, line); | |
100 } | |
101 } | |
102 } | |
103 | |
104 private: | |
105 | |
106 struct StackFrameInfo { | |
107 size_t va; | |
108 string moduleName; | |
109 SymbolInfo symbol; | |
110 FileLineInfo fileLine; | |
111 } | |
112 | |
113 struct DebugImage { | |
114 DebugImage* next; | |
115 string moduleName; | |
116 size_t baseAddress; | |
117 uint rvaOffset; | |
118 IExecutableImage exeModule; | |
119 ISymbolicDebugInfo debugInfo; | |
120 } | |
121 | |
122 void ResolveStackFrames(size_t[] backtrace, StackFrameInfo[] frames) const { | |
123 StackFrameInfo* frame = void; | |
124 DebugImage* imageList, image = void; | |
125 char[255] buffer = void; | |
126 uint len = void; | |
127 uint rva = void; | |
128 | |
129 version(Windows) MEMORY_BASIC_INFORMATION mbi = void; | |
130 | |
131 foreach(i, va; backtrace) { | |
132 frame = &frames[i]; | |
133 frame.va = va; | |
134 | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
135 version(Windows) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
136 // mbi.Allocation base is the handle to stack frame's module |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
137 VirtualQuery(cast(void*)va, &mbi, MEMORY_BASIC_INFORMATION.sizeof); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
138 if(!mbi.AllocationBase) break; |
70 | 139 |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
140 image = imageList; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
141 while(image) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
142 if(image.baseAddress == cast(size_t)mbi.AllocationBase) break; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
143 image = image.next; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
144 } |
70 | 145 |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
146 if(!image) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
147 image = new DebugImage; |
70 | 148 |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
149 with(*image) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
150 next = imageList; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
151 imageList = image; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
152 baseAddress = cast(size_t)mbi.AllocationBase; |
70 | 153 |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
154 len = GetModuleFileNameA(cast(HMODULE)baseAddress, buffer.ptr, buffer.length); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
155 moduleName = buffer[0 .. len].idup; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
156 if (len != 0) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
157 exeModule = new PEImage(moduleName); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
158 rvaOffset = baseAddress + exeModule.codeOffset; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
159 debugInfo = exeModule.debugInfo; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
160 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
161 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
162 } |
70 | 163 } |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
164 else version(POSIX) |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
165 { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
166 assert(0); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
167 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
168 else static assert(0); |
70 | 169 |
170 frame.moduleName = image.moduleName; | |
171 | |
172 if(!image.debugInfo) continue; | |
173 | |
174 rva = va - image.rvaOffset; | |
175 | |
176 with(image.debugInfo) { | |
177 frame.symbol = ResolveSymbol(rva); | |
178 frame.fileLine = ResolveFileLine(rva); | |
179 } | |
180 } | |
181 | |
182 while(imageList) { | |
183 image = imageList.next; | |
184 delete imageList.debugInfo; | |
185 delete imageList.exeModule; | |
186 delete imageList; | |
187 imageList = image; | |
188 } | |
189 } | |
190 } | |
191 | |
192 void CrashHandlerInit() { | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
193 version(Windows) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
194 //SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
195 SetErrorMode(0); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
196 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
197 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
198 else version(Posix) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
199 assert(0); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
200 /+ sigaction_t sa; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
201 sa.sa_handler = cast(sighandler_t)&SignalHandler; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
202 sigemptyset(&sa.sa_mask); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
203 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
204 |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
205 sigaction(SIGILL, &sa, null); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
206 sigaction(SIGFPE, &sa, null); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
207 sigaction(SIGSEGV, &sa, null);+/ |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
208 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
209 else static assert(0); |
70 | 210 } |
211 enum EXCEPTION_EXECUTE_HANDLER = 1; | |
212 | |
213 extern(Windows) int UnhandledExceptionHandler(EXCEPTION_POINTERS* e) { | |
214 scope CallStackInfo info = new CallStackInfo(e); | |
215 info.dump(); | |
216 | |
217 return EXCEPTION_EXECUTE_HANDLER; | |
218 } | |
219 | |
220 extern (Windows) extern UINT SetErrorMode(UINT); | |
221 alias LONG function(EXCEPTION_POINTERS*) PTOP_LEVEL_EXCEPTION_FILTER; | |
222 extern (Windows) PTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(PTOP_LEVEL_EXCEPTION_FILTER); | |
223 | |
73 | 224 void append(T)(ref T[] array, ref size_t index, T value) |
70 | 225 { |
226 size_t capacity = array.length; | |
227 assert(capacity >= index); | |
228 if (capacity == index) { | |
229 if (capacity < 8) { | |
230 capacity = 8; | |
231 } else { | |
73 | 232 capacity *= 2; |
70 | 233 } |
73 | 234 |
235 array.length = capacity; | |
70 | 236 } |
237 | |
238 array[index++] = value; | |
239 } | |
240 | |
241 struct EXCEPTION_POINTERS { | |
242 EXCEPTION_RECORD* ExceptionRecord; | |
243 CONTEXT* ContextRecord; | |
244 } | |
245 | |
246 const MAXIMUM_SUPPORTED_EXTENSION = 512; | |
247 | |
248 struct CONTEXT { | |
249 DWORD ContextFlags; | |
250 DWORD Dr0; | |
251 DWORD Dr1; | |
252 DWORD Dr2; | |
253 DWORD Dr3; | |
254 DWORD Dr6; | |
255 DWORD Dr7; | |
256 FLOATING_SAVE_AREA FloatSave; | |
257 DWORD SegGs; | |
258 DWORD SegFs; | |
259 DWORD SegEs; | |
260 DWORD SegDs; | |
261 DWORD Edi; | |
262 DWORD Esi; | |
263 DWORD Ebx; | |
264 DWORD Edx; | |
265 DWORD Ecx; | |
266 DWORD Eax; | |
267 DWORD Ebp; | |
268 DWORD Eip; | |
269 DWORD SegCs; | |
270 DWORD EFlags; | |
271 DWORD Esp; | |
272 DWORD SegSs; | |
273 BYTE[MAXIMUM_SUPPORTED_EXTENSION] ExtendedRegisters; | |
274 } | |
275 | |
189 | 276 //extern Throwable _d_translate_se_to_d_exception(EXCEPTION_RECORD* exception_record); |