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