implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / extra / msvc_dbg.c
1 /*
2   Copyright (c) 2004 Andrei Polushin
3
4   Permission is hereby granted, free of charge,  to any person obtaining a copy
5   of this software and associated documentation files (the "Software"), to deal
6   in the Software without restriction,  including without limitation the rights
7   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8   copies of the Software, and to permit persons to whom the Software is
9   furnished to do so, subject to the following conditions:
10
11   The above copyright notice and this permission notice shall be included in
12   all copies or substantial portions of the Software.
13
14   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20   THE SOFTWARE.
21 */
22
23 #if !defined(_M_AMD64) && defined(_MSC_VER)
24
25 /* X86_64 is currently missing some meachine-dependent code below.  */
26
27 #include "private/msvc_dbg.h"
28
29 #include "gc.h"
30
31 #define WIN32_LEAN_AND_MEAN
32 #include <windows.h>
33
34 #pragma pack(push, 8)
35 #include <imagehlp.h>
36 #pragma pack(pop)
37
38 #pragma comment(lib, "dbghelp.lib")
39 #pragma optimize("gy", off)
40
41 typedef GC_word word;
42 #define GC_ULONG_PTR word
43
44 #ifdef _WIN64
45         typedef GC_ULONG_PTR ULONG_ADDR;
46 #else
47         typedef ULONG        ULONG_ADDR;
48 #endif
49
50 static HANDLE GetSymHandle()
51 {
52   static HANDLE symHandle = NULL;
53   if (!symHandle) {
54     BOOL bRet = SymInitialize(symHandle = GetCurrentProcess(), NULL, FALSE);
55     if (bRet) {
56       DWORD dwOptions = SymGetOptions();
57       dwOptions &= ~SYMOPT_UNDNAME;
58       dwOptions |= SYMOPT_LOAD_LINES;
59       SymSetOptions(dwOptions);
60     }
61   }
62   return symHandle;
63 }
64
65 static void* CALLBACK FunctionTableAccess(HANDLE hProcess,
66                                           ULONG_ADDR dwAddrBase)
67 {
68   return SymFunctionTableAccess(hProcess, dwAddrBase);
69 }
70
71 static ULONG_ADDR CALLBACK GetModuleBase(HANDLE hProcess, ULONG_ADDR dwAddress)
72 {
73   MEMORY_BASIC_INFORMATION memoryInfo;
74   ULONG_ADDR dwAddrBase = SymGetModuleBase(hProcess, dwAddress);
75   if (dwAddrBase) {
76     return dwAddrBase;
77   }
78   if (VirtualQueryEx(hProcess, (void*)(GC_ULONG_PTR)dwAddress, &memoryInfo,
79                      sizeof(memoryInfo))) {
80     char filePath[_MAX_PATH];
81     char curDir[_MAX_PATH];
82     char exePath[_MAX_PATH];
83     DWORD size = GetModuleFileNameA((HINSTANCE)memoryInfo.AllocationBase,
84                                     filePath, sizeof(filePath));
85
86     /* Save and restore current directory around SymLoadModule, see KB  */
87     /* article Q189780.                                                 */
88     GetCurrentDirectoryA(sizeof(curDir), curDir);
89     GetModuleFileNameA(NULL, exePath, sizeof(exePath));
90 #if defined(_MSC_VER) && _MSC_VER == 1200
91     /* use strcat for VC6 */
92     strcat(exePath, "\\..");
93 #else
94     strcat_s(exePath, sizeof(exePath), "\\..");
95 #endif /* _MSC_VER >= 1200 */
96     SetCurrentDirectoryA(exePath);
97 #ifdef _DEBUG
98     GetCurrentDirectoryA(sizeof(exePath), exePath);
99 #endif
100     SymLoadModule(hProcess, NULL, size ? filePath : NULL, NULL,
101                   (ULONG_ADDR)(GC_ULONG_PTR)memoryInfo.AllocationBase, 0);
102     SetCurrentDirectoryA(curDir);
103   }
104   return (ULONG_ADDR)(GC_ULONG_PTR)memoryInfo.AllocationBase;
105 }
106
107 static ULONG_ADDR CheckAddress(void* address)
108 {
109   ULONG_ADDR dwAddress = (ULONG_ADDR)(GC_ULONG_PTR)address;
110   GetModuleBase(GetSymHandle(), dwAddress);
111   return dwAddress;
112 }
113
114 size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames)
115 {
116   HANDLE hProcess = GetSymHandle();
117   HANDLE hThread = GetCurrentThread();
118   CONTEXT context;
119   context.ContextFlags = CONTEXT_FULL;
120   if (!GetThreadContext(hThread, &context)) {
121     return 0;
122   }
123   /* GetThreadContext might return invalid context for the current thread. */
124 #if defined(_M_IX86)
125     __asm mov context.Ebp, ebp
126 #endif
127   return GetStackFramesFromContext(hProcess, hThread, &context, skip + 1,
128                                    frames, maxFrames);
129 }
130
131 size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread,
132                                  CONTEXT* context, size_t skip,
133                                  void* frames[], size_t maxFrames)
134 {
135   size_t frameIndex;
136   DWORD machineType;
137   STACKFRAME stackFrame = { 0 };
138   stackFrame.AddrPC.Mode      = AddrModeFlat;
139 #if defined(_M_IX86)
140   machineType                 = IMAGE_FILE_MACHINE_I386;
141   stackFrame.AddrPC.Offset    = context->Eip;
142   stackFrame.AddrStack.Mode   = AddrModeFlat;
143   stackFrame.AddrStack.Offset = context->Esp;
144   stackFrame.AddrFrame.Mode   = AddrModeFlat;
145   stackFrame.AddrFrame.Offset = context->Ebp;
146 #elif defined(_M_MRX000)
147   machineType                 = IMAGE_FILE_MACHINE_R4000;
148   stackFrame.AddrPC.Offset    = context->Fir;
149 #elif defined(_M_ALPHA)
150   machineType                 = IMAGE_FILE_MACHINE_ALPHA;
151   stackFrame.AddrPC.Offset    = (unsigned long)context->Fir;
152 #elif defined(_M_PPC)
153   machineType                 = IMAGE_FILE_MACHINE_POWERPC;
154   stackFrame.AddrPC.Offset    = context->Iar;
155 #elif defined(_M_IA64)
156   machineType                 = IMAGE_FILE_MACHINE_IA64;
157   stackFrame.AddrPC.Offset    = context->StIIP;
158 #elif defined(_M_ALPHA64)
159   machineType                 = IMAGE_FILE_MACHINE_ALPHA64;
160   stackFrame.AddrPC.Offset    = context->Fir;
161 #else
162 #error Unknown CPU
163 #endif
164   for (frameIndex = 0; frameIndex < maxFrames; ) {
165     BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame,
166                     &context, NULL, FunctionTableAccess, GetModuleBase, NULL);
167     if (!bRet) {
168       break;
169     }
170     if (skip) {
171       skip--;
172     } else {
173       frames[frameIndex++] = (void*)(GC_ULONG_PTR)stackFrame.AddrPC.Offset;
174     }
175   }
176   return frameIndex;
177 }
178
179 size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size)
180 {
181   if (size) *moduleName = 0;
182   {
183     const char* sourceName;
184     IMAGEHLP_MODULE moduleInfo = { sizeof (moduleInfo) };
185     if (!SymGetModuleInfo(GetSymHandle(), CheckAddress(address),
186                           &moduleInfo)) {
187       return 0;
188     }
189     sourceName = strrchr(moduleInfo.ImageName, '\\');
190     if (sourceName) {
191       sourceName++;
192     } else {
193       sourceName = moduleInfo.ImageName;
194     }
195     if (size) {
196       strncpy(moduleName, sourceName, size)[size - 1] = 0;
197     }
198     return strlen(sourceName);
199   }
200 }
201
202 size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size)
203 {
204   void* address = NULL;
205   GetStackFrames(skip + 1, &address, 1);
206   if (address) {
207     return GetModuleNameFromAddress(address, moduleName, size);
208   }
209   return 0;
210 }
211
212 size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size,
213                                 size_t* offsetBytes)
214 {
215   if (size) *symbolName = 0;
216   if (offsetBytes) *offsetBytes = 0;
217   __try {
218     ULONG_ADDR dwOffset = 0;
219     union {
220       IMAGEHLP_SYMBOL sym;
221       char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME];
222     } u;
223     u.sym.SizeOfStruct  = sizeof(u.sym);
224     u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym);
225
226     if (!SymGetSymFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset,
227                            &u.sym)) {
228       return 0;
229     } else {
230       const char* sourceName = u.sym.Name;
231       char undName[1024];
232       if (UnDecorateSymbolName(u.sym.Name, undName, sizeof(undName),
233                 UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)) {
234         sourceName = undName;
235       } else if (SymUnDName(&u.sym, undName, sizeof(undName))) {
236         sourceName = undName;
237       }
238       if (offsetBytes) {
239         *offsetBytes = dwOffset;
240       }
241       if (size) {
242         strncpy(symbolName, sourceName, size)[size - 1] = 0;
243       }
244       return strlen(sourceName);
245     }
246   } __except (EXCEPTION_EXECUTE_HANDLER) {
247     SetLastError(GetExceptionCode());
248   }
249   return 0;
250 }
251
252 size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size,
253                               size_t* offsetBytes)
254 {
255   void* address = NULL;
256   GetStackFrames(skip + 1, &address, 1);
257   if (address) {
258     return GetSymbolNameFromAddress(address, symbolName, size, offsetBytes);
259   }
260   return 0;
261 }
262
263 size_t GetFileLineFromAddress(void* address, char* fileName, size_t size,
264                               size_t* lineNumber, size_t* offsetBytes)
265 {
266   if (size) *fileName = 0;
267   if (lineNumber) *lineNumber = 0;
268   if (offsetBytes) *offsetBytes = 0;
269   {
270     char* sourceName;
271     IMAGEHLP_LINE line = { sizeof (line) };
272     GC_ULONG_PTR dwOffset = 0;
273     if (!SymGetLineFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset,
274                             &line)) {
275       return 0;
276     }
277     if (lineNumber) {
278       *lineNumber = line.LineNumber;
279     }
280     if (offsetBytes) {
281       *offsetBytes = dwOffset;
282     }
283     sourceName = line.FileName;
284     /* TODO: resolve relative filenames, found in 'source directories'  */
285     /* registered with MSVC IDE.                                        */
286     if (size) {
287       strncpy(fileName, sourceName, size)[size - 1] = 0;
288     }
289     return strlen(sourceName);
290   }
291 }
292
293 size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size,
294                             size_t* lineNumber, size_t* offsetBytes)
295 {
296   void* address = NULL;
297   GetStackFrames(skip + 1, &address, 1);
298   if (address) {
299     return GetFileLineFromAddress(address, fileName, size, lineNumber,
300                                   offsetBytes);
301   }
302   return 0;
303 }
304
305 size_t GetDescriptionFromAddress(void* address, const char* format,
306                                  char* buffer, size_t size)
307 {
308   char*const begin = buffer;
309   char*const end = buffer + size;
310   size_t line_number = 0;
311   char   str[128];
312
313   if (size) {
314     *buffer = 0;
315   }
316   buffer += GetFileLineFromAddress(address, buffer, size, &line_number, NULL);
317   size = end < buffer ? 0 : end - buffer;
318
319   if (line_number) {
320     wsprintf(str, "(%d) : ", line_number);
321     if (size) {
322       strncpy(buffer, str, size)[size - 1] = 0;
323     }
324     buffer += strlen(str);
325     size = end < buffer ? 0 : end - buffer;
326   }
327
328   if (size) {
329     strncpy(buffer, "at ", size)[size - 1] = 0;
330   }
331   buffer += strlen("at ");
332   size = end < buffer ? 0 : end - buffer;
333
334   buffer += GetSymbolNameFromAddress(address, buffer, size, NULL);
335   size = end < buffer ? 0 : end - buffer;
336
337   if (size) {
338     strncpy(buffer, " in ", size)[size - 1] = 0;
339   }
340   buffer += strlen(" in ");
341   size = end < buffer ? 0 : end - buffer;
342
343   buffer += GetModuleNameFromAddress(address, buffer, size);
344   size = end < buffer ? 0 : end - buffer;
345
346   return buffer - begin;
347 }
348
349 size_t GetDescriptionFromStack(void* const frames[], size_t count,
350                                const char* format, char* description[],
351                                size_t size)
352 {
353   char*const begin = (char*)description;
354   char*const end = begin + size;
355   char* buffer = begin + (count + 1) * sizeof(char*);
356   size_t i;
357   for (i = 0; i < count; ++i) {
358     if (description) description[i] = buffer;
359     size = end < buffer ? 0 : end - buffer;
360     buffer += 1 + GetDescriptionFromAddress(frames[i], NULL, buffer, size);
361   }
362   if (description) description[count] = NULL;
363   return buffer - begin;
364 }
365
366 /* Compatibility with <execinfo.h> */
367
368 int backtrace(void* addresses[], int count)
369 {
370   return GetStackFrames(1, addresses, count);
371 }
372
373 char** backtrace_symbols(void*const* addresses, int count)
374 {
375   size_t size = GetDescriptionFromStack(addresses, count, NULL, NULL, 0);
376   char** symbols = (char**)malloc(size);
377   GetDescriptionFromStack(addresses, count, NULL, symbols, size);
378   return symbols;
379 }
380
381 #endif /* !_M_AMD64 */