1 /**
2  *   Stacktracing
3  *
4  *   Inclusion of this module activates traced exceptions using the tango own tracers if possible.
5  *
6  *  Copyright: Copyright (C) 2009 h3r3tic
7  *  License:   Tango License, Apache 2.0
8  *  Author:    Tomasz Stachowiak (h3r3tic)
9  */
10 module tango.core.tools.WinStackTrace;
11 
12 version(Windows) {
13 
14 import tango.core.Thread;
15 import tango.core.tools.FrameInfo;
16 
17 version(D_Version2)
18 {
19     private const(char)[] intToUtf8 (char[] tmp, uint val)
20     in {
21          assert (tmp.length > 9, "atoi buffer should be more than 9 chars wide");
22          }
23     body
24     {
25             char* p = tmp.ptr + tmp.length;
26 
27             do {
28                  *--p = cast(char)((val % 10) + '0');
29                  } while (val /= 10);
30 
31             return tmp [cast(size_t)(p - tmp.ptr) .. $];
32     }
33 
34     // function to compare two strings
35     private int stringCompare (in char[] s1, in char[] s2)
36     {
37             auto len = s1.length;
38 
39             if (s2.length < len)
40                     len = s2.length;
41 
42             int result = memcmp(s1.ptr, s2.ptr, len);
43 
44             if (result == 0)
45                     result = (s1.length<s2.length)?-1:((s1.length==s2.length)?0:1);
46 
47             return result;
48     }
49 }
50 
51     private {
52         import tango.core.tools.Demangler;
53         import tango.core.Runtime;
54         static import tango.stdc.stdlib;
55         static import tango.stdc.string;
56         version (StacktraceSpam) import tango.stdc.stdio : printf;
57     }
58 
59     version = StacktraceTryMatchCallAddresses;
60     version = StacktraceTryToBeSmart;
61     //version = UseCustomFiberForDemangling;
62     version = DemangleFunctionNames;
63 
64     struct TraceContext{
65         LPCONTEXT context;
66         HANDLE hProcess;
67         HANDLE hThread;
68     }
69 
70     size_t winAddrBacktrace(TraceContext* winCtx,TraceContext* contextOut,size_t*traceBuf,size_t traceBufLength,int *flags){
71         CONTEXT     context;
72         CONTEXT*    ctxPtr = &context;
73         
74         HANDLE hProcess = void;
75         HANDLE hThread = void;
76         
77         if (winCtx !is null) {
78             ctxPtr=winCtx.context;
79             hProcess=winCtx.hProcess;
80             hThread=winCtx.hThread;
81         } else {
82             uint eipReg, espReg, ebpReg;
83             asm {
84                 call GIMMEH_EIP;
85                 GIMMEH_EIP:
86                     pop EAX;
87                     mov eipReg, EAX;
88                 mov espReg, ESP;
89                 mov ebpReg, EBP;
90             }
91 
92             hProcess = GetCurrentProcess();
93             hThread = GetCurrentThread();
94             
95             context.ContextFlags = CONTEXT_i386 | CONTEXT_CONTROL;
96             GetThreadContext(hThread, &context);
97             context.Eip = eipReg;
98             context.Esp = espReg;
99             context.Ebp = ebpReg;
100         }
101         if (contextOut !is null){
102             contextOut.context=ctxPtr;
103             contextOut.hProcess=hProcess;
104             contextOut.hThread=hThread;
105         }
106         
107         version (StacktraceSpam) printf("Eip: %x, Esp: %x, Ebp: %x\n", ctxPtr.Eip, ctxPtr.Esp, ctxPtr.Ebp);
108     
109         version (StacktraceUseWinApiStackWalking) {
110             // IsBadReadPtr will always return true here
111         } else {
112             if (IsBadReadPtr(cast(void*)ctxPtr.Ebp, 4)) {
113                 ctxPtr.Ebp = ctxPtr.Esp;
114             }
115         }
116 
117         size_t traceLen = 0;
118         walkStack(ctxPtr, hProcess, hThread, delegate void(size_t[]tr){
119             if (tr.length > traceBufLength) {
120                 traceLen = traceBufLength;
121             } else {
122                 traceLen = tr.length;
123             }
124 
125             traceBuf[0..traceLen] = tr[0..traceLen];
126         });
127         
128         version(StacktraceTryMatchCallAddresses){
129             *flags=3;
130         } else {
131             *flags=1;
132         }
133         return traceLen;
134     }
135     
136     
137     bool winSymbolizeFrameInfo(ref FrameInfo fInfo, const(TraceContext) *context,char[] buf){
138         HANDLE hProcess;
139         if (context!is null){
140             hProcess=cast(HANDLE)context.hProcess;
141         } else {
142             hProcess=GetCurrentProcess();
143         }
144         return addrToSymbolDetails(fInfo.address, hProcess, (const(char)[] func, const(char)[] file, int line, ptrdiff_t addrOffset) {
145             if (func.length > buf.length) {
146                 buf[] = func[0..buf.length];
147                 fInfo.func = buf;
148             } else {
149                 buf[0..func.length] = func;
150                 fInfo.func = buf[0..func.length];
151             }
152             fInfo.file = file;
153             fInfo.line = line;
154             fInfo.offsetSymb = addrOffset;
155         });
156     }
157 
158 //#line 2 "parts/Main.di"
159 
160 
161 private extern(C) {
162     void        _Dmain();
163     void        D4core6thread5Fiber3runMFZv();
164 }
165 private {
166     size_t  fiberRunFuncLength = 0;
167 }
168 
169 struct Context
170 {
171     void*    bstack,
172              tstack;
173     Context* within;
174     Context* next,
175              prev;
176 }
177 
178 extern(C) Context* D4core6thread6Thread10topContextMFZPS4core6thread6Thread7Context(core.thread.Thread);
179 alias D4core6thread6Thread10topContextMFZPS4core6thread6Thread7Context Thread_topContext;
180 
181 
182 void walkStack(LPCONTEXT ContextRecord, HANDLE hProcess, HANDLE hThread, void delegate(size_t[]) traceReceiver) {
183     const int maxStackSpace = 32;
184     const int maxHeapSpace      = 256;
185     static assert (maxHeapSpace  > maxStackSpace);
186     
187     size_t[maxStackSpace]   stackTraceArr = void;
188     size_t[]                            heapTraceArr;
189     size_t[]                            stacktrace = stackTraceArr;
190     uint                                i = void;
191     
192     void addAddress(size_t addr) {
193         if (i < maxStackSpace) {
194             stacktrace[i++] = addr;
195         } else {
196             if (maxStackSpace == i) {
197                 if (heapTraceArr is null) {
198                     heapTraceArr.alloc(maxHeapSpace, false);
199                     heapTraceArr[0..maxStackSpace] = stackTraceArr;
200                     stacktrace = heapTraceArr;
201                 }
202                 stacktrace[i++] = addr;
203             } else if (i < maxHeapSpace) {
204                 stacktrace[i++] = addr;
205             }
206         }
207     }
208 
209 
210     version (StacktraceUseWinApiStackWalking) {
211         STACKFRAME64 frame;
212         memset(&frame, 0, frame.sizeof);
213 
214         frame.AddrStack.Offset  = ContextRecord.Esp;
215         frame.AddrPC.Offset     = ContextRecord.Eip;
216         frame.AddrFrame.Offset  = ContextRecord.Ebp;
217         frame.AddrStack.Mode    = frame.AddrPC.Mode = frame.AddrFrame.Mode = ADDRESS_MODE.AddrModeFlat;
218 
219         //for (int sanity = 0; sanity < 256; ++sanity) {
220         for (i = 0; i < maxHeapSpace; ) {
221             auto swres = StackWalk64(
222                 IMAGE_FILE_MACHINE_I386,
223                 hProcess,
224                 hThread,
225                 &frame,
226                 ContextRecord,
227                 null,
228                 SymFunctionTableAccess64,
229                 SymGetModuleBase64,
230                 null
231             );
232             
233             if (!swres) {
234                 break;
235             }
236             
237             version (StacktraceSpam) printf("pc:%x ret:%x frm:%x stk:%x parm:%x %x %x %x\n",
238                     frame.AddrPC.Offset, frame.AddrReturn.Offset, frame.AddrFrame.Offset, frame.AddrStack.Offset,
239                     frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3]);
240 
241             addAddress(frame.AddrPC.Offset);
242         }
243     } else {
244         struct Layout {
245             Layout* ebp;
246             size_t  ret;
247         }
248         Layout* p = cast(Layout*)ContextRecord.Esp;
249         
250         
251         bool foundMain = false;     
252         enum Phase {
253             TryEsp,
254             TryEbp,
255             GiveUp
256         }
257         
258         Phase phase = ContextRecord.Esp == ContextRecord.Ebp ? Phase.TryEbp : Phase.TryEsp;
259         stacktrace[0] = ContextRecord.Eip;
260         
261         version (StacktraceTryToBeSmart) {
262             Thread tobj = Thread.getThis();
263         }
264         
265         while (!foundMain && phase < Phase.GiveUp) {
266             version (StacktraceSpam) printf("starting a new tracing phase\n");
267             
268             version (StacktraceTryToBeSmart) {
269                 auto curStack = Thread_topContext(tobj);
270             }
271             
272             for (i = 1; p && !IsBadReadPtr(p, Layout.sizeof) && i < maxHeapSpace && !IsBadReadPtr(cast(void*)p.ret, 4);) {
273                 auto sym = p.ret;
274                 
275                 enum {
276                     NearPtrCallOpcode = 0xe8,
277                     RegisterBasedCallOpcode = 0xff
278                 }
279 
280                 uint callAddr = p.ret;
281                 if (size_t.sizeof == 4 && !IsBadReadPtr(cast(void*)(p.ret - 5), 8) && NearPtrCallOpcode == *cast(ubyte*)(p.ret - 5)) {
282                     callAddr += *cast(uint*)(p.ret - 4);
283                     version (StacktraceSpam) printf("ret:%x frm:%x call:%x\n", sym, p, callAddr);
284                     version (StacktraceTryMatchCallAddresses) {
285                         addAddress(p.ret - 5);  // a near call is 5 bytes
286                     }
287                 } else {
288                     version (StacktraceTryMatchCallAddresses) {
289                         if (!IsBadReadPtr(cast(void*)p.ret - 2, 4) && RegisterBasedCallOpcode == *cast(ubyte*)(p.ret - 2)) {
290                             version (StacktraceSpam) printf("ret:%x frm:%x register-based call:[%x]\n", sym, p, *cast(ubyte*)(p.ret - 1));
291                             addAddress(p.ret - 2);  // an offset-less register-based call is 2 bytes for the call + register setup
292                         } else if (!IsBadReadPtr(cast(void*)p.ret - 3, 4) && RegisterBasedCallOpcode == *cast(ubyte*)(p.ret - 3)) {
293                             version (StacktraceSpam) printf("ret:%x frm:%x register-based call:[%x,%x]\n", sym, p, *cast(ubyte*)(p.ret - 2), *cast(ubyte*)(p.ret - 1));
294                             addAddress(p.ret - 3);  // a register-based call is 3 bytes for the call + register setup
295                         } else {
296                             version (StacktraceSpam) printf("ret:%x frm:%x\n", sym, p);
297                             addAddress(p.ret);
298                         }
299                     }
300                 }
301 
302                 version (StacktraceTryToBeSmart) {
303                     bool inFiber = false;
304                     if  (
305                             callAddr == cast(uint)&_Dmain
306                             || true == (inFiber = (
307                                 callAddr >= cast(uint)&D4core6thread5Fiber3runMFZv
308                                 && callAddr < cast(uint)&D4core6thread5Fiber3runMFZv + fiberRunFuncLength
309                             ))
310                         )
311                     {
312                         foundMain = true;
313                         if (inFiber) {
314                             version (StacktraceSpam) printf("Got or Thread.Fiber.run\n");
315 
316                             version (StacktraceTryMatchCallAddresses) {
317                                 // handled above
318                             } else {
319                                 addAddress(p.ret);
320                             }
321 
322                             curStack = curStack.within;
323                             if (curStack) {
324                                 void* newp = curStack.tstack;
325 
326                                 if (!IsBadReadPtr(newp + 28, 8)) {
327                                     addAddress(*cast(size_t*)(newp + 32));
328                                     p = *cast(Layout**)(newp + 28);
329                                     continue;
330                                 }
331                             }
332                         } else {
333                             version (StacktraceSpam) printf("Got _Dmain\n");
334                         }
335                     }
336                 }
337                 
338                 version (StacktraceTryMatchCallAddresses) {
339                     // handled above
340                 } else {
341                     addAddress(p.ret);
342                 }
343                 
344                 p = p.ebp;
345             }
346 
347             ++phase;
348             p = cast(Layout*)ContextRecord.Ebp;
349             version (StacktraceSpam) printf("end of phase\n");
350         }
351         
352         version (StacktraceSpam) printf("calling traceReceiver\n");
353     }
354 
355     traceReceiver(stacktrace[0..i]);
356     heapTraceArr.free();
357 }
358 
359 
360 bool addrToSymbolDetails(size_t addr, HANDLE hProcess, void delegate(const(char)[] func, const(char)[] file, int line, ptrdiff_t addrOffset) dg) {
361     ubyte[256] buffer;
362 
363     SYMBOL_INFO* symbol_info = cast(SYMBOL_INFO*)buffer.ptr;
364     symbol_info.SizeOfStruct = SYMBOL_INFO.sizeof;
365     symbol_info.MaxNameLen = buffer.length - SYMBOL_INFO.sizeof + 1;
366     
367     ptrdiff_t addrOffset = 0;
368     auto ln = getAddrDbgInfo(addr, &addrOffset);
369 
370     bool success = true;
371 
372     char* symname = null;
373     if (!SymFromAddr(hProcess, addr, null, symbol_info)) {
374         //printf("%.*s\n", SysError.lastMsg);
375         symname = ln.func;
376         success = ln != AddrDebugInfo.init;
377     } else {
378         symname = symbol_info.Name.ptr;
379     }
380 
381     dg(fromStringz(symname).dup, fromStringz(ln.file).dup, ln.line, addrOffset);
382     return success;
383 }
384 
385 
386 //#line 2 "parts/Memory.di"
387 private {
388     import tango.stdc.stdlib : cMalloc = malloc, cRealloc = realloc, cFree = free;
389 }
390 
391 public {
392     import tango.stdc.string : memset;
393 }
394 
395 
396 /**
397     Allocate the array using malloc
398     
399     Params:
400     array = the array which will be resized
401     numItems = number of items to be allocated in the array
402     init = whether to init the allocated items to their default values or not
403     
404     Examples:
405     ---
406     int[] foo;
407     foo.alloc(20);
408     ---
409     
410     Remarks:
411     The array must be null and empty for this function to succeed. The rationale behind this is that the coder should state his decision clearly. This will help and has
412     already helped to spot many intricate bugs. 
413 */
414 void alloc(T, intT)(ref T array, intT numItems, bool init = true) 
415 in {
416     assert (array is null);
417     assert (numItems >= 0);
418 }
419 out {
420     assert (numItems == array.length);
421 }
422 body {
423     alias typeof(T.init[0]) ItemT;
424     array = (cast(ItemT*)cMalloc(ItemT.sizeof * numItems))[0 .. numItems];
425     
426     static if (is(typeof(ItemT.init))) {
427         if (init) {
428             array[] = ItemT.init;
429         }
430     }
431 }
432 
433 
434 /**
435     Clone the given array. The result is allocated using alloc() and copied piecewise from the param. Then it's returned
436 */
437 T clone(T)(T array) {
438     T res;
439     res.alloc(array.length, false);
440     res[] = array[];
441     return res;
442 }
443 
444 
445 /**
446     Realloc the contents of an array
447     
448     array = the array which will be resized
449     numItems = the new size for the array
450     init = whether to init the newly allocated items to their default values or not
451     
452     Examples:
453     ---
454     int[] foo;
455     foo.alloc(20);
456     foo.realloc(10);        // <--
457     ---
458 */
459 void realloc(T, intT)(ref T array, intT numItems, bool init = true)
460 in {
461     assert (numItems >= 0);
462 }
463 out {
464     assert (numItems == array.length);
465 }
466 body {
467     alias typeof(T.init[0]) ItemT;
468     intT oldLen = array.length;
469     array = (cast(ItemT*)cRealloc(array.ptr, ItemT.sizeof * numItems))[0 .. numItems];
470     
471     static if (is(typeof(ItemT.init))) {
472         if (init && numItems > oldLen) {
473             array[oldLen .. numItems] = ItemT.init;
474         }
475     }
476 }
477 
478 
479 /**
480     Deallocate an array allocated with alloc()
481 */
482 void free(T)(ref T array)
483 out {
484     assert (0 == array.length);
485 }
486 body {
487     cFree(array.ptr);
488     array = null;
489 }
490 
491 
492 /**
493     Append an item to an array. Optionally keep track of an external 'real length', while doing squared reallocation of the array
494     
495     Params:
496     array = the array to append the item to
497     elem = the new item to be appended
498     realLength = the optional external 'real length'
499     
500     Remarks:
501     if realLength isn't null, the array is not resized by one, but allocated in a std::vector manner. The array's length becomes it's capacity, while 'realLength'
502     is the number of items in the array.
503     
504     Examples:
505     ---
506     uint barLen = 0;
507     int[] bar;
508     append(bar, 10, &barLen);
509     append(bar, 20, &barLen);
510     append(bar, 30, &barLen);
511     append(bar, 40, &barLen);
512     assert (bar.length == 16);
513     assert (barLen == 4);
514     ---
515 */
516 void append(T, I)(ref T array, I elem, uint* realLength = null) {
517     uint len = realLength is null ? array.length : *realLength;
518     uint capacity = array.length;
519     alias typeof(T.init[0]) ItemT;
520     
521     if (len >= capacity) {
522         if (realLength is null) {       // just add one element to the array
523             int numItems = len+1;
524             array = (cast(ItemT*)cRealloc(array.ptr, ItemT.sizeof * numItems))[0 .. numItems];
525         } else {                                // be smarter and allocate in power-of-two increments
526             const uint initialCapacity = 4;
527             int numItems = capacity == 0 ? initialCapacity : capacity * 2; 
528             array = (cast(ItemT*)cRealloc(array.ptr, ItemT.sizeof * numItems))[0 .. numItems];
529             ++*realLength;
530         }
531     } else if (realLength !is null) ++*realLength;
532     
533     array[len] = elem;
534 }
535 //#line 2 "parts/WinApi.di"
536 import tango.text.Util;
537 import tango.core.Thread;
538 import tango.core.Array;
539 import tango.sys.Common : SysError;
540 import tango.sys.SharedLib : SharedLib;
541 import tango.stdc.stdio;
542 import tango.stdc.string;
543 import tango.stdc.stringz;
544 
545 
546 
547 
548 
549 enum {
550     MAX_PATH = 260,
551 }
552 
553 enum : WORD {
554     IMAGE_FILE_MACHINE_UNKNOWN = 0,
555     IMAGE_FILE_MACHINE_I386    = 332,
556     IMAGE_FILE_MACHINE_R3000   = 354,
557     IMAGE_FILE_MACHINE_R4000   = 358,
558     IMAGE_FILE_MACHINE_R10000  = 360,
559     IMAGE_FILE_MACHINE_ALPHA   = 388,
560     IMAGE_FILE_MACHINE_POWERPC = 496
561 }
562 
563 version(X86) {
564     const SIZE_OF_80387_REGISTERS=80;
565     const CONTEXT_i386=0x10000;
566     const CONTEXT_i486=0x10000;
567     const CONTEXT_CONTROL=(CONTEXT_i386|0x00000001L);
568     const CONTEXT_INTEGER=(CONTEXT_i386|0x00000002L);
569     const CONTEXT_SEGMENTS=(CONTEXT_i386|0x00000004L);
570     const CONTEXT_FLOATING_POINT=(CONTEXT_i386|0x00000008L);
571     const CONTEXT_DEBUG_REGISTERS=(CONTEXT_i386|0x00000010L);
572     const CONTEXT_EXTENDED_REGISTERS=(CONTEXT_i386|0x00000020L);
573     const CONTEXT_FULL=(CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_SEGMENTS);
574     const MAXIMUM_SUPPORTED_EXTENSION=512;
575 
576     struct FLOATING_SAVE_AREA {
577         DWORD    ControlWord;
578         DWORD    StatusWord;
579         DWORD    TagWord;
580         DWORD    ErrorOffset;
581         DWORD    ErrorSelector;
582         DWORD    DataOffset;
583         DWORD    DataSelector;
584         BYTE[80] RegisterArea;
585         DWORD    Cr0NpxState;
586     }
587 
588     struct CONTEXT {
589         DWORD ContextFlags;
590         DWORD Dr0;
591         DWORD Dr1;
592         DWORD Dr2;
593         DWORD Dr3;
594         DWORD Dr6;
595         DWORD Dr7;
596         FLOATING_SAVE_AREA FloatSave;
597         DWORD SegGs;
598         DWORD SegFs;
599         DWORD SegEs;
600         DWORD SegDs;
601         DWORD Edi;
602         DWORD Esi;
603         DWORD Ebx;
604         DWORD Edx;
605         DWORD Ecx;
606         DWORD Eax;
607         DWORD Ebp;
608         DWORD Eip;
609         DWORD SegCs;
610         DWORD EFlags;
611         DWORD Esp;
612         DWORD SegSs;
613         BYTE[MAXIMUM_SUPPORTED_EXTENSION] ExtendedRegisters;
614     }
615 
616 } else {
617     pragma(msg, "Unsupported CPU");
618     static assert(0);
619     // Versions for PowerPC, Alpha, SHX, and MIPS removed.
620 }
621 
622 
623 alias CONTEXT* PCONTEXT, LPCONTEXT;
624 
625 alias void* HANDLE;
626 
627 alias char CHAR;
628 alias void* PVOID, LPVOID;
629 
630 alias wchar WCHAR;
631 alias WCHAR* PWCHAR, LPWCH, PWCH, LPWSTR, PWSTR;
632 alias CHAR* PCHAR, LPCH, PCH, LPSTR, PSTR;
633 
634 // const versions
635 alias const(WCHAR)* LPCWCH, PCWCH, LPCWSTR, PCWSTR;
636 alias const(CHAR)* LPCCH, PCSTR, LPCSTR;
637 
638 version(Unicode) {
639     alias WCHAR TCHAR, _TCHAR;
640 } else {
641     alias CHAR TCHAR, _TCHAR;
642 }
643 
644 alias TCHAR* PTCH, PTBYTE, LPTCH, PTSTR, LPTSTR, LP, PTCHAR, LPCTSTR;
645 
646 alias ubyte   BYTE;
647 alias ubyte*  PBYTE, LPBYTE;
648 alias ushort  USHORT, WORD, ATOM;
649 alias ushort* PUSHORT, PWORD, LPWORD;
650 alias uint    ULONG, DWORD, UINT, COLORREF;
651 alias uint*   PULONG, PDWORD, LPDWORD, PUINT, LPUINT;
652 alias int     BOOL, INT, LONG;
653 alias HANDLE HMODULE;
654 
655 enum : BOOL {
656     FALSE = 0,
657     TRUE = 1,
658 }
659 
660 struct EXCEPTION_POINTERS {
661   void* ExceptionRecord;
662   CONTEXT* ContextRecord;
663 }
664 
665 version (Win64) {
666     alias long INT_PTR, LONG_PTR;
667     alias ulong UINT_PTR, ULONG_PTR, HANDLE_PTR;
668 } else {
669     alias int INT_PTR, LONG_PTR;
670     alias uint UINT_PTR, ULONG_PTR, HANDLE_PTR;
671 }
672 
673 alias ulong ULONG64, DWORD64, UINT64;
674 alias ulong* PULONG64, PDWORD64, PUINT64;
675 
676 
677 extern(Windows) {
678     HANDLE GetCurrentProcess();
679     HANDLE GetCurrentThread();
680     BOOL GetThreadContext(HANDLE, LPCONTEXT);
681 }
682 
683 
684 void loadWinAPIFunctions() {
685     auto dbghelp = SharedLib.load(`dbghelp.dll`);
686     
687     auto SymEnumerateModules64 = cast(fp_SymEnumerateModules64)dbghelp.getSymbol("SymEnumerateModules64");
688     SymFromAddr = cast(fp_SymFromAddr)dbghelp.getSymbol("SymFromAddr");
689     assert (SymFromAddr !is null);
690     SymFromName = cast(fp_SymFromName)dbghelp.getSymbol("SymFromName");
691     assert (SymFromName !is null);
692     SymLoadModule64 = cast(fp_SymLoadModule64)dbghelp.getSymbol("SymLoadModule64");
693     assert (SymLoadModule64 !is null);
694     SymInitialize = cast(fp_SymInitialize)dbghelp.getSymbol("SymInitialize");
695     assert (SymInitialize !is null);
696     SymCleanup = cast(fp_SymCleanup)dbghelp.getSymbol("SymCleanup");
697     assert (SymCleanup !is null);
698     SymSetOptions = cast(fp_SymSetOptions)dbghelp.getSymbol("SymSetOptions");
699     assert (SymSetOptions !is null);
700     SymGetLineFromAddr64 = cast(fp_SymGetLineFromAddr64)dbghelp.getSymbol("SymGetLineFromAddr64");
701     assert (SymGetLineFromAddr64 !is null);
702     SymEnumSymbols = cast(fp_SymEnumSymbols)dbghelp.getSymbol("SymEnumSymbols");
703     assert (SymEnumSymbols !is null);
704     SymGetModuleBase64 = cast(fp_SymGetModuleBase64)dbghelp.getSymbol("SymGetModuleBase64");
705     assert (SymGetModuleBase64 !is null);
706     StackWalk64 = cast(fp_StackWalk64)dbghelp.getSymbol("StackWalk64");
707     assert (StackWalk64 !is null);
708     SymFunctionTableAccess64 = cast(fp_SymFunctionTableAccess64)dbghelp.getSymbol("SymFunctionTableAccess64");
709     assert (SymFunctionTableAccess64 !is null);
710     
711     
712     auto psapi = SharedLib.load(`psapi.dll`);
713     GetModuleFileNameExA = cast(fp_GetModuleFileNameExA)psapi.getSymbol("GetModuleFileNameExA");
714     assert (GetModuleFileNameExA !is null);
715 }
716 
717 
718 
719 extern (Windows) {
720     __gshared fp_SymFromAddr      SymFromAddr;
721     __gshared fp_SymFromName      SymFromName;
722     __gshared fp_SymLoadModule64  SymLoadModule64;
723     __gshared fp_SymInitialize            SymInitialize;
724     __gshared fp_SymCleanup           SymCleanup;
725     __gshared fp_SymSetOptions        SymSetOptions;
726     __gshared fp_SymGetLineFromAddr64 SymGetLineFromAddr64;
727     __gshared fp_SymEnumSymbols           SymEnumSymbols;
728     __gshared fp_SymGetModuleBase64   SymGetModuleBase64;
729     __gshared fp_GetModuleFileNameExA     GetModuleFileNameExA;
730     __gshared fp_StackWalk64                      StackWalk64;
731     __gshared fp_SymFunctionTableAccess64 SymFunctionTableAccess64;
732 
733 
734     alias DWORD function(
735         DWORD SymOptions
736     ) fp_SymSetOptions;
737     
738     enum {
739         SYMOPT_ALLOW_ABSOLUTE_SYMBOLS = 0x00000800,
740         SYMOPT_DEFERRED_LOADS = 0x00000004,
741         SYMOPT_UNDNAME = 0x00000002
742     }
743 
744     alias BOOL function(
745         HANDLE hProcess,
746         LPCTSTR UserSearchPath,
747         BOOL fInvadeProcess
748     ) fp_SymInitialize;
749     
750     alias BOOL function(
751         HANDLE hProcess
752     ) fp_SymCleanup;
753 
754     alias DWORD64 function(
755         HANDLE hProcess,
756         HANDLE hFile,
757         LPCSTR ImageName,
758         LPCSTR ModuleName,
759         DWORD64 BaseOfDll,
760         DWORD SizeOfDll
761     ) fp_SymLoadModule64;
762     
763     struct SYMBOL_INFO {
764         ULONG SizeOfStruct;
765         ULONG TypeIndex;
766         ULONG64[2] Reserved;
767         ULONG Index;
768         ULONG Size;
769         ULONG64 ModBase;
770         ULONG Flags;
771         ULONG64 Value;
772         ULONG64 Address;
773         ULONG Register;
774         ULONG Scope;
775         ULONG Tag;
776         ULONG NameLen;
777         ULONG MaxNameLen;
778         TCHAR[1] Name;
779     }
780     alias SYMBOL_INFO* PSYMBOL_INFO;
781     
782     alias BOOL function(
783         HANDLE hProcess,
784         DWORD64 Address,
785         PDWORD64 Displacement,
786         PSYMBOL_INFO Symbol
787     ) fp_SymFromAddr;
788 
789     alias BOOL function(
790         HANDLE hProcess,
791         PCSTR Name,
792         PSYMBOL_INFO Symbol
793     ) fp_SymFromName;
794 
795     alias BOOL function(
796         HANDLE hProcess,
797         PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
798         PVOID UserContext
799     ) fp_SymEnumerateModules64;
800     
801     alias BOOL function(
802         LPTSTR ModuleName,
803         DWORD64 BaseOfDll,
804         PVOID UserContext
805     ) PSYM_ENUMMODULES_CALLBACK64;
806 
807     const DWORD TH32CS_SNAPPROCESS = 0x00000002;
808     const DWORD TH32CS_SNAPTHREAD = 0x00000004;
809     
810 
811     enum {
812         MAX_MODULE_NAME32 = 255,
813         TH32CS_SNAPMODULE = 0x00000008,
814         SYMOPT_LOAD_LINES = 0x10,
815     }
816 
817     struct IMAGEHLP_LINE64 {
818         DWORD SizeOfStruct;
819         PVOID Key;
820         DWORD LineNumber;
821         PTSTR FileName;
822         DWORD64 Address;
823     }
824     alias IMAGEHLP_LINE64* PIMAGEHLP_LINE64;
825  
826     alias BOOL function(
827         HANDLE hProcess,
828         DWORD64 dwAddr,
829         PDWORD pdwDisplacement,
830         PIMAGEHLP_LINE64 Line
831     ) fp_SymGetLineFromAddr64;
832     
833 
834     alias BOOL function(
835         PSYMBOL_INFO pSymInfo,
836         ULONG SymbolSize,
837         PVOID UserContext
838     ) PSYM_ENUMERATESYMBOLS_CALLBACK;
839 
840     alias BOOL function(
841         HANDLE hProcess,
842         ULONG64 BaseOfDll,
843         LPCTSTR Mask,
844         PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
845         PVOID UserContext
846     ) fp_SymEnumSymbols;
847 
848 
849     alias DWORD64 function(
850         HANDLE hProcess,
851         DWORD64 dwAddr
852     ) fp_SymGetModuleBase64;
853     alias fp_SymGetModuleBase64 PGET_MODULE_BASE_ROUTINE64;
854     
855     
856     alias DWORD function(
857       HANDLE hProcess,
858       HMODULE hModule,
859       LPSTR lpFilename,
860       DWORD nSize
861     ) fp_GetModuleFileNameExA;
862     
863 
864     enum ADDRESS_MODE {
865         AddrMode1616,
866         AddrMode1632,
867         AddrModeReal,
868         AddrModeFlat
869     }
870     
871     struct KDHELP64 {
872         DWORD64 Thread;
873         DWORD ThCallbackStack;
874         DWORD ThCallbackBStore;
875         DWORD NextCallback;
876         DWORD FramePointer;
877         DWORD64 KiCallUserMode;
878         DWORD64 KeUserCallbackDispatcher;
879         DWORD64 SystemRangeStart;
880         DWORD64 KiUserExceptionDispatcher;
881         DWORD64 StackBase;
882         DWORD64 StackLimit;
883         DWORD64[5] Reserved;
884     } 
885     alias KDHELP64* PKDHELP64;
886     
887     struct ADDRESS64 {
888         DWORD64 Offset;
889         WORD Segment;
890         ADDRESS_MODE Mode;
891     }
892     alias ADDRESS64* LPADDRESS64;
893 
894 
895     struct STACKFRAME64 {
896         ADDRESS64 AddrPC;
897         ADDRESS64 AddrReturn;
898         ADDRESS64 AddrFrame;
899         ADDRESS64 AddrStack;
900         ADDRESS64 AddrBStore;
901         PVOID FuncTableEntry;
902         DWORD64[4] Params;
903         BOOL Far;
904         BOOL Virtual;
905         DWORD64[3] Reserved;
906         KDHELP64 KdHelp;
907     }
908     alias STACKFRAME64* LPSTACKFRAME64;
909     
910     
911     
912     alias BOOL function(
913         HANDLE hProcess,
914         DWORD64 lpBaseAddress,
915         PVOID lpBuffer,
916         DWORD nSize,
917         LPDWORD lpNumberOfBytesRead
918     ) PREAD_PROCESS_MEMORY_ROUTINE64;
919     
920     alias PVOID function(
921         HANDLE hProcess,
922         DWORD64 AddrBase
923     ) PFUNCTION_TABLE_ACCESS_ROUTINE64;
924     alias PFUNCTION_TABLE_ACCESS_ROUTINE64 fp_SymFunctionTableAccess64;
925     
926     alias DWORD64 function(
927         HANDLE hProcess,
928         HANDLE hThread,
929         LPADDRESS64 lpaddr
930     ) PTRANSLATE_ADDRESS_ROUTINE64;
931     
932     
933     alias BOOL function (
934         DWORD MachineType,
935         HANDLE hProcess,
936         HANDLE hThread,
937         LPSTACKFRAME64 StackFrame,
938         PVOID ContextRecord,
939         PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
940         PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
941         PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
942         PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
943     ) fp_StackWalk64;
944     
945     
946     BOOL IsBadReadPtr(void*, uint);
947 }
948 
949 //#line 2 "parts/DbgInfo.di"
950 import tango.text.Util;
951 import tango.stdc.stdio;
952 import tango.stdc.stringz;
953 import tango.stdc.string : strcpy;
954 import tango.sys.win32.CodePage;
955 import tango.core.Exception;
956 
957 
958 
959 struct AddrDebugInfo {
960     align(1) {
961         size_t  addr;
962         char*   file;
963         char*   func;
964         ushort  line;
965     }
966 }
967 
968 class ModuleDebugInfo {
969     AddrDebugInfo[] debugInfo;
970     uint                        debugInfoLen;
971     size_t[char*]           fileMaxAddr;
972     char*[]                 strBuffer;
973     uint                        strBufferLen;
974     
975     void addDebugInfo(size_t addr, char* file, char* func, ushort line) {
976         debugInfo.append(AddrDebugInfo(addr, file, func, line), &debugInfoLen);
977 
978         if (auto a = file in fileMaxAddr) {
979             if (addr > *a) *a = addr;
980         } else {
981             fileMaxAddr[file] = addr;
982         }
983     }
984     
985     char* bufferString(const(char)[] str) {
986         char[] res;
987         res.alloc(str.length+1, false);
988         res[0..$-1] = str[];
989         res[str.length] = 0;
990         strBuffer.append(res.ptr, &strBufferLen);
991         return res.ptr;
992     }
993     
994     void freeArrays() {
995         debugInfo.free();
996         debugInfoLen = 0;
997 
998         fileMaxAddr = null;
999         foreach (ref s; strBuffer[0..strBufferLen]) {
1000             cFree(s);
1001         }
1002         strBuffer.free();
1003         strBufferLen = 0;
1004     }
1005     
1006     ModuleDebugInfo prev;
1007     ModuleDebugInfo next;
1008 }
1009 
1010 class GlobalDebugInfo {
1011     ModuleDebugInfo head;
1012     ModuleDebugInfo tail;
1013     
1014     
1015      int opApply(scope int delegate(ref ModuleDebugInfo) dg) {
1016 			synchronized(this)
1017 			{
1018         for (auto it = head; it !is null; it = it.next) {
1019             if (auto res = dg(it)) {
1020                 return res;
1021             }
1022         }
1023 			}
1024         return 0;
1025     }
1026     
1027     
1028      void addDebugInfo(ModuleDebugInfo info) {
1029 			synchronized(this)
1030         if (head is null) {
1031             head = tail = info;
1032             info.next = info.prev = null;
1033         } else {
1034             tail.next = info;
1035             info.prev = tail;
1036             info.next = null;
1037             tail = info;
1038         }
1039     }
1040     
1041     
1042     void removeDebugInfo(ModuleDebugInfo info) {
1043         assert (info !is null);
1044         assert (info.next !is null || info.prev !is null || head is info);
1045         synchronized(this)
1046 				{
1047         if (info is head) {
1048             head = head.next;
1049         }
1050         if (info is tail) {
1051             tail = tail.prev;
1052         }
1053         if (info.prev) {
1054             info.prev.next = info.next;
1055         }
1056         if (info.next) {
1057             info.next.prev = info.prev;
1058         }
1059         info.freeArrays();
1060         info.prev = info.next = null;
1061         
1062         info.destroy;
1063 			}
1064     }
1065 }
1066 
1067 private __gshared GlobalDebugInfo globalDebugInfo;
1068 shared static this() {
1069     globalDebugInfo = new GlobalDebugInfo;
1070 }
1071 
1072 extern(C) void _initLGPLHostExecutableDebugInfo(const(char)[] progName) {
1073     scope info = new DebugInfo(progName);
1074     // we'll let it die now :)
1075 }
1076 
1077 
1078 AddrDebugInfo getAddrDbgInfo(size_t a, ptrdiff_t* diff = null) {
1079     AddrDebugInfo bestInfo;
1080     int minDiff = 0x7fffffff;
1081     int bestOff = 0;
1082     const int addBias = 0;
1083     
1084     foreach (modInfo; globalDebugInfo) {
1085         bool local = false;
1086         
1087         foreach (l; modInfo.debugInfo[0 .. modInfo.debugInfoLen]) {
1088             int diff = a - l.addr - addBias;
1089             
1090             // increasing it will make the lookup give results 'higher' in the code (at lower addresses)
1091             // using the value of 1 is recommended when not using version StacktraceTryMatchCallAddresses,
1092             // but it may result in AVs reporting an earlier line in the source code
1093             const int minSymbolOffset = 0;
1094             
1095             if (diff < minSymbolOffset) {
1096                 continue;
1097             }
1098             
1099             int absdiff = diff > 0 ? diff : -diff;
1100             if (absdiff < minDiff) {
1101                 minDiff = absdiff;
1102                 bestOff = diff;
1103                 bestInfo = l;
1104                 local = true;
1105             }
1106         }
1107         
1108         if (local) {
1109             if (minDiff > 0x100) {
1110                 bestInfo = bestInfo.init;
1111                 minDiff = 0x7fffffff;
1112             }
1113             else {
1114                 if (auto ma = bestInfo.file in modInfo.fileMaxAddr) {
1115                     if (a > *ma+addBias) {
1116                         bestInfo = bestInfo.init;
1117                         minDiff = 0x7fffffff;
1118                     }
1119                 } else {
1120                     version (StacktraceSpam) printf("there ain't '%s' in fileMaxAddr\n", bestInfo.file);
1121                     bestInfo = bestInfo.init;
1122                     minDiff = 0x7fffffff;
1123                 }
1124             }
1125         }
1126     }
1127     
1128     if (diff !is null) {
1129         *diff = bestOff;
1130     }
1131     return bestInfo;
1132 }
1133 
1134    
1135 
1136 class DebugInfo {
1137     ModuleDebugInfo info;
1138     
1139     
1140     this(const(char)[] filename) {
1141         info = new ModuleDebugInfo;
1142         ParseCVFile(filename);
1143         assert (globalDebugInfo !is null);
1144         globalDebugInfo.addDebugInfo(info);
1145     }
1146      
1147     private {
1148         int ParseCVFile(const(char)[] filename) {
1149             FILE* debugfile;
1150 
1151             if (filename == "") return (-1);
1152 
1153             //try {
1154                 debugfile = fopen((filename ~ "\0").ptr, "rb");
1155             /+} catch(Exception e){
1156                 return -1;
1157             }+/
1158 
1159             if (!ParseFileHeaders (debugfile)) return -1;
1160 
1161             g_secthdrs.length = g_nthdr.FileHeader.NumberOfSections;
1162 
1163             if (!ParseSectionHeaders (debugfile)) return -1;
1164 
1165             g_debugdirs.length = g_nthdr.OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size /
1166                 IMAGE_DEBUG_DIRECTORY.sizeof;
1167 
1168             if (!ParseDebugDir (debugfile)) return -1;
1169             if (g_dwStartOfCodeView == 0) return -1;
1170             if (!ParseCodeViewHeaders (debugfile)) return -1;
1171             if (!ParseAllModules (debugfile)) return -1;
1172 
1173             g_dwStartOfCodeView = 0;
1174             g_exe_mode = true;
1175             g_secthdrs = null;
1176             g_debugdirs = null;
1177             g_cvEntries = null;
1178             g_cvModules = null;
1179             g_filename = null;
1180             g_filenameStringz = null;
1181 
1182             fclose(debugfile);
1183             return 0;
1184         }
1185             
1186         bool ParseFileHeaders(FILE* debugfile) {
1187             CVHeaderType hdrtype;
1188 
1189             hdrtype = GetHeaderType (debugfile);
1190 
1191             if (hdrtype == CVHeaderType.DOS) {
1192                 if (!ReadDOSFileHeader (debugfile, &g_doshdr))return false;
1193                 hdrtype = GetHeaderType (debugfile);
1194             }
1195             if (hdrtype == CVHeaderType.NT) {
1196                 if (!ReadPEFileHeader (debugfile, &g_nthdr)) return false;
1197             }
1198 
1199             return true;
1200         }
1201             
1202         CVHeaderType GetHeaderType(FILE* debugfile) {
1203             ushort hdrtype;
1204             CVHeaderType ret = CVHeaderType.NONE;
1205 
1206             int oldpos = ftell(debugfile);
1207 
1208             if (!ReadChunk (debugfile, &hdrtype, ushort.sizeof, -1)){
1209                 fseek(debugfile, oldpos, SEEK_SET);
1210                 return CVHeaderType.NONE;
1211             }
1212 
1213             if (hdrtype == 0x5A4D)       // "MZ"
1214                 ret = CVHeaderType.DOS;
1215             else if (hdrtype == 0x4550)  // "PE"
1216                 ret = CVHeaderType.NT;
1217             else if (hdrtype == 0x4944)  // "DI"
1218                 ret = CVHeaderType.DBG;
1219 
1220             fseek(debugfile, oldpos, SEEK_SET);
1221 
1222             return ret;
1223         }
1224          
1225         /*
1226          * Extract the DOS file headers from an executable
1227          */
1228         bool ReadDOSFileHeader(FILE* debugfile, IMAGE_DOS_HEADER *doshdr) {
1229             uint bytes_read;
1230 
1231             bytes_read = fread(doshdr, 1, IMAGE_DOS_HEADER.sizeof, debugfile);
1232             if (bytes_read < IMAGE_DOS_HEADER.sizeof){
1233                 return false;
1234             }
1235 
1236             // Skip over stub data, if present
1237             if (doshdr.e_lfanew) {
1238                 fseek(debugfile, doshdr.e_lfanew, SEEK_SET);
1239             }
1240 
1241             return true;
1242         }
1243          
1244         /*
1245          * Extract the DOS and NT file headers from an executable
1246          */
1247         bool ReadPEFileHeader(FILE* debugfile, IMAGE_NT_HEADERS *nthdr) {
1248             uint bytes_read;
1249 
1250             bytes_read = fread(nthdr, 1, IMAGE_NT_HEADERS.sizeof, debugfile);
1251             if (bytes_read < IMAGE_NT_HEADERS.sizeof) {
1252                 return false;
1253             }
1254 
1255             return true;
1256         }
1257           
1258         bool ParseSectionHeaders(FILE* debugfile) {
1259             if (!ReadSectionHeaders (debugfile, g_secthdrs)) return false;
1260             return true;
1261         }
1262             
1263         bool ReadSectionHeaders(FILE* debugfile, ref IMAGE_SECTION_HEADER[] secthdrs) {
1264             for(int i=0;i<secthdrs.length;i++){
1265                 uint bytes_read;
1266                 bytes_read = fread((&secthdrs[i]), 1, IMAGE_SECTION_HEADER.sizeof, debugfile);
1267                 if (bytes_read < 1){
1268                     return false;
1269                 }
1270             }
1271             return true;
1272         }
1273           
1274         bool ParseDebugDir(FILE* debugfile) {
1275             int i;
1276             int filepos;
1277 
1278             if (g_debugdirs.length == 0) return false;
1279 
1280             filepos = GetOffsetFromRVA (g_nthdr.OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress);
1281 
1282             fseek(debugfile, filepos, SEEK_SET);
1283 
1284             if (!ReadDebugDir (debugfile, g_debugdirs)) return false;
1285 
1286             for (i = 0; i < g_debugdirs.length; i++) {
1287                 enum {
1288                     IMAGE_DEBUG_TYPE_CODEVIEW = 2,
1289                 }
1290 
1291                 if (g_debugdirs[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
1292                     g_dwStartOfCodeView = g_debugdirs[i].PointerToRawData;
1293                 }
1294             }
1295 
1296             g_debugdirs = null;
1297 
1298             return true;
1299         }
1300             
1301         // Calculate the file offset, based on the RVA.
1302         uint GetOffsetFromRVA(uint rva) {
1303             int i;
1304             uint sectbegin;
1305 
1306             for (i = g_secthdrs.length - 1; i >= 0; i--) {
1307                 sectbegin = g_secthdrs[i].VirtualAddress;
1308                 if (rva >= sectbegin) break;
1309             }
1310             uint offset = g_secthdrs[i].VirtualAddress - g_secthdrs[i].PointerToRawData;
1311             uint filepos = rva - offset;
1312             return filepos;
1313         }
1314          
1315         // Load in the debug directory table.  This directory describes the various
1316         // blocks of debug data that reside at the end of the file (after the COFF
1317         // sections), including FPO data, COFF-style debug info, and the CodeView
1318         // we are *really* after.
1319         bool ReadDebugDir(FILE* debugfile, ref IMAGE_DEBUG_DIRECTORY[] debugdirs) {
1320             uint bytes_read;
1321             for(int i=0;i<debugdirs.length;i++) {
1322                 bytes_read = fread((&debugdirs[i]), 1, IMAGE_DEBUG_DIRECTORY.sizeof, debugfile);
1323                 if (bytes_read < IMAGE_DEBUG_DIRECTORY.sizeof) {
1324                     return false;
1325                 }
1326             }
1327             return true;
1328         }
1329           
1330         bool ParseCodeViewHeaders(FILE* debugfile) {
1331             fseek(debugfile, g_dwStartOfCodeView, SEEK_SET);
1332             if (!ReadCodeViewHeader (debugfile, g_cvSig, g_cvHeader)) return false;
1333             g_cvEntries.length = g_cvHeader.cDir;
1334             if (!ReadCodeViewDirectory (debugfile, g_cvEntries)) return false;
1335             return true;
1336         }
1337 
1338             
1339         bool ReadCodeViewHeader(FILE* debugfile, out OMFSignature sig, out OMFDirHeader dirhdr) {
1340             uint bytes_read;
1341 
1342             bytes_read = fread((&sig), 1, OMFSignature.sizeof, debugfile);
1343             if (bytes_read < OMFSignature.sizeof){
1344                 return false;
1345             }
1346 
1347             fseek(debugfile, sig.filepos + g_dwStartOfCodeView, SEEK_SET);
1348             bytes_read = fread((&dirhdr), 1, OMFDirHeader.sizeof, debugfile);
1349             if (bytes_read < OMFDirHeader.sizeof){
1350                 return false;
1351             }
1352             return true;
1353         }
1354          
1355         bool ReadCodeViewDirectory(FILE* debugfile, ref OMFDirEntry[] entries) {
1356             uint bytes_read;
1357 
1358             for(int i=0;i<entries.length;i++){
1359                 bytes_read = fread((&entries[i]), 1, OMFDirEntry.sizeof, debugfile);
1360                 if (bytes_read < OMFDirEntry.sizeof){
1361                     return false;
1362                 }
1363             }
1364             return true;
1365         }
1366           
1367         bool ParseAllModules (FILE* debugfile) {
1368             if (g_cvHeader.cDir == 0){
1369                 return true;
1370             }
1371 
1372             if (g_cvEntries.length == 0){
1373                 return false;
1374             }
1375 
1376             fseek(debugfile, g_dwStartOfCodeView + g_cvEntries[0].lfo, SEEK_SET);
1377 
1378             if (!ReadModuleData (debugfile, g_cvEntries, g_cvModules)){
1379                 return false;
1380             }
1381 
1382 
1383             for (int i = 0; i < g_cvModules.length; i++){
1384                 ParseRelatedSections (i, debugfile);
1385             }
1386 
1387             return true;
1388         }
1389 
1390             
1391         bool ReadModuleData(FILE* debugfile, OMFDirEntry[] entries, out OMFModuleFull[] modules) {
1392             uint bytes_read;
1393             int pad;
1394 
1395             int module_bytes = (ushort.sizeof * 3) + (char.sizeof * 2);
1396 
1397             if (entries == null) return false;
1398 
1399             modules.length = 0;
1400 
1401             for (int i = 0; i < entries.length; i++){
1402                 if (entries[i].SubSection == sstModule)
1403                     modules.length = modules.length + 1;
1404             }
1405 
1406             for (int i = 0; i < modules.length; i++){
1407 
1408                 bytes_read = fread((&modules[i]), 1, module_bytes, debugfile);
1409                 if (bytes_read < module_bytes){
1410                     return false;
1411                 }
1412 
1413                 int segnum = modules[i].cSeg;
1414                 OMFSegDesc[] segarray;
1415                 segarray.length=segnum;
1416                 for(int j=0;j<segnum;j++){
1417                     bytes_read =  fread((&segarray[j]), 1, OMFSegDesc.sizeof, debugfile);
1418                     if (bytes_read < OMFSegDesc.sizeof){
1419                         return false;
1420                     }
1421                 }
1422                 modules[i].SegInfo = segarray.ptr;
1423 
1424                 char namelen;
1425                 bytes_read = fread((&namelen), 1, char.sizeof, debugfile);
1426                 if (bytes_read < 1){
1427                     return false;
1428                 }
1429 
1430                 pad = ((namelen + 1) % 4);
1431                 if (pad) namelen += (4 - pad);
1432 
1433                 modules[i].Name = (new char[namelen+1]).ptr;
1434                 modules[i].Name[namelen]=0;
1435                 bytes_read = fread((modules[i].Name), 1, namelen, debugfile);
1436                 if (bytes_read < namelen){
1437                     return false;
1438                 }
1439             }
1440             return true;
1441         }
1442          
1443         bool ParseRelatedSections(int index, FILE* debugfile) {
1444             int i;
1445 
1446             if (g_cvEntries == null)
1447                 return false;
1448 
1449             for (i = 0; i < g_cvHeader.cDir; i++){
1450                 if (g_cvEntries[i].iMod != (index + 1) ||
1451                     g_cvEntries[i].SubSection == sstModule)
1452                     continue;
1453 
1454                 switch (g_cvEntries[i].SubSection){
1455                 case sstSrcModule:
1456                     ParseSrcModuleInfo (i, debugfile);
1457                     break;
1458                 default:
1459                     break;
1460                 }
1461             }
1462 
1463             return true;
1464         }
1465             
1466         bool ParseSrcModuleInfo (int index, FILE* debugfile) {
1467             int i;
1468 
1469             byte *rawdata;
1470             byte *curpos;
1471             short filecount;
1472             short segcount;
1473 
1474             int moduledatalen;
1475             int filedatalen;
1476             int linedatalen;
1477 
1478             if (g_cvEntries == null || debugfile == null ||
1479                 g_cvEntries[index].SubSection != sstSrcModule)
1480                 return false;
1481 
1482             int fileoffset = g_dwStartOfCodeView + g_cvEntries[index].lfo;
1483 
1484             rawdata = (new byte[g_cvEntries[index].cb]).ptr;
1485             if (!rawdata) return false;
1486 
1487             if (!ReadChunk (debugfile, rawdata, g_cvEntries[index].cb, fileoffset)) return false;
1488             uint[] baseSrcFile;
1489             ExtractSrcModuleInfo (rawdata, &filecount, &segcount,baseSrcFile);
1490 
1491             for(i=0;i<baseSrcFile.length;i++){
1492                 uint[] baseSrcLn;
1493                 ExtractSrcModuleFileInfo (rawdata+baseSrcFile[i],baseSrcLn);
1494                 for(int j=0;j<baseSrcLn.length;j++){
1495                     ExtractSrcModuleLineInfo (rawdata+baseSrcLn[j], j);
1496                 }
1497             }
1498 
1499             return true;
1500         }
1501         
1502         void ExtractSrcModuleInfo (byte* rawdata, short *filecount, short *segcount,out uint[] fileinfopos) {
1503             int i;
1504             int datalen;
1505 
1506             short cFile;
1507             short cSeg;
1508             uint *baseSrcFile;
1509             uint *segarray;
1510             ushort *segindexarray;
1511 
1512             cFile = *cast(short*)rawdata;
1513             cSeg = *cast(short*)(rawdata + 2);
1514             baseSrcFile = cast(uint*)(rawdata + 4);
1515             segarray = &baseSrcFile[cFile];
1516             segindexarray = cast(ushort*)(&segarray[cSeg * 2]);
1517 
1518             *filecount = cFile;
1519             *segcount = cSeg;
1520 
1521             fileinfopos.length=cFile;
1522             for (i = 0; i < cFile; i++) {
1523                 fileinfopos[i]=baseSrcFile[i];
1524             }
1525         }
1526          
1527         void ExtractSrcModuleFileInfo(byte* rawdata,out uint[] offset) {
1528             int i;
1529             int datalen;
1530 
1531             short cSeg;
1532             uint *baseSrcLn;
1533             uint *segarray;
1534             byte cFName;
1535 
1536             cSeg = *cast(short*)(rawdata);
1537             // Skip the 'pad' field
1538             baseSrcLn = cast(uint*)(rawdata + 4);
1539             segarray = &baseSrcLn[cSeg];
1540             cFName = *(cast(byte*)&segarray[cSeg*2]);
1541 
1542             g_filename = (cast(char*)&segarray[cSeg*2] + 1)[0..cFName].dup;
1543             g_filenameStringz = info.bufferString(g_filename);
1544 
1545             offset.length=cSeg;
1546             for (i = 0; i < cSeg; i++){
1547                 offset[i]=baseSrcLn[i];
1548             }
1549         }
1550          
1551         void ExtractSrcModuleLineInfo(byte* rawdata, int tablecount) {
1552             int i;
1553 
1554             ushort Seg;
1555             ushort cPair;
1556             uint *offset;
1557             ushort *linenumber;
1558 
1559             Seg = *cast(ushort*)rawdata;
1560             cPair = *cast(ushort*)(rawdata + 2);
1561             offset = cast(uint*)(rawdata + 4);
1562             linenumber = cast(ushort*)&offset[cPair];
1563 
1564             uint base=0;
1565             if (Seg != 0){
1566                 base = g_nthdr.OptionalHeader.ImageBase+g_secthdrs[Seg-1].VirtualAddress;
1567             }
1568             
1569             for (i = 0; i < cPair; i++) {
1570                 uint address = offset[i]+base;
1571                 info.addDebugInfo(address, g_filenameStringz, null, linenumber[i]);
1572             }
1573         }
1574 
1575            
1576         bool ReadChunk(FILE* debugfile, void *dest, int length, int fileoffset) {
1577             uint bytes_read;
1578 
1579             if (fileoffset >= 0) {
1580                 fseek(debugfile, fileoffset, SEEK_SET);
1581             }
1582 
1583             bytes_read = fread(dest, 1, length, debugfile);
1584             if (bytes_read < length) {
1585                 return false;
1586             }
1587 
1588             return true;
1589         }
1590 
1591 
1592         enum CVHeaderType : int {
1593             NONE,
1594             DOS,
1595             NT,
1596             DBG
1597         }
1598 
1599         int g_dwStartOfCodeView = 0;
1600 
1601         bool g_exe_mode = true;
1602         IMAGE_DOS_HEADER g_doshdr;
1603         IMAGE_SEPARATE_DEBUG_HEADER g_dbghdr;
1604         IMAGE_NT_HEADERS g_nthdr;
1605 
1606         IMAGE_SECTION_HEADER[] g_secthdrs;
1607 
1608         IMAGE_DEBUG_DIRECTORY[] g_debugdirs;
1609         OMFSignature g_cvSig;
1610         OMFDirHeader g_cvHeader;
1611         OMFDirEntry[] g_cvEntries;
1612         OMFModuleFull[] g_cvModules;
1613         const(char)[] g_filename;
1614         char* g_filenameStringz;
1615     }
1616 }
1617 
1618 
1619 
1620 
1621 enum {
1622     IMAGE_FILE_DEBUG_DIRECTORY = 6
1623 }
1624  
1625 enum {
1626     sstModule           = 0x120,
1627     sstSrcModule        = 0x127,
1628     sstGlobalPub        = 0x12a,
1629 }
1630  
1631 struct OMFSignature {
1632     char[4]    Signature;
1633     int filepos;
1634 }
1635  
1636 struct OMFDirHeader {
1637     ushort  cbDirHeader;
1638     ushort  cbDirEntry;
1639     uint    cDir;
1640     int     lfoNextDir;
1641     uint    flags;
1642 }
1643  
1644 struct OMFDirEntry {
1645     ushort  SubSection;
1646     ushort  iMod;
1647     int     lfo;
1648     uint    cb;
1649 }
1650   
1651 struct OMFSegDesc {
1652     ushort  Seg;
1653     ushort  pad;
1654     uint    Off;
1655     uint    cbSeg;
1656 }
1657  
1658 struct OMFModule {
1659     ushort  ovlNumber;
1660     ushort  iLib;
1661     ushort  cSeg;
1662     char[2]            Style;
1663 }
1664  
1665 struct OMFModuleFull {
1666     ushort  ovlNumber;
1667     ushort  iLib;
1668     ushort  cSeg;
1669     char[2]            Style;
1670     OMFSegDesc      *SegInfo;
1671     char            *Name;
1672 }
1673     
1674 struct OMFSymHash {
1675     ushort  symhash;
1676     ushort  addrhash;
1677     uint    cbSymbol;
1678     uint    cbHSym;
1679     uint    cbHAddr;
1680 }
1681  
1682 struct DATASYM16 {
1683         ushort reclen;  // Record length
1684         ushort rectyp;  // S_LDATA or S_GDATA
1685         int off;        // offset of symbol
1686         ushort seg;     // segment of symbol
1687         ushort typind;  // Type index
1688         byte[1] name;   // Length-prefixed name
1689 }
1690 alias DATASYM16 PUBSYM16;
1691  
1692 
1693 struct IMAGE_DOS_HEADER {      // DOS .EXE header
1694     ushort   e_magic;                     // Magic number
1695     ushort   e_cblp;                      // Bytes on last page of file
1696     ushort   e_cp;                        // Pages in file
1697     ushort   e_crlc;                      // Relocations
1698     ushort   e_cparhdr;                   // Size of header in paragraphs
1699     ushort   e_minalloc;                  // Minimum extra paragraphs needed
1700     ushort   e_maxalloc;                  // Maximum extra paragraphs needed
1701     ushort   e_ss;                        // Initial (relative) SS value
1702     ushort   e_sp;                        // Initial SP value
1703     ushort   e_csum;                      // Checksum
1704     ushort   e_ip;                        // Initial IP value
1705     ushort   e_cs;                        // Initial (relative) CS value
1706     ushort   e_lfarlc;                    // File address of relocation table
1707     ushort   e_ovno;                      // Overlay number
1708     ushort[4]   e_res;                    // Reserved words
1709     ushort   e_oemid;                     // OEM identifier (for e_oeminfo)
1710     ushort   e_oeminfo;                   // OEM information; e_oemid specific
1711     ushort[10]   e_res2;                  // Reserved words
1712     int      e_lfanew;                    // File address of new exe header
1713 }
1714  
1715 struct IMAGE_FILE_HEADER {
1716     ushort    Machine;
1717     ushort    NumberOfSections;
1718     uint      TimeDateStamp;
1719     uint      PointerToSymbolTable;
1720     uint      NumberOfSymbols;
1721     ushort    SizeOfOptionalHeader;
1722     ushort    Characteristics;
1723 }
1724  
1725 struct IMAGE_SEPARATE_DEBUG_HEADER {
1726     ushort        Signature;
1727     ushort        Flags;
1728     ushort        Machine;
1729     ushort        Characteristics;
1730     uint       TimeDateStamp;
1731     uint       CheckSum;
1732     uint       ImageBase;
1733     uint       SizeOfImage;
1734     uint       NumberOfSections;
1735     uint       ExportedNamesSize;
1736     uint       DebugDirectorySize;
1737     uint       SectionAlignment;
1738     uint[2]    Reserved;
1739 }
1740  
1741 struct IMAGE_DATA_DIRECTORY {
1742     uint   VirtualAddress;
1743     uint   Size;
1744 }
1745  
1746 struct IMAGE_OPTIONAL_HEADER {
1747     //
1748     // Standard fields.
1749     //
1750 
1751     ushort    Magic;
1752     byte    MajorLinkerVersion;
1753     byte    MinorLinkerVersion;
1754     uint   SizeOfCode;
1755     uint   SizeOfInitializedData;
1756     uint   SizeOfUninitializedData;
1757     uint   AddressOfEntryPoint;
1758     uint   BaseOfCode;
1759     uint   BaseOfData;
1760 
1761     //
1762     // NT additional fields.
1763     //
1764 
1765     uint   ImageBase;
1766     uint   SectionAlignment;
1767     uint   FileAlignment;
1768     ushort    MajorOperatingSystemVersion;
1769     ushort    MinorOperatingSystemVersion;
1770     ushort    MajorImageVersion;
1771     ushort    MinorImageVersion;
1772     ushort    MajorSubsystemVersion;
1773     ushort    MinorSubsystemVersion;
1774     uint   Win32VersionValue;
1775     uint   SizeOfImage;
1776     uint   SizeOfHeaders;
1777     uint   CheckSum;
1778     ushort    Subsystem;
1779     ushort    DllCharacteristics;
1780     uint   SizeOfStackReserve;
1781     uint   SizeOfStackCommit;
1782     uint   SizeOfHeapReserve;
1783     uint   SizeOfHeapCommit;
1784     uint   LoaderFlags;
1785     uint   NumberOfRvaAndSizes;
1786 
1787     enum {
1788         IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16,
1789     }
1790 
1791     IMAGE_DATA_DIRECTORY[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] DataDirectory;
1792 }
1793  
1794 struct IMAGE_NT_HEADERS {
1795     uint Signature;
1796     IMAGE_FILE_HEADER FileHeader;
1797     IMAGE_OPTIONAL_HEADER OptionalHeader;
1798 }
1799  
1800 enum {
1801     IMAGE_SIZEOF_SHORT_NAME = 8,
1802 }
1803 
1804 struct IMAGE_SECTION_HEADER {
1805     byte[IMAGE_SIZEOF_SHORT_NAME]    Name;//8
1806     union misc{
1807             uint   PhysicalAddress;
1808             uint   VirtualSize;//12
1809     }
1810     misc Misc;
1811     uint   VirtualAddress;//16
1812     uint   SizeOfRawData;//20
1813     uint   PointerToRawData;//24
1814     uint   PointerToRelocations;//28
1815     uint   PointerToLinenumbers;//32
1816     ushort NumberOfRelocations;//34
1817     ushort NumberOfLinenumbers;//36
1818     uint   Characteristics;//40
1819 }
1820  
1821 struct IMAGE_DEBUG_DIRECTORY {
1822     uint   Characteristics;
1823     uint   TimeDateStamp;
1824     ushort MajorVersion;
1825     ushort MinorVersion;
1826     uint   Type;
1827     uint   SizeOfData;
1828     uint   AddressOfRawData;
1829     uint   PointerToRawData;
1830 }
1831  
1832 struct OMFSourceLine {
1833     ushort  Seg;
1834     ushort  cLnOff;
1835     uint[1]    offset;
1836     ushort[1]  lineNbr;
1837 }
1838  
1839 struct OMFSourceFile {
1840     ushort  cSeg;
1841     ushort  reserved;
1842     uint[1]    baseSrcLn;
1843     ushort  cFName;
1844     char    Name;
1845 }
1846  
1847 struct OMFSourceModule {
1848     ushort  cFile;
1849     ushort  cSeg;
1850     uint[1]    baseSrcFile;
1851 }
1852 //#line 2 "parts/CInterface.di"
1853 extern (C) {
1854     ModuleDebugInfo ModuleDebugInfo_new() {
1855         return new ModuleDebugInfo;
1856     }
1857     
1858     void ModuleDebugInfo_addDebugInfo(ModuleDebugInfo minfo, size_t addr, char* file, char* func, ushort line) {
1859         minfo.addDebugInfo(addr, file, func, line);
1860     }
1861     
1862     char* ModuleDebugInfo_bufferString(ModuleDebugInfo minfo, char[] str) {
1863         char[] res;
1864         res.alloc(str.length+1, false);
1865         res[0..$-1] = str[];
1866         res[str.length] = 0;
1867         minfo.strBuffer.append(res.ptr, &minfo.strBufferLen);
1868         return res.ptr;
1869     }
1870     
1871     void GlobalDebugInfo_addDebugInfo(ModuleDebugInfo minfo) {
1872         globalDebugInfo.addDebugInfo(minfo);
1873     }
1874     
1875     void GlobalDebugInfo_removeDebugInfo(ModuleDebugInfo minfo) {
1876         globalDebugInfo.removeDebugInfo(minfo);
1877     }
1878 }
1879 //#line 2 "parts/Init.di"
1880 shared static this() {
1881     loadWinAPIFunctions();
1882 
1883     for (fiberRunFuncLength = 0; fiberRunFuncLength < 0x100; ++fiberRunFuncLength) {
1884         ubyte* ptr = cast(ubyte*)&D4core6thread5Fiber3runMFZv + fiberRunFuncLength;
1885         enum {
1886             RetOpcode = 0xc3
1887         }
1888         if (IsBadReadPtr(ptr, 1) || RetOpcode == *ptr) {
1889             break;
1890         }
1891     }
1892     
1893     version (StacktraceSpam) printf ("found Thread.Fiber.run at %p with length %x",
1894             &D4core6thread5Fiber3runMFZv, fiberRunFuncLength);
1895 
1896     char[512] modNameBuf = 0;
1897     int modNameLen = GetModuleFileNameExA(GetCurrentProcess(), null, modNameBuf.ptr, modNameBuf.length-1);
1898     char[] modName = modNameBuf[0..modNameLen];
1899     SymSetOptions(SYMOPT_DEFERRED_LOADS/+ | SYMOPT_UNDNAME+/);
1900     SymInitialize(GetCurrentProcess(), null, false);
1901     DWORD64 base;
1902     if (0 == (base = SymLoadModule64(GetCurrentProcess(), HANDLE.init, modName.ptr, null, 0, 0))) {
1903         if (SysError.lastCode != 0) {
1904             throw new Exception("Could not SymLoadModule64: " ~ SysError.lastMsg.idup);
1905         }
1906     }
1907 
1908     size_t slash_idx;
1909     for(slash_idx = modName.length - 1; slash_idx >= 0; slash_idx--)
1910     {
1911         if(modName[slash_idx] == '\\')
1912             break;
1913     }
1914     auto sym_name = modName[slash_idx + 1..$-4] ~ "!__initLGPLHostExecutableDebugInfo\0";
1915 
1916     SYMBOL_INFO sym;
1917     sym.SizeOfStruct = SYMBOL_INFO.sizeof; 
1918 
1919     extern(C) void function(const(char)[]) initTrace;
1920     if (SymFromName(GetCurrentProcess(), sym_name.ptr, &sym)) {
1921         initTrace = cast(typeof(initTrace))sym.Address;
1922         assert (initTrace !is null); 
1923         initTrace(modName);
1924     } else {
1925         throw new Exception ("Can't initialize the TangoTrace LGPL stuff");
1926     }
1927 }
1928 
1929 }