implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / extra / msvc_dbg.c
diff --git a/gc-7.2/extra/msvc_dbg.c b/gc-7.2/extra/msvc_dbg.c
new file mode 100644 (file)
index 0000000..5bc216a
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+  Copyright (c) 2004 Andrei Polushin
+
+  Permission is hereby granted, free of charge,  to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction,  including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#if !defined(_M_AMD64) && defined(_MSC_VER)
+
+/* X86_64 is currently missing some meachine-dependent code below.  */
+
+#include "private/msvc_dbg.h"
+
+#include "gc.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#pragma pack(push, 8)
+#include <imagehlp.h>
+#pragma pack(pop)
+
+#pragma comment(lib, "dbghelp.lib")
+#pragma optimize("gy", off)
+
+typedef GC_word word;
+#define GC_ULONG_PTR word
+
+#ifdef _WIN64
+        typedef GC_ULONG_PTR ULONG_ADDR;
+#else
+        typedef ULONG        ULONG_ADDR;
+#endif
+
+static HANDLE GetSymHandle()
+{
+  static HANDLE symHandle = NULL;
+  if (!symHandle) {
+    BOOL bRet = SymInitialize(symHandle = GetCurrentProcess(), NULL, FALSE);
+    if (bRet) {
+      DWORD dwOptions = SymGetOptions();
+      dwOptions &= ~SYMOPT_UNDNAME;
+      dwOptions |= SYMOPT_LOAD_LINES;
+      SymSetOptions(dwOptions);
+    }
+  }
+  return symHandle;
+}
+
+static void* CALLBACK FunctionTableAccess(HANDLE hProcess,
+                                          ULONG_ADDR dwAddrBase)
+{
+  return SymFunctionTableAccess(hProcess, dwAddrBase);
+}
+
+static ULONG_ADDR CALLBACK GetModuleBase(HANDLE hProcess, ULONG_ADDR dwAddress)
+{
+  MEMORY_BASIC_INFORMATION memoryInfo;
+  ULONG_ADDR dwAddrBase = SymGetModuleBase(hProcess, dwAddress);
+  if (dwAddrBase) {
+    return dwAddrBase;
+  }
+  if (VirtualQueryEx(hProcess, (void*)(GC_ULONG_PTR)dwAddress, &memoryInfo,
+                     sizeof(memoryInfo))) {
+    char filePath[_MAX_PATH];
+    char curDir[_MAX_PATH];
+    char exePath[_MAX_PATH];
+    DWORD size = GetModuleFileNameA((HINSTANCE)memoryInfo.AllocationBase,
+                                    filePath, sizeof(filePath));
+
+    /* Save and restore current directory around SymLoadModule, see KB  */
+    /* article Q189780.                                                 */
+    GetCurrentDirectoryA(sizeof(curDir), curDir);
+    GetModuleFileNameA(NULL, exePath, sizeof(exePath));
+#if defined(_MSC_VER) && _MSC_VER == 1200
+    /* use strcat for VC6 */
+    strcat(exePath, "\\..");
+#else
+    strcat_s(exePath, sizeof(exePath), "\\..");
+#endif /* _MSC_VER >= 1200 */
+    SetCurrentDirectoryA(exePath);
+#ifdef _DEBUG
+    GetCurrentDirectoryA(sizeof(exePath), exePath);
+#endif
+    SymLoadModule(hProcess, NULL, size ? filePath : NULL, NULL,
+                  (ULONG_ADDR)(GC_ULONG_PTR)memoryInfo.AllocationBase, 0);
+    SetCurrentDirectoryA(curDir);
+  }
+  return (ULONG_ADDR)(GC_ULONG_PTR)memoryInfo.AllocationBase;
+}
+
+static ULONG_ADDR CheckAddress(void* address)
+{
+  ULONG_ADDR dwAddress = (ULONG_ADDR)(GC_ULONG_PTR)address;
+  GetModuleBase(GetSymHandle(), dwAddress);
+  return dwAddress;
+}
+
+size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames)
+{
+  HANDLE hProcess = GetSymHandle();
+  HANDLE hThread = GetCurrentThread();
+  CONTEXT context;
+  context.ContextFlags = CONTEXT_FULL;
+  if (!GetThreadContext(hThread, &context)) {
+    return 0;
+  }
+  /* GetThreadContext might return invalid context for the current thread. */
+#if defined(_M_IX86)
+    __asm mov context.Ebp, ebp
+#endif
+  return GetStackFramesFromContext(hProcess, hThread, &context, skip + 1,
+                                   frames, maxFrames);
+}
+
+size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread,
+                                 CONTEXT* context, size_t skip,
+                                 void* frames[], size_t maxFrames)
+{
+  size_t frameIndex;
+  DWORD machineType;
+  STACKFRAME stackFrame = { 0 };
+  stackFrame.AddrPC.Mode      = AddrModeFlat;
+#if defined(_M_IX86)
+  machineType                 = IMAGE_FILE_MACHINE_I386;
+  stackFrame.AddrPC.Offset    = context->Eip;
+  stackFrame.AddrStack.Mode   = AddrModeFlat;
+  stackFrame.AddrStack.Offset = context->Esp;
+  stackFrame.AddrFrame.Mode   = AddrModeFlat;
+  stackFrame.AddrFrame.Offset = context->Ebp;
+#elif defined(_M_MRX000)
+  machineType                 = IMAGE_FILE_MACHINE_R4000;
+  stackFrame.AddrPC.Offset    = context->Fir;
+#elif defined(_M_ALPHA)
+  machineType                 = IMAGE_FILE_MACHINE_ALPHA;
+  stackFrame.AddrPC.Offset    = (unsigned long)context->Fir;
+#elif defined(_M_PPC)
+  machineType                 = IMAGE_FILE_MACHINE_POWERPC;
+  stackFrame.AddrPC.Offset    = context->Iar;
+#elif defined(_M_IA64)
+  machineType                 = IMAGE_FILE_MACHINE_IA64;
+  stackFrame.AddrPC.Offset    = context->StIIP;
+#elif defined(_M_ALPHA64)
+  machineType                 = IMAGE_FILE_MACHINE_ALPHA64;
+  stackFrame.AddrPC.Offset    = context->Fir;
+#else
+#error Unknown CPU
+#endif
+  for (frameIndex = 0; frameIndex < maxFrames; ) {
+    BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame,
+                    &context, NULL, FunctionTableAccess, GetModuleBase, NULL);
+    if (!bRet) {
+      break;
+    }
+    if (skip) {
+      skip--;
+    } else {
+      frames[frameIndex++] = (void*)(GC_ULONG_PTR)stackFrame.AddrPC.Offset;
+    }
+  }
+  return frameIndex;
+}
+
+size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size)
+{
+  if (size) *moduleName = 0;
+  {
+    const char* sourceName;
+    IMAGEHLP_MODULE moduleInfo = { sizeof (moduleInfo) };
+    if (!SymGetModuleInfo(GetSymHandle(), CheckAddress(address),
+                          &moduleInfo)) {
+      return 0;
+    }
+    sourceName = strrchr(moduleInfo.ImageName, '\\');
+    if (sourceName) {
+      sourceName++;
+    } else {
+      sourceName = moduleInfo.ImageName;
+    }
+    if (size) {
+      strncpy(moduleName, sourceName, size)[size - 1] = 0;
+    }
+    return strlen(sourceName);
+  }
+}
+
+size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size)
+{
+  void* address = NULL;
+  GetStackFrames(skip + 1, &address, 1);
+  if (address) {
+    return GetModuleNameFromAddress(address, moduleName, size);
+  }
+  return 0;
+}
+
+size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size,
+                                size_t* offsetBytes)
+{
+  if (size) *symbolName = 0;
+  if (offsetBytes) *offsetBytes = 0;
+  __try {
+    ULONG_ADDR dwOffset = 0;
+    union {
+      IMAGEHLP_SYMBOL sym;
+      char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME];
+    } u;
+    u.sym.SizeOfStruct  = sizeof(u.sym);
+    u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym);
+
+    if (!SymGetSymFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset,
+                           &u.sym)) {
+      return 0;
+    } else {
+      const char* sourceName = u.sym.Name;
+      char undName[1024];
+      if (UnDecorateSymbolName(u.sym.Name, undName, sizeof(undName),
+                UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)) {
+        sourceName = undName;
+      } else if (SymUnDName(&u.sym, undName, sizeof(undName))) {
+        sourceName = undName;
+      }
+      if (offsetBytes) {
+        *offsetBytes = dwOffset;
+      }
+      if (size) {
+        strncpy(symbolName, sourceName, size)[size - 1] = 0;
+      }
+      return strlen(sourceName);
+    }
+  } __except (EXCEPTION_EXECUTE_HANDLER) {
+    SetLastError(GetExceptionCode());
+  }
+  return 0;
+}
+
+size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size,
+                              size_t* offsetBytes)
+{
+  void* address = NULL;
+  GetStackFrames(skip + 1, &address, 1);
+  if (address) {
+    return GetSymbolNameFromAddress(address, symbolName, size, offsetBytes);
+  }
+  return 0;
+}
+
+size_t GetFileLineFromAddress(void* address, char* fileName, size_t size,
+                              size_t* lineNumber, size_t* offsetBytes)
+{
+  if (size) *fileName = 0;
+  if (lineNumber) *lineNumber = 0;
+  if (offsetBytes) *offsetBytes = 0;
+  {
+    char* sourceName;
+    IMAGEHLP_LINE line = { sizeof (line) };
+    GC_ULONG_PTR dwOffset = 0;
+    if (!SymGetLineFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset,
+                            &line)) {
+      return 0;
+    }
+    if (lineNumber) {
+      *lineNumber = line.LineNumber;
+    }
+    if (offsetBytes) {
+      *offsetBytes = dwOffset;
+    }
+    sourceName = line.FileName;
+    /* TODO: resolve relative filenames, found in 'source directories'  */
+    /* registered with MSVC IDE.                                        */
+    if (size) {
+      strncpy(fileName, sourceName, size)[size - 1] = 0;
+    }
+    return strlen(sourceName);
+  }
+}
+
+size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size,
+                            size_t* lineNumber, size_t* offsetBytes)
+{
+  void* address = NULL;
+  GetStackFrames(skip + 1, &address, 1);
+  if (address) {
+    return GetFileLineFromAddress(address, fileName, size, lineNumber,
+                                  offsetBytes);
+  }
+  return 0;
+}
+
+size_t GetDescriptionFromAddress(void* address, const char* format,
+                                 char* buffer, size_t size)
+{
+  char*const begin = buffer;
+  char*const end = buffer + size;
+  size_t line_number = 0;
+  char   str[128];
+
+  if (size) {
+    *buffer = 0;
+  }
+  buffer += GetFileLineFromAddress(address, buffer, size, &line_number, NULL);
+  size = end < buffer ? 0 : end - buffer;
+
+  if (line_number) {
+    wsprintf(str, "(%d) : ", line_number);
+    if (size) {
+      strncpy(buffer, str, size)[size - 1] = 0;
+    }
+    buffer += strlen(str);
+    size = end < buffer ? 0 : end - buffer;
+  }
+
+  if (size) {
+    strncpy(buffer, "at ", size)[size - 1] = 0;
+  }
+  buffer += strlen("at ");
+  size = end < buffer ? 0 : end - buffer;
+
+  buffer += GetSymbolNameFromAddress(address, buffer, size, NULL);
+  size = end < buffer ? 0 : end - buffer;
+
+  if (size) {
+    strncpy(buffer, " in ", size)[size - 1] = 0;
+  }
+  buffer += strlen(" in ");
+  size = end < buffer ? 0 : end - buffer;
+
+  buffer += GetModuleNameFromAddress(address, buffer, size);
+  size = end < buffer ? 0 : end - buffer;
+
+  return buffer - begin;
+}
+
+size_t GetDescriptionFromStack(void* const frames[], size_t count,
+                               const char* format, char* description[],
+                               size_t size)
+{
+  char*const begin = (char*)description;
+  char*const end = begin + size;
+  char* buffer = begin + (count + 1) * sizeof(char*);
+  size_t i;
+  for (i = 0; i < count; ++i) {
+    if (description) description[i] = buffer;
+    size = end < buffer ? 0 : end - buffer;
+    buffer += 1 + GetDescriptionFromAddress(frames[i], NULL, buffer, size);
+  }
+  if (description) description[count] = NULL;
+  return buffer - begin;
+}
+
+/* Compatibility with <execinfo.h> */
+
+int backtrace(void* addresses[], int count)
+{
+  return GetStackFrames(1, addresses, count);
+}
+
+char** backtrace_symbols(void*const* addresses, int count)
+{
+  size_t size = GetDescriptionFromStack(addresses, count, NULL, NULL, 0);
+  char** symbols = (char**)malloc(size);
+  GetDescriptionFromStack(addresses, count, NULL, symbols, size);
+  return symbols;
+}
+
+#endif /* !_M_AMD64 */