Mercurial > projects > ddmd
annotate dbg/CallStackInfo.d @ 74:7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
author | Eldar Insafutdinov <e.insafutdinov@gmail.com> |
---|---|
date | Sun, 29 Aug 2010 09:43:40 +0100 |
parents | ef02e2e203c2 |
children | 43073c7c7769 |
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 | |
23 class CallStackInfo | |
24 { | |
25 this(EXCEPTION_POINTERS* e = null) | |
26 { | |
27 size_t[16] buff; | |
28 size_t[] backtrace = buff[]; | |
29 size_t numTraces = 0; | |
30 | |
31 bool skipFirst = false; | |
32 | |
33 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
|
34 version(Windows) { |
70 | 35 if (e !is null) { |
36 ip = e.ContextRecord.Eip; | |
37 bp = e.ContextRecord.Ebp; | |
38 | |
39 error = _d_translate_se_to_d_exception(e.ExceptionRecord); | |
40 append(backtrace, numTraces, ip); | |
41 } else { | |
42 asm { | |
43 mov bp, EBP; | |
44 } | |
45 } | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
46 } |
70 | 47 |
48 while (true) { | |
49 ip = cast(size_t)*(cast(void**)bp + 1); | |
50 if (ip == 0) break; | |
51 | |
52 append(backtrace, numTraces, ip); | |
53 | |
54 bp = cast(size_t)*cast(void**)bp; | |
55 } | |
56 | |
57 frames = new StackFrameInfo[numTraces]; | |
58 ResolveStackFrames(backtrace[0..numTraces], frames); | |
59 } | |
60 | |
61 Throwable error; | |
62 StackFrameInfo[] frames; | |
63 | |
64 string toString() { | |
65 string text; | |
66 | |
67 if (error !is null) { | |
68 text ~= error.toString() ~ "\n"; | |
69 } | |
70 | |
71 text ~= "Stack trace:\n------------------\n"; | |
72 char buffer[128]; | |
73 foreach(ref frame; frames) { | |
74 with(frame.fileLine) if(line) { | |
75 auto len = snprintf(buffer.ptr, buffer.length, "%u", line); | |
76 text ~= file ~ ":" ~ buffer[0 .. len] ~ "\r\n"; | |
77 } | |
78 } | |
79 | |
80 text ~= '\0'; | |
81 | |
82 return text; | |
83 } | |
84 | |
85 void dump() { | |
86 if (error !is null) { | |
87 printf("%.*s\n", error.toString()); | |
88 } | |
89 | |
90 printf("Stack trace:\n------------------\n"); | |
91 foreach(ref frame; frames) { | |
92 with(frame.fileLine) if (line) { | |
93 printf("%.*s:%d\r\n", file, line); | |
94 } | |
95 } | |
96 } | |
97 | |
98 private: | |
99 | |
100 struct StackFrameInfo { | |
101 size_t va; | |
102 string moduleName; | |
103 SymbolInfo symbol; | |
104 FileLineInfo fileLine; | |
105 } | |
106 | |
107 struct DebugImage { | |
108 DebugImage* next; | |
109 string moduleName; | |
110 size_t baseAddress; | |
111 uint rvaOffset; | |
112 IExecutableImage exeModule; | |
113 ISymbolicDebugInfo debugInfo; | |
114 } | |
115 | |
116 void ResolveStackFrames(size_t[] backtrace, StackFrameInfo[] frames) const { | |
117 StackFrameInfo* frame = void; | |
118 DebugImage* imageList, image = void; | |
119 char[255] buffer = void; | |
120 uint len = void; | |
121 uint rva = void; | |
122 | |
123 version(Windows) MEMORY_BASIC_INFORMATION mbi = void; | |
124 | |
125 foreach(i, va; backtrace) { | |
126 frame = &frames[i]; | |
127 frame.va = va; | |
128 | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
129 version(Windows) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
130 // 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
|
131 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
|
132 if(!mbi.AllocationBase) break; |
70 | 133 |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
134 image = imageList; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
135 while(image) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
136 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
|
137 image = image.next; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
138 } |
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 if(!image) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
141 image = new DebugImage; |
70 | 142 |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
143 with(*image) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
144 next = imageList; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
145 imageList = image; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
146 baseAddress = cast(size_t)mbi.AllocationBase; |
70 | 147 |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
148 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
|
149 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
|
150 if (len != 0) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
151 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
|
152 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
|
153 debugInfo = exeModule.debugInfo; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
154 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
155 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
156 } |
70 | 157 } |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
158 else version(POSIX) |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
159 { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
160 assert(0); |
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 else static assert(0); |
70 | 163 |
164 frame.moduleName = image.moduleName; | |
165 | |
166 if(!image.debugInfo) continue; | |
167 | |
168 rva = va - image.rvaOffset; | |
169 | |
170 with(image.debugInfo) { | |
171 frame.symbol = ResolveSymbol(rva); | |
172 frame.fileLine = ResolveFileLine(rva); | |
173 } | |
174 } | |
175 | |
176 while(imageList) { | |
177 image = imageList.next; | |
178 delete imageList.debugInfo; | |
179 delete imageList.exeModule; | |
180 delete imageList; | |
181 imageList = image; | |
182 } | |
183 } | |
184 } | |
185 | |
186 void CrashHandlerInit() { | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
187 version(Windows) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
188 //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
|
189 SetErrorMode(0); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
190 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
191 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
192 else version(Posix) { |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
193 assert(0); |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
194 /+ sigaction_t sa; |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
195 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
|
196 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
|
197 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
|
198 |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
199 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
|
200 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
|
201 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
|
202 } |
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
203 else static assert(0); |
70 | 204 } |
205 enum EXCEPTION_EXECUTE_HANDLER = 1; | |
206 | |
207 extern(Windows) int UnhandledExceptionHandler(EXCEPTION_POINTERS* e) { | |
208 scope CallStackInfo info = new CallStackInfo(e); | |
209 info.dump(); | |
210 | |
211 return EXCEPTION_EXECUTE_HANDLER; | |
212 } | |
213 | |
214 extern (Windows) extern UINT SetErrorMode(UINT); | |
215 alias LONG function(EXCEPTION_POINTERS*) PTOP_LEVEL_EXCEPTION_FILTER; | |
216 extern (Windows) PTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(PTOP_LEVEL_EXCEPTION_FILTER); | |
217 | |
73 | 218 void append(T)(ref T[] array, ref size_t index, T value) |
70 | 219 { |
220 size_t capacity = array.length; | |
221 assert(capacity >= index); | |
222 if (capacity == index) { | |
223 if (capacity < 8) { | |
224 capacity = 8; | |
225 } else { | |
73 | 226 capacity *= 2; |
70 | 227 } |
73 | 228 |
229 array.length = capacity; | |
70 | 230 } |
231 | |
232 array[index++] = value; | |
233 } | |
234 | |
235 struct EXCEPTION_POINTERS { | |
236 EXCEPTION_RECORD* ExceptionRecord; | |
237 CONTEXT* ContextRecord; | |
238 } | |
239 | |
240 const size_t EXCEPTION_MAXIMUM_PARAMETERS = 15; | |
241 | |
242 struct EXCEPTION_RECORD { | |
243 DWORD ExceptionCode; | |
244 DWORD ExceptionFlags; | |
245 EXCEPTION_RECORD* ExceptionRecord; | |
246 PVOID ExceptionAddress; | |
247 DWORD NumberParameters; | |
248 DWORD[EXCEPTION_MAXIMUM_PARAMETERS] ExceptionInformation; | |
249 } | |
250 | |
251 const MAXIMUM_SUPPORTED_EXTENSION = 512; | |
252 | |
253 struct CONTEXT { | |
254 DWORD ContextFlags; | |
255 DWORD Dr0; | |
256 DWORD Dr1; | |
257 DWORD Dr2; | |
258 DWORD Dr3; | |
259 DWORD Dr6; | |
260 DWORD Dr7; | |
261 FLOATING_SAVE_AREA FloatSave; | |
262 DWORD SegGs; | |
263 DWORD SegFs; | |
264 DWORD SegEs; | |
265 DWORD SegDs; | |
266 DWORD Edi; | |
267 DWORD Esi; | |
268 DWORD Ebx; | |
269 DWORD Edx; | |
270 DWORD Ecx; | |
271 DWORD Eax; | |
272 DWORD Ebp; | |
273 DWORD Eip; | |
274 DWORD SegCs; | |
275 DWORD EFlags; | |
276 DWORD Esp; | |
277 DWORD SegSs; | |
278 BYTE[MAXIMUM_SUPPORTED_EXTENSION] ExtendedRegisters; | |
279 } | |
280 | |
74
7e0d548de9e6
Switch Arrays of Dsymbols to the new templated Vector type
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
281 extern(C) Throwable _d_translate_se_to_d_exception(EXCEPTION_RECORD* exception_record); |